
你要做的是Python3 LLM 入门级高星 GitHub 项目,之前纠结 Gradio 和 FastAPI 做 WebUI 的区别,核心关注点是开发效率、用户体验、部署难度、代码量这几个维度。
Gradio 是一个专门为机器学习模型(尤其是 LLM)快速开发可视化 Web 界面的 Python 库,它的核心优势是无需前端基础、快速搭建、开箱即用的交互组件。
import gradio as gr
from langchain.llms import Ollama
def chat_with_llm(message, history):
"""
与本地部署的Llama 3 8B-Chat聊天
:param message: 用户输入的消息
:param history: 聊天历史记录(格式:[(user_msg1, bot_msg1), (user_msg2, bot_msg2)])
:return: LLM的回复
"""
llm = Ollama(model="llama3:8b")
full_prompt = ""
for user_msg, bot_msg in history:
full_prompt += f"User: {user_msg}\nAssistant: {bot_msg}\n"
full_prompt += f"User: {message}\nAssistant: "
response = llm.predict(full_prompt)
return response
# 创建Gradio聊天界面
demo = gr.ChatInterface(
fn=chat_with_llm,
title="本地部署的Llama 3 8B-Chat聊天机器人",
description="支持本地部署,数据不传到云端,保护隐私",
theme="soft"
)
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0", server_port=7860, share=False)答案是肯定的,但要讲清楚换的代价和适用场景。
如果你的项目对界面有极高定制化要求(比如需要品牌风格、复杂的交互逻辑),或者项目需要和已有 FastAPI 后端深度集成(比如需要统一的 API 接口、身份验证、权限控制),那么可以考虑用 FastAPI 做 WebUI。
用 FastAPI 做 WebUI 需要自己写前端代码(HTML+CSS+JS),开发效率比 Gradio 低很多,代码量也会增加几倍甚至十几倍。
from fastapi import FastAPI, Depends, HTTPException, status, Form
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from langchain.llms import Ollama
from typing import List, Optional
from pydantic import BaseModel
app = FastAPI(title="FastAPI LLM聊天机器人")
# 挂载静态资源
app.mount("/static", StaticFiles(directory="static"), name="static")
# 初始化Jinja2模板引擎
templates = Jinja2Templates(directory="templates")
# 定义聊天请求的数据验证模型
class ChatRequest(BaseModel):
message: str
history: Optional[List[List[str]]] = []
# 定义聊天响应的数据验证模型
class ChatResponse(BaseModel):
response: str
# 聊天接口
@app.post("/api/chat", response_model=ChatResponse)
async def chat(request: ChatRequest):
"""
与本地部署的Llama 3 8B-Chat聊天
:param request: 聊天请求数据
:return: 聊天响应数据
"""
try:
llm = Ollama(model="llama3:8b")
full_prompt = ""
for user_msg, bot_msg in request.history:
full_prompt += f"User: {user_msg}\nAssistant: {bot_msg}\n"
full_prompt += f"User: {request.message}\nAssistant: "
response = llm.predict(full_prompt)
return {"response": response}
except Exception as e:
raise HTTPException(status_code=500, detail=f"聊天失败:{e}")
# 聊天界面
@app.get("/", response_class=HTMLResponse)
async def chat_page():
return templates.TemplateResponse("chat.html", {"request": None})<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FastAPI LLM聊天机器人</title>
<link rel="stylesheet" href="/static/css/style.css">
</head>
<body>
<div class="container">
<div class="header">
<h1>FastAPI LLM聊天机器人</h1>
<p>支持本地部署,数据不传到云端,保护隐私</p>
</div>
<div class="chat-container">
<div class="chat-history" id="chat-history">
<!-- 聊天历史记录会动态添加到这里 -->
</div>
<div class="chat-input-container">
<input type="text" id="chat-input" placeholder="请输入您的消息..." autofocus>
<button id="send-btn">发送</button>
</div>
</div>
</div>
<script src="/static/js/script.js"></script>
</body>
</html>* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Microsoft YaHei", sans-serif;
}
body {
background-color: #f5f5f5;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.header {
text-align: center;
margin-bottom: 30px;
}
.header h1 {
color: #333;
margin-bottom: 10px;
}
.header p {
color: #666;
font-size: 14px;
}
.chat-container {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.chat-history {
height: 400px;
overflow-y: auto;
padding: 20px;
}
.chat-history .message {
margin-bottom: 15px;
padding: 10px 15px;
border-radius: 8px;
max-width: 70%;
word-wrap: break-word;
}
.chat-history .user-message {
background-color: #007bff;
color: #fff;
margin-left: auto;
text-align: right;
}
.chat-history .bot-message {
background-color: #f8f9fa;
color: #333;
margin-right: auto;
text-align: left;
}
.chat-input-container {
display: flex;
padding: 20px;
}
.chat-input-container input {
flex: 1;
padding: 10px 15px;
border: 1px solid #ddd;
border-radius: 8px 0 0 8px;
font-size: 14px;
}
.chat-input-container button {
padding: 10px 20px;
background-color: #007bff;
color: #fff;
border: none;
border-radius: 0 8px 8px 0;
font-size: 14px;
cursor: pointer;
transition: background-color 0.3s;
}
.chat-input-container button:hover {
background-color: #0056b3;
}// 聊天历史记录
let chatHistory = [];
// 发送消息的函数
async function sendMessage() {
const chatInput = document.getElementById("chat-input");
const message = chatInput.value.trim();
if (!message) return;
// 清空输入框
chatInput.value = "";
// 添加用户消息到聊天历史记录
chatHistory.push([message, ""]);
renderChatHistory();
// 发送消息到后端
try {
const response = await fetch("/api/chat", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
message: message,
history: chatHistory.slice(0, -1)
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
// 更新聊天历史记录
chatHistory[chatHistory.length - 1][1] = data.response;
renderChatHistory();
} catch (error) {
console.error("发送消息失败:", error);
chatHistory[chatHistory.length - 1][1] = "抱歉,聊天失败,请重试。";
renderChatHistory();
}
}
// 渲染聊天历史记录的函数
function renderChatHistory() {
const chatHistoryDiv = document.getElementById("chat-history");
chatHistoryDiv.innerHTML = "";
chatHistory.forEach(([userMsg, botMsg]) => {
// 渲染用户消息
const userMessageDiv = document.createElement("div");
userMessageDiv.className = "message user-message";
userMessageDiv.textContent = userMsg;
chatHistoryDiv.appendChild(userMessageDiv);
// 渲染机器人消息
if (botMsg) {
const botMessageDiv = document.createElement("div");
botMessageDiv.className = "message bot-message";
botMessageDiv.textContent = botMsg;
chatHistoryDiv.appendChild(botMessageDiv);
}
});
// 滚动到聊天历史记录的底部
chatHistoryDiv.scrollTop = chatHistoryDiv.scrollHeight;
}
// 绑定事件
document.getElementById("send-btn").addEventListener("click", sendMessage);
document.getElementById("chat-input").addEventListener("keypress", (e) => {
if (e.key === "Enter") {
sendMessage();
}
});如果是入门级高星 GitHub 项目,建议优先用Gradio,因为:
如果你的项目对界面有极高定制化要求,或者项目需要和已有 FastAPI 后端深度集成,那么可以考虑用FastAPI + 前端框架(如 React、Vue、Angular) 做 WebUI。