落地并存测服全端:智能体 Graph/路由、后台切 8180、主账与部署脚本齐备,便于线上重发与验收。
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
"""
|
||||
报价模板访问壳。
|
||||
|
||||
真相在主账:后台上传/启用/停用 → 对象存储存字节 → 主账存元数据。
|
||||
智能体生成报价前经 ledger 拉取已启用模板指针,再从对象存储取字节。
|
||||
|
||||
本文件职责:声明「从主账列模板」的空 API;可选本地缓存目录仅联调。
|
||||
禁止:把仓库 resources 当生产模板真相;禁止在本包发明价格或改 quoteVersion。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any, Optional
|
||||
|
||||
from agent.ledger import LedgerClient, LedgerResponse
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class TemplateEntry:
|
||||
"""一条模板元数据(来自主账或联调缓存)。"""
|
||||
|
||||
code: str
|
||||
filename: str = ""
|
||||
object_key: str = ""
|
||||
enabled: bool = False
|
||||
source: str = "ledger"
|
||||
|
||||
|
||||
def local_cache_dir() -> Path:
|
||||
"""
|
||||
可选本机缓存目录(非生产真相)。
|
||||
|
||||
正式模板由后台上传;此目录仅开发落盘缓存,可空。
|
||||
"""
|
||||
here = Path(__file__).resolve()
|
||||
return here.parents[2] / "resources" / "quote_templates"
|
||||
|
||||
|
||||
def list_templates_from_ledger(
|
||||
client: Optional[LedgerClient] = None,
|
||||
) -> LedgerResponse:
|
||||
"""
|
||||
向主账查询已启用报价模板列表(壳)。
|
||||
|
||||
正式路径以主账 OpenAPI 为准;当前返回 not_implemented,不假装本地文件即生产模板。
|
||||
"""
|
||||
c = client or LedgerClient.from_settings()
|
||||
logger.info("quote_templates.list_from_ledger(壳,未打真实 API)")
|
||||
return LedgerResponse(
|
||||
ok=False,
|
||||
status_code=501,
|
||||
error="not_implemented:list_quote_templates",
|
||||
data={"hint": "admin_upload_via_ledger"},
|
||||
)
|
||||
|
||||
|
||||
def list_local_cache_files() -> list[TemplateEntry]:
|
||||
"""
|
||||
列出本机缓存目录中的 xlsx(仅联调;可空)。
|
||||
|
||||
不等于后台已启用模板。
|
||||
"""
|
||||
root = local_cache_dir()
|
||||
if not root.is_dir():
|
||||
return []
|
||||
out: list[TemplateEntry] = []
|
||||
for path in sorted(root.iterdir()):
|
||||
if not path.is_file():
|
||||
continue
|
||||
if path.suffix.lower() not in {".xlsx", ".xlsm", ".xltx"}:
|
||||
continue
|
||||
if path.name.startswith("."):
|
||||
continue
|
||||
out.append(
|
||||
TemplateEntry(
|
||||
code=path.stem,
|
||||
filename=path.name,
|
||||
object_key="",
|
||||
enabled=False,
|
||||
source="local_cache",
|
||||
)
|
||||
)
|
||||
logger.info("quote_templates.local_cache count=%s", len(out))
|
||||
return out
|
||||
|
||||
|
||||
def list_template_registry() -> list[TemplateEntry]:
|
||||
"""
|
||||
兼容旧名:框架阶段返回本地缓存列表(可空)。
|
||||
|
||||
生产应改用 list_templates_from_ledger + 对象存储下载。
|
||||
"""
|
||||
return list_local_cache_files()
|
||||
|
||||
|
||||
def registry_as_dicts() -> list[dict[str, Any]]:
|
||||
"""便于 JSON/自检。"""
|
||||
return [
|
||||
{
|
||||
"code": e.code,
|
||||
"filename": e.filename,
|
||||
"object_key": e.object_key,
|
||||
"enabled": e.enabled,
|
||||
"source": e.source,
|
||||
}
|
||||
for e in list_template_registry()
|
||||
]
|
||||
Reference in New Issue
Block a user