Files
gangyan/scripts/excalidraw-ai-proxy.py

99 lines
3.9 KiB
Python
Raw Normal View History

"""
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"<html><body><h1>Generation Error</h1><p>{str(e)[:100]}</p></body></html>"
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=18082)