feat: 品牌升级(知冶→战知) + 应用工具广场重构 + 新增工具集成
品牌升级: - 全站品牌从"知冶"更名为"战知" - 更换 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>
This commit is contained in:
98
scripts/excalidraw-ai-proxy.py
Normal file
98
scripts/excalidraw-ai-proxy.py
Normal file
@@ -0,0 +1,98 @@
|
||||
"""
|
||||
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)
|
||||
Reference in New Issue
Block a user