Files
writer-work-flow/apps/api/ww_api/main.py
Yaojia Wang 765dbdfbd4 feat: M4 文风 + M5 生成/多provider/Skill + Kimi Code 订阅接入 + 本地联调修复
M4(文风): style-auditor 双轨(提取指纹/漂移第四审)+ jobs 长任务框架(zombie reaper) + 回炉 refine + GET /style read-back。
M5(生成+扩展): worldbuilder/character-gen(入库 continuity 409 gate + partition_writes 白名单 + schema→JSONB 形变);
  网关多 provider 回退链/熔断/能力降级(Anthropic/Gemini 适配器);Skill registry + 表权限沙箱 + 规则;
  前端 角色生成器/世界观/Codex/规则页/技能库/⌘K 命令面板。
K1(Kimi Code 订阅接入): OAuth device-flow(kimi-code)+ 静态 Console key(kimi-code-key)两路径;
  coding 端点 KimiCLI 伪造头(实测 UA allow-list 门禁,缺则 403)+ JSON 模式结构化(thinking ⊥ tool_choice)。
本地联调修复: CORS 中间件;assemble 注入 premise+「写第N章」指令(修空 prompt 400);
  GET /outline·/draft read-back + 大纲/工作台/审稿页重载;写页 client/server 常量边界 + notFound 健壮化;
  字数 toLocaleString locale 水合;审稿页终稿从已存草稿 seed(修 accept 422)。
门禁: backend ruff/mypy(157)/alembic 无漂移/pytest 451 · frontend lint/tsc/vitest/build。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 10:39:58 +02:00

94 lines
3.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""FastAPI 应用入口ARCH §7"""
from __future__ import annotations
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from ww_config import get_settings
from ww_core.domain.job_repo import SqlJobRepo
from ww_db import get_sessionmaker
from ww_shared import AppError, ErrorBody, ErrorEnvelope
from ww_api.logging_config import configure_logging, get_logger
from ww_api.middleware import request_id_middleware
from ww_api.routers import (
foreshadow,
generation,
health,
jobs,
kimi_oauth,
outline,
projects,
rules,
settings_providers,
style,
)
from ww_api.services.project_deps import seed_stub_user
configure_logging()
log = get_logger("ww.api")
@asynccontextmanager
async def _lifespan(app: FastAPI) -> AsyncIterator[None]:
# 幂等 seed 单用户 stub——所有 owner_id FK 依赖它(见 memory/gotchas
async with get_sessionmaker()() as session:
await seed_stub_user(session)
# zombie reaperM4-d / §7.4 缓解):进程重启会丢未跑完的 BackgroundTask把残留
# status=running 的 job 标 failed让用户看到失败可重试而非进度条永转。自 commit、幂等。
async with get_sessionmaker()() as session:
reaped = await SqlJobRepo(session).reap_zombies()
if reaped:
log.info("job_zombies_reaped", count=reaped)
yield
def create_app() -> FastAPI:
app = FastAPI(title="网文创作工作流 API", version="0.0.0", lifespan=_lifespan)
# CORS前端Next.js与 API 分端口/跨源,浏览器端 `api.POST/PUT` 需 CORS 放行
# RSC 服务端取数同源、无需 CORS故此前同进程测试从未暴露此缺口。原型单用户、
# 本地开发:放行 localhost:3000可经 env `CORS_ORIGINS`(逗号分隔)覆盖。
settings = get_settings()
app.add_middleware(
CORSMiddleware,
allow_origins=settings.cors_origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.middleware("http")(request_id_middleware)
@app.exception_handler(AppError)
async def _app_error_handler(request: Request, exc: AppError) -> JSONResponse:
request_id = getattr(request.state, "request_id", None)
log.warning("app_error", code=exc.code, message=exc.message)
envelope = ErrorEnvelope(
error=ErrorBody(
code=exc.code,
message=exc.message,
details=exc.details,
request_id=request_id,
)
)
return JSONResponse(status_code=exc.http_status, content=envelope.model_dump())
app.include_router(health.router)
app.include_router(jobs.router)
app.include_router(projects.router)
app.include_router(foreshadow.router)
app.include_router(outline.router)
app.include_router(rules.router)
app.include_router(style.router)
app.include_router(generation.router)
app.include_router(generation.skills_router)
app.include_router(settings_providers.router)
app.include_router(kimi_oauth.router)
return app
app = create_app()