通过 API 与 Gradio 构建 AI 应用
通过 API 与 Gradio 构建 AI 应用
任务背景
该代码实现了一个基于阿里云 DashScope API 的 AI 聊天助手应用,采用 Gradio 框架构建交互式界面。项目背景源于当前大模型 API 的广泛应用需求,特别是对于需要快速接入对话功能的开发者而言。该实现方案利用兼容 OpenAI 标准的阿里云 API,降低了迁移成本,同时通过轻量级 Web 界面提供便捷的对话体验。
核心功能
API 集成层
- 使用
openai库兼容模式连接阿里云 DashScope 服务 - 通过
qwen-turbo模型实现对话生成能力 - 包含 API 连通性测试模块,运行时会自动验证密钥有效性
对话逻辑处理
- 支持多轮对话历史维护
- 自动处理系统提示、用户消息和助手回复的格式转换
- 实现错误捕获机制,将 API 异常转化为用户可见的友好提示
交互界面设计
- 采用 Gradio 的
Chatbot组件实现类即时通讯的对话窗口 - 包含消息输入框、发送按钮和对话清空功能
- 响应式设计同时支持回车提交和按钮点击两种交互方式
技术实现要点
架构设计
客户端请求 → Gradio 界面 → 消息格式化 → 阿里云API → 响应处理 → 界面更新
关键参数说明
OPENAI_API_KEY: 需替换为有效的 DashScope API 密钥base_url: 固定指向阿里云兼容性端点stream=False: 关闭流式传输以简化首版实现
扩展性设计
- 环境变量作为备用密钥获取方式
- 模块化的
chat_with_ai函数便于后续增加:- 对话历史持久化
- 上下文长度管理
- 高级推理参数配置
部署与使用
运行要求
- Python 3.7+
- 依赖库:
openai,gradio
启动方式
python app.py
默认访问地址: http://127.0.0.1:7860
定制建议
- 修改
gr.themes.Soft()更换界面主题 - 调整
max_tokens控制生成长度 - 添加
temperature参数改变生成随机性
安全注意事项
- 避免在代码中硬编码 API 密钥
- 生产环境建议启用 HTTPS
- 敏感业务场景需添加对话内容审核模块
代码
import os
import json
from typing import List, Dict, Tupleimport openai
import gradio as gr# TODO: 设置你的API,需要支持openai库,这里以阿里云DashScope API密钥为例
OPENAI_API_KEY = "TripleH"
client = openai.OpenAI(api_key=OPENAI_API_KEY,base_url="https://dashscope.aliyuncs.com/compatible-mode/v1", # 使用阿里云大模型API
)# 检查是否正确设置了 API
# 如果一切正常,你将看到 "API 设置成功!!"
try:response = client.chat.completions.create(model="qwen-turbo", # 使用阿里云 DashScope 的模型messages=[{'role': 'user', 'content': "测试"}], # 设置一个简单的测试消息max_tokens=1,)print("API 设置成功!!") # 输出成功信息
except Exception as e:print(f"API 可能有问题,请检查:{e}") # 输出详细的错误信息# 定义聊天函数
def chat_with_ai(message, history):"""与AI模型进行对话的函数Args:message: 用户输入的消息history: 对话历史记录(Gradio Chatbot格式:[[user_msg, assistant_msg], ...])Returns:更新后的对话历史"""# 检查消息是否为空if not message or not message.strip():return history, ""# 构建消息列表messages = []# 添加系统提示(可选)messages.append({'role': 'system', 'content': 'You are a helpful assistant.'})# 添加历史对话(Gradio的history格式是列表的列表)for user_msg, assistant_msg in history:messages.append({'role': 'user', 'content': user_msg})messages.append({'role': 'assistant', 'content': assistant_msg})# 添加当前用户消息messages.append({'role': 'user', 'content': message})try:# 调用API获取响应response = client.chat.completions.create(model="qwen-turbo",messages=messages,stream=False)# 提取助手回复assistant_reply = response.choices[0].message.content# 更新历史记录(Gradio Chatbot使用列表格式)history.append([message, assistant_reply])return history, ""except Exception as e:error_msg = f"发生错误:{str(e)}"history.append([message, error_msg])return history, ""# 创建 Gradio 界面
def create_interface():"""创建并返回 Gradio 聊天界面"""with gr.Blocks(title="AI 聊天助手", theme=gr.themes.Soft()) as demo:gr.Markdown("# 🤖 AI 聊天助手")gr.Markdown("基于阿里云 DashScope API 和 Gradio 构建的 AI 对话应用")# 创建聊天机器人对话窗口组件# gr.Chatbot 是 Gradio 提供的聊天界面组件,用于显示对话历史chatbot = gr.Chatbot(label="对话窗口", # 组件标签,显示在界面上方的标题height=500, # 对话窗口的高度(像素),设置为500像素show_copy_button=True # 是否显示复制按钮,True表示每条消息旁边会显示复制按钮,方便用户复制对话内容)# 创建一个水平布局行,用于放置输入框和发送按钮with gr.Row():# 创建文本输入框组件,用于用户输入消息msg = gr.Textbox(label="输入消息", # 输入框的标签文本placeholder="请输入您的问题...", # 输入框为空时显示的提示文字scale=4, # 在Row布局中的相对宽度比例,4表示占4份container=False # 不显示容器边框,使界面更简洁)# 创建发送按钮submit_btn = gr.Button("发送", # 按钮上显示的文本variant="primary", # 按钮样式为主色调(通常是蓝色)scale=1 # 在Row布局中的相对宽度比例,1表示占1份)# 创建另一个水平布局行,用于放置清空按钮with gr.Row():# 创建清空对话按钮clear_btn = gr.Button("清空对话", # 按钮上显示的文本variant="secondary" # 按钮样式为次要色调(通常是灰色))# 绑定事件处理函数# 当用户在输入框中按回车键时,触发chat_with_ai函数# [msg, chatbot] 是输入参数:用户消息和对话历史# [chatbot, msg] 是输出参数:更新后的对话历史和清空的输入框msg.submit(chat_with_ai, [msg, chatbot], [chatbot, msg])# 当用户点击发送按钮时,触发chat_with_ai函数# 参数含义同上submit_btn.click(chat_with_ai, [msg, chatbot], [chatbot, msg])# 当用户点击清空按钮时,执行lambda函数清空对话历史和输入框# lambda: ([], "") 返回空列表和空字符串,分别清空chatbot和msg# outputs=[chatbot, msg] 指定要更新的组件clear_btn.click(lambda: ([], ""), outputs=[chatbot, msg])return demo# 主函数
if __name__ == "__main__":# 检查 API 密钥,如果代码中未设置,尝试从环境变量获取if not OPENAI_API_KEY or OPENAI_API_KEY.strip() == "":OPENAI_API_KEY = os.getenv('OPENAI_API_KEY', '')if OPENAI_API_KEY:client.api_key = OPENAI_API_KEYprint("已从环境变量读取 API 密钥")else:print("警告:请设置 OPENAI_API_KEY 环境变量或在代码中直接设置 API 密钥")# 创建并启动界面demo = create_interface()demo.launch(server_name="127.0.0.1", # 本地访问,如需外部访问可改为 "0.0.0.0"server_port=7860, # 端口号share=False # 是否创建公共链接)