Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import os | |
| import time | |
| # ------------------------------------------------------------------ | |
| # 1. 加载环境变量 (在Hugging Face Spaces中从Secrets加载) | |
| # ------------------------------------------------------------------ | |
| # 使用os.environ.get()来安全地获取,如果没有设置,可以给一个默认值或报错 | |
| # 这里假设你在Hugging Face Spaces的Secrets中设置了'GEMINI_API_KEY' | |
| api_key = os.environ.get("GEMINI_API_KEY") | |
| if not api_key: | |
| print("警告:未找到 GEMINI_API_KEY。请在Hugging Face Spaces的Secrets中设置它。") | |
| # 为了本地测试,可以从.env文件加载(需要安装python-dotenv) | |
| # from dotenv import load_dotenv | |
| # load_dotenv() | |
| # api_key = os.environ.get("GEMINI_API_KEY") | |
| # ------------------------------------------------------------------ | |
| # 2. 初始化后端 (这是整个系统的启动点) | |
| # ------------------------------------------------------------------ | |
| print("--- 正在启动 AI 助理系统 ---") | |
| # 导入我们的核心模块 | |
| # 使用try...except来处理可能的导入错误,这在调试时很有用 | |
| try: | |
| from database.setup import initialize_system | |
| from core.agent import SmartAIAgent | |
| print("核心模块导入成功。") | |
| except ImportError as e: | |
| print(f"导入模块时出错: {e}") | |
| print("请确保所有项目文件都已正确放置。") | |
| # 如果导入失败,系统无法运行,这里可以抛出异常或退出 | |
| raise | |
| # 执行一次性的系统初始化(创建数据库、向量索引、加载工具等) | |
| # 这个函数应该被设计为幂等的,即多次运行不会产生副作用 | |
| try: | |
| # initialize_system() 函数将负责所有数据库和向量库的设置 | |
| # 它会返回一个已注册工具的列表或其他必要信息 | |
| registered_tools, tool_recommender = initialize_system() | |
| print("系统数据库和工具推荐器初始化完成。") | |
| # 创建 AI 智能体实例,并将推荐器和工具传递给它 | |
| # Agent需要知道所有可以执行的工具函数 | |
| agent = SmartAIAgent( | |
| tool_recommender=tool_recommender, | |
| registered_tools=registered_tools, | |
| api_key=api_key, | |
| ) | |
| print("AI 智能体核心已成功创建。") | |
| except Exception as e: | |
| print(f"系统初始化过程中发生严重错误: {e}") | |
| agent = None # 标记Agent不可用 | |
| # 在Gradio界面上可以显示错误信息 | |
| print("--- AI 助理系统已准备就绪 ---") | |
| # ------------------------------------------------------------------ | |
| # 3. Gradio 事件处理函数 | |
| # ------------------------------------------------------------------ | |
| def handle_user_message(user_input, history): | |
| """ | |
| 当用户发送消息时,此函数首先被调用。 | |
| 它将用户的消息添加到聊天历史记录中。 | |
| """ | |
| if not user_input.strip(): | |
| # 如果用户输入为空,不做任何事 | |
| return "", history | |
| # 将用户消息和一条空的机器人消息占位符添加到历史 | |
| history.append((user_input, None)) | |
| # 返回空字符串以清空输入框,并返回更新后的历史记录 | |
| return "", history | |
| def generate_bot_response(history): | |
| """ | |
| 此函数以流式方式生成机器人的响应。 | |
| 它调用Agent核心来处理最新的用户消息。 | |
| """ | |
| if agent is None: | |
| # 如果Agent初始化失败,返回错误信息 | |
| history[-1][1] = "抱歉,AI助理系统初始化失败,无法提供服务。" | |
| yield history | |
| return | |
| # 获取最新的用户问题 | |
| user_question = history[-1][0] | |
| # 初始化一个空的机器人消息 | |
| bot_message = "" | |
| history[-1][1] = bot_message | |
| try: | |
| # 调用Agent的流式处理方法 | |
| # agent.stream_run() 应该是一个生成器,逐步yield出思考过程和最终答案 | |
| for chunk in agent.stream_run(user_question): | |
| # 将每个新的文本块追加到机器人消息中 | |
| bot_message += chunk | |
| # 更新历史记录中最后一个元组的机器人部分 | |
| history[-1][1] = bot_message | |
| # yield更新后的历史记录,Gradio会用它来刷新界面 | |
| yield history | |
| # (可选) 增加一个微小的延迟,让流式效果更明显 | |
| time.sleep(0.01) | |
| except Exception as e: | |
| # 如果在处理过程中发生错误,将错误信息显示给用户 | |
| error_message = f"\n\n抱歉,处理您的请求时发生了错误:\n`{str(e)}`" | |
| history[-1][1] += error_message | |
| yield history | |
| # ------------------------------------------------------------------ | |
| # 4. 创建 Gradio 界面 | |
| # ------------------------------------------------------------------ | |
| # 自定义CSS来美化界面 | |
| custom_css = """ | |
| /* 简单的CSS自定义,让界面更好看 */ | |
| #chatbot .user { | |
| background-color: #E0F7FA; /* 浅青色背景 */ | |
| } | |
| #chatbot .bot { | |
| background-color: #F1F8E9; /* 浅绿色背景 */ | |
| } | |
| """ | |
| with gr.Blocks( | |
| theme=gr.themes.Soft(primary_hue="teal", secondary_hue="lime"), | |
| css=custom_css, | |
| title="智能 AI 助理", | |
| ) as demo: | |
| gr.Markdown( | |
| """ | |
| # 🚀 智能 AI 助理 Demo | |
| ### (LangChain + LlamaIndex + Gemini) | |
| 这是一个演示如何结合 LangChain (智能体编排) 和 LlamaIndex (工具检索) 构建高级AI助理的Demo。 | |
| - **提问:** 在下面的文本框中输入你的问题。 | |
| - **观察:** 观察AI的思考过程,包括它如何推荐、选择和调用工具。 | |
| """ | |
| ) | |
| chatbot = gr.Chatbot( | |
| [], | |
| elem_id="chatbot", | |
| label="聊天窗口", | |
| bubble_full_width=False, | |
| height=650, | |
| avatar_images=( | |
| None, | |
| "https://raw.githubusercontent.com/gradio-app/gradio/main/guides/assets/logo.png", | |
| ), # 机器人用Gradio logo | |
| ) | |
| with gr.Row(): | |
| text_input = gr.Textbox( | |
| scale=4, | |
| show_label=False, | |
| placeholder="例如: '苹果公司(AAPL)今天的股价是多少?' 或 '关于AI的最新进展有什么新闻?'", | |
| container=False, | |
| ) | |
| submit_button = gr.Button("发送", variant="primary", scale=1, min_width=150) | |
| # 示例问题,方便用户快速体验 | |
| gr.Examples( | |
| examples=[ | |
| "苹果公司(AAPL)的股价是多少?", | |
| "关于AI驱动的药物发现有什么最新新闻?", | |
| "你好,你能做什么?", | |
| "用Python写一个快速排序算法", # 测试不使用工具的场景 | |
| ], | |
| inputs=text_input, | |
| ) | |
| # 定义事件的触发流程 | |
| # 当用户提交输入时(点击按钮或按回车) | |
| submit_event = text_input.submit( | |
| fn=handle_user_message, | |
| inputs=[text_input, chatbot], | |
| outputs=[text_input, chatbot], | |
| queue=False, # 立即执行,不排队 | |
| ).then( | |
| fn=generate_bot_response, | |
| inputs=[chatbot], | |
| outputs=[chatbot], | |
| ) | |
| submit_button.click( | |
| fn=handle_user_message, | |
| inputs=[text_input, chatbot], | |
| outputs=[text_input, chatbot], | |
| queue=False, | |
| ).then( | |
| fn=generate_bot_response, | |
| inputs=[chatbot], | |
| outputs=[chatbot], | |
| ) | |
| # ------------------------------------------------------------------ | |
| # 5. 启动应用 | |
| # ------------------------------------------------------------------ | |
| if __name__ == "__main__": | |
| # 使用 .queue() 来允许多个用户同时使用,这在Hugging Face Spaces上是推荐做法 | |
| demo.queue() | |
| # .launch() 会启动Web服务器 | |
| # 在Hugging Face Spaces上,它会自动找到并运行这个 | |
| demo.launch(debug=True) # debug=True可以在本地看到更详细的日志 | |