You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决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)
原因分析

问题核心在于异步流响应的时序不匹配:

  1. await chat.append_message_stream(response) 是异步流式输出AI响应,但该方法不会等待所有流内容完全渲染到DOM中就会返回,只是启动了流式写入的过程。
  2. 紧接着调用的await session.send_custom_message("typeset", {"msg": "dummy"})会立刻触发MathJax的Typeset操作,此时当前新消息的DOM内容还未完全加载完成,MathJax无法识别这条新消息里的LaTeX公式。
  3. 当用户提交下一次请求时,再次触发Typeset操作,此时上一条未被处理的消息已经完全加载到DOM中,MathJax才会处理它的公式,从而出现“延迟一次渲染”的现象。

简单来说:触发MathJax渲染的时机过早,早于当前流式消息完全写入DOM的时间点,导致当前消息的公式没被处理,只能等下一次渲染时机到来时才被处理。

内容的提问来源于stack exchange,提问作者sbik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 22:52:42