from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from app.config import API_TITLE, API_VERSION from app.routers import jokes_router, categories_router, auth_router, admin_router, settings_router, links_router, feedback_router, generate_router from app.routers.submit import router as submit_router from app.database import Base, engine from app.models.setting import AiSetting from app.models.link import Link from app.models.feedback import Feedback # 注册模型,确保 create_all 能看到 # 创建新表(如果不存在) Base.metadata.create_all(bind=engine) # 对已有表新增字段的兼容迁移(SQLite 不支持 ALTER TABLE ADD COLUMN IF NOT EXISTS) # 默认提示词 _GENERATE_PROMPT_DEFAULT = """你是一位幽默大师,专门创作轻松搞笑的短笑话。 {context} 要求: 1. 根据场景和关键词创作一条原创笑话 2. 笑话要有反转或意外结局 3. 语言风格:{style} 4. 字数要求:{length_requirement} 5. 直接输出笑话内容,不需要解释 请严格按照以下 JSON 格式输出,不要加任何额外说明: {{ "title": "笑话标题", "content": "笑话正文", "score": 8, "reason": "这个笑话巧妙结合了场景和关键词,结尾有反转" }} score 是 1-10 的整数评分,reason 是用一句话说明亮点。""" _OPTIMIZER_QUALITY_DEFAULT = """你是一个幽默内容审核专家。判断以下内容是否是一个合格的笑话/段子。 合格标准(满足任一即可): 1. 有明确的笑点或反转(punchline) 2. 有幽默的语言表达或双关 3. 有意外结局或情理之中意料之外 不合格标准(符合任一即判定不合格): 1. 纯粹的事实陈述,没有任何幽默元素 2. 只是对话片段,没有笑点 3. 普通故事或叙事,没有幽默设计 4. 说教或道理阐述 5. 内容不完整或难以理解 始终返回 JSON 格式:{"has_punchline": true/false, "reason": "简要说明判断理由"}""" _OPTIMIZER_POLISH_DEFAULT = """你是一个专业的幽默文案编辑。请润色以下笑话,要求: 1. 保持核心笑点不变 2. 优化语言表达,使其更通顺、更精炼 3. 增强节奏感和幽默效果,但不改变原意 4. 字数控制在原内容的 80%-120% 5. 不要添加额外解释或评论 6. 直接输出润色后的内容,不要加任何前缀""" _OPTIMIZER_EVALUATE_DEFAULT = """你是一个笑话分类和评价专家。对给定的笑话进行分析,返回 JSON 格式的分类和评分结果。 要求: 1. types: 从提供的类型列表中选择所有匹配的类型名称(数组,可以选多个) 2. crowds: 从提供的人群列表中选择所有匹配的人群名称(数组,可以选多个) 3. score: 1-10 分,基于幽默程度、创意和表达效果 4. comment: 简短评语(10字以内) 始终返回 JSON 格式。""" _CRAWLER_EXTRACT_DEFAULT = """你是一个笑话提取专家。从给定的网页文本中识别并提取所有笑话、幽默段子或有趣内容。 要求: 1. 只返回真正的笑话内容,不要提取普通文章或新闻 2. 每条笑话需要包含:title(简短标题)、content(完整笑话内容)、type(类型)、crowd(人群) 3. 如果网页中没有笑话,返回空数组 [] 4. 永远返回合法的 JSON 格式,根节点为数组或包含 jokes 键的对象""" _CRAWLER_REWRITE_DEFAULT = """你是一个幽默作家,负责润色和改写笑话。 要求: 1. 保持笑话的核心笑点不变 2. 语言更通顺、更幽默 3. 字数控制在原内容的 80%-120% 之间 4. 不要添加任何解释说明""" def _migrate_db(): from sqlalchemy import inspect, text inspector = inspect(engine) columns = [c["name"] for c in inspector.get_columns("ai_settings")] # 新增提示词字段 prompt_fields = { "generate_prompt": _GENERATE_PROMPT_DEFAULT, "optimizer_quality_prompt": _OPTIMIZER_QUALITY_DEFAULT, "optimizer_polish_prompt": _OPTIMIZER_POLISH_DEFAULT, "optimizer_evaluate_prompt": _OPTIMIZER_EVALUATE_DEFAULT, "crawler_extract_prompt": _CRAWLER_EXTRACT_DEFAULT, "crawler_rewrite_prompt": _CRAWLER_REWRITE_DEFAULT, } for field, default_val in prompt_fields.items(): if field not in columns: from sqlalchemy import Text col_type = "TEXT" with engine.connect() as conn: conn.execute(text(f"ALTER TABLE ai_settings ADD COLUMN {field} {col_type}")) conn.commit() # 新增 temperature 字段 temp_fields = [ ("optimizer_quality_temperature", "FLOAT", "0.3"), ("optimizer_polish_temperature", "FLOAT", "0.8"), ("optimizer_evaluate_temperature", "FLOAT", "0.3"), ] for field, col_type, default_val in temp_fields: if field not in columns: with engine.connect() as conn: conn.execute(text(f"ALTER TABLE ai_settings ADD COLUMN {field} {col_type} DEFAULT {default_val}")) conn.commit() # 给新增字段填充默认值(已有记录) with engine.connect() as conn: for field, default_val in prompt_fields.items(): conn.execute(text(f"UPDATE ai_settings SET {field} = :val WHERE {field} IS NULL"), {"val": default_val}) conn.commit() _migrate_db() # Create FastAPI application app = FastAPI(title=API_TITLE, version=API_VERSION) # Configure CORS app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Mount routers app.include_router(jokes_router, prefix="/api") app.include_router(categories_router, prefix="/api") app.include_router(auth_router, prefix="/api") app.include_router(admin_router, prefix="/api") app.include_router(settings_router, prefix="/api") app.include_router(links_router, prefix="/api") app.include_router(feedback_router, prefix="/api") app.include_router(generate_router, prefix="/api") app.include_router(submit_router, prefix="/api/jokes") # 公开提交接口 @app.get("/") def root(): return {"message": "欢迎使用笑话大全 API"} @app.get("/health") def health_check(): return {"status": "healthy"}