From df15f9a6fb385466a94a7f4a7a17d39184975726 Mon Sep 17 00:00:00 2001 From: OpenClaw Agent Date: Wed, 11 Feb 2026 01:10:45 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E7=BB=9F=E4=B8=80CLI=E8=BE=93?= =?UTF-8?q?=E5=87=BA=E6=A0=BC=E5=BC=8F=E4=B8=BA=E6=A0=87=E5=87=86JSON?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kb-bilibili-content/bilibili_content.py | 26 ++++++--- .../kb-bilibili-metadata/bilibili_metadata.py | 43 +++++++-------- skills/kb-deep-analyzer/deep_analyzer.py | 25 +++++++-- skills/kb-link-parser/link-parser.py | 55 ++++++++++++++++--- skills/kb-ocr-processor/ocr_processor.py | 35 +++++++++--- 5 files changed, 134 insertions(+), 50 deletions(-) diff --git a/skills/kb-bilibili-content/bilibili_content.py b/skills/kb-bilibili-content/bilibili_content.py index cc5f790..9831004 100644 --- a/skills/kb-bilibili-content/bilibili_content.py +++ b/skills/kb-bilibili-content/bilibili_content.py @@ -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) diff --git a/skills/kb-bilibili-metadata/bilibili_metadata.py b/skills/kb-bilibili-metadata/bilibili_metadata.py index 0287ece..1ef2673 100755 --- a/skills/kb-bilibili-metadata/bilibili_metadata.py +++ b/skills/kb-bilibili-metadata/bilibili_metadata.py @@ -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) diff --git a/skills/kb-deep-analyzer/deep_analyzer.py b/skills/kb-deep-analyzer/deep_analyzer.py index a0c0e8e..cf04c05 100644 --- a/skills/kb-deep-analyzer/deep_analyzer.py +++ b/skills/kb-deep-analyzer/deep_analyzer.py @@ -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) diff --git a/skills/kb-link-parser/link-parser.py b/skills/kb-link-parser/link-parser.py index ce00cec..b8cb635 100644 --- a/skills/kb-link-parser/link-parser.py +++ b/skills/kb-link-parser/link-parser.py @@ -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 diff --git a/skills/kb-ocr-processor/ocr_processor.py b/skills/kb-ocr-processor/ocr_processor.py index 9e5ec82..b58d618 100644 --- a/skills/kb-ocr-processor/ocr_processor.py +++ b/skills/kb-ocr-processor/ocr_processor.py @@ -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,19 +331,29 @@ 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__":