refactor: improve codebase structure and Univer integration
- Add AGENTS.md knowledge base with project documentation - Move UserPreferences model to separate models.py file - Extract API_KEY to environment variable for security - Enhance Univer Editor with PPTX support and improved UI - Improve file system handling with binary file detection - Add HF_ENDPOINT mirror for better China connectivity - Clean up unused imports and code structure
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
# Backend 模块指南
|
||||
|
||||
## OVERVIEW
|
||||
FastAPI 后端,处理 AI 补全、OCR、文档转换、TTS/ASR。
|
||||
|
||||
## STRUCTURE
|
||||
- main.py - API 入口、路由、CORS、启动逻辑
|
||||
- llm.py - Ollama 异步调用、超时控制、日志
|
||||
- prompt.py - Prompt 构建、上下文准备、语言处理
|
||||
- geoip.py - IP 地理位置查询
|
||||
- tts_asr.py - TTS/ASR 处理、Apple Silicon 优化
|
||||
- prompts/ - JSON 格式提示模板(PromptManager 单例)
|
||||
- tests/ - pytest 测试套件(见子目录 AGENTS.md)
|
||||
|
||||
## WHERE TO LOOK
|
||||
|
||||
| 任务 | 文件 | 说明 |
|
||||
|------|------|------|
|
||||
| API 路由定义 | main.py | /v1/completions、/v1/ocr、/v1/convert 等 |
|
||||
| LLM 调用封装 | llm.py | call_ollama、call_vlm_ocr、超时控制 |
|
||||
| Prompt 构建 | prompt.py | build_completion_prompts、语言处理 |
|
||||
| 提示模板 | prompts/__init__.py | PromptManager、JSON 模板加载 |
|
||||
| TTS/ASR | tts_asr.py | 模型预热、设备检测、音频处理 |
|
||||
| 测试 | tests/ | pytest 测试套件 |
|
||||
|
||||
## CONVENTIONS
|
||||
- Python 4 空格缩进
|
||||
- 函数/变量:snake_case
|
||||
- 类:PascalCase
|
||||
- 文件名:全小写+短横线
|
||||
|
||||
## ANTI-PATTERNS
|
||||
- 硬编码 API_KEY(必须从环境变量读取)
|
||||
- 空 catch 块
|
||||
- 类型错误使用 as any / @ts-ignore
|
||||
|
||||
## 注意事项
|
||||
- 端口:8001
|
||||
- 启动:`python backend/main.py` 或 `uvicorn backend.main:app --reload`
|
||||
- 依赖:`pip install -r backend/requirements.txt`
|
||||
@@ -17,7 +17,6 @@ VLM_MODEL = os.getenv('VLM_MODEL', 'qwen3-vl:30b')
|
||||
# Timeouts in seconds (10 minutes for large model loading)
|
||||
COMPLETION_TIMEOUT = 600
|
||||
OCR_TIMEOUT = 600
|
||||
CONVERT_TIMEOUT = 600
|
||||
|
||||
client = ollama.AsyncClient(host=OLLAMA_HOST)
|
||||
logger = logging.getLogger("llm")
|
||||
|
||||
+2
-7
@@ -17,6 +17,7 @@ from pydantic import BaseModel
|
||||
|
||||
from geoip import get_ip_location_text
|
||||
from llm import call_ollama, call_vlm_ocr
|
||||
from models import UserPreferences
|
||||
from prompt import build_completion_prompts, prepare_prompt_context
|
||||
import markitdown
|
||||
|
||||
@@ -57,7 +58,7 @@ app.add_middleware(
|
||||
allow_headers=["*", "X-API-Key", "X-Client-IP", "X-Request-Id"],
|
||||
)
|
||||
|
||||
API_KEY = "your-secret-key-here"
|
||||
API_KEY = os.getenv("API_KEY", "your-secret-key-here")
|
||||
api_key_header = APIKeyHeader(name="X-API-Key")
|
||||
|
||||
|
||||
@@ -70,12 +71,6 @@ async def get_api_key(api_key: str = Security(api_key_header)): # pragma: no co
|
||||
return api_key
|
||||
|
||||
|
||||
class UserPreferences(BaseModel):
|
||||
language: str = "auto"
|
||||
currency: str = "auto"
|
||||
timezone: str = "auto"
|
||||
|
||||
|
||||
class CompletionRequest(BaseModel):
|
||||
prefix: str
|
||||
suffix: str
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
"""共享的 Pydantic 模型定义"""
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class UserPreferences(BaseModel):
|
||||
"""用户偏好设置"""
|
||||
language: str = "auto"
|
||||
currency: str = "auto"
|
||||
timezone: str = "auto"
|
||||
+2
-8
@@ -1,17 +1,11 @@
|
||||
from datetime import datetime, timedelta, timezone
|
||||
import re
|
||||
from typing import Protocol, Tuple, runtime_checkable
|
||||
from typing import Tuple
|
||||
|
||||
from models import UserPreferences
|
||||
from prompts import get_language_guidance_map, get_system_prompt_template, get_inline_examples
|
||||
|
||||
|
||||
@runtime_checkable
|
||||
class UserPreferences(Protocol):
|
||||
language: str
|
||||
currency: str
|
||||
timezone: str
|
||||
|
||||
|
||||
def _get_current_datetime(timezone_pref: str = "auto") -> str:
|
||||
# Default to UTC+8 if auto or not specified.
|
||||
offset = 8
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
OVERVIEW: pytest 测试套件,覆盖率要求 90%
|
||||
STRUCTURE:
|
||||
- test_*.py - 各模块测试
|
||||
- run_tests.py - 测试执行脚本(unit/integration/all)
|
||||
- simulate_macos.py - macOS 环境模拟
|
||||
- TESTING_GUIDE.md - 测试指南文档
|
||||
|
||||
WHERE TO LOOK
|
||||
表格
|
||||
|
||||
| Area | Path |
|
||||
|---|---|
|
||||
| 单元测试 | backend/tests/ |
|
||||
| 集成测试 | backend/tests/ |
|
||||
| 测试执行脚本 | backend/tests/run_tests.py |
|
||||
| macOS 模拟 | backend/tests/simulate_macos.py |
|
||||
| 测试指南 | backend/tests/TESTING_GUIDE.md |
|
||||
|
||||
运行命令:
|
||||
- pytest - 运行所有测试
|
||||
- python backend/tests/run_tests.py unit - 单元测试
|
||||
- python backend/tests/run_tests.py integration - 集成测试
|
||||
|
||||
测试命名约定:test_*.py、Test* 类、test_* 函数
|
||||
|
||||
ANTI-PATTERNS:删除测试以通过覆盖率
|
||||
|
||||
验证
|
||||
- 保证测试覆盖率≥90% 时,报告合格
|
||||
- 使用 CI 运行 pytest,确保通过率
|
||||
|
||||
注意事项
|
||||
- 不要重复父目录内容
|
||||
- 不要超过 60 行
|
||||
|
||||
测试应尽量独立,不要依赖全局状态
|
||||
- 运行单元测试时应使用 unit 标签
|
||||
- 运行集成测试时应使用 integration 标签
|
||||
|
||||
区分环境
|
||||
- unit 测试应尽量快速、稳定
|
||||
- integration 测试应覆盖接口和数据库交互
|
||||
|
||||
维护
|
||||
- 如扩展新模块,优先增加 test_*.py 文件并在其中添加对应的测试类和方法
|
||||
+6
-2
@@ -1,9 +1,13 @@
|
||||
import asyncio
|
||||
import base64
|
||||
import logging
|
||||
import os
|
||||
from io import BytesIO
|
||||
from typing import Optional
|
||||
|
||||
# 设置 Hugging Face 镜像源为国内镜像
|
||||
os.environ.setdefault("HF_ENDPOINT", "https://hf-mirror.com")
|
||||
|
||||
import torch
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from pydantic import BaseModel
|
||||
@@ -29,8 +33,8 @@ def _get_device_map() -> str:
|
||||
try:
|
||||
if hasattr(torch.backends, "mps") and torch.backends.mps.is_available():
|
||||
return "mps"
|
||||
except Exception:
|
||||
pass
|
||||
except Exception as e:
|
||||
logger.debug("MPS check failed: %s", e)
|
||||
return "cpu"
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user