autocoder-nano 0.1.27__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 +286 -301
- 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/llm_types.py +1 -0
- autocoder_nano/project/pyproject.py +1 -1
- autocoder_nano/project/suffixproject.py +1 -1
- 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.29.dist-info/METADATA +444 -0
- {autocoder_nano-0.1.27.dist-info → autocoder_nano-0.1.29.dist-info}/RECORD +19 -17
- autocoder_nano-0.1.27.dist-info/METADATA +0 -432
- {autocoder_nano-0.1.27.dist-info → autocoder_nano-0.1.29.dist-info}/LICENSE +0 -0
- {autocoder_nano-0.1.27.dist-info → autocoder_nano-0.1.29.dist-info}/WHEEL +0 -0
- {autocoder_nano-0.1.27.dist-info → autocoder_nano-0.1.29.dist-info}/entry_points.txt +0 -0
- {autocoder_nano-0.1.27.dist-info → autocoder_nano-0.1.29.dist-info}/top_level.txt +0 -0
@@ -23,11 +23,12 @@ from autocoder_nano.git_utils import (repo_init, commit_changes, revert_changes,
|
|
23
23
|
get_uncommitted_changes, generate_commit_message)
|
24
24
|
from autocoder_nano.sys_utils import default_exclude_dirs, detect_env
|
25
25
|
from autocoder_nano.project import PyProject, SuffixProject
|
26
|
+
from autocoder_nano.utils.printer_utils import Printer
|
26
27
|
|
27
28
|
import yaml
|
28
|
-
import tabulate
|
29
|
+
# import tabulate
|
29
30
|
from jinja2 import Template
|
30
|
-
from loguru import logger
|
31
|
+
# from loguru import logger
|
31
32
|
from prompt_toolkit import prompt as _toolkit_prompt, PromptSession
|
32
33
|
from prompt_toolkit.completion import Completer, Completion
|
33
34
|
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
|
@@ -45,14 +46,16 @@ from rich.table import Table
|
|
45
46
|
from rich.text import Text
|
46
47
|
|
47
48
|
|
48
|
-
|
49
|
+
printer = Printer()
|
50
|
+
console = printer.get_console()
|
51
|
+
# console = Console()
|
49
52
|
project_root = os.getcwd()
|
50
53
|
base_persist_dir = os.path.join(project_root, ".auto-coder", "plugins", "chat-auto-coder")
|
51
54
|
# defaut_exclude_dirs = [".git", ".svn", "node_modules", "dist", "build", "__pycache__", ".auto-coder", "actions",
|
52
55
|
# ".vscode", ".idea", ".hg"]
|
53
56
|
commands = [
|
54
57
|
"/add_files", "/remove_files", "/list_files", "/conf", "/coding", "/chat", "/revert", "/index/query",
|
55
|
-
"/index/build", "/exclude_dirs", "/help", "/shell", "/exit", "/mode", "/models", "/commit", "/new"
|
58
|
+
"/index/build", "/exclude_dirs", "/exclude_files", "/help", "/shell", "/exit", "/mode", "/models", "/commit", "/new"
|
56
59
|
]
|
57
60
|
|
58
61
|
memory = {
|
@@ -197,7 +200,9 @@ COMMANDS = {
|
|
197
200
|
"/conf": "",
|
198
201
|
"/mode": "",
|
199
202
|
"/models": ""
|
200
|
-
}
|
203
|
+
},
|
204
|
+
"/exclude_files": {"/list": "", "/drop": ""},
|
205
|
+
"/exclude_dirs": {}
|
201
206
|
}
|
202
207
|
|
203
208
|
|
@@ -675,6 +680,15 @@ class CommandCompleter(Completer):
|
|
675
680
|
if current_word and current_word in file_name:
|
676
681
|
yield Completion(file_name, start_position=-len(current_word))
|
677
682
|
|
683
|
+
elif words[0] == "/exclude_files":
|
684
|
+
new_text = text[len("/exclude_files"):]
|
685
|
+
parser = CommandTextParser(new_text, words[0])
|
686
|
+
parser.add_files()
|
687
|
+
current_word = parser.current_word()
|
688
|
+
for command in parser.get_sub_commands():
|
689
|
+
if command.startswith(current_word):
|
690
|
+
yield Completion(command, start_position=-len(current_word))
|
691
|
+
|
678
692
|
elif words[0] == "/models":
|
679
693
|
new_text = text[len("/models"):]
|
680
694
|
parser = CommandTextParser(new_text, words[0])
|
@@ -772,11 +786,76 @@ def load_memory():
|
|
772
786
|
completer.update_current_files(memory["current_files"]["files"])
|
773
787
|
|
774
788
|
|
789
|
+
def exclude_dirs(dir_names: List[str]):
|
790
|
+
new_dirs = dir_names
|
791
|
+
existing_dirs = memory.get("exclude_dirs", [])
|
792
|
+
dirs_to_add = [d for d in new_dirs if d not in existing_dirs]
|
793
|
+
|
794
|
+
if dirs_to_add:
|
795
|
+
existing_dirs.extend(dirs_to_add)
|
796
|
+
if "exclude_dirs" not in memory:
|
797
|
+
memory["exclude_dirs"] = existing_dirs
|
798
|
+
printer.print_text(Text(f"已添加排除目录: {dirs_to_add}", style="bold green"))
|
799
|
+
for d in dirs_to_add:
|
800
|
+
exclude_files(f"regex://.*/{d}/*.")
|
801
|
+
# exclude_files([f"regex://.*/{d}/*." for d in dirs_to_add])
|
802
|
+
else:
|
803
|
+
printer.print_text(Text(f"所有指定目录已在排除列表中. ", style="bold green"))
|
804
|
+
save_memory()
|
805
|
+
completer.refresh_files()
|
806
|
+
|
807
|
+
|
808
|
+
def exclude_files(query: str):
|
809
|
+
if "/list" in query:
|
810
|
+
query = query.replace("/list", "", 1).strip()
|
811
|
+
existing_file_patterns = memory.get("exclude_files", [])
|
812
|
+
|
813
|
+
printer.print_table_compact(
|
814
|
+
headers=["File Pattern"],
|
815
|
+
data=[[file_pattern] for file_pattern in existing_file_patterns],
|
816
|
+
title="Exclude Files",
|
817
|
+
show_lines=False
|
818
|
+
)
|
819
|
+
return
|
820
|
+
|
821
|
+
if "/drop" in query:
|
822
|
+
query = query.replace("/drop", "", 1).strip()
|
823
|
+
existing_file_patterns = memory.get("exclude_files", [])
|
824
|
+
existing_file_patterns.remove(query.strip())
|
825
|
+
memory["exclude_files"] = existing_file_patterns
|
826
|
+
if query.startswith("regex://.*/") and query.endswith("/*."):
|
827
|
+
existing_dirs_patterns = memory.get("exclude_dirs", [])
|
828
|
+
dir_query = query.replace("regex://.*/", "", 1).replace("/*.", "", 1)
|
829
|
+
if dir_query in existing_dirs_patterns:
|
830
|
+
existing_dirs_patterns.remove(dir_query.strip())
|
831
|
+
save_memory()
|
832
|
+
completer.refresh_files()
|
833
|
+
return
|
834
|
+
|
835
|
+
new_file_patterns = query.strip().split(",")
|
836
|
+
|
837
|
+
existing_file_patterns = memory.get("exclude_files", [])
|
838
|
+
file_patterns_to_add = [f for f in new_file_patterns if f not in existing_file_patterns]
|
839
|
+
|
840
|
+
for file_pattern in file_patterns_to_add:
|
841
|
+
if not file_pattern.startswith("regex://"):
|
842
|
+
raise
|
843
|
+
|
844
|
+
if file_patterns_to_add:
|
845
|
+
existing_file_patterns.extend(file_patterns_to_add)
|
846
|
+
if "exclude_files" not in memory:
|
847
|
+
memory["exclude_files"] = existing_file_patterns
|
848
|
+
save_memory()
|
849
|
+
printer.print_text(f"已添加排除文件: {file_patterns_to_add}. ", style="green")
|
850
|
+
else:
|
851
|
+
printer.print_text(f"所有指定文件已在排除列表中. ", style="green")
|
852
|
+
|
853
|
+
|
775
854
|
def index_command(llm):
|
776
855
|
update_config_to_args(query="", delete_execute_file=True)
|
777
856
|
|
778
857
|
source_dir = os.path.abspath(args.source_dir)
|
779
|
-
|
858
|
+
printer.print_text(f"开始对目录 {source_dir} 中的源代码进行索引", style="green")
|
780
859
|
if args.project_type == "py":
|
781
860
|
pp = PyProject(llm=llm, args=args)
|
782
861
|
else:
|
@@ -791,7 +870,7 @@ def index_export(export_path: str) -> bool:
|
|
791
870
|
try:
|
792
871
|
index_path = os.path.join(project_root, ".auto-coder", "index.json")
|
793
872
|
if not os.path.exists(index_path):
|
794
|
-
|
873
|
+
printer.print_text(Text(f"索引文件不存在. ", style="bold red"))
|
795
874
|
return False
|
796
875
|
|
797
876
|
with open(index_path, "r", encoding="utf-8") as f:
|
@@ -804,16 +883,16 @@ def index_export(export_path: str) -> bool:
|
|
804
883
|
data["module_name"] = rel_path
|
805
884
|
converted_data[rel_path] = data
|
806
885
|
except ValueError:
|
807
|
-
|
886
|
+
printer.print_text(Text(f"索引转换路径失败. ", style="dim yellow"))
|
808
887
|
converted_data[abs_path] = data
|
809
888
|
|
810
889
|
export_file = os.path.join(export_path, "index.json")
|
811
890
|
with open(export_file, "w", encoding="utf-8") as f:
|
812
891
|
json.dump(converted_data, f, indent=2)
|
813
|
-
|
892
|
+
printer.print_text(Text(f"索引文件导出成功. ", style="bold green"))
|
814
893
|
return True
|
815
894
|
except Exception as err:
|
816
|
-
|
895
|
+
printer.print_text(Text(f"索引文件导出失败: {err}", style="bold red"))
|
817
896
|
return False
|
818
897
|
|
819
898
|
|
@@ -821,12 +900,10 @@ def index_import(import_path: str):
|
|
821
900
|
try:
|
822
901
|
import_file = os.path.join(import_path, "index.json")
|
823
902
|
if not os.path.exists(import_file):
|
824
|
-
|
903
|
+
printer.print_text(Text(f"导入索引文件不存在", style="bold red"))
|
825
904
|
return False
|
826
|
-
# Read and convert paths
|
827
905
|
with open(import_file, "r", encoding="utf-8") as f:
|
828
906
|
index_data = json.load(f)
|
829
|
-
# Convert relative paths to absolute
|
830
907
|
converted_data = {}
|
831
908
|
for rel_path, data in index_data.items():
|
832
909
|
try:
|
@@ -834,12 +911,12 @@ def index_import(import_path: str):
|
|
834
911
|
data["module_name"] = abs_path
|
835
912
|
converted_data[abs_path] = data
|
836
913
|
except Exception as err:
|
837
|
-
|
914
|
+
printer.print_text(Text(f"{rel_path} 索引转换路径失败: {err}", style="dim yellow"))
|
838
915
|
converted_data[rel_path] = data
|
839
916
|
# Backup existing index
|
840
917
|
index_path = os.path.join(project_root, ".auto-coder", "index.json")
|
841
918
|
if os.path.exists(index_path):
|
842
|
-
|
919
|
+
printer.print_text(Text(f"原索引文件不存在", style="bold yellow"))
|
843
920
|
backup_path = index_path + ".bak"
|
844
921
|
shutil.copy2(index_path, backup_path)
|
845
922
|
|
@@ -848,7 +925,7 @@ def index_import(import_path: str):
|
|
848
925
|
json.dump(converted_data, f, indent=2)
|
849
926
|
return True
|
850
927
|
except Exception as err:
|
851
|
-
|
928
|
+
printer.print_text(Text(f"索引文件导入失败: {err}", style="bold red"))
|
852
929
|
return False
|
853
930
|
|
854
931
|
|
@@ -894,16 +971,23 @@ def index_query_command(query: str, llm: AutoLLM):
|
|
894
971
|
final_files.extend(related_fiels.file_list)
|
895
972
|
|
896
973
|
all_results = list({file.file_path: file for file in final_files}.values())
|
897
|
-
|
898
|
-
f"
|
974
|
+
printer.print_key_value(
|
975
|
+
{"索引过滤级别": f"{args.index_filter_level}", "查询条件": f"{args.query}", "过滤后的文件数": f"{len(all_results)}"},
|
976
|
+
panel=True
|
899
977
|
)
|
900
978
|
|
901
|
-
headers = TargetFile.model_fields.keys()
|
902
|
-
table_data = wrap_text_in_table(
|
903
|
-
|
979
|
+
# headers = TargetFile.model_fields.keys()
|
980
|
+
# table_data = wrap_text_in_table(
|
981
|
+
# [[getattr(file_item, name) for name in headers] for file_item in all_results]
|
982
|
+
# )
|
983
|
+
# table_output = tabulate.tabulate(table_data, headers, tablefmt="grid")
|
984
|
+
# print(table_output, flush=True)
|
985
|
+
printer.print_table_compact(
|
986
|
+
headers=["文件路径", "原因"],
|
987
|
+
data=[[_target_file.file_path, _target_file.reason] for _target_file in all_results],
|
988
|
+
title="Index Query 结果",
|
989
|
+
show_lines=True,
|
904
990
|
)
|
905
|
-
table_output = tabulate.tabulate(table_data, headers, tablefmt="grid")
|
906
|
-
print(table_output, flush=True)
|
907
991
|
return
|
908
992
|
|
909
993
|
|
@@ -951,7 +1035,7 @@ def convert_config_value(key, value):
|
|
951
1035
|
else:
|
952
1036
|
return value
|
953
1037
|
else:
|
954
|
-
|
1038
|
+
printer.print_text(f"无效的配置项: {key}", style="red")
|
955
1039
|
return None
|
956
1040
|
|
957
1041
|
|
@@ -965,7 +1049,8 @@ def update_config_to_args(query, delete_execute_file: bool = False):
|
|
965
1049
|
"skip_confirm": conf.get("skip_confirm", "true") == "true",
|
966
1050
|
"chat_model": conf.get("chat_model", ""),
|
967
1051
|
"code_model": conf.get("code_model", ""),
|
968
|
-
"auto_merge": conf.get("auto_merge", "editblock")
|
1052
|
+
"auto_merge": conf.get("auto_merge", "editblock"),
|
1053
|
+
"exclude_files": memory.get("exclude_files", [])
|
969
1054
|
}
|
970
1055
|
current_files = memory["current_files"]["files"]
|
971
1056
|
yaml_config["urls"] = current_files
|
@@ -992,23 +1077,14 @@ def update_config_to_args(query, delete_execute_file: bool = False):
|
|
992
1077
|
|
993
1078
|
def print_chat_history(history, max_entries=5):
|
994
1079
|
recent_history = history[-max_entries:]
|
995
|
-
|
996
|
-
# 遍历聊天记录
|
1080
|
+
data_list = []
|
997
1081
|
for entry in recent_history:
|
998
1082
|
role = entry["role"]
|
999
1083
|
content = entry["content"]
|
1000
|
-
|
1001
|
-
# 根据角色设置样式
|
1002
1084
|
if role == "user":
|
1003
|
-
|
1085
|
+
printer.print_text(Text(content, style="bold red"))
|
1004
1086
|
else:
|
1005
|
-
|
1006
|
-
markdown_content = Markdown(content)
|
1007
|
-
# 将内容和角色添加到表格中
|
1008
|
-
table.add_row(role_text, markdown_content)
|
1009
|
-
# 使用 Panel 包裹表格,增加美观性
|
1010
|
-
panel = Panel(table, title="历史聊天记录", border_style="bold yellow")
|
1011
|
-
console.print(panel)
|
1087
|
+
printer.print_markdown(content, panel=True)
|
1012
1088
|
|
1013
1089
|
|
1014
1090
|
@prompt()
|
@@ -1067,13 +1143,10 @@ def chat(query: str, llm: AutoLLM):
|
|
1067
1143
|
json_str = json.dumps(chat_history, ensure_ascii=False)
|
1068
1144
|
fp.write(json_str)
|
1069
1145
|
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
expand=False,
|
1075
|
-
border_style="green",
|
1076
|
-
)
|
1146
|
+
printer.print_panel(
|
1147
|
+
Text("新会话已开始, 之前的聊天历史已存档.", style="green"),
|
1148
|
+
title="Session Status",
|
1149
|
+
center=True
|
1077
1150
|
)
|
1078
1151
|
if not query:
|
1079
1152
|
return
|
@@ -1132,7 +1205,7 @@ def chat(query: str, llm: AutoLLM):
|
|
1132
1205
|
assistant_response = ""
|
1133
1206
|
|
1134
1207
|
try:
|
1135
|
-
with Live(Panel("", title="Response"), refresh_per_second=12) as live:
|
1208
|
+
with Live(Panel("", title="Response", style="cyan"), refresh_per_second=12) as live:
|
1136
1209
|
for chunk in v:
|
1137
1210
|
if chunk.choices and chunk.choices[0].delta.content:
|
1138
1211
|
content = chunk.choices[0].delta.content
|
@@ -1154,7 +1227,7 @@ def chat(query: str, llm: AutoLLM):
|
|
1154
1227
|
display_content = '\n'.join(lines_buffer[-MAX_HISTORY_LINES:] + [current_line])
|
1155
1228
|
|
1156
1229
|
live.update(
|
1157
|
-
Panel(Markdown(display_content), title="模型返回", border_style="
|
1230
|
+
Panel(Markdown(display_content), title="模型返回", border_style="cyan",
|
1158
1231
|
height=min(25, live.console.height - 4))
|
1159
1232
|
)
|
1160
1233
|
|
@@ -1164,10 +1237,10 @@ def chat(query: str, llm: AutoLLM):
|
|
1164
1237
|
|
1165
1238
|
# 最终完整渲染
|
1166
1239
|
live.update(
|
1167
|
-
Panel(Markdown(assistant_response), title="模型返回", border_style="blue")
|
1240
|
+
Panel(Markdown(assistant_response), title="模型返回", border_style="dim blue")
|
1168
1241
|
)
|
1169
1242
|
except Exception as e:
|
1170
|
-
|
1243
|
+
printer.print_panel(Text(f"{str(e)}", style="red"), title="模型返回", center=True)
|
1171
1244
|
|
1172
1245
|
chat_history["ask_conversation"].append({"role": "assistant", "content": assistant_response})
|
1173
1246
|
|
@@ -1180,8 +1253,8 @@ def chat(query: str, llm: AutoLLM):
|
|
1180
1253
|
|
1181
1254
|
def init_project():
|
1182
1255
|
if not args.project_type:
|
1183
|
-
|
1184
|
-
"请指定项目类型。可选的项目类型包括:py|ts|
|
1256
|
+
printer.print_text(
|
1257
|
+
f"请指定项目类型。可选的项目类型包括:py|ts| 或文件扩展名(例如:.java,.scala), 多个扩展名逗号分隔.", style="green"
|
1185
1258
|
)
|
1186
1259
|
return
|
1187
1260
|
os.makedirs(os.path.join(args.source_dir, "actions"), exist_ok=True)
|
@@ -1199,7 +1272,7 @@ def init_project():
|
|
1199
1272
|
f.write("\nactions/")
|
1200
1273
|
f.write("\noutput.txt")
|
1201
1274
|
|
1202
|
-
|
1275
|
+
printer.print_text(f"已在 {os.path.abspath(args.source_dir)} 成功初始化 autocoder-nano 项目", style="green")
|
1203
1276
|
return
|
1204
1277
|
|
1205
1278
|
|
@@ -1234,11 +1307,11 @@ def load_include_files(config, base_path, max_depth=10, current_depth=0):
|
|
1234
1307
|
|
1235
1308
|
for include_file in include_files:
|
1236
1309
|
abs_include_path = resolve_include_path(base_path, include_file)
|
1237
|
-
|
1310
|
+
printer.print_text(f"正在加载 Include file: {abs_include_path}", style="green")
|
1238
1311
|
with open(abs_include_path, "r") as f:
|
1239
1312
|
include_config = yaml.safe_load(f)
|
1240
1313
|
if not include_config:
|
1241
|
-
|
1314
|
+
printer.print_text(f"Include file {abs_include_path} 为空,跳过处理.", style="green")
|
1242
1315
|
continue
|
1243
1316
|
config.update(
|
1244
1317
|
{
|
@@ -1254,7 +1327,7 @@ def prepare_chat_yaml():
|
|
1254
1327
|
# auto_coder_main(["next", "chat_action"]) 准备聊天 yaml 文件
|
1255
1328
|
actions_dir = os.path.join(args.source_dir, "actions")
|
1256
1329
|
if not os.path.exists(actions_dir):
|
1257
|
-
|
1330
|
+
printer.print_text("当前目录中未找到 actions 目录。请执行初始化 AutoCoder Nano", style="yellow")
|
1258
1331
|
return
|
1259
1332
|
|
1260
1333
|
action_files = [
|
@@ -1285,7 +1358,7 @@ def prepare_chat_yaml():
|
|
1285
1358
|
with open(new_file, "w") as f:
|
1286
1359
|
f.write(content)
|
1287
1360
|
|
1288
|
-
|
1361
|
+
printer.print_text(f"已成功创建新的 action 文件: {new_file}", style="green")
|
1289
1362
|
return
|
1290
1363
|
|
1291
1364
|
|
@@ -1344,9 +1417,8 @@ def coding(query: str, llm: AutoLLM):
|
|
1344
1417
|
memory_file = os.path.join(memory_dir, "chat_history.json")
|
1345
1418
|
|
1346
1419
|
def error_message():
|
1347
|
-
|
1348
|
-
|
1349
|
-
expand=False, border_style="yellow",)
|
1420
|
+
printer.print_panel(
|
1421
|
+
Text("No chat history found to apply.", style="yellow"), title="Chat History", center=True
|
1350
1422
|
)
|
1351
1423
|
|
1352
1424
|
if not os.path.exists(memory_file):
|
@@ -1379,7 +1451,7 @@ def coding(query: str, llm: AutoLLM):
|
|
1379
1451
|
dispacher = Dispacher(args=args, llm=llm)
|
1380
1452
|
dispacher.dispach()
|
1381
1453
|
else:
|
1382
|
-
|
1454
|
+
printer.print_text(f"创建新的 YAML 文件失败.", style="yellow")
|
1383
1455
|
|
1384
1456
|
save_memory()
|
1385
1457
|
completer.refresh_files()
|
@@ -1395,9 +1467,9 @@ def execute_revert():
|
|
1395
1467
|
revert_result = revert_changes(repo_path, f"auto_coder_{file_name}_{md5}")
|
1396
1468
|
if revert_result:
|
1397
1469
|
os.remove(args.file)
|
1398
|
-
|
1470
|
+
printer.print_text(f"已成功回退最后一次 chat action 的更改,并移除 YAML 文件 {args.file}", style="green")
|
1399
1471
|
else:
|
1400
|
-
|
1472
|
+
printer.print_text(f"回退文件 {args.file} 的更改失败", style="red")
|
1401
1473
|
return
|
1402
1474
|
|
1403
1475
|
|
@@ -1408,29 +1480,24 @@ def revert():
|
|
1408
1480
|
convert_yaml_to_config(file_path)
|
1409
1481
|
execute_revert()
|
1410
1482
|
else:
|
1411
|
-
|
1483
|
+
printer.print_text(f"No previous chat action found to revert.", style="yellow")
|
1412
1484
|
|
1413
1485
|
|
1414
1486
|
def print_commit_info(commit_result: CommitResult):
|
1415
|
-
|
1416
|
-
|
1417
|
-
|
1418
|
-
|
1419
|
-
|
1420
|
-
|
1421
|
-
"
|
1422
|
-
"\n".join(commit_result.changed_files) if commit_result.changed_files else "No files changed"
|
1423
|
-
)
|
1424
|
-
|
1425
|
-
console.print(
|
1426
|
-
Panel(table, expand=False, border_style="green", title="Git 提交摘要")
|
1487
|
+
printer.print_table_compact(
|
1488
|
+
data=[
|
1489
|
+
["提交哈希", commit_result.commit_hash],
|
1490
|
+
["提交信息", commit_result.commit_message],
|
1491
|
+
["更改的文件", "\n".join(commit_result.changed_files) if commit_result.changed_files else "No files changed"]
|
1492
|
+
],
|
1493
|
+
title="提交信息", headers=["属性", "值"], caption="(使用 /revert 撤销此提交)"
|
1427
1494
|
)
|
1428
1495
|
|
1429
1496
|
if commit_result.diffs:
|
1430
1497
|
for file, diff in commit_result.diffs.items():
|
1431
|
-
|
1498
|
+
printer.print_text(f"File: {file}", style="green")
|
1432
1499
|
syntax = Syntax(diff, "diff", theme="monokai", line_numbers=True)
|
1433
|
-
|
1500
|
+
printer.print_panel(syntax, title="File Diff", center=True)
|
1434
1501
|
|
1435
1502
|
|
1436
1503
|
def commit_info(query: str, llm: AutoLLM):
|
@@ -1473,7 +1540,7 @@ def commit_info(query: str, llm: AutoLLM):
|
|
1473
1540
|
# commit_message = ""
|
1474
1541
|
commit_llm = llm
|
1475
1542
|
commit_llm.setup_default_model_name(args.chat_model)
|
1476
|
-
|
1543
|
+
printer.print_text(f"Commit 信息生成中...", style="green")
|
1477
1544
|
|
1478
1545
|
try:
|
1479
1546
|
uncommitted_changes = get_uncommitted_changes(repo_path)
|
@@ -1482,7 +1549,7 @@ def commit_info(query: str, llm: AutoLLM):
|
|
1482
1549
|
)
|
1483
1550
|
memory["conversation"].append({"role": "user", "content": commit_message.output})
|
1484
1551
|
except Exception as err:
|
1485
|
-
|
1552
|
+
printer.print_text(f"Commit 信息生成失败: {err}", style="red")
|
1486
1553
|
return
|
1487
1554
|
|
1488
1555
|
yaml_config["query"] = commit_message.output
|
@@ -1496,11 +1563,11 @@ def commit_info(query: str, llm: AutoLLM):
|
|
1496
1563
|
commit_result = commit_changes(repo_path, f"auto_coder_nano_{file_name}_{md5}\n{commit_message}")
|
1497
1564
|
print_commit_info(commit_result=commit_result)
|
1498
1565
|
if commit_message:
|
1499
|
-
|
1566
|
+
printer.print_text(f"Commit 成功", style="green")
|
1500
1567
|
except Exception as err:
|
1501
1568
|
import traceback
|
1502
1569
|
traceback.print_exc()
|
1503
|
-
|
1570
|
+
printer.print_text(f"Commit 失败: {err}", style="red")
|
1504
1571
|
if execute_file:
|
1505
1572
|
os.remove(execute_file)
|
1506
1573
|
|
@@ -1545,22 +1612,14 @@ def generate_shell_command(input_text: str, llm: AutoLLM) -> str | None:
|
|
1545
1612
|
update_config_to_args(query=input_text, delete_execute_file=True)
|
1546
1613
|
|
1547
1614
|
try:
|
1548
|
-
|
1549
|
-
|
1550
|
-
f"正在根据用户输入 {input_text} 生成 Shell 脚本...",
|
1551
|
-
title="命令生成",
|
1552
|
-
border_style="green",
|
1553
|
-
)
|
1615
|
+
printer.print_panel(
|
1616
|
+
Text(f"正在根据用户输入 {input_text} 生成 Shell 脚本...", style="green"), title="命令生成",
|
1554
1617
|
)
|
1555
1618
|
llm.setup_default_model_name(args.code_model)
|
1556
1619
|
result = _generate_shell_script.with_llm(llm).run(user_input=input_text)
|
1557
1620
|
shell_script = extract_code(result.output)[0][1]
|
1558
|
-
|
1559
|
-
|
1560
|
-
shell_script,
|
1561
|
-
title="Shell 脚本",
|
1562
|
-
border_style="magenta",
|
1563
|
-
)
|
1621
|
+
printer.print_code(
|
1622
|
+
code=shell_script, lexer="shell", panel=True
|
1564
1623
|
)
|
1565
1624
|
return shell_script
|
1566
1625
|
finally:
|
@@ -1591,31 +1650,31 @@ def execute_shell_command(command: str):
|
|
1591
1650
|
output.append(output_line.strip())
|
1592
1651
|
live.update(
|
1593
1652
|
Panel(
|
1594
|
-
Text("\n".join(output[-20:])),
|
1653
|
+
Text("\n".join(output[-20:]), style="green"),
|
1595
1654
|
title="Shell 输出",
|
1596
|
-
border_style="
|
1655
|
+
border_style="dim blue",
|
1597
1656
|
)
|
1598
1657
|
)
|
1599
1658
|
if error_line:
|
1600
1659
|
output.append(f"ERROR: {error_line.strip()}")
|
1601
1660
|
live.update(
|
1602
1661
|
Panel(
|
1603
|
-
Text("\n".join(output[-20:])),
|
1662
|
+
Text("\n".join(output[-20:]), style="red"),
|
1604
1663
|
title="Shell 输出",
|
1605
|
-
border_style="
|
1664
|
+
border_style="dim blue",
|
1606
1665
|
)
|
1607
1666
|
)
|
1608
1667
|
if output_line == "" and error_line == "" and process.poll() is not None:
|
1609
1668
|
break
|
1610
1669
|
|
1611
1670
|
if process.returncode != 0:
|
1612
|
-
|
1671
|
+
printer.print_text(f"命令执行失败,返回码: {process.returncode}", style="red")
|
1613
1672
|
else:
|
1614
|
-
|
1673
|
+
printer.print_text(f"命令执行成功", style="green")
|
1615
1674
|
except FileNotFoundError:
|
1616
|
-
|
1675
|
+
printer.print_text(f"未找到命令:", style="yellow")
|
1617
1676
|
except subprocess.SubprocessError as e:
|
1618
|
-
|
1677
|
+
printer.print_text(f"命令执行错误:", style="yellow")
|
1619
1678
|
|
1620
1679
|
|
1621
1680
|
def parse_args(input_args: Optional[List[str]] = None):
|
@@ -1767,10 +1826,10 @@ def configure_project_type() -> str:
|
|
1767
1826
|
print_info("项目类型支持:")
|
1768
1827
|
print_info(" - 语言后缀(例如:.py, .java, .ts)")
|
1769
1828
|
print_info(" - 预定义类型:py(Python), ts(TypeScript/JavaScript)")
|
1770
|
-
print_info("
|
1829
|
+
print_info("对于混合语言项目,使用逗号分隔的值.")
|
1771
1830
|
print_info("示例:'.java,.scala' 或 '.py,.ts'")
|
1772
1831
|
|
1773
|
-
print_warning(f"
|
1832
|
+
print_warning(f"如果留空, 默认为 'py'.\n")
|
1774
1833
|
|
1775
1834
|
project_type = _toolkit_prompt("请输入项目类型:", default="py", style=style).strip()
|
1776
1835
|
|
@@ -1787,45 +1846,34 @@ def configure_project_type() -> str:
|
|
1787
1846
|
return project_type
|
1788
1847
|
|
1789
1848
|
|
1790
|
-
def print_status(message, status):
|
1791
|
-
if status == "success":
|
1792
|
-
print(f"\033[32m✓ {message}\033[0m")
|
1793
|
-
elif status == "warning":
|
1794
|
-
print(f"\033[33m! {message}\033[0m")
|
1795
|
-
elif status == "error":
|
1796
|
-
print(f"\033[31m✗ {message}\033[0m")
|
1797
|
-
else:
|
1798
|
-
print(f" {message}")
|
1799
|
-
|
1800
|
-
|
1801
1849
|
def initialize_system():
|
1802
|
-
|
1850
|
+
printer.print_text(f"🚀 正在初始化系统...", style="green")
|
1803
1851
|
|
1804
1852
|
def _init_project():
|
1805
1853
|
first_time = False
|
1806
1854
|
if not os.path.exists(os.path.join(args.source_dir, ".auto-coder")):
|
1807
1855
|
first_time = True
|
1808
|
-
|
1856
|
+
printer.print_text("当前目录未初始化为auto-coder项目.", style="yellow")
|
1809
1857
|
init_choice = input(f" 是否现在初始化项目?(y/n): ").strip().lower()
|
1810
1858
|
if init_choice == "y":
|
1811
1859
|
try:
|
1812
1860
|
init_project()
|
1813
|
-
|
1861
|
+
printer.print_text("项目初始化成功.", style="green")
|
1814
1862
|
except Exception as e:
|
1815
|
-
|
1863
|
+
printer.print_text(f"项目初始化失败, {str(e)}.", style="red")
|
1816
1864
|
exit(1)
|
1817
1865
|
else:
|
1818
|
-
|
1866
|
+
printer.print_text("退出而不初始化.", style="yellow")
|
1819
1867
|
exit(1)
|
1820
1868
|
|
1821
1869
|
if not os.path.exists(base_persist_dir):
|
1822
1870
|
os.makedirs(base_persist_dir, exist_ok=True)
|
1823
|
-
|
1871
|
+
printer.print_text("创建目录:{}".format(base_persist_dir), style="green")
|
1824
1872
|
|
1825
1873
|
if first_time: # 首次启动,配置项目类型
|
1826
1874
|
configure_project_type()
|
1827
1875
|
|
1828
|
-
|
1876
|
+
printer.print_text("项目初始化完成.", style="green")
|
1829
1877
|
|
1830
1878
|
_init_project()
|
1831
1879
|
|
@@ -1841,70 +1889,49 @@ def add_files(add_files_args: List[str]):
|
|
1841
1889
|
groups_info = memory["current_files"]["groups_info"]
|
1842
1890
|
|
1843
1891
|
if not add_files_args:
|
1844
|
-
|
1845
|
-
Panel("请为 /add_files 命令提供参数.", title="错误", border_style="red")
|
1846
|
-
)
|
1892
|
+
printer.print_panel(Text("请为 /add_files 命令提供参数.", style="red"), title="错误", center=True)
|
1847
1893
|
return
|
1848
1894
|
|
1849
1895
|
if add_files_args[0] == "/refresh": # 刷新
|
1850
1896
|
completer.refresh_files()
|
1851
1897
|
load_memory()
|
1852
|
-
|
1853
|
-
Panel("已刷新的文件列表.", title="文件刷新", border_style="green")
|
1854
|
-
)
|
1898
|
+
printer.print_panel(Text("已刷新的文件列表.", style="green"), title="文件刷新", center=True)
|
1855
1899
|
return
|
1856
1900
|
|
1857
1901
|
if add_files_args[0] == "/group":
|
1858
1902
|
# 列出组
|
1859
1903
|
if len(add_files_args) == 1 or (len(add_files_args) == 2 and add_files_args[1] == "list"):
|
1860
1904
|
if not groups:
|
1861
|
-
|
1862
|
-
Panel("未定义任何文件组.", title="文件组",
|
1863
|
-
border_style="yellow")
|
1864
|
-
)
|
1905
|
+
printer.print_panel(Text("未定义任何文件组.", style="yellow"), title="文件组", center=True)
|
1865
1906
|
else:
|
1866
|
-
|
1867
|
-
title="已定义文件组",
|
1868
|
-
show_header=True,
|
1869
|
-
header_style="bold magenta",
|
1870
|
-
show_lines=True,
|
1871
|
-
)
|
1872
|
-
table.add_column("Group Name", style="cyan", no_wrap=True)
|
1873
|
-
table.add_column("Files", style="green")
|
1874
|
-
table.add_column("Query Prefix", style="yellow")
|
1875
|
-
table.add_column("Active", style="magenta")
|
1876
|
-
|
1907
|
+
data_list = []
|
1877
1908
|
for i, (group_name, files) in enumerate(groups.items()):
|
1878
1909
|
query_prefix = groups_info.get(group_name, {}).get("query_prefix", "")
|
1879
1910
|
is_active = ("✓" if group_name in memory["current_files"]["current_groups"] else "")
|
1880
|
-
|
1911
|
+
data_list.append([
|
1881
1912
|
group_name,
|
1882
1913
|
"\n".join([os.path.relpath(f, project_root) for f in files]),
|
1883
1914
|
query_prefix,
|
1884
|
-
is_active
|
1885
|
-
|
1886
|
-
|
1887
|
-
|
1915
|
+
is_active
|
1916
|
+
])
|
1917
|
+
printer.print_table_compact(
|
1918
|
+
data=data_list,
|
1919
|
+
title="已定义文件组",
|
1920
|
+
headers=["Group Name", "Files", "Query Prefix", "Active"]
|
1921
|
+
)
|
1888
1922
|
# 重置活动组
|
1889
1923
|
elif len(add_files_args) >= 2 and add_files_args[1] == "/reset":
|
1890
1924
|
memory["current_files"]["current_groups"] = []
|
1891
|
-
|
1892
|
-
|
1893
|
-
|
1894
|
-
title="活动组重置",
|
1895
|
-
border_style="green",
|
1896
|
-
)
|
1925
|
+
printer.print_panel(
|
1926
|
+
Text("活动组名称已重置。如果你想清除活动文件,可使用命令 /remove_files /all .", style="green"),
|
1927
|
+
title="活动组重置", center=True
|
1897
1928
|
)
|
1898
1929
|
# 新增组
|
1899
1930
|
elif len(add_files_args) >= 3 and add_files_args[1] == "/add":
|
1900
1931
|
group_name = add_files_args[2]
|
1901
1932
|
groups[group_name] = memory["current_files"]["files"].copy()
|
1902
|
-
|
1903
|
-
|
1904
|
-
f"已将当前文件添加到组 '{group_name}' .",
|
1905
|
-
title="新增组",
|
1906
|
-
border_style="green",
|
1907
|
-
)
|
1933
|
+
printer.print_panel(
|
1934
|
+
Text(f"已将当前文件添加到组 '{group_name}' .", style="green"), title="新增组", center=True
|
1908
1935
|
)
|
1909
1936
|
# 删除组
|
1910
1937
|
elif len(add_files_args) >= 3 and add_files_args[1] == "/drop":
|
@@ -1915,20 +1942,12 @@ def add_files(add_files_args: List[str]):
|
|
1915
1942
|
del memory["current_files"]["groups_info"][group_name]
|
1916
1943
|
if group_name in memory["current_files"]["current_groups"]:
|
1917
1944
|
memory["current_files"]["current_groups"].remove(group_name)
|
1918
|
-
|
1919
|
-
|
1920
|
-
f"已删除组 '{group_name}'.",
|
1921
|
-
title="删除组",
|
1922
|
-
border_style="green",
|
1923
|
-
)
|
1945
|
+
printer.print_panel(
|
1946
|
+
Text(f"已删除组 '{group_name}'.", style="green"), title="删除组", center=True
|
1924
1947
|
)
|
1925
1948
|
else:
|
1926
|
-
|
1927
|
-
|
1928
|
-
f"组 '{group_name}' 未找到.",
|
1929
|
-
title="Error",
|
1930
|
-
border_style="red",
|
1931
|
-
)
|
1949
|
+
printer.print_panel(
|
1950
|
+
Text(f"组 '{group_name}' 未找到.", style="red"), title="Error", center=True
|
1932
1951
|
)
|
1933
1952
|
# 支持多个组的合并,允许组名之间使用逗号或空格分隔
|
1934
1953
|
elif len(add_files_args) >= 2:
|
@@ -1941,54 +1960,29 @@ def add_files(add_files_args: List[str]):
|
|
1941
1960
|
else:
|
1942
1961
|
missing_groups.append(group_name)
|
1943
1962
|
if missing_groups:
|
1944
|
-
|
1945
|
-
|
1946
|
-
f"未找到组: {', '.join(missing_groups)}",
|
1947
|
-
title="Error",
|
1948
|
-
border_style="red",
|
1949
|
-
)
|
1963
|
+
printer.print_panel(
|
1964
|
+
Text(f"未找到组: {', '.join(missing_groups)}", style="red"), title="Error", center=True
|
1950
1965
|
)
|
1951
1966
|
if merged_files:
|
1952
1967
|
memory["current_files"]["files"] = list(merged_files)
|
1953
1968
|
memory["current_files"]["current_groups"] = [
|
1954
1969
|
name for name in group_names if name in groups
|
1955
1970
|
]
|
1956
|
-
|
1957
|
-
|
1958
|
-
f"合并来自组 {', '.join(group_names)} 的文件 .",
|
1959
|
-
title="文件合并",
|
1960
|
-
border_style="green",
|
1961
|
-
)
|
1971
|
+
printer.print_panel(
|
1972
|
+
Text(f"合并来自组 {', '.join(group_names)} 的文件 .", style="green"), title="文件合并", center=True
|
1962
1973
|
)
|
1963
|
-
|
1974
|
+
printer.print_table_compact(
|
1975
|
+
data=[[os.path.relpath(f, project_root)] for f in memory["current_files"]["files"]],
|
1964
1976
|
title="当前文件",
|
1965
|
-
|
1966
|
-
header_style="bold magenta",
|
1967
|
-
show_lines=True, # 这会在每行之间添加分割线
|
1977
|
+
headers=["File"]
|
1968
1978
|
)
|
1969
|
-
|
1970
|
-
|
1971
|
-
|
1972
|
-
os.path.relpath(f, project_root),
|
1973
|
-
end_section=(
|
1974
|
-
i == len(memory["current_files"]["files"]) - 1
|
1975
|
-
), # 在最后一行之后不添加分割线
|
1976
|
-
)
|
1977
|
-
console.print(Panel(table, border_style="blue"))
|
1978
|
-
console.print(
|
1979
|
-
Panel(
|
1980
|
-
f"当前组: {', '.join(memory['current_files']['current_groups'])}",
|
1981
|
-
title="当前组",
|
1982
|
-
border_style="green",
|
1983
|
-
)
|
1979
|
+
printer.print_panel(
|
1980
|
+
Text(f"当前组: {', '.join(memory['current_files']['current_groups'])}", style="green"),
|
1981
|
+
title="当前组", center=True
|
1984
1982
|
)
|
1985
1983
|
elif not missing_groups:
|
1986
|
-
|
1987
|
-
|
1988
|
-
"指定组中没有文件.",
|
1989
|
-
title="未添加任何文件",
|
1990
|
-
border_style="yellow",
|
1991
|
-
)
|
1984
|
+
printer.print_panel(
|
1985
|
+
Text(f"指定组中没有文件.", style="yellow"), title="未添加任何文件", center=True
|
1992
1986
|
)
|
1993
1987
|
|
1994
1988
|
else:
|
@@ -1998,26 +1992,14 @@ def add_files(add_files_args: List[str]):
|
|
1998
1992
|
files_to_add = [f for f in matched_files if f not in existing_files]
|
1999
1993
|
if files_to_add:
|
2000
1994
|
memory["current_files"]["files"].extend(files_to_add)
|
2001
|
-
|
1995
|
+
printer.print_table_compact(
|
1996
|
+
data=[[os.path.relpath(f, project_root)] for f in files_to_add],
|
2002
1997
|
title="新增文件",
|
2003
|
-
|
2004
|
-
header_style="bold magenta",
|
2005
|
-
show_lines=True, # 这会在每行之间添加分割线
|
1998
|
+
headers=["文件"]
|
2006
1999
|
)
|
2007
|
-
table.add_column("File", style="green")
|
2008
|
-
for i, f in enumerate(files_to_add):
|
2009
|
-
table.add_row(
|
2010
|
-
os.path.relpath(f, project_root),
|
2011
|
-
end_section=(i == len(files_to_add) - 1), # 在最后一行之后不添加分割线
|
2012
|
-
)
|
2013
|
-
console.print(Panel(table, border_style="green"))
|
2014
2000
|
else:
|
2015
|
-
|
2016
|
-
|
2017
|
-
"所有指定文件已存在于当前会话中,或者未找到匹配的文件.",
|
2018
|
-
title="未新增文件",
|
2019
|
-
border_style="yellow",
|
2020
|
-
)
|
2001
|
+
printer.print_panel(
|
2002
|
+
Text(f"所有指定文件已存在于当前会话中,或者未找到匹配的文件.", style="yellow"), title="未新增文件", center=True
|
2021
2003
|
)
|
2022
2004
|
|
2023
2005
|
completer.update_current_files(memory["current_files"]["files"])
|
@@ -2028,7 +2010,7 @@ def remove_files(file_names: List[str]):
|
|
2028
2010
|
if "/all" in file_names:
|
2029
2011
|
memory["current_files"]["files"] = []
|
2030
2012
|
memory["current_files"]["current_groups"] = []
|
2031
|
-
|
2013
|
+
printer.print_panel("已移除所有文件", title="文件移除", center=True)
|
2032
2014
|
else:
|
2033
2015
|
removed_files = []
|
2034
2016
|
for file in memory["current_files"]["files"]:
|
@@ -2040,13 +2022,13 @@ def remove_files(file_names: List[str]):
|
|
2040
2022
|
memory["current_files"]["files"].remove(file)
|
2041
2023
|
|
2042
2024
|
if removed_files:
|
2043
|
-
|
2044
|
-
|
2045
|
-
|
2046
|
-
|
2047
|
-
|
2025
|
+
printer.print_table_compact(
|
2026
|
+
data=[[os.path.relpath(f, project_root)] for f in removed_files],
|
2027
|
+
title="文件移除",
|
2028
|
+
headers=["File"]
|
2029
|
+
)
|
2048
2030
|
else:
|
2049
|
-
|
2031
|
+
printer.print_panel("未移除任何文件", title="未移除文件", border_style="dim yellow", center=True)
|
2050
2032
|
completer.update_current_files(memory["current_files"]["files"])
|
2051
2033
|
save_memory()
|
2052
2034
|
|
@@ -2055,21 +2037,17 @@ def list_files():
|
|
2055
2037
|
current_files = memory["current_files"]["files"]
|
2056
2038
|
|
2057
2039
|
if current_files:
|
2058
|
-
|
2059
|
-
|
2040
|
+
printer.print_table_compact(
|
2041
|
+
data=[[os.path.relpath(file, project_root)] for file in current_files],
|
2042
|
+
title="当前活跃文件",
|
2043
|
+
headers=["File"]
|
2060
2044
|
)
|
2061
|
-
table.add_column("File", style="green")
|
2062
|
-
for file in current_files:
|
2063
|
-
table.add_row(os.path.relpath(file, project_root))
|
2064
|
-
console.print(Panel(table, border_style="blue"))
|
2065
2045
|
else:
|
2066
|
-
|
2046
|
+
printer.print_panel("当前会话中无文件。", title="当前文件", center=True)
|
2067
2047
|
|
2068
2048
|
|
2069
2049
|
def print_conf(content: Dict[str, Any]):
|
2070
|
-
|
2071
|
-
table.add_column("键", style="cyan", justify="right", width=30, no_wrap=True)
|
2072
|
-
table.add_column("值", style="green", justify="left", width=50, no_wrap=True)
|
2050
|
+
data_list = []
|
2073
2051
|
for key in sorted(content.keys()):
|
2074
2052
|
value = content[key]
|
2075
2053
|
# Format value based on type
|
@@ -2081,31 +2059,32 @@ def print_conf(content: Dict[str, Any]):
|
|
2081
2059
|
formatted_value = Text(str(value), style="bright_cyan")
|
2082
2060
|
else:
|
2083
2061
|
formatted_value = Text(str(value), style="green")
|
2084
|
-
|
2085
|
-
|
2062
|
+
data_list.append([str(key), formatted_value])
|
2063
|
+
printer.print_table_compact(
|
2064
|
+
data=data_list,
|
2065
|
+
title="Conf 配置",
|
2066
|
+
headers=["键", "值"],
|
2067
|
+
caption="使用 /conf <key>:<value> 修改这些设置"
|
2068
|
+
)
|
2086
2069
|
|
2087
2070
|
|
2088
2071
|
def print_models(content: Dict[str, Any]):
|
2089
|
-
|
2090
|
-
table.add_column("Name", style="cyan", width=40, no_wrap=False)
|
2091
|
-
table.add_column("Model Name", style="magenta", width=30, overflow="fold")
|
2092
|
-
table.add_column("Base URL", style="white", width=50, overflow="fold")
|
2072
|
+
data_list = []
|
2093
2073
|
if content:
|
2094
2074
|
for name in content:
|
2095
|
-
|
2096
|
-
name,
|
2097
|
-
content[name].get("model", ""),
|
2098
|
-
content[name].get("base_url", "")
|
2099
|
-
)
|
2075
|
+
data_list.append([name, content[name].get("model", ""), content[name].get("base_url", "")])
|
2100
2076
|
else:
|
2101
|
-
|
2102
|
-
|
2077
|
+
data_list.append(["", "", ""])
|
2078
|
+
printer.print_table_compact(
|
2079
|
+
headers=["Name", "Model Name", "Base URL"],
|
2080
|
+
title="模型列表",
|
2081
|
+
data=data_list,
|
2082
|
+
show_lines=True,
|
2083
|
+
expand=True
|
2084
|
+
)
|
2103
2085
|
|
2104
2086
|
|
2105
2087
|
def check_models(content: Dict[str, Any], llm: AutoLLM):
|
2106
|
-
|
2107
|
-
status_info = {}
|
2108
|
-
|
2109
2088
|
def _check_single_llm(model):
|
2110
2089
|
_start_time = time.monotonic()
|
2111
2090
|
try:
|
@@ -2119,25 +2098,21 @@ def check_models(content: Dict[str, Any], llm: AutoLLM):
|
|
2119
2098
|
except Exception as e:
|
2120
2099
|
return False, str(e)
|
2121
2100
|
|
2122
|
-
|
2123
|
-
table.add_column("模型", style="cyan")
|
2124
|
-
table.add_column("状态", justify="center")
|
2125
|
-
table.add_column("延迟", justify="right", style="green")
|
2101
|
+
data_list = []
|
2126
2102
|
if content:
|
2127
2103
|
for name in content:
|
2128
|
-
logger.info(f"正在测试 {name} 模型")
|
2129
2104
|
attempt_ok, attempt_latency = _check_single_llm(name)
|
2130
2105
|
if attempt_ok:
|
2131
|
-
|
2132
|
-
name, Text("✓", style="green"), f"{attempt_latency:.2f}s"
|
2133
|
-
)
|
2106
|
+
data_list.append([name, Text("✓", style="green"), f"{attempt_latency:.2f}s"])
|
2134
2107
|
else:
|
2135
|
-
|
2136
|
-
"✗", Text("✓", style="red"), "-"
|
2137
|
-
)
|
2108
|
+
data_list.append([name, Text("✗", style="red"), "-"])
|
2138
2109
|
else:
|
2139
|
-
|
2140
|
-
|
2110
|
+
data_list.append(["", "", ""])
|
2111
|
+
printer.print_table_compact(
|
2112
|
+
headers=["模型名称", "状态", "延迟情况"],
|
2113
|
+
title="模型状态检测",
|
2114
|
+
data=data_list
|
2115
|
+
)
|
2141
2116
|
|
2142
2117
|
|
2143
2118
|
def manage_models(models_args, models_data, llm: AutoLLM):
|
@@ -2155,30 +2130,30 @@ def manage_models(models_args, models_data, llm: AutoLLM):
|
|
2155
2130
|
elif models_args[0] == "/add_model":
|
2156
2131
|
add_model_args = models_args[1:]
|
2157
2132
|
add_model_info = {item.split('=')[0]: item.split('=')[1] for item in add_model_args if item}
|
2158
|
-
|
2159
|
-
|
2160
|
-
if
|
2161
|
-
memory["models"][
|
2133
|
+
mn = add_model_info["name"]
|
2134
|
+
printer.print_text(f"正在为 {mn} 更新缓存信息", style="green")
|
2135
|
+
if mn not in memory["models"]:
|
2136
|
+
memory["models"][mn] = {
|
2162
2137
|
"base_url": add_model_info["base_url"],
|
2163
2138
|
"api_key": add_model_info["api_key"],
|
2164
2139
|
"model": add_model_info["model"]
|
2165
2140
|
}
|
2166
2141
|
else:
|
2167
|
-
|
2168
|
-
|
2169
|
-
llm.setup_sub_client(
|
2142
|
+
printer.print_text(f"{mn} 已经存在, 请执行 /models /remove <name> 进行删除", style="red")
|
2143
|
+
printer.print_text(f"正在部署 {mn} 模型", style="green")
|
2144
|
+
llm.setup_sub_client(mn, add_model_info["api_key"], add_model_info["base_url"], add_model_info["model"])
|
2170
2145
|
elif models_args[0] == "/remove":
|
2171
|
-
|
2172
|
-
|
2173
|
-
if
|
2174
|
-
del memory["models"][
|
2175
|
-
|
2176
|
-
if llm.get_sub_client(
|
2177
|
-
llm.remove_sub_client(
|
2178
|
-
if
|
2179
|
-
|
2180
|
-
if
|
2181
|
-
|
2146
|
+
rmn = models_args[1]
|
2147
|
+
printer.print_text(f"正在清理 {rmn} 缓存信息", style="green")
|
2148
|
+
if rmn in memory["models"]:
|
2149
|
+
del memory["models"][rmn]
|
2150
|
+
printer.print_text(f"正在卸载 {rmn} 模型", style="green")
|
2151
|
+
if llm.get_sub_client(rmn):
|
2152
|
+
llm.remove_sub_client(rmn)
|
2153
|
+
if rmn == memory["conf"]["chat_model"]:
|
2154
|
+
printer.print_text(f"当前首选Chat模型 {rmn} 已被删除, 请立即 /conf chat_model: 调整", style="yellow")
|
2155
|
+
if rmn == memory["conf"]["code_model"]:
|
2156
|
+
printer.print_text(f"当前首选Code模型 {rmn} 已被删除, 请立即 /conf code_model: 调整", style="yellow")
|
2182
2157
|
|
2183
2158
|
|
2184
2159
|
def configure_project_model():
|
@@ -2229,7 +2204,7 @@ def configure_project_model():
|
|
2229
2204
|
model_num = input(f" 请选择您想使用的模型供应商编号(1-6): ").strip().lower()
|
2230
2205
|
|
2231
2206
|
if int(model_num) < 1 or int(model_num) > 7:
|
2232
|
-
|
2207
|
+
printer.print_text("请选择 1-7", style="red")
|
2233
2208
|
exit(1)
|
2234
2209
|
|
2235
2210
|
if model_num == "7":
|
@@ -2309,7 +2284,7 @@ def is_old_version():
|
|
2309
2284
|
不再使用 current_chat_model 和 current_chat_model
|
2310
2285
|
"""
|
2311
2286
|
if 'current_chat_model' in memory['conf'] and 'current_code_model' in memory['conf']:
|
2312
|
-
|
2287
|
+
printer.print_text(f"您当前使用的版本偏低 {__version__}, 正在进行配置兼容性处理", style="yellow")
|
2313
2288
|
memory['conf']['chat_model'] = memory['conf']['current_chat_model']
|
2314
2289
|
memory['conf']['code_model'] = memory['conf']['current_code_model']
|
2315
2290
|
del memory['conf']['current_chat_model']
|
@@ -2331,30 +2306,30 @@ def main():
|
|
2331
2306
|
_model_pass = input(f" 是否跳过模型配置(y/n): ").strip().lower()
|
2332
2307
|
if _model_pass == "n":
|
2333
2308
|
m1, m2, m3, m4 = configure_project_model()
|
2334
|
-
|
2309
|
+
printer.print_text("正在更新缓存...", style="yellow")
|
2335
2310
|
memory["conf"]["chat_model"] = m1
|
2336
2311
|
memory["conf"]["code_model"] = m1
|
2337
2312
|
memory["models"][m1] = {"base_url": m3, "api_key": m4, "model": m2}
|
2338
|
-
|
2313
|
+
printer.print_text(f"供应商配置已成功完成!后续你可以使用 /models 命令, 查看, 新增和修改所有模型", style="green")
|
2339
2314
|
else:
|
2340
|
-
|
2341
|
-
|
2315
|
+
printer.print_text("你已跳过模型配置,后续请使用 /models /add_model 添加模型...", style="yellow")
|
2316
|
+
printer.print_text("添加示例 /models /add_model name=& base_url=& api_key=& model=&", style="yellow")
|
2342
2317
|
|
2343
2318
|
auto_llm = AutoLLM() # 创建模型
|
2344
2319
|
if len(memory["models"]) > 0:
|
2345
2320
|
for _model_name in memory["models"]:
|
2346
|
-
|
2321
|
+
printer.print_text(f"正在部署 {_model_name} 模型...", style="green")
|
2347
2322
|
auto_llm.setup_sub_client(_model_name,
|
2348
2323
|
memory["models"][_model_name]["api_key"],
|
2349
2324
|
memory["models"][_model_name]["base_url"],
|
2350
2325
|
memory["models"][_model_name]["model"])
|
2351
2326
|
|
2352
|
-
|
2327
|
+
printer.print_text("初始化完成.", style="green")
|
2353
2328
|
|
2354
2329
|
if memory["conf"]["chat_model"] not in memory["models"].keys():
|
2355
|
-
|
2330
|
+
printer.print_text("首选 Chat 模型与部署模型不一致, 请使用 /conf chat_model:& 设置", style="red")
|
2356
2331
|
if memory["conf"]["code_model"] not in memory["models"].keys():
|
2357
|
-
|
2332
|
+
printer.print_text("首选 Code 模型与部署模型不一致, 请使用 /conf code_model:& 设置", style="red")
|
2358
2333
|
|
2359
2334
|
MODES = {
|
2360
2335
|
"normal": "正常模式",
|
@@ -2402,9 +2377,13 @@ def main():
|
|
2402
2377
|
key_bindings=kb,
|
2403
2378
|
bottom_toolbar=get_bottom_toolbar,
|
2404
2379
|
)
|
2405
|
-
|
2406
|
-
|
2407
|
-
|
2380
|
+
printer.print_key_value(
|
2381
|
+
{
|
2382
|
+
"AutoCoder Nano": f"v{__version__}",
|
2383
|
+
"Url": "https://github.com/w4n9H/autocoder-nano",
|
2384
|
+
"Help": "输入 /help 可以查看可用的命令."
|
2385
|
+
}
|
2386
|
+
)
|
2408
2387
|
|
2409
2388
|
style = Style.from_dict(
|
2410
2389
|
{
|
@@ -2509,6 +2488,12 @@ def main():
|
|
2509
2488
|
print(f"{memory['mode']} [{MODES[memory['mode']]}]")
|
2510
2489
|
else:
|
2511
2490
|
memory["mode"] = conf
|
2491
|
+
elif user_input.startswith("/exclude_dirs"):
|
2492
|
+
dir_names = user_input[len("/exclude_dirs"):].strip().split(",")
|
2493
|
+
exclude_dirs(dir_names)
|
2494
|
+
elif user_input.startswith("/exclude_files"):
|
2495
|
+
query = user_input[len("/exclude_files"):].strip()
|
2496
|
+
exclude_files(query)
|
2512
2497
|
else:
|
2513
2498
|
command = user_input
|
2514
2499
|
if user_input.startswith("/shell"):
|