from __future__ import annotations from pathlib import Path from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from .schemas import ( TemplateCreate, MachineConfigCreate, MachineConfigUpdate, TemplatePreviewRequest, TemplateRenderRequest, TemplateRenderResponse, TemplateUpdate, ) from .services.renderer import renderer from .services.template_store import TemplateStore, load_store from .services.machine_store import MachineStore, load_machine_store def create_app() -> FastAPI: base_dir = Path(__file__).resolve().parents[1] store: TemplateStore = load_store(base_dir) machine_store: MachineStore = load_machine_store(base_dir / "data") app = FastAPI(title="洗衣机语音播报模板运营系统", version="1.0.0") app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"], ) @app.get("/api/health") async def health(): return {"status": "ok"} @app.get("/api/machine-configs") async def list_machine_configs(): """获取所有机型配置""" return { "configs": machine_store.configs, "reuse_map": machine_store.reuse_map, } @app.post("/api/machine-configs", status_code=201) async def create_machine_config(payload: MachineConfigCreate): """创建新机型""" try: config = { "label": payload.label, "type_ids": payload.type_ids, "zone_ids": payload.zone_ids, "card_type": payload.card_type, } result = machine_store.create(payload.model_key, config) if payload.reuse_from: machine_store.set_reuse(payload.model_key, {"all": payload.reuse_from}) return result except ValueError as e: from fastapi import HTTPException raise HTTPException(status_code=400, detail=str(e)) @app.put("/api/machine-configs/{model_key}") async def update_machine_config(model_key: str, payload: MachineConfigUpdate): """更新机型配置""" try: existing = machine_store.get(model_key) if not existing: from fastapi import HTTPException raise HTTPException(status_code=404, detail=f"机型 '{model_key}' 不存在") config = { "label": payload.label if payload.label is not None else existing["label"], "type_ids": payload.type_ids if payload.type_ids is not None else existing["type_ids"], "zone_ids": payload.zone_ids if payload.zone_ids is not None else existing["zone_ids"], "card_type": payload.card_type if payload.card_type is not None else existing["card_type"], } result = machine_store.update(model_key, config) if payload.reuse_from is not None: if payload.reuse_from: machine_store.set_reuse(model_key, {"all": payload.reuse_from}) elif model_key in machine_store.reuse_map: del machine_store.reuse_map[model_key] machine_store._save_reuse() return result except ValueError as e: from fastapi import HTTPException raise HTTPException(status_code=404, detail=str(e)) @app.delete("/api/machine-configs/{model_key}", status_code=204) async def delete_machine_config(model_key: str): """删除机型""" try: machine_store.delete(model_key) return {"status": "deleted"} except ValueError as e: from fastapi import HTTPException raise HTTPException(status_code=404, detail=str(e)) @app.get("/api/templates") async def list_templates( machine_model: str = None, device_type: str = None, template_type: str = None ): return store.list_templates(machine_model, device_type, template_type) @app.get("/api/templates/categories") async def list_categories(machine_model: str = None): return {"categories": store.list_categories(machine_model)} @app.get("/api/templates/machine-models") async def list_machine_models(): return {"machine_models": store.list_machine_models()} @app.get("/api/templates/device-types") async def list_device_types(machine_model: str = None): return {"device_types": store.list_device_types(machine_model)} @app.get("/api/templates/template-types") async def list_template_types(machine_model: str = None, device_type: str = None): return {"template_types": store.list_template_types(machine_model, device_type)} @app.get("/api/templates/{template_id}") async def get_template(template_id: str): return store.get_template(template_id) @app.post("/api/templates", status_code=201) async def create_template(payload: TemplateCreate): return store.create_template(payload) @app.put("/api/templates/{template_id}") async def update_template(template_id: str, payload: TemplateUpdate): return store.update_template(template_id, payload) @app.delete("/api/templates/{template_id}", status_code=204) async def delete_template(template_id: str): store.delete_template(template_id) return {"status": "deleted"} @app.get("/api/templates/{template_id}/redis-keys") async def get_template_redis_keys(template_id: str): record = store.get_template(template_id) return store.generate_redis_keys(record) @app.post("/api/templates/render", response_model=TemplateRenderResponse) async def render_template(payload: TemplateRenderRequest): record = store.get_template(payload.template_id) rendered = renderer.render_from_record(record, payload.parameters) return {"rendered_text": rendered} @app.post("/api/templates/preview") async def preview_template(payload: TemplatePreviewRequest): """预览模板 - 自动识别变量""" return renderer.preview(payload) return app app = create_app()