Files

97 lines
4.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""IMA 上传单篇 Markdown 知识笔记到 daily 知识库。
用法: python3 ima_upload_one.py "<绝对路径/summary.md>" "<完整文章标题>"
依赖环境变量: IMA_OPENAPI_CLIENTID / IMA_OPENAPI_APIKEY / IMA_DAILY_KNOWLEDGE_BASE_ID
流程: preflight -> check_repeated_names -> create_media -> cos-upload -> add_knowledge
说明: 用 Python 而非 bash 编排,避免中文文件名/引号转义问题。
退出码 2 = 文件名重复(需与用户确认保留双方或取消),非 0 均为失败。
"""
import json, os, subprocess, sys
SKILL_DIR = "/root/.hermes/skills/openclaw-imports/ima-skill"
IMA_API = os.path.join(SKILL_DIR, "ima_api.cjs")
COS_UPLOAD = os.path.join(SKILL_DIR, "knowledge-base/scripts/cos-upload.cjs")
PREFLIGHT = os.path.join(SKILL_DIR, "knowledge-base/scripts/preflight-check.cjs")
def run_node(script, args):
r = subprocess.run(["node", script] + args, capture_output=True, text=True, timeout=120)
if r.returncode != 0:
raise RuntimeError(f"{script} exit={r.returncode} stderr={r.stderr[:500]}")
return json.loads(r.stdout)
def ima_api(api_path, body):
r = subprocess.run(["node", IMA_API, api_path, json.dumps(body, ensure_ascii=False)],
capture_output=True, text=True, timeout=120)
if r.returncode != 0:
raise RuntimeError(f"ima_api {api_path} exit={r.returncode} stderr={r.stderr[:500]}")
resp = json.loads(r.stdout)
if resp.get("code") != 0:
raise RuntimeError(f"ima_api {api_path} code={resp.get('code')} msg={resp.get('msg')}")
return resp.get("data", {})
def main():
kb_id = os.environ["IMA_DAILY_KNOWLEDGE_BASE_ID"]
file_path = sys.argv[1]
title = sys.argv[2] # 完整文章标题(不含 .md)
pf = run_node(PREFLIGHT, ["--file", file_path])
if not pf.get("pass"):
raise RuntimeError(f"preflight failed: {pf}")
file_name = pf["file_name"]; media_type = pf["media_type"]
content_type = pf["content_type"]; file_size = pf["file_size"]; file_ext = pf["file_ext"]
print(f"[preflight] ok file={file_name} ext={file_ext} size={file_size} media_type={media_type}")
dup = ima_api("openapi/wiki/v1/check_repeated_names", {
"params": [{"name": file_name, "media_type": media_type}],
"knowledge_base_id": kb_id
})
is_rep = dup.get("results", [{}])[0].get("is_repeated", False) if dup.get("results") else False
if is_rep:
print(f"[check_repeated_names] REPEATED: {file_name} — 需要处理")
sys.exit(2)
print("[check_repeated_names] no duplicate")
cm = ima_api("openapi/wiki/v1/create_media", {
"file_name": file_name,
"file_size": file_size,
"content_type": content_type,
"knowledge_base_id": kb_id,
"file_ext": file_ext
})
media_id = cm["media_id"]
cos = cm["cos_credential"]
print(f"[create_media] media_id={media_id} cos_bucket={cos.get('bucket_name')} cos_key={cos.get('cos_key','')[:40]}")
r = subprocess.run(["node", COS_UPLOAD,
"--file", file_path,
"--secret-id", cos["secret_id"],
"--secret-key", cos["secret_key"],
"--token", cos["token"],
"--bucket", cos["bucket_name"],
"--region", cos["region"],
"--cos-key", cos["cos_key"],
"--content-type", content_type,
"--start-time", str(cos.get("start_time", "")),
"--expired-time", str(cos.get("expired_time", "")),
"--timeout", "300000"
], capture_output=True, text=True, timeout=360)
if r.returncode != 0:
raise RuntimeError(f"cos-upload exit={r.returncode} stderr={r.stderr[:800]}")
print(f"[cos-upload] ok rc=0 stdout={r.stdout.strip()[:200]}")
ak = ima_api("openapi/wiki/v1/add_knowledge", {
"media_type": media_type,
"media_id": media_id,
"title": title,
"knowledge_base_id": kb_id,
"file_info": {
"cos_key": cos["cos_key"],
"file_size": file_size,
"file_name": file_name
}
})
print(f"[add_knowledge] ok media_id={ak.get('media_id') or media_id}")
if __name__ == "__main__":
main()