- wwwroot/api/ 六个对外端点(Bearer Key 鉴权,路由授 any、业务鉴权在 api_core):
kb_create/kb_delete/doc_upload/doc_delete/tag_create/doc_set_tags/search
- rag/api_core.py: verify_api_key + make_api_env(org注入) + 六个业务核心
(复用 init.py 底层检索/入库能力,杜绝双实现分叉)
- 统一返回格式 {"status":"ok"|"error","data":...}
- rag/ingest.py: 入库管线从 upload_file.dspy 抽出共享(UI/API同一引擎)
- rag/tools.py: RAG_TOOL_SCHEMAS + exec_rag_tool(与API同构,供内部助手调用)
- rag_api_keys 表 model(key 只存 SHA256);管理端 api_key_create/list/revoke
- load_path.py 注册 7 个 API 端点(any) + 3 个管理端点(logined)
43 lines
2.1 KiB
Plaintext
43 lines
2.1 KiB
Plaintext
# 管理端:创建对外 API Key(登录用户;org 取自会话)
|
||
# POST /rag/knowledge_bases_list/api_key_create.dspy
|
||
# params: {name, scopes?, expires_days?}
|
||
# 返回 widget:一次性展示明文 key(库里只存 SHA256)
|
||
import secrets
|
||
from rag import api_core as C
|
||
|
||
ns = params_kw.copy()
|
||
env = request._run_ns
|
||
org_id = await env.get_userorgid()
|
||
name = (ns.get('name') or '默认密钥').strip()
|
||
scopes = ns.get('scopes') or ''
|
||
if isinstance(scopes, (list, tuple)):
|
||
scopes = ','.join(str(x) for x in scopes)
|
||
scopes = str(scopes).strip() or 'kb.create,kb.delete,doc.upload,doc.delete,tag.write,search'
|
||
try:
|
||
exp_days = int(ns.get('expires_days') or 0)
|
||
except (TypeError, ValueError):
|
||
exp_days = 0
|
||
|
||
plain = 'rag-' + secrets.token_hex(24)
|
||
kid = str(uuid()).replace('-', '')[:16]
|
||
db = DBPools()
|
||
async with db.sqlorContext(get_module_dbname('rag')) as sor:
|
||
if exp_days > 0:
|
||
await sor.sqlExe(
|
||
"INSERT INTO rag_api_keys (id, org_id, name, key_hash, prefix, scopes, status, expires_at, created_at) "
|
||
"VALUES (${id}$, ${o}$, ${n}$, ${h}$, ${p}$, ${s}$, 'active', DATE_ADD(NOW(), INTERVAL ${d}$ DAY), NOW())",
|
||
{"id": kid, "o": org_id, "n": name, "h": C.hash_key(plain),
|
||
"p": plain[:12], "s": scopes, "d": exp_days})
|
||
else:
|
||
await sor.sqlExe(
|
||
"INSERT INTO rag_api_keys (id, org_id, name, key_hash, prefix, scopes, status, created_at) "
|
||
"VALUES (${id}$, ${o}$, ${n}$, ${h}$, ${p}$, ${s}$, 'active', NOW())",
|
||
{"id": kid, "o": org_id, "n": name, "h": C.hash_key(plain), "p": plain[:12], "s": scopes})
|
||
await sor.sqlExe("COMMIT", {})
|
||
|
||
return {"widgettype": "VBox", "options": {"padding": "12px", "spacing": "8px"}, "subwidgets": [
|
||
{"widgettype": "Text", "options": {"text": "✅ API Key 已创建(仅此一次展示,请立即保存)", "cfontsize": 15, "color": "#10b981"}},
|
||
{"widgettype": "Text", "options": {"text": plain, "cfontsize": 13, "bgcolor": "#f5f7fa", "padding": "8px", "css": "selectable monospace"}},
|
||
{"widgettype": "Text", "options": {"text": "名称: " + name + " · 范围: " + scopes, "cfontsize": 12, "color": "#888"}},
|
||
]}
|