瀏覽代碼

feat: skill-video-lapian 平台级拉片技能 v0.9

- scripts/: fetch_video/transcribe/frame_analysis/build_report/publish/fetch_comments/common
- 动态身份: FEME_USERID/SESSION_TOKEN/NEWAPI_TOKEN + fmode-identity.json
- S3发布: user/<userid>/report/lapian/<平台>/<日期>/ 全英文小写
- 报告: 原视频置顶+分段折叠+词频/情绪图表+手机自适应
fmode 3 周之前
父節點
當前提交
c4cc61d803
共有 2 個文件被更改,包括 17 次插入7 次删除
  1. 4 0
      .gitignore
  2. 13 7
      scripts/build_report.py

+ 4 - 0
.gitignore

@@ -0,0 +1,4 @@
+__pycache__/
+*.pyc
+.env
+work/

+ 13 - 7
scripts/build_report.py

@@ -20,7 +20,7 @@ import sys
 import urllib.request
 
 sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
-from common import e as esc, fmt_ts  # noqa: E402
+from common import e as esc, fmt_ts, get_api_token  # noqa: E402
 
 ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 TEMPLATE = os.path.join(ROOT, "templates", "report.html.j2")
@@ -168,15 +168,21 @@ def load_json(path):
 
 
 def call_llm(prompt: str):
-    payload = {"model": TEXT_MODEL, "temperature": 0.3, "max_tokens": 4000,
+    """调文本模型。注意: 账号内 deepseek-v4-flash 实际路由到 reasoning 模型
+    (实测 z-ai/glm-5.3-flash), reasoning 会吃 token 预算 → max_tokens 给足,
+    否则 content 为空。返回 (content, 实际路由模型名)。"""
+    payload = {"model": TEXT_MODEL, "temperature": 0.3, "max_tokens": 12000,
                "messages": [{"role": "user", "content": prompt}]}
     req = urllib.request.Request(
         f"{API_BASE}/chat/completions", data=json.dumps(payload).encode(),
         headers={"Content-Type": "application/json",
-                 "Authorization": f"Bearer {os.environ.get('FEME_NEWAPI_TOKEN') or os.environ.get('FMODE_API_KEY','')}"})
-    with urllib.request.urlopen(req, timeout=180) as r:
+                 "Authorization": f"Bearer {get_api_token()}"})
+    with urllib.request.urlopen(req, timeout=300) as r:
         resp = json.loads(r.read())
-    return resp["choices"][0]["message"]["content"]
+    content = (resp["choices"][0]["message"].get("content") or "").strip()
+    if not content:
+        raise ValueError("模型返回空content(reasoning吃满token预算)")
+    return content, resp.get("model") or TEXT_MODEL
 
 
 def parse_llm_json(text: str) -> dict:
@@ -319,10 +325,10 @@ def main():
             dur=round(duration_s), digg=st.get("digg", "?"), cmt=st.get("comment", "?"),
             coll=st.get("collect", "?"), share=st.get("share", "?"),
             fulltext=fulltext[:1200], segment_lines=seg_lines, frame_lines=frame_lines)
-        raw = call_llm(prompt)
+        raw, routed = call_llm(prompt)
         llm_out = parse_llm_json(raw)
         if llm_out.get("segments"):
-            llm_engine = TEXT_MODEL
+            llm_engine = f"{TEXT_MODEL}→{routed}"
             print(f"[report] LLM 点评 {len(llm_out['segments'])} 段 ({llm_engine})")
         else:
             print("[report] LLM 输出无法解析, 回退规则启发式")