autocoder-nano 0.1.28__py3-none-any.whl → 0.1.29__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- autocoder_nano/auto_coder_nano.py +210 -308
- autocoder_nano/edit/actions.py +19 -13
- autocoder_nano/edit/code/merge_editblock.py +35 -43
- autocoder_nano/git_utils.py +18 -14
- autocoder_nano/index/entry.py +30 -32
- autocoder_nano/index/index_manager.py +23 -15
- autocoder_nano/llm_client.py +20 -4
- autocoder_nano/utils/__init__.py +0 -0
- autocoder_nano/utils/printer_utils.py +455 -0
- autocoder_nano/version.py +1 -1
- {autocoder_nano-0.1.28.dist-info → autocoder_nano-0.1.29.dist-info}/METADATA +2 -3
- {autocoder_nano-0.1.28.dist-info → autocoder_nano-0.1.29.dist-info}/RECORD +16 -14
- {autocoder_nano-0.1.28.dist-info → autocoder_nano-0.1.29.dist-info}/LICENSE +0 -0
- {autocoder_nano-0.1.28.dist-info → autocoder_nano-0.1.29.dist-info}/WHEEL +0 -0
- {autocoder_nano-0.1.28.dist-info → autocoder_nano-0.1.29.dist-info}/entry_points.txt +0 -0
- {autocoder_nano-0.1.28.dist-info → autocoder_nano-0.1.29.dist-info}/top_level.txt +0 -0
autocoder_nano/edit/actions.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import time
|
2
2
|
|
3
|
-
from loguru import logger
|
3
|
+
# from loguru import logger
|
4
4
|
|
5
5
|
from autocoder_nano.edit.code.generate_editblock import CodeAutoGenerateEditBlock
|
6
6
|
from autocoder_nano.edit.code.merge_editblock import CodeAutoMergeEditBlock
|
@@ -8,6 +8,10 @@ from autocoder_nano.index.entry import build_index_and_filter_files
|
|
8
8
|
from autocoder_nano.llm_client import AutoLLM
|
9
9
|
from autocoder_nano.llm_types import AutoCoderArgs
|
10
10
|
from autocoder_nano.project import PyProject, SuffixProject
|
11
|
+
from autocoder_nano.utils.printer_utils import Printer
|
12
|
+
|
13
|
+
|
14
|
+
printer = Printer()
|
11
15
|
|
12
16
|
|
13
17
|
class BaseAction:
|
@@ -39,13 +43,14 @@ class ActionPyProject(BaseAction):
|
|
39
43
|
if self.args.execute and self.llm:
|
40
44
|
content_length = self._get_content_length(content)
|
41
45
|
if content_length > self.args.model_max_input_length:
|
42
|
-
|
43
|
-
f"发送给模型的内容长度为 {content_length} 个 token
|
44
|
-
f"已超过最大输入长度限制 {self.args.model_max_input_length}
|
46
|
+
printer.print_text(
|
47
|
+
f"发送给模型的内容长度为 {content_length} 个 token(可能收集了过多文件),"
|
48
|
+
f"已超过最大输入长度限制 {self.args.model_max_input_length}.",
|
49
|
+
style="yellow"
|
45
50
|
)
|
46
51
|
|
47
52
|
if self.args.execute:
|
48
|
-
|
53
|
+
printer.print_text("正在自动生成代码...", style="green")
|
49
54
|
start_time = time.time()
|
50
55
|
# diff, strict_diff, editblock 是代码自动生成或合并的不同策略, 通常用于处理代码的变更或生成
|
51
56
|
# diff 模式,基于差异生成代码,生成最小的变更集,适用于局部优化,代码重构
|
@@ -60,10 +65,10 @@ class ActionPyProject(BaseAction):
|
|
60
65
|
generate_result = generate.multi_round_run(query=self.args.query, source_content=content)
|
61
66
|
else:
|
62
67
|
generate_result = generate.single_round_run(query=self.args.query, source_content=content)
|
63
|
-
|
68
|
+
printer.print_text(f"代码生成完毕,耗时 {time.time() - start_time:.2f} 秒", style="green")
|
64
69
|
|
65
70
|
if self.args.auto_merge:
|
66
|
-
|
71
|
+
printer.print_text("正在自动合并代码...", style="green")
|
67
72
|
if self.args.auto_merge == "editblock":
|
68
73
|
code_merge = CodeAutoMergeEditBlock(args=self.args, llm=self.llm)
|
69
74
|
merge_result = code_merge.merge_code(generate_result=generate_result)
|
@@ -97,13 +102,14 @@ class ActionSuffixProject(BaseAction):
|
|
97
102
|
if self.args.execute and self.llm:
|
98
103
|
content_length = self._get_content_length(content)
|
99
104
|
if content_length > self.args.model_max_input_length:
|
100
|
-
|
101
|
-
f"发送给模型的内容长度为 {content_length} 个 token
|
102
|
-
f"已超过最大输入长度限制 {self.args.model_max_input_length}
|
105
|
+
printer.print_text(
|
106
|
+
f"发送给模型的内容长度为 {content_length} 个 token(可能收集了过多文件),"
|
107
|
+
f"已超过最大输入长度限制 {self.args.model_max_input_length}.",
|
108
|
+
style="yellow"
|
103
109
|
)
|
104
110
|
|
105
111
|
if self.args.execute:
|
106
|
-
|
112
|
+
printer.print_text("正在自动生成代码...", style="green")
|
107
113
|
start_time = time.time()
|
108
114
|
# diff, strict_diff, editblock 是代码自动生成或合并的不同策略, 通常用于处理代码的变更或生成
|
109
115
|
# diff 模式,基于差异生成代码,生成最小的变更集,适用于局部优化,代码重构
|
@@ -118,10 +124,10 @@ class ActionSuffixProject(BaseAction):
|
|
118
124
|
generate_result = generate.multi_round_run(query=self.args.query, source_content=content)
|
119
125
|
else:
|
120
126
|
generate_result = generate.single_round_run(query=self.args.query, source_content=content)
|
121
|
-
|
127
|
+
printer.print_text(f"代码生成完毕,耗时 {time.time() - start_time:.2f} 秒", style="green")
|
122
128
|
|
123
129
|
if self.args.auto_merge:
|
124
|
-
|
130
|
+
printer.print_text("正在自动合并代码...", style="green")
|
125
131
|
if self.args.auto_merge == "editblock":
|
126
132
|
code_merge = CodeAutoMergeEditBlock(args=self.args, llm=self.llm)
|
127
133
|
merge_result = code_merge.merge_code(generate_result=generate_result)
|
@@ -17,33 +17,29 @@ from autocoder_nano.llm_client import AutoLLM
|
|
17
17
|
from autocoder_nano.llm_prompt import prompt
|
18
18
|
from autocoder_nano.llm_types import AutoCoderArgs, PathAndCode, MergeCodeWithoutEffect, CodeGenerateResult, \
|
19
19
|
CommitResult
|
20
|
+
from autocoder_nano.utils.printer_utils import Printer
|
20
21
|
|
21
22
|
|
22
|
-
|
23
|
+
printer = Printer()
|
24
|
+
console = printer.get_console()
|
25
|
+
# console = Console()
|
23
26
|
|
24
27
|
|
25
28
|
def git_print_commit_info(commit_result: CommitResult):
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
table.add_row("Commit Message", commit_result.commit_message)
|
34
|
-
table.add_row("Changed Files", "\n".join(commit_result.changed_files))
|
35
|
-
|
36
|
-
console.print(
|
37
|
-
Panel(table, expand=False, border_style="green", title="Git Commit Summary")
|
29
|
+
printer.print_table_compact(
|
30
|
+
data=[
|
31
|
+
["Commit Hash", commit_result.commit_hash],
|
32
|
+
["Commit Message", commit_result.commit_message],
|
33
|
+
["Changed Files", "\n".join(commit_result.changed_files)]
|
34
|
+
],
|
35
|
+
title="Commit 信息", headers=["Attribute", "Value"], caption="(Use /revert to revert this commit)"
|
38
36
|
)
|
39
37
|
|
40
38
|
if commit_result.diffs:
|
41
39
|
for file, diff in commit_result.diffs.items():
|
42
|
-
|
40
|
+
printer.print_text(f"File: {file}", style="green")
|
43
41
|
syntax = Syntax(diff, "diff", theme="monokai", line_numbers=True)
|
44
|
-
|
45
|
-
Panel(syntax, expand=False, border_style="yellow", title="File Diff")
|
46
|
-
)
|
42
|
+
printer.print_panel(syntax, title="File Diff", center=True)
|
47
43
|
|
48
44
|
|
49
45
|
class CodeAutoMergeEditBlock:
|
@@ -79,12 +75,12 @@ class CodeAutoMergeEditBlock:
|
|
79
75
|
os.unlink(temp_file_path)
|
80
76
|
if result.returncode != 0:
|
81
77
|
error_message = result.stdout.strip() or result.stderr.strip()
|
82
|
-
|
78
|
+
printer.print_text(f"Pylint 检查代码失败: {error_message}", style="yellow")
|
83
79
|
return False, error_message
|
84
80
|
return True, ""
|
85
81
|
except subprocess.CalledProcessError as e:
|
86
82
|
error_message = f"运行 Pylint 时发生错误: {str(e)}"
|
87
|
-
|
83
|
+
printer.print_text(error_message, style="red")
|
88
84
|
os.unlink(temp_file_path)
|
89
85
|
return False, error_message
|
90
86
|
|
@@ -257,7 +253,7 @@ class CodeAutoMergeEditBlock:
|
|
257
253
|
def choose_best_choice(self, generate_result: CodeGenerateResult) -> CodeGenerateResult:
|
258
254
|
""" 选择最佳代码 """
|
259
255
|
if len(generate_result.contents) == 1: # 仅一份代码立即返回
|
260
|
-
|
256
|
+
printer.print_text("仅有一个候选结果,跳过排序", style="green")
|
261
257
|
return generate_result
|
262
258
|
|
263
259
|
ranker = CodeModificationRanker(args=self.args, llm=self.llm)
|
@@ -339,7 +335,8 @@ class CodeAutoMergeEditBlock:
|
|
339
335
|
}
|
340
336
|
)
|
341
337
|
return
|
342
|
-
|
338
|
+
printer.print_text(f"发现 {len(unmerged_blocks)} 个未合并的代码块,更改将不会应用,请手动检查这些代码块后重试.",
|
339
|
+
style="yellow")
|
343
340
|
self._print_unmerged_blocks(unmerged_blocks)
|
344
341
|
return
|
345
342
|
|
@@ -348,16 +345,15 @@ class CodeAutoMergeEditBlock:
|
|
348
345
|
if file_path.endswith(".py"):
|
349
346
|
pylint_passed, error_message = self.run_pylint(new_content)
|
350
347
|
if not pylint_passed:
|
351
|
-
|
348
|
+
printer.print_text(
|
349
|
+
f"代码文件 {file_path} 的 Pylint 检查未通过,本次更改未应用。错误信息: {error_message}",
|
350
|
+
style="yellow")
|
352
351
|
|
353
352
|
if changes_made and not force_skip_git and not self.args.skip_commit:
|
354
353
|
try:
|
355
354
|
commit_changes(self.args.source_dir, f"auto_coder_pre_{file_name}_{md5}")
|
356
355
|
except Exception as e:
|
357
|
-
|
358
|
-
self.git_require_msg(
|
359
|
-
source_dir=self.args.source_dir, error=str(e))
|
360
|
-
)
|
356
|
+
printer.print_text(self.git_require_msg(source_dir=self.args.source_dir, error=str(e)), style="red")
|
361
357
|
return
|
362
358
|
# Now, apply the changes
|
363
359
|
for file_path, new_content in file_content_mapping.items():
|
@@ -385,17 +381,14 @@ class CodeAutoMergeEditBlock:
|
|
385
381
|
commit_result = commit_changes(self.args.source_dir, f"auto_coder_{file_name}_{md5}")
|
386
382
|
git_print_commit_info(commit_result=commit_result)
|
387
383
|
except Exception as e:
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
logger.info(
|
394
|
-
f"已在 {len(file_content_mapping.keys())} 个文件中合并更改,"
|
395
|
-
f"完成 {len(changes_to_make)}/{len(codes)} 个代码块。"
|
384
|
+
printer.print_text(self.git_require_msg(source_dir=self.args.source_dir, error=str(e)),
|
385
|
+
style="red")
|
386
|
+
printer.print_text(
|
387
|
+
f"已在 {len(file_content_mapping.keys())} 个文件中合并更改,完成 {len(changes_to_make)}/{len(codes)} 个代码块.",
|
388
|
+
style="green"
|
396
389
|
)
|
397
390
|
else:
|
398
|
-
|
391
|
+
printer.print_text("未对任何文件进行更改.", style="yellow")
|
399
392
|
|
400
393
|
def merge_code(self, generate_result: CodeGenerateResult, force_skip_git: bool = False):
|
401
394
|
result = self.choose_best_choice(generate_result)
|
@@ -404,15 +397,14 @@ class CodeAutoMergeEditBlock:
|
|
404
397
|
|
405
398
|
@staticmethod
|
406
399
|
def _print_unmerged_blocks(unmerged_blocks: List[tuple]):
|
407
|
-
|
400
|
+
printer.print_text("未合并的代码块:", style="yellow")
|
408
401
|
for file_path, head, update, similarity in unmerged_blocks:
|
409
|
-
|
410
|
-
|
411
|
-
f"\n[bold green]搜索代码块(相似度:{similarity}):[/bold green]")
|
402
|
+
printer.print_text(f"文件: {file_path}", style="yellow")
|
403
|
+
printer.print_text(f"搜索代码块(相似度:{similarity}):", style="yellow")
|
412
404
|
syntax = Syntax(head, "python", theme="monokai", line_numbers=True)
|
413
|
-
|
414
|
-
|
405
|
+
printer.print_panel(syntax)
|
406
|
+
printer.print_text(f"替换代码块:", style="yellow")
|
415
407
|
syntax = Syntax(update, "python", theme="monokai",
|
416
408
|
line_numbers=True)
|
417
|
-
|
418
|
-
|
409
|
+
printer.print_panel(syntax)
|
410
|
+
printer.print_text(f"未合并的代码块总数: {len(unmerged_blocks)}", style="yellow")
|
autocoder_nano/git_utils.py
CHANGED
@@ -2,9 +2,13 @@ import os
|
|
2
2
|
|
3
3
|
from autocoder_nano.llm_prompt import prompt
|
4
4
|
from git import Repo, GitCommandError
|
5
|
-
from loguru import logger
|
5
|
+
# from loguru import logger
|
6
6
|
|
7
7
|
from autocoder_nano.llm_types import CommitResult
|
8
|
+
from autocoder_nano.utils.printer_utils import Printer
|
9
|
+
|
10
|
+
|
11
|
+
printer = Printer()
|
8
12
|
|
9
13
|
|
10
14
|
def repo_init(repo_path: str) -> bool:
|
@@ -12,14 +16,14 @@ def repo_init(repo_path: str) -> bool:
|
|
12
16
|
os.makedirs(repo_path)
|
13
17
|
|
14
18
|
if os.path.exists(os.path.join(repo_path, ".git")):
|
15
|
-
|
19
|
+
printer.print_text(f"目录 {repo_path} 已是一个 Git 仓库,跳过初始化操作.", style="yellow")
|
16
20
|
return False
|
17
21
|
try:
|
18
22
|
Repo.init(repo_path)
|
19
|
-
|
23
|
+
printer.print_text(f"已在 {repo_path} 初始化新的 Git 仓库.", style="green")
|
20
24
|
return True
|
21
25
|
except GitCommandError as e:
|
22
|
-
|
26
|
+
printer.print_text(f"Git 初始化过程中发生错误: {e}.", style="red")
|
23
27
|
return False
|
24
28
|
|
25
29
|
|
@@ -72,19 +76,19 @@ def commit_changes(repo_path: str, message: str) -> CommitResult:
|
|
72
76
|
def revert_changes(repo_path: str, message: str) -> bool:
|
73
77
|
repo = get_repo(repo_path)
|
74
78
|
if repo is None:
|
75
|
-
|
79
|
+
printer.print_text("仓库未初始化.", style="red")
|
76
80
|
return False
|
77
81
|
|
78
82
|
try:
|
79
83
|
# 检查当前工作目录是否有未提交的更改
|
80
84
|
if repo.is_dirty():
|
81
|
-
|
85
|
+
printer.print_text("工作目录有未提交的更改,请在回退前提交或暂存您的修改.", style="yellow")
|
82
86
|
return False
|
83
87
|
|
84
88
|
# 通过message定位到commit_hash
|
85
89
|
commit = repo.git.log("--all", f"--grep={message}", "--format=%H", "-n", "1")
|
86
90
|
if not commit:
|
87
|
-
|
91
|
+
printer.print_text(f"未找到提交信息包含 '{message}' 的提交记录.", style="yellow")
|
88
92
|
return False
|
89
93
|
|
90
94
|
commit_hash = commit
|
@@ -94,25 +98,25 @@ def revert_changes(repo_path: str, message: str) -> bool:
|
|
94
98
|
|
95
99
|
if not commits:
|
96
100
|
repo.git.revert(commit, no_edit=True)
|
97
|
-
|
101
|
+
printer.print_text(f"已回退单条提交记录: {commit}", style="green")
|
98
102
|
else:
|
99
103
|
# 从最新的提交开始,逐个回滚
|
100
104
|
for commit in reversed(commits):
|
101
105
|
try:
|
102
106
|
repo.git.revert(commit.hexsha, no_commit=True)
|
103
|
-
|
107
|
+
printer.print_text(f"已回退提交 {commit.hexsha} 的更改", style="green")
|
104
108
|
except GitCommandError as e:
|
105
|
-
|
109
|
+
printer.print_text(f"回退提交 {commit.hexsha} 时发生错误: {e}", style="red")
|
106
110
|
repo.git.revert("--abort")
|
107
111
|
return False
|
108
112
|
# 提交所有的回滚更改
|
109
113
|
repo.git.commit(message=f"Reverted all changes up to {commit_hash}")
|
110
|
-
|
114
|
+
printer.print_text(f"已成功回退到提交 {commit_hash} 的状态", style="green")
|
111
115
|
# this is a mark, chat_auto_coder.py need this
|
112
116
|
print(f"Successfully reverted changes", flush=True)
|
113
117
|
return True
|
114
118
|
except GitCommandError as e:
|
115
|
-
|
119
|
+
printer.print_text(f"回退操作过程中发生错误: {e}", style="red")
|
116
120
|
return False
|
117
121
|
|
118
122
|
|
@@ -154,7 +158,7 @@ def get_uncommitted_changes(repo_path: str) -> str:
|
|
154
158
|
content = f.read()
|
155
159
|
changes['new'].append((file_path, f'+++ {file_path}\n{content}'))
|
156
160
|
except Exception as e:
|
157
|
-
|
161
|
+
printer.print_text(f"Error reading file {file_path}: {e}", style="red")
|
158
162
|
# 生成markdown报告
|
159
163
|
report = ["# Git Changes Report\n"]
|
160
164
|
# 新增文件
|
@@ -187,7 +191,7 @@ def get_uncommitted_changes(repo_path: str) -> str:
|
|
187
191
|
|
188
192
|
return "\n".join(report)
|
189
193
|
except GitCommandError as e:
|
190
|
-
|
194
|
+
printer.print_text(f"Error getting uncommitted changes: {e}", style="red")
|
191
195
|
return f"Error: {str(e)}"
|
192
196
|
|
193
197
|
|
autocoder_nano/index/entry.py
CHANGED
@@ -2,15 +2,17 @@ import os
|
|
2
2
|
import time
|
3
3
|
from typing import List, Dict
|
4
4
|
|
5
|
-
from loguru import logger
|
6
|
-
from rich.console import Console
|
7
|
-
from rich.table import Table
|
5
|
+
# from loguru import logger
|
6
|
+
# from rich.console import Console
|
7
|
+
# from rich.table import Table
|
8
8
|
|
9
9
|
from autocoder_nano.index.index_manager import IndexManager
|
10
10
|
from autocoder_nano.llm_types import SourceCode, TargetFile, VerifyFileRelevance, AutoCoderArgs
|
11
11
|
from autocoder_nano.llm_client import AutoLLM
|
12
|
+
from autocoder_nano.utils.printer_utils import Printer
|
12
13
|
|
13
|
-
|
14
|
+
|
15
|
+
printer = Printer()
|
14
16
|
|
15
17
|
|
16
18
|
def build_index_and_filter_files(args: AutoCoderArgs, llm: AutoLLM, sources: List[SourceCode]) -> str:
|
@@ -20,7 +22,7 @@ def build_index_and_filter_files(args: AutoCoderArgs, llm: AutoLLM, sources: Lis
|
|
20
22
|
return _file_path
|
21
23
|
|
22
24
|
final_files: Dict[str, TargetFile] = {}
|
23
|
-
|
25
|
+
printer.print_text("第一阶段:处理 REST/RAG/Search 资源...", style="green")
|
24
26
|
for source in sources:
|
25
27
|
if source.tag in ["REST", "RAG", "SEARCH"]:
|
26
28
|
final_files[get_file_path(source.module_name)] = TargetFile(
|
@@ -28,14 +30,14 @@ def build_index_and_filter_files(args: AutoCoderArgs, llm: AutoLLM, sources: Lis
|
|
28
30
|
)
|
29
31
|
|
30
32
|
if not args.skip_build_index and llm:
|
31
|
-
|
33
|
+
printer.print_text("第二阶段:为所有文件构建索引...", style="green")
|
32
34
|
index_manager = IndexManager(args=args, llm=llm, source_codes=sources)
|
33
35
|
index_data = index_manager.build_index()
|
34
36
|
indexed_files_count = len(index_data) if index_data else 0
|
35
|
-
|
37
|
+
printer.print_text(f"总索引文件数: {indexed_files_count}", style="green")
|
36
38
|
|
37
39
|
if not args.skip_filter_index and args.index_filter_level >= 1:
|
38
|
-
|
40
|
+
printer.print_text("第三阶段:执行 Level 1 过滤(基于查询) ...", style="green")
|
39
41
|
target_files = index_manager.get_target_files_by_query(args.query)
|
40
42
|
if target_files:
|
41
43
|
for file in target_files.file_list:
|
@@ -43,7 +45,7 @@ def build_index_and_filter_files(args: AutoCoderArgs, llm: AutoLLM, sources: Lis
|
|
43
45
|
final_files[get_file_path(file_path)] = file
|
44
46
|
|
45
47
|
if target_files is not None and args.index_filter_level >= 2:
|
46
|
-
|
48
|
+
printer.print_text("第四阶段:执行 Level 2 过滤(基于相关文件)...", style="green")
|
47
49
|
related_files = index_manager.get_related_files(
|
48
50
|
[file.file_path for file in target_files.file_list]
|
49
51
|
)
|
@@ -54,29 +56,28 @@ def build_index_and_filter_files(args: AutoCoderArgs, llm: AutoLLM, sources: Lis
|
|
54
56
|
|
55
57
|
# 如果 Level 1 filtering 和 Level 2 filtering 都未获取路径,则使用全部文件
|
56
58
|
if not final_files:
|
57
|
-
|
59
|
+
printer.print_text("Level 1, Level 2 过滤未找到相关文件, 将使用所有文件 ...", style="yellow")
|
58
60
|
for source in sources:
|
59
61
|
final_files[get_file_path(source.module_name)] = TargetFile(
|
60
62
|
file_path=source.module_name,
|
61
63
|
reason="No related files found, use all files",
|
62
64
|
)
|
63
65
|
|
64
|
-
|
66
|
+
printer.print_text("第五阶段:执行相关性验证 ...", style="green")
|
65
67
|
verified_files = {}
|
66
68
|
temp_files = list(final_files.values())
|
67
69
|
verification_results = []
|
68
70
|
|
69
71
|
def _print_verification_results(results):
|
70
|
-
|
71
|
-
table.add_column("文件路径", style="cyan", no_wrap=True)
|
72
|
-
table.add_column("得分", justify="right", style="green")
|
73
|
-
table.add_column("状态", style="yellow")
|
74
|
-
table.add_column("原因/错误")
|
72
|
+
data_list = []
|
75
73
|
if result:
|
76
74
|
for _file_path, _score, _status, _reason in results:
|
77
|
-
|
78
|
-
|
79
|
-
|
75
|
+
data_list.append([_file_path, str(_score) if _score is not None else "N/A", _status, _reason])
|
76
|
+
printer.print_table_compact(
|
77
|
+
data=data_list,
|
78
|
+
title="文件相关性验证结果",
|
79
|
+
headers=["文件路径", "得分", "状态", "原因/错误"]
|
80
|
+
)
|
80
81
|
|
81
82
|
def _verify_single_file(single_file: TargetFile):
|
82
83
|
for _source in sources:
|
@@ -115,12 +116,12 @@ def build_index_and_filter_files(args: AutoCoderArgs, llm: AutoLLM, sources: Lis
|
|
115
116
|
# Keep all files, not just verified ones
|
116
117
|
final_files = verified_files
|
117
118
|
|
118
|
-
|
119
|
+
printer.print_text("第六阶段:筛选文件并应用限制条件 ...", style="green")
|
119
120
|
if args.index_filter_file_num > 0:
|
120
|
-
|
121
|
+
printer.print_text(f"> 从 {len(final_files)} 个文件中获取前 {args.index_filter_file_num} 个文件(Limit)", style="green")
|
121
122
|
final_filenames = [file.file_path for file in final_files.values()]
|
122
123
|
if not final_filenames:
|
123
|
-
|
124
|
+
printer.print_text("未找到目标文件,你可能需要重新编写查询并重试.", style="yellow")
|
124
125
|
if args.index_filter_file_num > 0:
|
125
126
|
final_filenames = final_filenames[: args.index_filter_file_num]
|
126
127
|
|
@@ -135,16 +136,13 @@ def build_index_and_filter_files(args: AutoCoderArgs, llm: AutoLLM, sources: Lis
|
|
135
136
|
return path
|
136
137
|
|
137
138
|
def _print_selected(data):
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
console.print(table)
|
146
|
-
|
147
|
-
logger.info("第七阶段:准备最终输出 ...")
|
139
|
+
printer.print_table_compact(
|
140
|
+
data=[[_shorten_path(_file, keep_levels=3), _reason] for _file, _reason in data],
|
141
|
+
title="代码上下文文件",
|
142
|
+
headers=["文件路径", "原因"]
|
143
|
+
)
|
144
|
+
|
145
|
+
printer.print_text("第七阶段:准备最终输出 ...", style="green")
|
148
146
|
_print_selected(
|
149
147
|
[
|
150
148
|
(file.file_path, file.reason)
|
@@ -4,12 +4,16 @@ import os
|
|
4
4
|
import time
|
5
5
|
from typing import List, Optional
|
6
6
|
|
7
|
-
from loguru import logger
|
7
|
+
# from loguru import logger
|
8
8
|
|
9
9
|
from autocoder_nano.index.symbols_utils import extract_symbols, symbols_info_to_str
|
10
10
|
from autocoder_nano.llm_client import AutoLLM
|
11
11
|
from autocoder_nano.llm_prompt import prompt
|
12
12
|
from autocoder_nano.llm_types import SourceCode, AutoCoderArgs, IndexItem, SymbolType, FileList
|
13
|
+
from autocoder_nano.utils.printer_utils import Printer
|
14
|
+
|
15
|
+
|
16
|
+
printer = Printer()
|
13
17
|
|
14
18
|
|
15
19
|
class IndexManager:
|
@@ -34,7 +38,7 @@ class IndexManager:
|
|
34
38
|
with open(self.index_file, "r") as file: # 读缓存
|
35
39
|
index_data = json.load(file)
|
36
40
|
else: # 首次 build index
|
37
|
-
|
41
|
+
printer.print_text("首次生成索引.", style="green")
|
38
42
|
index_data = {}
|
39
43
|
|
40
44
|
@prompt()
|
@@ -47,7 +51,7 @@ class IndexManager:
|
|
47
51
|
|
48
52
|
for item in index_data.keys():
|
49
53
|
if not item.startswith(self.source_dir):
|
50
|
-
|
54
|
+
printer.print_text(error_message.prompt(source_dir=self.source_dir, file_path=item), style="yellow")
|
51
55
|
break
|
52
56
|
|
53
57
|
updated_sources = []
|
@@ -60,13 +64,13 @@ class IndexManager:
|
|
60
64
|
counter = 0
|
61
65
|
num_files = len(wait_to_build_files)
|
62
66
|
total_files = len(self.sources)
|
63
|
-
|
67
|
+
printer.print_text(f"总文件数: {total_files}, 需要索引文件数: {num_files}", style="green")
|
64
68
|
|
65
69
|
for source in wait_to_build_files:
|
66
70
|
build_result = self.build_index_for_single_source(source)
|
67
71
|
if build_result is not None:
|
68
72
|
counter += 1
|
69
|
-
|
73
|
+
printer.print_text(f"正在构建索引:{counter}/{num_files}...", style="green")
|
70
74
|
module_name = build_result["module_name"]
|
71
75
|
index_data[module_name] = build_result
|
72
76
|
updated_sources.append(module_name)
|
@@ -168,10 +172,13 @@ class IndexManager:
|
|
168
172
|
start_time = time.monotonic()
|
169
173
|
source_code = source.source_code
|
170
174
|
if len(source.source_code) > self.max_input_length:
|
171
|
-
|
172
|
-
f"
|
173
|
-
|
174
|
-
|
175
|
+
printer.print_text(
|
176
|
+
f"""
|
177
|
+
警告[构建索引]: 源代码({source.module_name})长度过长,
|
178
|
+
({len(source.source_code)}) > 模型最大输入长度({self.max_input_length}),
|
179
|
+
正在分割为多个块...
|
180
|
+
""",
|
181
|
+
style="yellow"
|
175
182
|
)
|
176
183
|
chunks = self.split_text_into_chunks(source_code)
|
177
184
|
symbols_list = []
|
@@ -185,9 +192,10 @@ class IndexManager:
|
|
185
192
|
symbols = single_symbols.output
|
186
193
|
time.sleep(self.anti_quota_limit)
|
187
194
|
|
188
|
-
|
195
|
+
printer.print_text(f"解析并更新索引:{file_path}(MD5: {md5}),耗时 {time.monotonic() - start_time:.2f} 秒",
|
196
|
+
style="green")
|
189
197
|
except Exception as e:
|
190
|
-
|
198
|
+
printer.print_text(f"源文件 {file_path} 处理失败: {e}", style="yellow")
|
191
199
|
return None
|
192
200
|
|
193
201
|
return {
|
@@ -313,11 +321,11 @@ class IndexManager:
|
|
313
321
|
all_results.extend(result.file_list)
|
314
322
|
completed += 1
|
315
323
|
else:
|
316
|
-
|
324
|
+
printer.print_text(f"无法找到分块的目标文件.原因可能是模型响应未返回格式错误.", style="yellow")
|
317
325
|
total += 1
|
318
326
|
time.sleep(self.anti_quota_limit)
|
319
327
|
|
320
|
-
|
328
|
+
printer.print_text(f"已完成 {completed}/{total} 个分块(基于查询条件)", style="green")
|
321
329
|
all_results = list({file.file_path: file for file in all_results}.values())
|
322
330
|
if self.args.index_filter_file_num > 0:
|
323
331
|
limited_results = all_results[: self.args.index_filter_file_num]
|
@@ -378,10 +386,10 @@ class IndexManager:
|
|
378
386
|
all_results.extend(result.file_list)
|
379
387
|
completed += 1
|
380
388
|
else:
|
381
|
-
|
389
|
+
printer.print_text(f"无法找到与分块相关的文件。原因可能是模型限制或查询条件与文件不匹配.", style="yellow")
|
382
390
|
total += 1
|
383
391
|
time.sleep(self.anti_quota_limit)
|
384
|
-
|
392
|
+
printer.print_text(f"已完成 {completed}/{total} 个分块(基于相关文件)", style="green")
|
385
393
|
all_results = list({file.file_path: file for file in all_results}.values())
|
386
394
|
return FileList(file_list=all_results)
|
387
395
|
|
autocoder_nano/llm_client.py
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
from typing import List
|
2
2
|
|
3
|
-
from loguru import logger
|
3
|
+
# from loguru import logger
|
4
4
|
from openai import OpenAI, Stream
|
5
5
|
from openai.types.chat import ChatCompletionChunk, ChatCompletion
|
6
6
|
|
7
7
|
from autocoder_nano.llm_types import LLMRequest, LLMResponse
|
8
|
+
from autocoder_nano.utils.printer_utils import Printer
|
9
|
+
|
10
|
+
|
11
|
+
printer = Printer()
|
8
12
|
|
9
13
|
|
10
14
|
class AutoLLM:
|
@@ -37,7 +41,11 @@ class AutoLLM:
|
|
37
41
|
model = self.default_model_name
|
38
42
|
|
39
43
|
model_name = self.sub_clients[model]["model_name"]
|
40
|
-
|
44
|
+
printer.print_card(
|
45
|
+
title="模型调用",
|
46
|
+
content=f"调用函数: stream_chat_ai\n使用模型: {model}\n模型名称: {model_name}",
|
47
|
+
width=60
|
48
|
+
)
|
41
49
|
request = LLMRequest(
|
42
50
|
model=model_name,
|
43
51
|
messages=conversations
|
@@ -57,7 +65,11 @@ class AutoLLM:
|
|
57
65
|
conversations = [{"role": "user", "content": conversations}]
|
58
66
|
|
59
67
|
model_name = self.sub_clients[model]["model_name"]
|
60
|
-
|
68
|
+
printer.print_card(
|
69
|
+
title="模型调用",
|
70
|
+
content=f"调用函数: chat_ai\n使用模型: {model}\n模型名称: {model_name}",
|
71
|
+
width=60
|
72
|
+
)
|
61
73
|
request = LLMRequest(
|
62
74
|
model=model_name,
|
63
75
|
messages=conversations
|
@@ -98,7 +110,11 @@ class AutoLLM:
|
|
98
110
|
model = self.default_model_name
|
99
111
|
|
100
112
|
model_name = self.sub_clients[model]["model_name"]
|
101
|
-
|
113
|
+
printer.print_card(
|
114
|
+
title="模型调用",
|
115
|
+
content=f"调用函数: embedding\n使用模型: {model}\n模型名称: {model_name}",
|
116
|
+
width=60
|
117
|
+
)
|
102
118
|
|
103
119
|
res = self.sub_clients[model]["client"].embeddings.create(
|
104
120
|
model=model_name,
|
File without changes
|