release: bump version to 0.62.0
Some checks failed
ci / backend (push) Has been cancelled
ci / frontend (push) Has been cancelled
ci / delivery (push) Has been cancelled
release / images (push) Has been cancelled

This commit is contained in:
linkong
2026-05-21 01:37:32 +08:00
parent 5c65ee24d6
commit fbca381512
138 changed files with 21303 additions and 5721 deletions

View File

@@ -3,9 +3,11 @@
from __future__ import annotations
from dataclasses import dataclass
from copy import deepcopy
from typing import Any
from sqlalchemy import select
from sqlalchemy.orm.attributes import flag_modified
from app.ai_tasks.prompts import get_effective_prompt
from app.models.system_setting import SystemSetting
@@ -135,33 +137,57 @@ DEFAULT_CREDENTIAL_GUIDES = {
}
def _normalize_provider(provider: str) -> str:
return provider.strip().lower().replace(" ", "_")
def _credential_guide_default(provider: str) -> CredentialGuideDefault:
normalized = _normalize_provider(provider)
known = DEFAULT_CREDENTIAL_GUIDES.get(normalized)
if known is not None:
return known
title = f"{normalized or 'collector'} 凭证配置教程"
return CredentialGuideDefault(
provider=normalized,
title=title,
prompt=(
f"请生成一份中文教程,指导开发者为 Planet 采集器配置 {normalized} 凭证。"
"教程要面向已经有本地开发环境的人,包含官方入口或文档查找方式、"
"获取 API Key / Token / Client credentials 的通用步骤、在 Planet 采集器配置中"
"填写凭证字段、连接测试、保存、常见失败排查。不要编造具体页面按钮文案;"
"如果公开资料不足,必须明确提醒以 provider 官方文档和当前控制台页面为准。"
),
markdown="",
)
async def _get_guide_store(db) -> tuple[SystemSetting | None, dict[str, Any]]:
result = await db.execute(
select(SystemSetting).where(SystemSetting.category == CREDENTIAL_GUIDES_CATEGORY)
)
record = result.scalar_one_or_none()
payload = dict(record.payload or {}) if record and isinstance(record.payload, dict) else {}
payload = deepcopy(record.payload) if record and isinstance(record.payload, dict) else {}
return record, payload
async def get_credential_guide(db, provider: str) -> dict[str, Any]:
default = DEFAULT_CREDENTIAL_GUIDES.get(provider)
if default is None:
raise ValueError(f"Unsupported credential guide provider: {provider}")
provider = _normalize_provider(provider)
default = _credential_guide_default(provider)
_record, store = await _get_guide_store(db)
custom = store.get(provider) if isinstance(store.get(provider), dict) else None
has_default_markdown = bool(default.markdown.strip())
return {
"provider": provider,
"title": custom.get("title") if custom else default.title,
"markdown": custom.get("markdown") if custom else default.markdown,
"prompt": default.prompt,
"source": "ai" if custom else "default",
"source": "ai" if custom else "default" if has_default_markdown else "missing",
"sources": custom.get("sources", []) if custom else [],
"verification_status": (
custom.get("verification_status", "verified_with_search_evidence")
if custom
else "default_unverified"
else "default_unverified" if has_default_markdown else "missing"
),
"verification_error": custom.get("verification_error") if custom else None,
}
@@ -177,9 +203,8 @@ async def save_credential_guide(
verification_status: str = "verified_with_search_evidence",
verification_error: str | None = None,
) -> dict[str, Any]:
default = DEFAULT_CREDENTIAL_GUIDES.get(provider)
if default is None:
raise ValueError(f"Unsupported credential guide provider: {provider}")
provider = _normalize_provider(provider)
default = _credential_guide_default(provider)
record, store = await _get_guide_store(db)
store[provider] = {
@@ -192,21 +217,21 @@ async def save_credential_guide(
if record is None:
db.add(SystemSetting(category=CREDENTIAL_GUIDES_CATEGORY, payload=store))
else:
record.payload = store
record.payload = deepcopy(store)
flag_modified(record, "payload")
await db.commit()
return await get_credential_guide(db, provider)
async def reset_credential_guide(db, provider: str) -> dict[str, Any]:
default = DEFAULT_CREDENTIAL_GUIDES.get(provider)
if default is None:
raise ValueError(f"Unsupported credential guide provider: {provider}")
provider = _normalize_provider(provider)
record, store = await _get_guide_store(db)
if provider in store:
store.pop(provider, None)
if record is not None:
record.payload = store
record.payload = deepcopy(store)
flag_modified(record, "payload")
await db.commit()
return await get_credential_guide(db, provider)
@@ -217,9 +242,8 @@ async def generate_credential_guide(
ai_client: AIProviderClient,
web_search_client: WebSearchClient | None = None,
) -> dict[str, Any]:
default = DEFAULT_CREDENTIAL_GUIDES.get(provider)
if default is None:
raise ValueError(f"Unsupported credential guide provider: {provider}")
provider = _normalize_provider(provider)
default = _credential_guide_default(provider)
search_evidence: list[dict[str, Any]] = []
search_error: str | None = None