Files
nanocode/ai-chatbot-service/app/main.py
T
Ubuntu 32b43f85bd a
2026-07-03 16:58:28 +08:00

165 lines
4.6 KiB
Python

"""
FastAPI 主服务 - AI 客服系统
"""
import os
import sys
import uuid
from pathlib import Path
from fastapi import FastAPI, Request, UploadFile, File
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from pydantic import BaseModel
import uvicorn
# 确保可以导入 app 模块
sys.path.insert(0, str(Path(__file__).parent))
from config import HOST, PORT, BASE_DIR
from chatbot import get_chatbot
from knowledge import init_knowledge_base, get_knowledge_base
# 创建 FastAPI 应用
app = FastAPI(
title="AI 客服系统",
description="基于 LangChain + LangGraph 的智能客服",
version="1.0.0"
)
# 静态文件和模板
app.mount("/static", StaticFiles(directory=str(BASE_DIR / "static")), name="static")
templates = Jinja2Templates(directory=str(BASE_DIR / "templates"))
# 修复 Jinja2 模板缓存问题
templates.env.cache.clear() if hasattr(templates.env, 'cache') and hasattr(templates.env.cache, 'clear') else None
# 数据模型
class ChatRequest(BaseModel):
message: str
session_id: str = None
class ChatResponse(BaseModel):
response: str
session_id: str
# 路由
@app.get("/", response_class=HTMLResponse)
async def index(request: Request):
"""聊天界面"""
# 生成新会话ID
session_id = str(uuid.uuid4())[:8]
# 直接读取 HTML 文件
html_path = BASE_DIR / "templates" / "index.html"
with open(html_path, "r", encoding="utf-8") as f:
html_content = f.read()
# 替换 session_id
html_content = html_content.replace('{{ session_id }}', session_id)
return HTMLResponse(content=html_content)
@app.post("/chat", response_model=ChatResponse)
async def chat(request: ChatRequest):
"""发送消息"""
chatbot = get_chatbot()
# 如果没有 session_id,生成一个
session_id = request.session_id or str(uuid.uuid4())[:8]
# 获取回复
response = await chatbot.chat(request.message, session_id)
return ChatResponse(response=response, session_id=session_id)
@app.get("/history/{session_id}")
async def get_history(session_id: str):
"""获取对话历史"""
chatbot = get_chatbot()
history = chatbot.get_history(session_id)
return {"session_id": session_id, "history": history}
@app.post("/upload")
async def upload_file(file: UploadFile = File(...)):
"""上传知识库文档"""
from config import KNOWLEDGE_DIR
from knowledge import KnowledgeBase
from langchain.schema import Document
# 保存文件
file_path = KNOWLEDGE_DIR / file.filename
with open(file_path, "wb") as f:
content = await file.read()
f.write(content)
# 加载并添加到知识库
kb = get_knowledge_base()
# 简单文本加载
if file.filename.endswith(".txt") or file.filename.endswith(".md"):
with open(file_path, "r", encoding="utf-8") as f:
text = f.read()
doc = Document(page_content=text, metadata={"source": file.filename})
kb.add_documents([doc])
return {"message": f"✅ 已上传并添加到知识库: {file.filename}"}
return {"message": f"✅ 已上传: {file.filename},请重启服务加载"}
@app.get("/health")
async def health_check():
"""健康检查"""
return {"status": "ok", "service": "ai-chatbot"}
@app.on_event("startup")
async def startup_event():
"""启动时初始化"""
print("=" * 60)
print("🤖 AI 客服系统启动中...")
print("=" * 60)
# 检查 API Key
from config import LLM_API_KEY
if LLM_API_KEY == "your-deepseek-api-key-here":
print("⚠️ 警告: 请在 app/config.py 中设置 DEEPSEEK_API_KEY")
print(" 或者设置环境变量: export DEEPSEEK_API_KEY=your-key")
else:
print("✅ API Key 已配置")
# 初始化知识库
print("\n📚 初始化知识库...")
try:
kb = get_knowledge_base()
# 尝试加载已有文档
from pathlib import Path
from config import KNOWLEDGE_DIR
if KNOWLEDGE_DIR.exists():
docs = list(KNOWLEDGE_DIR.glob("*"))
if docs:
print(f" 发现 {len(docs)} 个文档文件")
else:
print(" 知识库目录为空,请在 knowledge_base/ 添加文档")
except Exception as e:
print(f" ⚠️ 知识库初始化失败: {e}")
print("\n🚀 服务已启动!")
print(f" 访问: http://{HOST}:{PORT}")
print("=" * 60)
if __name__ == "__main__":
# 开发模式运行
uvicorn.run(
"main:app",
host=HOST,
port=PORT,
reload=True,
log_level="info"
)