账号分析产物入库闭环:工作台入库接口+选题读视频解析

- server.js 新增 POST /api/import/account:扫描账号产出目录直写 mcn-plugin.db(视频分析→analysis/source、账号设定→persona、账号数据分析→analysis、短视频表格.xlsx→videos upsert)
- 新增 scripts/export_video_map.py:python 读 xlsx 13列输出 JSON 权威 aweme_id 映射
- /api/ai/topics 增加读最新3条视频解析 JOIN account_videos 拼入 prompt,选题基于真实视频内容
- 修复 aweme_id 匹配:normTitle 删全角标点(xlsx「!」「”」vs 文件夹无标点,4/6 失败根因)+下划线转空格;入库前清 null 脏数据
- mcn-dou-analysis SKILL.md:功能五补充工作台入库方式+注意事项第6条匹配红线
- 验证:俊希 6 analysis+6 source+137 videos 入库,JOIN 全关联,选题端到端返回贴合视频解析
This commit is contained in:
maogeigei committed 2026-09-01 10:12:36 +08:00
1 parent 4e29ddb881
commit 92c93cf66a
5 files changed
+228 -5

No files matched your search

@@ -0,0 +1,59 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
export_video_map.py - 短视频表格.xlsx → 视频映射 JSON(工作台入库接口配套,09-01 新增)
背景:短视频表格.xlsx(功能二产出,13列:序号/视频ID/视频标题/...)包含视频的权威 aweme_id,
工作台 server.js 入库接口用它匹配 视频分析/ 目录下的解析文件,避免仅靠 account_videos 表标题模糊匹配。
用法:
python export_video_map.py <短视频表格.xlsx>
→ stdout 输出 JSON 数组:[{"aweme_id": "...", "title": "...", "url": "...",
"like_count": 123, "comment_count": 4, "share_count": 5, "collect_count": 6,
"play_count": 7, "duration": 8, "publish_time": "...", "tags": "..."}]
"""
import json
import sys
def main():
if len(sys.argv) < 2:
print("usage: export_video_map.py <短视频表格.xlsx>", file=sys.stderr)
sys.exit(1)
xlsx = sys.argv[1]
try:
import openpyxl
except ImportError:
print("[]", file=sys.stderr)
print("[error] openpyxl 不可用", file=sys.stderr)
sys.exit(2)
wb = openpyxl.load_workbook(xlsx, read_only=True, data_only=True)
ws = wb.active
out = []
for row in ws.iter_rows(values_only=True):
if not row or len(row) < 3:
continue
aweme_id, title = row[1], row[2]
if aweme_id is None or not title:
continue
rec = {
"aweme_id": str(aweme_id).strip(),
"title": str(title).strip(),
"url": str(row[3] or "").strip(),
"like_count": row[4],
"comment_count": row[6],
"share_count": row[7],
"collect_count": row[8],
"play_count": row[9],
"duration": row[10],
"publish_time": str(row[11] or "").strip(),
"tags": str(row[12] or "").strip(),
}
out.append(rec)
wb.close()
print(json.dumps(out, ensure_ascii=False))
if __name__ == "__main__":
main()