品牌升级: - 全站品牌从"知冶"更名为"战知" - 更换 favicon、侧边栏 logo、登录页 logo - 更新登录页标语和首页欢迎语 应用广场重构: - 从后端数据库驱动改为前端静态配置,按分类 tab 展示 - 新增工具卡片 UI,支持 logo 图片和 emoji 图标 新增工具部署: - Stirling PDF (端口18080) - PDF 处理工具箱 - Excalidraw (端口18081) - 手绘风格白板,集成 AI 绘图 - TrWebOCR (端口18083) - 中文离线 OCR - LibreTranslate (端口18084) - 中英翻译引擎 - PPTist (端口18085) - 在线 PPT 编辑器 - PPTist AI 后端 (端口18086) - 对接 deepseek-v3 生成大纲/PPT/写作 - Excalidraw AI 代理 (端口18082) - 对接 deepseek-v3 生成 Mermaid 图 其他: - 智能场景仅保留"选题推荐" - vite 代理配置增加 /pdf/ 和 /draw/ 路由 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
99 lines
3.9 KiB
Python
99 lines
3.9 KiB
Python
"""
|
|
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)
|