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

基于NiceGUI的Gemini流式聊天机器人重复处理历史消息问题

解决Gemini-Pro流式聊天重复处理历史消息的问题

核心问题分析

  1. 每次刷新chat_messages组件时,会遍历所有历史消息,对每条标记为"Bot"的消息重新调用Gemini-Pro生成回复,导致重复处理历史提问
  2. send函数逻辑错误,直接将用户消息作为Bot消息加入列表,没有正确触发单次回复生成流程

修复方案及代码修改

以下是修正后的核心代码:

import asyncio
from typing import List, Tuple
import vertexai
from vertexai.generative_models import GenerativeModel, ChatSession
from nicegui import ui, context

PROJECT_ID = "你的项目ID"
LOCATION = "你的区域"

vertexai.init(project=PROJECT_ID, location=LOCATION)
model = GenerativeModel("gemini-pro")
chat = model.start_chat()

async def get_async_chat_response(chat: ChatSession, prompt: str):
    response = await chat.send_message_async(prompt, stream=True)
    async for chunk in response:
        if chunk.text:
            yield chunk.text

messages: List[Tuple[str, str]] = []
pending_prompt: str | None = None

@ui.refreshable
async def chat_messages() -> None:
    # 渲染所有已完成的消息
    for name, text in messages:
        avatar = "👤" if name == 'You' else "🤖"  # 替换为你的头像资源
        ui.chat_message(avatar=avatar, name=name, text=text, sent=name == 'You')
    
    # 处理当前待回复的请求
    if pending_prompt:
        spinner = ui.spinner(size='3rem').classes('self-center')
        # 生成流式回复
        bot_response = ""
        response_label = ui.label().classes('max-w-full')
        async for chunk in get_async_chat_response(chat, pending_prompt):
            bot_response += chunk
            response_label.text = bot_response
            await asyncio.sleep(0.01)  # 确保UI实时更新
        spinner.delete()
        # 将完成的回复加入消息列表,清除待处理状态
        messages.append(('Bot', bot_response))
        global pending_prompt
        pending_prompt = None
        chat_messages.refresh()
    
    # 滚动到底部
    if context.get_client().has_socket_connection:
        ui.run_javascript('window.scrollTo(0, document.body.scrollHeight)')
        ui.run_javascript('history.scrollRestoration = "manual"')

async def send() -> None:
    global pending_prompt
    message = text.value.strip()
    if not message or pending_prompt:
        return  # 避免重复发送空消息或重复请求
    # 添加用户消息到列表
    messages.append(('You', message))
    text.value = ''
    # 设置待处理的提问,触发组件刷新
    pending_prompt = message
    chat_messages.refresh()

# 构建UI(假设tabs和chat_tab已定义)
with ui.tab_panels(tabs, value=chat_tab).classes('w-full max-w-2xl mx-auto flex-grow items-stretch'):
    with ui.tab_panel(chat_tab).classes('items-stretch'):
        chat_messages()
        with ui.footer().classes('bg-white'):
            with ui.row().classes('w-full max-w-2xl mx-auto items-center'):
                text = ui.input(placeholder='输入消息...').props('rounded outlined input-class=mx-3').classes('flex-grow')
                ui.button('发送', on_click=send).props('rounded')

ui.run(title='Gemini-Pro 流式聊天机器人')

关键修改说明

  • 新增pending_prompt变量:仅存储当前待处理的用户提问,避免重复触发模型调用
  • 拆分渲染与生成逻辑:chat_messages先渲染所有已完成的历史消息,再单独处理当前待回复的请求,流式生成并实时更新UI
  • 修正send函数:仅负责提交用户消息、标记待处理状态,不直接操作Bot消息列表,由组件自动处理回复生成和追加
  • 移除历史消息重复生成:不再遍历所有Bot消息调用模型,仅处理当前pending的提问

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 20:00:27