如何解决Shiny Chat中LaTeX公式渲染的时序延迟问题?
问题
实现可渲染LaTeX公式的聊天机器人时出现时序异常:当前响应的公式未被LaTeX格式化,而上一条响应的格式却正常。即请求1的格式化效果需在提交请求2后才显现,请求2的格式化需提交请求3后完成。例如,针对“solve $x^2-4=0$”的第二次回复返回的是LaTeX代码而非渲染后的公式。相关实现代码如下:
import os from app_utils import load_dotenv from openai import AsyncOpenAI from langchain_openai import ChatOpenAI load_dotenv() llm = AsyncOpenAI(api_key=os.environ.get("OPENAI_API_KEY")) from shiny import App, Inputs, Outputs, Session, ui mathjax = ui.head_content( ui.tags.script( src="https://mathjax.rstudio.com/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML" ), ui.tags.script("""if (window.MathJax) { MathJax.Hub.Config({ tex2jax: { inlineMath: [["$", "$"], ["\\(", "\\)"]], displayMath: [["$$", "$$"], ["\\[", "\\]"]], processEscapes: true }, config: ["MMLorHTML.js"], jax: ["input/TeX", "output/HTML-CSS", "output/NativeMML"], extensions: ["MathMenu.js", "MathZoom.js"] }); $(function() { Shiny.addCustomMessageHandler("typeset", function(message) { MathJax.Hub.Queue(['Typeset', MathJax.Hub]); }); }); } """), ) app_ui = ui.page_fillable( mathjax, ui.panel_title("Demo Shiny Chat"), ui.chat_ui("chat"), fillable_mobile=True, ) def server(input: Inputs, output: Outputs, session: Session): # Create a chat instance and display it system_message = { "content": f""" act like a math teacher """, "role": "system" } chat = ui.Chat(id="chat", messages=[system_message, {"content": "I am here to answer your math questions!", "role": "assistant"}, ],) model_params = { "model": "gpt-4o", "temperature": 1, "max_tokens": 4096, } llm = ChatOpenAI(**model_params) @chat.on_user_submit async def _(): messages = chat.messages(format="langchain") response = llm.astream(messages) await chat.append_message_stream(response) await session.send_custom_message("typeset", {"msg": "dummy"}) app = App(app_ui, server)
原因分析
问题核心在于异步流响应的时序不匹配:
await chat.append_message_stream(response)是异步流式输出AI响应,但该方法不会等待所有流内容完全渲染到DOM中就会返回,只是启动了流式写入的过程。- 紧接着调用的
await session.send_custom_message("typeset", {"msg": "dummy"})会立刻触发MathJax的Typeset操作,此时当前新消息的DOM内容还未完全加载完成,MathJax无法识别这条新消息里的LaTeX公式。 - 当用户提交下一次请求时,再次触发Typeset操作,此时上一条未被处理的消息已经完全加载到DOM中,MathJax才会处理它的公式,从而出现“延迟一次渲染”的现象。
简单来说:触发MathJax渲染的时机过早,早于当前流式消息完全写入DOM的时间点,导致当前消息的公式没被处理,只能等下一次渲染时机到来时才被处理。
内容的提问来源于stack exchange,提问作者sbik
相关产品推荐
相关产品推荐

