Vue 3 + FastAPI + Hugging Face 构建智能文本摘要生成器全栈实战
在实际前端开发与 AI 应用结合的领域,很多开发者面临一个困境:前端技术栈日新月异,而 AI 能力又似乎深不可测,两者结合时,往往感觉无从下手。要么是前端界面炫酷但后端 AI 模型调用不通,要么是模型跑通了却不知道怎么构建一个稳定、可交互的用户界面。更常见的情况是,教程要么只讲前端框架,要么只讲模型调参,缺少一个将两者无缝衔接、从环境搭建到项目部署的完整链路。
本文的目标,就是解决这个痛点。我们将以一个具体的“智能文本摘要生成器”项目为主线,完整走通从前端 Vue 3 界面开发、后端 FastAPI 服务搭建,到集成 Hugging Face 开源模型、处理异步任务、最终部署上线的全流程。这个过程不仅涉及代码编写,更重要的是理解前后端与 AI 服务之间的数据流、错误处理和性能考量。学完后,你将掌握如何将一个 AI 能力封装成可用的 Web 服务,并为其配备一个专业的前端操作界面。
1. 理解前端与 AI 应用开发的核心协作模式
在开始写代码之前,必须厘清前端、后端和 AI 模型在这个架构中各自扮演的角色。很多项目失败的第一步,就是角色分工混乱。
1.1 前端:交互层与状态管理
前端不再是简单的静态页面。在现代 AI 应用中,前端需要处理复杂的用户交互状态,例如:
- 长时任务处理:模型推理可能耗时数秒甚至数十秒,前端需要提供加载状态、进度提示,并支持取消操作。
- 复杂数据输入:除了文本,可能还有文件上传(如图片、音频)、参数调整滑块等。
- 实时数据流:对于某些 AI 应用(如聊天、文生图),可能需要使用 WebSocket 或 Server-Sent Events (SSE) 来接收模型生成的流式数据。
因此,前端框架的选择至关重要。Vue 3 的 Composition API 或 React Hooks 非常适合管理这类异步、响应式的应用状态。
1.2 后端:服务桥接与任务调度
后端在这里是关键的“中间层”,它承担了多项职责:
- API 网关:接收前端请求,进行参数验证、用户认证和权限检查。
- 模型服务封装:调用本地或远程的 AI 模型推理接口。这里不建议在前端直接调用模型 API(如 Hugging Face Inference API),因为会暴露 API Token,且无法做缓存、限流等操作。
- 异步任务处理:对于耗时任务,后端不应阻塞 HTTP 响应。正确的做法是立即返回一个任务 ID,然后通过 WebSocket 或让前端轮询另一个 API 来获取任务结果。
- 错误处理与日志:将模型可能产生的各种错误(如输入过长、模型加载失败)转化为前端能理解的友好错误信息。
我们选择 Python 的 FastAPI 框架,因为它异步支持好、自动生成 API 文档,且与众多 AI 库(如 transformers, torch)集成方便。
1.3 AI 模型:能力提供者
AI 模型是核心计算单元。在本项目中,我们使用 Hugging Facetransformers库提供的预训练模型。对于生产环境,你需要考虑:
- 模型选择:根据任务(摘要、分类、生成)选择合适且大小适中的模型。过大模型会导致加载慢、内存消耗高。
- 模型部署:开发阶段可以在代码中动态加载。生产环境则可以考虑使用专门的模型服务化工具(如 TensorFlow Serving, TorchServe)或云服务,以提高并发能力和资源利用率。
- 输入输出规范:明确模型接受的输入格式(文本、Tensor)和输出格式,并在后端做好适配。
理解了这三者的关系,我们就能设计出一个清晰的数据流:用户输入 -> 前端收集 -> HTTP请求 -> 后端验证 -> 调用模型 -> 异步处理 -> 返回任务ID -> 前端轮询结果 -> 更新界面。
2. 项目环境准备与依赖配置
一个稳定的环境是项目成功的基石。我们将分别设置前端和后端(包括 AI 模型)的开发环境。
2.1 前端开发环境搭建
我们使用 Vue 3 和 TypeScript,并选择 Vite 作为构建工具,以获得更快的启动和热更新速度。
首先,确保你的系统已安装 Node.js(版本 16 或以上)和包管理器 npm 或 yarn。
# 检查 Node.js 和 npm 版本 node --version npm --version # 使用 Vite 官方模板创建 Vue+TS 项目 npm create vue@latest my-ai-frontend在创建过程中,通过命令行交互选择以下特性:
- TypeScript: Yes
- JSX: No
- Vue Router: Yes (用于页面路由)
- Pinia: Yes (用于状态管理)
- ESLint: Yes (代码检查)
创建完成后,进入项目目录并安装依赖:
cd my-ai-frontend npm install此外,我们还需要安装用于 UI 组件和 HTTP 请求的库:
npm install element-plus axios # Element Plus 是 Vue 3 的组件库,axios 用于发送 HTTP 请求2.2 后端与 AI 模型环境搭建
后端使用 Python 3.8+。强烈建议使用虚拟环境(如 venv 或 conda)来隔离项目依赖。
# 创建并激活虚拟环境 (以 venv 为例) python -m venv venv # Windows venv\Scripts\activate # Linux/Mac source venv/bin/activate安装核心的后端和 AI 依赖:
pip install fastapi uvicorn python-multipart pydantic # fastapi: Web 框架 # uvicorn: ASGI 服务器,用于运行 FastAPI # python-multipart: 用于处理文件上传 # pydantic: 用于数据验证和设置管理 pip install transformers torch # transformers: Hugging Face 模型库 # torch: PyTorch, transformers 的后端引擎之一注意:
torch的安装可能需要根据你的 CUDA 版本选择特定命令。如果仅用于 CPU 推理,上述命令通常可行。如需 GPU 支持,请访问 PyTorch 官网获取适合你环境的安装命令。
2.3 项目目录结构规划
一个清晰的结构有助于团队协作和长期维护。建议采用如下结构:
my-ai-summarizer/ ├── frontend/ # 前端 Vue 项目 │ ├── public/ │ ├── src/ │ │ ├── assets/ │ │ ├── components/ # 可复用组件,如 Loading.vue │ │ ├── router/ # 路由配置 │ │ ├── stores/ # Pinia 状态管理,如 taskStore.ts │ │ ├── views/ # 页面组件,如 HomeView.vue │ │ ├── utils/ # 工具函数,如 api.ts (axios 封装) │ │ └── App.vue │ ├── index.html │ ├── package.json │ └── vite.config.ts └── backend/ # 后端 FastAPI 项目 ├── app/ │ ├── __init__.py │ ├── main.py # FastAPI 应用入口 │ ├── api/ # 路由端点 │ │ ├── __init__.py │ │ └── endpoints/ # 具体端点,如 summarize.py │ ├── core/ # 核心配置 │ ├── models/ # Pydantic 数据模型 │ ├── services/ # 业务逻辑,如 model_service.py │ └── utils/ # 工具函数 ├── requirements.txt └── README.md3. 构建后端 FastAPI 服务与 AI 模型集成
后端是整个应用的中枢,我们先实现它,确保 AI 模型能够被正确调用。
3.1 创建 FastAPI 应用与数据模型
在backend/app/main.py中初始化 FastAPI 应用,并配置 CORS(跨域资源共享),以便前端能够访问。
# backend/app/main.py from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from app.api.endpoints import summarize # 导入我们即将编写的路由 app = FastAPI(title="AI Text Summarizer API", version="1.0.0") # 配置 CORS,允许前端域名访问。开发时通常是 localhost:5173 (Vite 默认端口) origins = [ "http://localhost:5173", "http://127.0.0.1:5173", ] app.add_middleware( CORSMiddleware, allow_origins=origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # 包含路由 app.include_router(summarize.router, prefix="/api/v1", tags=["summarize"]) @app.get("/") def read_root(): return {"message": "AI Summarizer API is running"}接下来,在backend/app/models/schemas.py中定义 Pydantic 模型,用于请求和响应的数据验证。
# backend/app/models/schemas.py from pydantic import BaseModel, Field from typing import Optional from enum import Enum class SummaryRequest(BaseModel): """摘要生成请求体""" text: str = Field(..., min_length=10, max_length=5000, description="需要摘要的原文") max_length: Optional[int] = Field(100, ge=30, le=300, description="摘要最大长度") min_length: Optional[int] = Field(30, ge=10, le=100, description="摘要最小长度") class TaskStatus(str, Enum): """任务状态枚举""" PENDING = "pending" PROCESSING = "processing" SUCCESS = "success" FAILED = "failed" class TaskResponse(BaseModel): """任务提交响应""" task_id: str status: TaskStatus message: str class SummaryResult(BaseModel): """摘要结果响应""" task_id: str status: TaskStatus summary: Optional[str] = None # 成功时有值 error: Optional[str] = None # 失败时有值使用 Pydantic 可以自动验证前端传入的数据,例如text长度必须在 10 到 5000 字符之间,否则 FastAPI 会直接返回 422 错误,省去我们手动校验的代码。
3.2 实现 AI 模型服务层
这是核心所在。我们在backend/app/services/model_service.py中封装模型加载和推理逻辑。
# backend/app/services/model_service.py import logging from typing import Optional from transformers import pipeline, Pipeline from app.models.schemas import SummaryRequest logger = logging.getLogger(__name__) class SummarizationService: _model: Optional[Pipeline] = None @classmethod def get_model(cls) -> Pipeline: """懒加载模型,避免每次请求都加载""" if cls._model is None: logger.info("Loading summarization model...") # 使用一个轻量级的摘要模型,例如 facebook/bart-large-cnn # 首次运行会自动从 Hugging Face 下载模型 cls._model = pipeline( "summarization", model="facebook/bart-large-cnn", tokenizer="facebook/bart-large-cnn", framework="pt" # 使用 PyTorch ) logger.info("Model loaded successfully.") return cls._model @classmethod def summarize_text(cls, request: SummaryRequest) -> str: """执行文本摘要""" model = cls.get_model() try: # 调用模型管道 result = model( request.text, max_length=request.max_length, min_length=request.min_length, do_sample=False, # 不使用采样,保证确定性输出(适合摘要) ) # result 是一个列表,例如 [{'summary_text': '...'}] summary = result[0]['summary_text'] return summary except Exception as e: logger.error(f"Model inference failed: {e}") # 这里可以捕获更具体的异常,如 Tokenizer 错误、GPU OOM 等 raise RuntimeError(f"Failed to generate summary: {str(e)}")这里有几个关键点:
- 模型懒加载:使用类变量
_model保存加载后的模型实例,避免每次请求都重复加载,极大提升响应速度。 - 模型选择:
facebook/bart-large-cnn是一个在 CNN/DailyMail 数据集上训练的、专门用于摘要的模型,效果和速度比较平衡。对于生产环境,你可能需要根据硬件条件和性能要求选择更小或更大的模型。 - 异常处理:将模型可能抛出的异常捕获并转换为业务异常,便于上层统一处理。
3.3 实现异步任务与 API 端点
对于可能耗时的模型调用,我们设计一个简单的异步任务机制。这里为了简化,使用内存字典模拟任务队列和状态存储。生产环境应使用 Celery + Redis 或 RQ。
首先,在backend/app/api/endpoints/summarize.py中创建任务管理器。
# backend/app/api/endpoints/summarize.py import uuid import asyncio from fastapi import APIRouter, HTTPException, BackgroundTasks from app.models.schemas import SummaryRequest, TaskResponse, SummaryResult, TaskStatus from app.services.model_service import SummarizationService router = APIRouter() # 内存存储任务状态和结果 (生产环境需替换为数据库或 Redis) tasks_store = {} async def run_summarization_task(task_id: str, request: SummaryRequest): """后台任务:执行摘要生成并更新状态""" tasks_store[task_id]["status"] = TaskStatus.PROCESSING try: summary = SummarizationService.summarize_text(request) tasks_store[task_id].update({ "status": TaskStatus.SUCCESS, "summary": summary, "error": None }) except Exception as e: tasks_store[task_id].update({ "status": TaskStatus.FAILED, "summary": None, "error": str(e) }) @router.post("/summarize", response_model=TaskResponse) async def create_summarization_task( request: SummaryRequest, background_tasks: BackgroundTasks ): """提交摘要生成任务""" task_id = str(uuid.uuid4()) # 初始化任务状态 tasks_store[task_id] = { "status": TaskStatus.PENDING, "request": request, "summary": None, "error": None } # 将耗时任务添加到后台执行 background_tasks.add_task(run_summarization_task, task_id, request) return TaskResponse( task_id=task_id, status=TaskStatus.PENDING, message="Task submitted successfully. Please poll for results using the task_id." ) @router.get("/summarize/{task_id}", response_model=SummaryResult) async def get_summarization_result(task_id: str): """根据 task_id 查询任务结果""" task_info = tasks_store.get(task_id) if not task_info: raise HTTPException(status_code=404, detail="Task not found") return SummaryResult( task_id=task_id, status=task_info["status"], summary=task_info.get("summary"), error=task_info.get("error") )这个设计实现了经典的异步任务模式:
POST /summarize:接收请求,立即生成一个唯一task_id并返回,同时将实际的计算任务run_summarization_task丢到后台执行。GET /summarize/{task_id}:前端可以轮询这个接口,根据返回的status字段知道任务是在处理中、成功还是失败,并获取最终结果或错误信息。
3.4 运行与测试后端服务
在backend目录下,运行以下命令启动开发服务器:
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000--reload参数使得代码修改后服务器会自动重启,方便开发。
打开浏览器访问http://127.0.0.1:8000/docs,你会看到自动生成的 Swagger UI 接口文档。你可以直接在这里测试两个接口:
- 点击
POST /api/v1/summarize的 “Try it out”,输入一段长文本,点击 Execute。观察返回的task_id。 - 复制这个
task_id,在GET /api/v1/summarize/{task_id}中测试,第一次可能返回"processing",稍等片刻再请求,就能看到生成的摘要。
4. 开发前端 Vue 3 应用界面
后端 API 就绪后,我们开始构建与之交互的前端界面。
4.1 配置 Axios 与 API 封装
首先,在frontend/src/utils/api.ts中封装 Axios 实例,统一处理请求基地址、超时和错误。
// frontend/src/utils/api.ts import axios from 'axios'; const apiClient = axios.create({ baseURL: 'http://localhost:8000/api/v1', // 指向后端 API 地址 timeout: 10000, // 10秒超时 headers: { 'Content-Type': 'application/json', }, }); // 可选:添加请求/响应拦截器,用于统一处理 token、错误等 apiClient.interceptors.response.use( (response) => response.data, // 直接返回 data 字段 (error) => { // 统一处理网络错误或后端返回的错误 const message = error.response?.data?.detail || error.message || 'Network Error'; console.error('API Request Failed:', message); return Promise.reject(new Error(message)); } ); export default apiClient;然后,在frontend/src/stores/taskStore.ts中创建 Pinia Store,用于集中管理任务状态(如当前任务 ID、加载状态、摘要结果等)。
// frontend/src/stores/taskStore.ts import { defineStore } from 'pinia'; import { ref } from 'vue'; import apiClient from '@/utils/api'; interface SummaryRequest { text: string; max_length?: number; min_length?: number; } interface TaskStatus { task_id: string; status: 'pending' | 'processing' | 'success' | 'failed'; message?: string; } interface SummaryResult { task_id: string; status: 'pending' | 'processing' | 'success' | 'failed'; summary?: string; error?: string; } export const useTaskStore = defineStore('task', () => { const currentTaskId = ref<string | null>(null); const isLoading = ref(false); const summaryResult = ref<SummaryResult | null>(null); const errorMessage = ref<string | null>(null); const submitSummaryTask = async (request: SummaryRequest) => { isLoading.value = true; errorMessage.value = null; summaryResult.value = null; try { const response: TaskStatus = await apiClient.post('/summarize', request); currentTaskId.value = response.task_id; // 开始轮询结果 pollTaskResult(response.task_id); } catch (error: any) { errorMessage.value = `提交任务失败: ${error.message}`; isLoading.value = false; } }; const pollTaskResult = async (taskId: string, maxAttempts: number = 30) => { let attempts = 0; const poll = async () => { if (attempts >= maxAttempts) { errorMessage.value = '任务处理超时'; isLoading.value = false; return; } attempts++; try { const result: SummaryResult = await apiClient.get(`/summarize/${taskId}`); summaryResult.value = result; if (result.status === 'success' || result.status === 'failed') { // 任务完成,停止轮询 isLoading.value = false; if (result.status === 'failed') { errorMessage.value = result.error || '任务处理失败'; } return; } // 任务仍在处理中,继续轮询 setTimeout(poll, 1000); // 每秒轮询一次 } catch (error: any) { errorMessage.value = `轮询结果失败: ${error.message}`; isLoading.value = false; } }; poll(); }; const resetTask = () => { currentTaskId.value = null; isLoading.value = false; summaryResult.value = null; errorMessage.value = null; }; return { currentTaskId, isLoading, summaryResult, errorMessage, submitSummaryTask, resetTask, }; });这个 Store 封装了核心业务逻辑:提交任务、轮询结果、管理加载和错误状态。前端组件只需调用submitSummaryTask并绑定 Store 中的状态即可。
4.2 构建主页面组件
现在,在frontend/src/views/HomeView.vue中创建主界面。
<!-- frontend/src/views/HomeView.vue --> <template> <div class="home-container"> <el-card class="box-card"> <template #header> <div class="card-header"> <span>智能文本摘要生成器</span> </div> </template> <!-- 输入区域 --> <div class="input-section"> <el-input v-model="inputText" type="textarea" :rows="8" placeholder="请输入需要摘要的长文本(10-5000字符)" :maxlength="5000" show-word-limit /> <div class="param-controls"> <el-slider v-model="maxLength" :min="30" :max="300" :step="10" show-stops show-input style="width: 100%;" > <template #prefix>摘要最大长度: </template> </el-slider> <el-slider v-model="minLength" :min="10" :max="100" :step="5" show-stops show-input style="width: 100%; margin-top: 20px;" > <template #prefix>摘要最小长度: </template> </el-slider> </div> <div class="action-buttons"> <el-button type="primary" :loading="taskStore.isLoading" :disabled="!isFormValid" @click="handleSubmit" > {{ taskStore.isLoading ? '处理中...' : '生成摘要' }} </el-button> <el-button @click="handleReset">重置</el-button> </div> </div> <!-- 错误提示 --> <el-alert v-if="taskStore.errorMessage" :title="taskStore.errorMessage" type="error" show-icon closable style="margin-top: 20px;" /> <!-- 结果展示 --> <div v-if="taskStore.summaryResult" class="result-section"> <el-divider content-position="left">摘要结果</el-divider> <el-alert v-if="taskStore.summaryResult.status === 'success'" :title="`任务ID: ${taskStore.summaryResult.task_id}`" type="success" show-icon /> <el-alert v-else-if="taskStore.summaryResult.status === 'failed'" :title="`任务失败: ${taskStore.summaryResult.error}`" type="error" show-icon /> <el-card v-else shadow="never"> <el-skeleton :rows="3" animated /> </el-card> <div v-if="taskStore.summaryResult.summary" class="summary-text"> <p>{{ taskStore.summaryResult.summary }}</p> </div> </div> </el-card> </div> </template> <script setup lang="ts"> import { ref, computed } from 'vue'; import { ElMessage } from 'element-plus'; import { useTaskStore } from '@/stores/taskStore'; const taskStore = useTaskStore(); const inputText = ref(''); const maxLength = ref(100); const minLength = ref(30); const isFormValid = computed(() => { return inputText.value.length >= 10 && inputText.value.length <= 5000; }); const handleSubmit = async () => { if (!isFormValid.value) { ElMessage.warning('请输入10到5000字符的文本'); return; } await taskStore.submitSummaryTask({ text: inputText.value, max_length: maxLength.value, min_length: minLength.value, }); }; const handleReset = () => { inputText.value = ''; maxLength.value = 100; minLength.value = 30; taskStore.resetTask(); }; </script> <style scoped> .home-container { max-width: 900px; margin: 40px auto; padding: 0 20px; } .input-section { margin-bottom: 30px; } .param-controls { margin-top: 20px; } .action-buttons { margin-top: 20px; display: flex; gap: 10px; } .summary-text { margin-top: 20px; padding: 15px; background-color: #f9f9f9; border-radius: 4px; border-left: 4px solid #409eff; } </style>这个组件完成了所有前端功能:
- 双向数据绑定:使用
v-model绑定文本框和滑块。 - 表单验证:通过计算属性
isFormValid实时检查输入有效性。 - 状态驱动UI:按钮的加载状态、错误提示、结果展示全部依赖于 Pinia Store 中的状态(
isLoading,errorMessage,summaryResult)。 - 用户交互:点击按钮触发
handleSubmit,调用 Store 中的异步方法。
4.3 运行前端应用
在frontend目录下,运行开发服务器:
npm run devVite 会启动一个开发服务器,通常地址是http://localhost:5173。现在,你可以打开浏览器,输入一段长文本,调整参数,点击“生成摘要”。前端会显示“处理中...”,并在后台轮询任务状态,最终将生成的摘要或错误信息展示出来。
5. 项目联调、部署与生产环境考量
前后端都开发完成后,需要进行集成测试,并考虑如何部署到生产环境。
5.1 联调与常见问题排查
启动后端 (localhost:8000) 和前端 (localhost:5173) 服务后,进行功能测试。以下是几个常见问题及排查步骤:
| 问题现象 | 可能原因 | 检查方式 | 处理建议 |
|---|---|---|---|
| 前端无法访问后端 API,控制台报 CORS 错误 | 后端 CORS 配置未包含前端地址或配置错误 | 1. 检查后端origins列表。2. 查看浏览器 Network 面板,请求的 Origin头是否被允许。 | 确保后端allow_origins包含了前端实际运行的地址(如http://localhost:5173)。 |
| 提交任务后,前端一直显示“处理中”,无结果 | 1. 后端任务执行出错但未更新状态。 2. 前端轮询逻辑有误。 3. 模型加载失败。 | 1. 查看后端控制台日志。 2. 检查前端浏览器 Network 面板,轮询请求是否正常返回。 3. 直接调用后端 GET /summarize/{task_id}接口看状态。 | 1. 在后端run_summarization_task函数中添加更详细的日志。2. 检查模型下载是否成功(首次运行需联网)。 3. 增加前端轮询超时和错误处理。 |
| 模型推理速度极慢 | 1. 模型太大。 2. 未使用 GPU(如果可用)。 3. 输入文本过长。 | 1. 检查任务管理器的 CPU/GPU 占用。 2. 测量单次推理时间。 | 1. 考虑换用更小的模型(如t5-small)。2. 确认 PyTorch 是否安装了 CUDA 版本。 3. 在后端对输入文本长度做更严格的限制。 |
| 返回“Task not found” | 1. 前端传错了task_id。2. 后端服务重启,内存中的 tasks_store丢失。 | 检查前端轮询请求的 URL 中的task_id是否正确。 | 生产环境必须使用持久化存储(如 Redis、数据库)来保存任务状态。 |
5.2 生产环境部署建议
开发环境跑通只是第一步,生产环境需要考虑更多。
1. 后端部署:
- 服务器:使用 Gunicorn 或 Uvicorn 搭配多个 Worker 进程来处理并发请求。
# 使用 Gunicorn 运行 (需安装 gunicorn) gunicorn -w 4 -k uvicorn.workers.UvicornWorker app.main:app --bind 0.0.0.0:8000 - 反向代理:使用 Nginx 或 Apache 作为反向代理,处理静态文件、SSL 卸载、负载均衡和限流。
- 进程管理:使用 systemd 或 Supervisor 来管理后端进程,确保崩溃后自动重启。
- 模型部署优化:考虑将模型服务单独部署,使用 TorchServe 或 Triton Inference Server,并通过 gRPC 或 HTTP 与后端业务服务通信,实现模型的热更新和资源隔离。
2. 前端部署:
- 构建:运行
npm run build生成静态文件(位于dist目录)。 - 托管:可以将
dist目录下的文件上传至 Nginx、Apache 等 Web 服务器,或使用云服务商的对象存储(如 AWS S3、阿里云 OSS)配合 CDN。 - API 地址配置:构建前,需将
api.ts中的baseURL从localhost:8000改为生产环境的真实域名或 IP。
3. 环境变量与配置管理:
- 不要将敏感信息(如 API Keys、数据库密码)硬编码在代码中。
- 使用
.env文件(通过python-dotenv或vite的环境变量支持)或配置中心来管理不同环境的配置。
4. 监控与日志:
- 后端应用应集成结构化日志(如使用
structlog或loguru),并收集到 ELK 或 Loki 等日志系统中。 - 为关键接口添加性能指标(如请求延迟、错误率),可以使用 Prometheus + Grafana。
5.3 项目扩展方向
本项目是一个最小可行产品(MVP),你可以在此基础上进行丰富:
- 支持更多 AI 任务:修改后端服务层,集成文本分类、情感分析、翻译、文生图等模型,并通过路由区分。
- 用户系统:添加用户注册、登录、JWT 认证,并记录用户的历史摘要任务。
- 文件上传:支持上传 TXT、PDF、Word 文档,后端解析文本内容后再进行摘要。
- 流式输出:对于文本生成类任务,可以使用 Server-Sent Events (SSE) 实现逐词或逐句的流式返回,提升用户体验。
- 任务队列:使用 Celery + Redis/RabbitMQ 替代简单的内存字典,实现真正的分布式任务队列,支持重试、优先级和任务取消。
- 前端优化:添加任务历史列表、结果导出(复制、下载)、更丰富的主题和响应式设计。
通过这个从零到一的完整项目,你不仅学会了如何将前端、后端和 AI 模型组合在一起,更重要的是理解了它们之间如何通信、如何处理异步、如何应对错误,以及从开发到部署的全链路思考。这才是构建一个可靠 AI 应用的核心能力。
