Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import requests | |
| import json | |
| import uuid | |
| import logging | |
| import os | |
| # 配置日志 | |
| logging.basicConfig(level=logging.DEBUG) | |
| logger = logging.getLogger(__name__) | |
| class FastGPTChat: | |
| """ | |
| def __init__(self, api_key="", | |
| system_prompt="我是一名AI用药咨询顾问,请向我提问有关用药的问题"): | |
| self.api_key = api_key | |
| self.base_url = "https://api.fastgpt.in/api" | |
| self.system_prompt = system_prompt | |
| self.headers = { | |
| "Authorization": f"Bearer {api_key}", | |
| "Content-Type": "application/json" | |
| } | |
| """ | |
| def __init__(self, system_prompt="我是一名AI用药咨询顾问,请向我提问有关用药的问题"): | |
| # 从环境变量获取API密钥和基础URL | |
| self.api_key = os.environ.get('FASTGPT_API_KEY') | |
| self.base_url = os.environ.get('FASTGPT_BASE_URL', 'https://api.fastgpt.in/api') | |
| self.system_prompt = system_prompt | |
| self.headers = { | |
| "Authorization": f"Bearer {self.api_key}", | |
| "Content-Type": "application/json" | |
| } | |
| def chat(self, message, chat_history): | |
| if not message.strip(): | |
| return "", chat_history | |
| chat_id = str(uuid.uuid4()) | |
| # 构建消息历史,包含系统提示词 | |
| messages = [] | |
| if self.system_prompt: | |
| messages.append({ | |
| "role": "system", | |
| "content": self.system_prompt | |
| }) | |
| # 添加聊天历史 | |
| for user_msg, bot_msg in chat_history: | |
| messages.append({"role": "user", "content": user_msg}) | |
| messages.append({"role": "assistant", "content": bot_msg}) | |
| # 添加当前用户消息 | |
| messages.append({"role": "user", "content": message}) | |
| # 准备请求数据 | |
| data = { | |
| "chatId": chat_id, | |
| "stream": True, | |
| "detail": True, | |
| "model": "gpt-4o", | |
| "messages": messages | |
| } | |
| try: | |
| # 发送流式请求 | |
| response = requests.post( | |
| f"{self.base_url}/v1/chat/completions", | |
| headers=self.headers, | |
| json=data, | |
| stream=True, | |
| timeout=30 | |
| ) | |
| if response.status_code != 200: | |
| error_msg = f"API Error: Status {response.status_code}" | |
| logger.error(error_msg) | |
| chat_history.append((message, f"Error: {error_msg}")) | |
| return "", chat_history | |
| # 处理流式响应 | |
| full_response = "" | |
| for line in response.iter_lines(): | |
| if line: | |
| try: | |
| line = line.decode('utf-8') | |
| if line.startswith('data: '): | |
| data = json.loads(line[6:]) | |
| if 'choices' in data and len(data['choices']) > 0: | |
| content = data['choices'][0]['delta'].get('content', '') | |
| if content: | |
| full_response += content | |
| # 更新聊天历史 | |
| if len(chat_history) > 0 and chat_history[-1][0] == message: | |
| chat_history[-1] = (message, full_response) | |
| else: | |
| chat_history.append((message, full_response)) | |
| yield "", chat_history | |
| except Exception as e: | |
| logger.error(f"Error processing stream: {str(e)}") | |
| return "", chat_history | |
| except requests.exceptions.RequestException as e: | |
| error_msg = f"Request failed: {str(e)}" | |
| logger.error(error_msg) | |
| chat_history.append((message, f"Error: {error_msg}")) | |
| return "", chat_history | |
| def create_chat_interface(): | |
| fastgpt_chat = FastGPTChat() | |
| with gr.Blocks( | |
| title="AI用药咨询助手", | |
| css=""" | |
| .container { max-width: 800px; margin: auto; } | |
| .chat-header { | |
| text-align: center; | |
| padding: 20px; | |
| background: linear-gradient(135deg, #00b4d8, #0077b6); | |
| color: white; | |
| border-radius: 15px 15px 0 0; | |
| margin-bottom: 20px; | |
| } | |
| .chat-container { | |
| background-color: #ffffff; | |
| border-radius: 15px; | |
| padding: 20px; | |
| box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
| border: 1px solid #e0e0e0; | |
| } | |
| .message-box { | |
| border: 2px solid #e0e0e0; | |
| border-radius: 10px; | |
| background-color: white; | |
| transition: all 0.3s ease; | |
| } | |
| .message-box:focus { | |
| border-color: #00b4d8; | |
| box-shadow: 0 0 0 2px rgba(0, 180, 216, 0.2); | |
| } | |
| .submit-btn { | |
| background-color: #00b4d8 !important; | |
| border: none !important; | |
| color: white !important; | |
| padding: 10px 20px !important; | |
| border-radius: 8px !important; | |
| transition: all 0.3s ease !important; | |
| font-weight: 600 !important; | |
| } | |
| .submit-btn:hover { | |
| background-color: #0077b6 !important; | |
| transform: translateY(-2px); | |
| } | |
| .clear-btn { | |
| background-color: #ff4757 !important; | |
| border: none !important; | |
| color: white !important; | |
| padding: 10px 20px !important; | |
| border-radius: 8px !important; | |
| transition: all 0.3s ease !important; | |
| font-weight: 600 !important; | |
| } | |
| .clear-btn:hover { | |
| background-color: #ff6b81 !important; | |
| transform: translateY(-2px); | |
| } | |
| .chatbot { | |
| background-color: #f8f9fa; | |
| border-radius: 10px; | |
| padding: 15px; | |
| margin-bottom: 20px; | |
| } | |
| /* 移除消息背景的白色遮盖,优化对话样式 */ | |
| .chatbot > div { | |
| background: transparent !important; | |
| } | |
| /* 用户消息样式 */ | |
| .chatbot .user-message { | |
| background-color: #fce4ec !important; | |
| border-radius: 15px 15px 2px 15px !important; | |
| padding: 12px 18px !important; | |
| margin: 8px 0 !important; | |
| max-width: 85% !important; | |
| float: right !important; | |
| clear: both !important; | |
| border: 1px solid #f48fb1 !important; | |
| color: #1a1a1a !important; | |
| font-size: 15px !important; | |
| } | |
| /* AI响应消息样式 */ | |
| .chatbot .bot-message { | |
| background-color: #e8f5e9 !important; | |
| border-radius: 15px 15px 15px 2px !important; | |
| padding: 12px 18px !important; | |
| margin: 8px 0 !important; | |
| max-width: 85% !important; | |
| float: left !important; | |
| clear: both !important; | |
| border: 1px solid #a5d6a7 !important; | |
| color: #1a1a1a !important; | |
| font-size: 15px !important; | |
| } | |
| /* 消息容器样式 */ | |
| .chatbot > div > div { | |
| padding: 0 !important; | |
| gap: 2rem !important; | |
| } | |
| /* 头像样式 */ | |
| .chatbot span.avatar { | |
| padding: 8px !important; | |
| margin: 8px !important; | |
| } | |
| /* 确保消息之间有适当的间距 */ | |
| .chatbot > div > div:not(:last-child) { | |
| margin-bottom: 15px !important; | |
| } | |
| """ | |
| ) as interface: | |
| with gr.Column(elem_classes="container"): | |
| gr.Markdown( | |
| """ | |
| # 🏥 AI用药咨询助手 | |
| ### 您的专业用药咨询顾问,随时为您解答用药相关问题 | |
| """ | |
| ) | |
| with gr.Column(elem_classes="chat-container"): | |
| chatbot = gr.Chatbot( | |
| height=500, | |
| container=False, | |
| elem_classes="chatbot", | |
| show_label=False, | |
| bubble_full_width=False, | |
| avatar_images=("👤", "🤖") | |
| ) | |
| with gr.Row(elem_id="input-container"): | |
| with gr.Column(scale=8): | |
| message = gr.Textbox( | |
| show_label=False, | |
| placeholder="请输入您的用药问题...", | |
| container=False, | |
| elem_classes="message-box", | |
| lines=2 | |
| ) | |
| with gr.Column(scale=1, min_width=100): | |
| submit = gr.Button( | |
| "发送 💊", | |
| variant="primary", | |
| elem_classes="submit-btn" | |
| ) | |
| with gr.Row(elem_id="control-container"): | |
| clear = gr.Button( | |
| "清空对话 🗑️", | |
| variant="secondary", | |
| elem_classes="clear-btn" | |
| ) | |
| # 设置事件处理 | |
| submit_click = submit.click( | |
| fastgpt_chat.chat, | |
| inputs=[message, chatbot], | |
| outputs=[message, chatbot], | |
| api_name="chat" | |
| ) | |
| message.submit( | |
| fastgpt_chat.chat, | |
| inputs=[message, chatbot], | |
| outputs=[message, chatbot] | |
| ) | |
| clear.click(lambda: None, None, chatbot, queue=False) | |
| return interface | |
| if __name__ == "__main__": | |
| demo = create_chat_interface() | |
| demo.launch(debug=True) |