|
|
import argparse
|
|
|
import os
|
|
|
import sys
|
|
|
from pathlib import Path
|
|
|
|
|
|
# 直接复用你在 test.py 里已经配置好的 client(里面含有 API Key 和 base_url)
|
|
|
try:
|
|
|
from test import client # type: ignore
|
|
|
except Exception as import_error: # noqa: PIE786
|
|
|
raise SystemExit(
|
|
|
"无法从 test.py 导入 client。请先确保 test.py 能正常运行,或在此脚本中自行创建 client。"
|
|
|
) from import_error
|
|
|
|
|
|
|
|
|
def detect_language_by_suffix(file_path: Path) -> str:
|
|
|
suffix = file_path.suffix.lower()
|
|
|
mapping = {
|
|
|
".py": "python",
|
|
|
".js": "javascript",
|
|
|
".ts": "typescript",
|
|
|
".tsx": "tsx",
|
|
|
".jsx": "jsx",
|
|
|
".java": "java",
|
|
|
".go": "go",
|
|
|
".rs": "rust",
|
|
|
".rb": "ruby",
|
|
|
".php": "php",
|
|
|
".cs": "csharp",
|
|
|
".cpp": "cpp",
|
|
|
".cc": "cpp",
|
|
|
".cxx": "cpp",
|
|
|
".c": "c",
|
|
|
".h": "c",
|
|
|
".json": "json",
|
|
|
".yaml": "yaml",
|
|
|
".yml": "yaml",
|
|
|
".md": "markdown",
|
|
|
".sql": "sql",
|
|
|
".sh": "bash",
|
|
|
".ps1": "powershell",
|
|
|
}
|
|
|
return mapping.get(suffix, "")
|
|
|
|
|
|
|
|
|
def read_text_file(file_path: Path) -> str:
|
|
|
try:
|
|
|
return file_path.read_text(encoding="utf-8")
|
|
|
except UnicodeDecodeError:
|
|
|
# 回退到系统默认编码
|
|
|
return file_path.read_text(errors="replace")
|
|
|
|
|
|
|
|
|
def build_messages(code_path: Path, code_content: str, instruction: str):
|
|
|
language = detect_language_by_suffix(code_path)
|
|
|
system_prompt = (
|
|
|
"你是严谨的代码审查与重构助手,请用中文回答。"
|
|
|
"输出请使用结构化 Markdown,包含:\n"
|
|
|
"1) 概览\n2) 问题清单(按严重程度排序,标注位置/片段)\n"
|
|
|
"3) 可执行的修复建议\n4) 示例修复代码(只给关键片段)\n"
|
|
|
"5) 边界与测试要点\n"
|
|
|
"除非必要,不要重复粘贴整份源码。"
|
|
|
)
|
|
|
user_prompt = (
|
|
|
f"任务:{instruction.strip()}\n"
|
|
|
f"文件:{code_path.name}\n"
|
|
|
"代码如下:\n"
|
|
|
f"```{language}\n{code_content}\n```"
|
|
|
)
|
|
|
return [
|
|
|
{"role": "system", "content": system_prompt},
|
|
|
{"role": "user", "content": user_prompt},
|
|
|
]
|
|
|
|
|
|
|
|
|
def analyze_file(input_path: Path, output_path: Path, instruction: str, model: str = "deepseek-chat") -> None:
|
|
|
code = read_text_file(input_path)
|
|
|
messages = build_messages(input_path, code, instruction)
|
|
|
|
|
|
resp = client.chat.completions.create(
|
|
|
model=model,
|
|
|
messages=messages,
|
|
|
stream=False,
|
|
|
temperature=0.2,
|
|
|
)
|
|
|
|
|
|
content = resp.choices[0].message.content if resp.choices else ""
|
|
|
output_path.write_text(content, encoding="utf-8")
|
|
|
|
|
|
|
|
|
def main(argv: list[str]) -> int:
|
|
|
parser = argparse.ArgumentParser(
|
|
|
description="分析指定代码文件,输出结构化反馈到文件(复用 test.py 的 client)",
|
|
|
)
|
|
|
parser.add_argument("input", help="要分析的源代码文件路径")
|
|
|
parser.add_argument("output", help="把反馈写入到的目标文件路径,例如 review.md")
|
|
|
parser.add_argument(
|
|
|
"--instruction",
|
|
|
default="请找出代码问题、潜在缺陷、可读性/性能/安全改进,并给出修复建议",
|
|
|
help="自定义任务说明(可选)",
|
|
|
)
|
|
|
parser.add_argument(
|
|
|
"--model",
|
|
|
default="deepseek-chat",
|
|
|
help="模型名称(默认 deepseek-chat)",
|
|
|
)
|
|
|
|
|
|
args = parser.parse_args(argv)
|
|
|
|
|
|
input_path = Path(args.input).expanduser().resolve()
|
|
|
output_path = Path(args.output).expanduser().resolve()
|
|
|
|
|
|
if not input_path.exists():
|
|
|
raise SystemExit(f"输入文件不存在: {input_path}")
|
|
|
|
|
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
|
analyze_file(input_path, output_path, args.instruction, model=args.model)
|
|
|
print(f"分析完成,结果已写入: {output_path}")
|
|
|
return 0
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
raise SystemExit(main(sys.argv[1:]))
|
|
|
|
|
|
|