refactor: 统一CLI输出格式为标准JSON

This commit is contained in:
OpenClaw Agent
2026-02-11 01:10:45 +08:00
parent 06f279451a
commit df15f9a6fb
5 changed files with 134 additions and 50 deletions
+19 -7
View File
@@ -204,7 +204,6 @@ async def main():
parser.add_argument('--type', '-t', required=True, choices=['video', 'subtitle', 'article'], help='内容类型')
parser.add_argument('--output', '-o', default='./output', help='输出目录')
parser.add_argument('--quality', '-q', type=int, default=32, help='视频质量: 16=360P, 32=480P, 64=720P, 80=1080P')
parser.add_argument('--json', action='store_true', help='JSON输出')
args = parser.parse_args()
@@ -218,13 +217,23 @@ async def main():
else:
result = await downloader.extract_article(args.id.replace('cv', ''))
if args.json:
print(json.dumps(result, ensure_ascii=False, indent=2))
# 统一输出格式
if result.get("success"):
output = {
"success": True,
"type": args.type,
"filename": Path(result.get('filepath', '')).name if result.get('filepath') else None,
"filepath": str(Path(result.get('filepath', '')).resolve()) if result.get('filepath') else None,
"message": result.get('message', '处理成功')
}
else:
print(f"\n{result['message']}")
if result.get('filepath'):
print(f"文件: {result['filepath']}")
output = {
"success": False,
"error": result.get('message', '处理失败'),
"detail": f"ID: {args.id}, 类型: {args.type}"
}
print(json.dumps(output, ensure_ascii=False, indent=2))
return result
@@ -233,5 +242,8 @@ if __name__ == '__main__':
result = asyncio.run(main())
sys.exit(0 if result.get("success") else 1)
except KeyboardInterrupt:
print("\n已取消")
print(json.dumps({"success": False, "error": "用户取消"}, ensure_ascii=False, indent=2))
sys.exit(1)
except Exception as e:
print(json.dumps({"success": False, "error": str(e)}, ensure_ascii=False, indent=2))
sys.exit(1)
@@ -176,7 +176,10 @@ def main():
result = extract_up(extractor, args.id, args.output)
elif args.type == 'series':
if not args.mid:
print("错误: series类型需要提供 --mid 参数")
print(json.dumps({
"success": False,
"error": "series类型需要提供 --mid 参数"
}, ensure_ascii=False, indent=2))
sys.exit(1)
result = extract_series(extractor, args.mid, args.id, args.output)
elif args.type == 'readlist':
@@ -184,37 +187,33 @@ def main():
elif args.type == 'favlist':
result = extract_favlist(extractor, args.id, args.output)
else:
print(f"错误: 不支持的类型 {args.type}")
print(json.dumps({
"success": False,
"error": f"不支持的类型 {args.type}"
}, ensure_ascii=False, indent=2))
sys.exit(1)
# 包装为标准输出格式
# 生成文件名
platform = "bilibili"
filename = f"{platform}_{args.id}.meta.json"
filepath = args.output or filename
# 统一输出格式
output = {
"success": True,
"data": result,
"metadata": {
"type": args.type,
"id": args.id,
"fetched_at": "2024-01-01T00:00:00"
}
"filename": filename,
"filepath": str(Path(filepath).resolve()) if filepath else None,
"message": f"{args.type}元数据提取成功"
}
# 输出结果
if not args.output:
if args.pretty:
print(json.dumps(output, ensure_ascii=False, indent=2))
else:
print(json.dumps(output, ensure_ascii=False))
if args.output:
print(f"结果已保存到: {args.output}")
print(json.dumps(output, ensure_ascii=False, indent=2))
except Exception as e:
error_output = {
print(json.dumps({
"success": False,
"error": str(e),
"error_type": type(e).__name__
}
print(json.dumps(error_output, ensure_ascii=False, indent=2))
"detail": type(e).__name__
}, ensure_ascii=False, indent=2))
sys.exit(1)
+21 -4
View File
@@ -951,10 +951,27 @@ def main():
with open(args.output, 'w', encoding='utf-8') as f:
f.write(markdown_content)
print(f"[Main] 分析完成!输出: {args.output}")
print(f"[Main] 摘要: {result.summary[:100]}...")
print(f"[Main] 主题数: {len(result.main_topics)}")
# 统一输出格式
output = {
"success": True,
"filename": Path(args.output).name,
"filepath": str(Path(args.output).resolve()),
"message": "深度分析完成",
"stats": {
"summary_length": len(result.summary),
"topics_count": len(result.main_topics),
"insights_count": len(result.key_insights)
}
}
print(json.dumps(output, ensure_ascii=False, indent=2))
if __name__ == "__main__":
main()
try:
main()
except Exception as e:
print(json.dumps({
"success": False,
"error": str(e)
}, ensure_ascii=False, indent=2))
sys.exit(1)
+47 -8
View File
@@ -565,30 +565,69 @@ Examples:
if args.url:
# Single URL mode
result = link_parser.parse(args.url)
print(format_output(result, args.format))
return 0 if result["success"] else 1
parsed = link_parser.parse(args.url)
# 统一输出格式
if parsed["success"]:
output = {
"success": True,
"platform": parsed.get("platform"),
"type": parsed.get("type"),
"id": parsed.get("id"),
"filename": f"{parsed.get('platform')}_{parsed.get('id')}.link.json" if parsed.get("platform") and parsed.get("id") else None,
"message": "URL解析成功"
}
else:
output = {
"success": False,
"error": parsed.get("error", "解析失败"),
"detail": f"URL: {args.url}"
}
print(json.dumps(output, ensure_ascii=False, indent=2))
return 0 if output["success"] else 1
elif args.batch:
try:
with open(args.batch, 'r', encoding='utf-8') as f:
urls = [line.strip() for line in f if line.strip()]
except Exception as e:
print(f"Error reading file: {e}", file=sys.stderr)
print(json.dumps({
"success": False,
"error": "读取文件失败",
"detail": str(e)
}, ensure_ascii=False, indent=2))
return 1
results = []
for url in urls:
result = link_parser.parse(url)
results.append(result)
parsed = link_parser.parse(url)
if parsed["success"]:
results.append({
"success": True,
"platform": parsed.get("platform"),
"type": parsed.get("type"),
"id": parsed.get("id"),
"filename": f"{parsed.get('platform')}_{parsed.get('id')}.link.json" if parsed.get("platform") and parsed.get("id") else None
})
else:
results.append({
"success": False,
"error": parsed.get("error", "解析失败"),
"detail": f"URL: {url}"
})
if args.output:
with open(args.output, 'w', encoding='utf-8') as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print(f"Results written to {args.output}")
print(json.dumps({
"success": True,
"message": f"结果已保存到 {args.output}",
"total": len(results)
}, ensure_ascii=False, indent=2))
else:
for result in results:
print(format_output(result, args.format))
print(json.dumps(result, ensure_ascii=False, indent=2))
print("-" * 40)
return 0
+26 -9
View File
@@ -304,7 +304,10 @@ def main():
input_dir = args.input
if args.video:
if not os.path.exists(args.video):
print(f"❌ 视频文件不存在: {args.video}")
print(json.dumps({
"success": False,
"error": f"视频文件不存在: {args.video}"
}, ensure_ascii=False, indent=2))
return 1
# 创建临时帧目录
@@ -312,6 +315,10 @@ def main():
input_dir = extract_frames(args.video, frames_dir, fps=args.fps)
if not input_dir:
print(json.dumps({
"success": False,
"error": "截帧失败"
}, ensure_ascii=False, indent=2))
return 1
# 初始化处理器
@@ -324,20 +331,30 @@ def main():
# 保存结果
processor.save_results(results, args.output, merge=args.merge)
# 打印摘要
# 统一输出格式
total_texts = sum(1 for r in results if r.get("text"))
avg_conf = sum(r.get("confidence", 0) for r in results) / len(results) if results else 0
print(f"\n=== 摘要 ===")
print(f"处理帧数: {len(results)}")
print(f"识别到文字的帧: {total_texts}")
print(f"平均置信度: {avg_conf:.2%}")
output = {
"success": True,
"filename": Path(args.output).name,
"filepath": str(Path(args.output).resolve()),
"message": f"OCR处理完成",
"stats": {
"total_frames": len(results),
"frames_with_text": total_texts,
"avg_confidence": round(avg_conf, 4)
}
}
print(json.dumps(output, ensure_ascii=False, indent=2))
return 0
else:
print("未处理到任何结果")
print(json.dumps({
"success": False,
"error": "未处理到任何结果"
}, ensure_ascii=False, indent=2))
return 1
return 0
if __name__ == "__main__":
exit(main())