chore: initial commit of ai site platform
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
83
ai-service/demo_fixtures.py
Normal file
83
ai-service/demo_fixtures.py
Normal file
@@ -0,0 +1,83 @@
|
||||
"""本地演示/测试素材:供控制台一键预填需求与上传文件。
|
||||
|
||||
目录默认:仓库 test/(可用 DEMO_FIXTURES_DIR 覆盖)。
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import mimetypes
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import HTTPException
|
||||
from fastapi.responses import FileResponse
|
||||
|
||||
_ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def fixtures_root() -> Path:
|
||||
raw = (os.getenv("DEMO_FIXTURES_DIR") or "").strip()
|
||||
if raw:
|
||||
return Path(raw).expanduser().resolve()
|
||||
return (_ROOT / "test").resolve()
|
||||
|
||||
|
||||
# 默认演示包:沉降观测(行业示例,仅测试用)
|
||||
DEFAULT_PACK = {
|
||||
"id": "settlement_demo",
|
||||
"label": "沉降观测演示包(test/)",
|
||||
"prompt": "prompts/prompt_1.txt",
|
||||
"data": "data/settlement.xlsx",
|
||||
"images": ["refs/board_a.png", "refs/board_b.png"],
|
||||
"layouts": ["refs/dashboard.html", "refs/nav.html"],
|
||||
"slug": "settlement_observation_system",
|
||||
}
|
||||
|
||||
|
||||
def _safe_file(rel: str) -> Path:
|
||||
root = fixtures_root()
|
||||
rel = (rel or "").replace("\\", "/").lstrip("/")
|
||||
if not rel or ".." in rel.split("/"):
|
||||
raise HTTPException(400, "非法路径")
|
||||
path = (root / rel).resolve()
|
||||
try:
|
||||
path.relative_to(root)
|
||||
except ValueError as e:
|
||||
raise HTTPException(400, "越界路径") from e
|
||||
if not path.is_file():
|
||||
raise HTTPException(404, f"文件不存在: {rel}")
|
||||
return path
|
||||
|
||||
|
||||
def fixtures_manifest() -> dict:
|
||||
root = fixtures_root()
|
||||
pack = dict(DEFAULT_PACK)
|
||||
pack["root"] = str(root)
|
||||
pack["available"] = root.is_dir()
|
||||
|
||||
def ok(rel: str) -> bool:
|
||||
try:
|
||||
return _safe_file(rel).is_file()
|
||||
except HTTPException:
|
||||
return False
|
||||
|
||||
pack["files"] = {
|
||||
"prompt": {"path": pack["prompt"], "ok": ok(pack["prompt"])},
|
||||
"data": {"path": pack["data"], "ok": ok(pack["data"])},
|
||||
"images": [{"path": p, "ok": ok(p)} for p in pack["images"]],
|
||||
"layouts": [{"path": p, "ok": ok(p)} for p in pack["layouts"]],
|
||||
}
|
||||
return pack
|
||||
|
||||
|
||||
def read_prompt_text() -> str:
|
||||
return _safe_file(DEFAULT_PACK["prompt"]).read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def file_response(rel: str) -> FileResponse:
|
||||
path = _safe_file(rel)
|
||||
ctype, _ = mimetypes.guess_type(str(path))
|
||||
return FileResponse(
|
||||
path,
|
||||
media_type=ctype or "application/octet-stream",
|
||||
filename=path.name,
|
||||
)
|
||||
Reference in New Issue
Block a user