""" Excalidraw AI 代理服务 接收 Excalidraw 的 text-to-diagram 请求,转发给 deepseek-v3 生成 Mermaid 语法 """ from fastapi import FastAPI, Request from fastapi.middleware.cors import CORSMiddleware import requests import json app = FastAPI() app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"], ) LLM_API = "http://10.102.24.75:3000/v1/chat/completions" LLM_KEY = "sk-BlQIGRrotbVDWE5mXCPBFjVWIvJ83hldzz67xInNwzVo7pPb" SYSTEM_PROMPT = """You are an expert at creating Mermaid diagrams. When the user describes a diagram, workflow, flowchart, or similar, generate ONLY valid Mermaid syntax. Do not include any explanation, just the Mermaid code. Do not wrap it in markdown code blocks. Always start with a diagram type declaration like: graph TD, flowchart LR, sequenceDiagram, classDiagram, etc.""" @app.post("/v1/ai/text-to-diagram/generate") async def text_to_diagram(request: Request): body = await request.json() print(f"[AI] Received request: {json.dumps(body, ensure_ascii=False)[:500]}") prompt = body.get("prompt", body.get("text", body.get("message", ""))) try: resp = requests.post(LLM_API, json={ "model": "deepseek-v3", "messages": [ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": prompt} ], "temperature": 0.3, "max_tokens": 2048 }, headers={"Authorization": f"Bearer {LLM_KEY}"}, timeout=60) result = resp.json() print(f"[AI] LLM response status: {resp.status_code}") mermaid_code = result["choices"][0]["message"]["content"].strip() # 清理可能的 markdown 包裹 if mermaid_code.startswith("```"): mermaid_code = mermaid_code.split("\n", 1)[1] if "\n" in mermaid_code else mermaid_code[3:] if mermaid_code.endswith("```"): mermaid_code = mermaid_code[:-3].strip() print(f"[AI] Mermaid output: {mermaid_code[:200]}") return {"generatedResponse": mermaid_code} except Exception as e: print(f"[AI] Error: {e}") return {"generatedResponse": f"graph TD\n A[Error: {str(e)[:50]}]"} @app.post("/v1/ai/diagram-to-code/generate") async def diagram_to_code(request: Request): body = await request.json() texts = body.get("texts", []) theme = body.get("theme", "light") print(f"[AI] diagram-to-code request, texts: {texts[:5]}, theme: {theme}") prompt = f"Based on these UI element labels: {', '.join(texts) if texts else 'empty wireframe'}. Theme: {theme}. Generate a complete, beautiful HTML page with inline CSS that represents this wireframe layout. Only output the HTML code, nothing else." try: resp = requests.post(LLM_API, json={ "model": "deepseek-v3", "messages": [ {"role": "system", "content": "You are an expert web developer. Generate complete HTML with inline CSS based on wireframe descriptions. Output ONLY the HTML code, no explanation, no markdown code blocks."}, {"role": "user", "content": prompt} ], "temperature": 0.3, "max_tokens": 4096 }, headers={"Authorization": f"Bearer {LLM_KEY}"}, timeout=60) result = resp.json() html_code = result["choices"][0]["message"]["content"].strip() if html_code.startswith("```"): html_code = html_code.split("\n", 1)[1] if "\n" in html_code else html_code[3:] if html_code.endswith("```"): html_code = html_code[:-3].strip() print(f"[AI] HTML output length: {len(html_code)}") return html_code except Exception as e: print(f"[AI] diagram-to-code error: {e}") return f"

Generation Error

{str(e)[:100]}

" if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=18082)