auto-coder 0.1.242__py3-none-any.whl → 0.1.244__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.

Potentially problematic release.


This version of auto-coder might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: auto-coder
3
- Version: 0.1.242
3
+ Version: 0.1.244
4
4
  Summary: AutoCoder: AutoCoder
5
5
  Author: allwefantasy
6
6
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
@@ -26,7 +26,7 @@ Requires-Dist: tabulate
26
26
  Requires-Dist: jupyter-client
27
27
  Requires-Dist: prompt-toolkit
28
28
  Requires-Dist: tokenizers
29
- Requires-Dist: byzerllm[saas] >=0.1.158
29
+ Requires-Dist: byzerllm[saas] >=0.1.160
30
30
  Requires-Dist: patch
31
31
  Requires-Dist: diff-match-patch
32
32
  Requires-Dist: GitPython
@@ -1,17 +1,17 @@
1
1
  autocoder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- autocoder/auto_coder.py,sha256=jbfgZoO9EguLjFifzl0Ea4QHiRh75WMoZ5LBEfhLHMs,61858
2
+ autocoder/auto_coder.py,sha256=ghIEJ8NzcFr77fosIZhKxI5F55EZoU6DMHFFpw5OFso,62671
3
3
  autocoder/auto_coder_lang.py,sha256=Rtupq6N3_HT7JRhDKdgCBcwRaiAnyCOR_Gsp4jUomrI,3229
4
4
  autocoder/auto_coder_rag.py,sha256=illKgzP2bv-Tq50ujsofJnOHdI4pzr0ALtfR8NHHWdQ,22351
5
5
  autocoder/auto_coder_rag_client_mcp.py,sha256=WV7j5JUiQge0x4-B7Hp5-pSAFXLbvLpzQMcCovbauIM,6276
6
6
  autocoder/auto_coder_rag_mcp.py,sha256=-RrjNwFaS2e5v8XDIrKR-zlUNUE8UBaeOtojffBrvJo,8521
7
7
  autocoder/auto_coder_server.py,sha256=XU9b4SBH7zjPPXaTWWHV4_zJm-XYa6njuLQaplYJH_c,20290
8
8
  autocoder/benchmark.py,sha256=Ypomkdzd1T3GE6dRICY3Hj547dZ6_inqJbBJIp5QMco,4423
9
- autocoder/chat_auto_coder.py,sha256=z4EPTD2fSR72BbzY0HjKm8mp-EJELXyp0C_dQCBUiTU,103431
10
- autocoder/chat_auto_coder_lang.py,sha256=rS6hD5ZiNLaQZx36WO4LohRBEN8uZfsgv3QEM7ax03A,14540
9
+ autocoder/chat_auto_coder.py,sha256=RJC3Fh_9ywkllETWFgxapHK3aY0M9ORhRON9PNCiKZs,105338
10
+ autocoder/chat_auto_coder_lang.py,sha256=pdGkEMR96TvjYIzgWWB51LYmBYSrS_pO3sjGH-muuDI,15052
11
11
  autocoder/command_args.py,sha256=9aYJ-AmPxP1sQh6ciw04FWHjSn31f2W9afXFwo8wgx4,30441
12
12
  autocoder/lang.py,sha256=U6AjVV8Rs1uLyjFCZ8sT6WWuNUxMBqkXXIOs4S120uk,14511
13
- autocoder/models.py,sha256=FlBrF6HhGao_RiCSgYhCmP7vs0KlG4hI_BI6dyZiL9s,5292
14
- autocoder/version.py,sha256=FFFI0ll8Bfzd8j7JSYymsgRmF-NwiONXrIeZWd_8lvQ,23
13
+ autocoder/models.py,sha256=8Tabnz3wlVswaeTpfPxnBhN55enP_5sdAJIx4Z79nOo,5342
14
+ autocoder/version.py,sha256=nyjL74IBCp8tNAtI88ddAEba5PkcN70aC5Kdv_PKe7w,23
15
15
  autocoder/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  autocoder/agent/auto_demand_organizer.py,sha256=NWSAEsEk94vT3lGjfo25kKLMwYdPcpy9e-i21txPasQ,6942
17
17
  autocoder/agent/auto_filegroup.py,sha256=CW7bqp0FW1GIEMnl-blyAc2UGT7O9Mom0q66ITz1ckM,6635
@@ -24,11 +24,11 @@ autocoder/agent/project_reader.py,sha256=tWLaPoLw1gI6kO_NzivQj28KbobU2ceOLuppHMb
24
24
  autocoder/chat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
25
  autocoder/common/JupyterClient.py,sha256=O-wi6pXeAEYhAY24kDa0BINrLYvKS6rKyWe98pDClS0,2816
26
26
  autocoder/common/ShellClient.py,sha256=fM1q8t_XMSbLBl2zkCNC2J9xuyKN3eXzGm6hHhqL2WY,2286
27
- autocoder/common/__init__.py,sha256=vpfo3RctksezDoraVSpHtfnxpspVNiYh8OmQhqQvcfE,11729
27
+ autocoder/common/__init__.py,sha256=2isE_u4VgfogwmcUCnFcussVFlzeNOLHDMFm5z_axbU,11774
28
28
  autocoder/common/anything2images.py,sha256=0ILBbWzY02M-CiWB-vzuomb_J1hVdxRcenAfIrAXq9M,25283
29
29
  autocoder/common/anything2img.py,sha256=4TREa-sOA-iargieUy7MpyCYVUE-9Mmq0wJtwomPqnE,7662
30
30
  autocoder/common/audio.py,sha256=Kn9nWKQddWnUrAz0a_ZUgjcu4VUU_IcZBigT7n3N3qc,7439
31
- autocoder/common/auto_coder_lang.py,sha256=Bs_jxhVcmvVnTGD2pNsS7r46i39ZPGT62fErfaC33EE,11850
31
+ autocoder/common/auto_coder_lang.py,sha256=rIr4WJCUHgwkUkGwAaAiEd5kNx1nYRvVArbISbCfXp0,13248
32
32
  autocoder/common/buildin_tokenizer.py,sha256=L7d5t39ZFvUd6EoMPXUhYK1toD0FHlRH1jtjKRGokWU,1236
33
33
  autocoder/common/chunk_validation.py,sha256=BrR_ZWavW8IANuueEE7hS8NFAwEvm8TX34WnPx_1hs8,3030
34
34
  autocoder/common/cleaner.py,sha256=NU72i8C6o9m0vXExab7nao5bstBUsfJFcj11cXa9l4U,1089
@@ -39,14 +39,14 @@ autocoder/common/code_auto_generate_editblock.py,sha256=QdUHUkGaervvQNCY8T2vQ_tf
39
39
  autocoder/common/code_auto_generate_strict_diff.py,sha256=uteWDEHfIbrnVgwKgqC7qwrIeW0enJCXcHzZGa48yY8,14774
40
40
  autocoder/common/code_auto_merge.py,sha256=8dtnz61l0B5gNbQmx26TZ4_jD825dsnnWtAFD_zs6es,7335
41
41
  autocoder/common/code_auto_merge_diff.py,sha256=yocfe8s3Pz6hTGDUl9wRIewY3NcTize_gEla64lsGT0,15331
42
- autocoder/common/code_auto_merge_editblock.py,sha256=B-zDKGEJ7uRFPLIasnX7w2I2DXe5UAj1T-rDSjL4xes,17477
42
+ autocoder/common/code_auto_merge_editblock.py,sha256=sp7C0fZJMVcNgI8uWy43CKDk7gGXFTkMB9kbP2VdY8k,17485
43
43
  autocoder/common/code_auto_merge_strict_diff.py,sha256=9rm0NJ_n6M3LohEX7xl1Jym0xmm8UEYqj_ZTSO3oSlM,9519
44
- autocoder/common/code_modification_ranker.py,sha256=7xHrNO4fXmWcrPXTCjZGZhE2FIn0ZnL7nEpZgP6-mq4,6120
44
+ autocoder/common/code_modification_ranker.py,sha256=l0OAR7ad0hTV3xdfn7rO0KqnY5Y5qSG4BmWcClZ9RUQ,6104
45
45
  autocoder/common/command_completer.py,sha256=SSeb8MDH0JPvfdyW-S2uaHnui4VBDfSQvQPLbv3ORPA,9314
46
46
  autocoder/common/command_generator.py,sha256=v4LmU7sO-P7jEZIXCWHUC6P-vT7AvBi_x_PTwCqBAE8,1323
47
47
  autocoder/common/command_templates.py,sha256=mnB3n8i0yjH1mqzyClEg8Wpr9VbZV44kxky66Zu6OJY,8557
48
48
  autocoder/common/const.py,sha256=eTjhjh4Aj4CUzviJ81jaf3Y5cwqsLATySn2wJxaS6RQ,2911
49
- autocoder/common/files.py,sha256=uGpfKASYwIncK_Vt_e_FOjFlO5VyAQOnRJe2SFdSWrg,877
49
+ autocoder/common/files.py,sha256=CguxG9digkWBJpRaILErZmL_G5ryPRahPmPFWGB7X18,1973
50
50
  autocoder/common/git_utils.py,sha256=btK45sxvfm4tX3fBRNUPRZoGQuZuOEQrWSAwLy1yoLw,23095
51
51
  autocoder/common/image_to_page.py,sha256=O0cNO_vHHUP-fP4GXiVojShmNqkPnZXeIyiY1MRLpKg,13936
52
52
  autocoder/common/interpreter.py,sha256=62-dIakOunYB4yjmX8SHC0Gdy2h8NtxdgbpdqRZJ5vk,2833
@@ -55,7 +55,7 @@ autocoder/common/mcp_hub.py,sha256=2ZyJv3Aiv4Y97UHut49oYhIFcu7ICR-mptDEBSgT3uE,1
55
55
  autocoder/common/mcp_server.py,sha256=QCFa-15kx7rbNsinwdGFFX2y47pww0fVdI-ldKFSSWI,12267
56
56
  autocoder/common/mcp_tools.py,sha256=KsLvRrB6pvmebqd-lDaSH6IBJR0AIxWRE-dtCEG_w9k,12485
57
57
  autocoder/common/memory_manager.py,sha256=2ZjYG7BPyvbYalZBF6AM_G5e10Qkw_zrqtD4Zd7GSsQ,3663
58
- autocoder/common/printer.py,sha256=h4AK7e_y8wlnlUYjckcv1qr4vBXRPBWXumlQN0izJ0I,1906
58
+ autocoder/common/printer.py,sha256=TIqgGOq5YdWqH4_776QHwHmwfVpubZ9zzUq8rstNxuM,1911
59
59
  autocoder/common/recall_validation.py,sha256=Avt9Q9dX3kG6Pf2zsdlOHmsjd-OeSj7U1PFBDp_Cve0,1700
60
60
  autocoder/common/screenshots.py,sha256=_gA-z1HxGjPShBrtgkdideq58MG6rqFB2qMUJKjrycs,3769
61
61
  autocoder/common/search.py,sha256=245iPFgWhMldoUK3CqCP89ltaxZiNPK73evoG6Fp1h8,16518
@@ -63,7 +63,7 @@ autocoder/common/search_replace.py,sha256=GphFkc57Hb673CAwmbiocqTbw8vrV7TrZxtOhD
63
63
  autocoder/common/sys_prompt.py,sha256=JlexfjZt554faqbgkCmzOJqYUzDHfbnxly5ugFfHfEE,26403
64
64
  autocoder/common/text.py,sha256=KGRQq314GHBmY4MWG8ossRoQi1_DTotvhxchpn78c-k,1003
65
65
  autocoder/common/types.py,sha256=PXTETrsTvhLE49jqAeUKGySvxBN9pjeyCgRHLDYdd9U,664
66
- autocoder/common/utils_code_auto_generate.py,sha256=QwJYr6QhjlQbSo231IWuI6c8G0kXkYDDoDHMo5NSXqI,3348
66
+ autocoder/common/utils_code_auto_generate.py,sha256=kDW5B_2wRLk7hAls2hewliDacV86lrPz8Jan01BvtCw,3573
67
67
  autocoder/common/mcp_servers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
68
68
  autocoder/common/mcp_servers/mcp_server_perplexity.py,sha256=jz0LkCgZcqKkNdLZ9swNOu9Besoba4JOyHDedoZnWHo,5546
69
69
  autocoder/data/tokenizer.json,sha256=QfO_ZCE9qMAS2L0IcaWKH99wRj6PCPEQ3bsQgvUp9mk,4607451
@@ -79,7 +79,7 @@ autocoder/dispacher/actions/plugins/action_translate.py,sha256=nVAtRSQpdGNmZxg1R
79
79
  autocoder/index/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
80
80
  autocoder/index/entry.py,sha256=KJaxqtaKgL27w8-j7OiAqI0anPpmrJSl7PkfeVF2ipE,11713
81
81
  autocoder/index/for_command.py,sha256=BFvljE4t6VaMBGboZAuhUCzVK0EitCy_n5D_7FEnihw,3204
82
- autocoder/index/index.py,sha256=8AcaELR1FS___7VlNyxPnJsDVQ4wjORbqXvcA6TifCE,20337
82
+ autocoder/index/index.py,sha256=VjfcBYHywU4tjQTA7mpHfzRM8nBPhPHrUnkuBbsj6do,20409
83
83
  autocoder/index/symbols_utils.py,sha256=CjcjUVajmJZB75Ty3a7kMv1BZphrm-tIBAdOJv6uo-0,2037
84
84
  autocoder/index/types.py,sha256=a2s_KV5FJlq7jqA2ELSo9E1sjuLwDB-JJYMhSpzBAhU,596
85
85
  autocoder/index/filter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -119,7 +119,7 @@ autocoder/rag/stream_event/event_writer.py,sha256=l7kq_LnDDE8E5dZ-73C7J2MgzSL7Wr
119
119
  autocoder/rag/stream_event/types.py,sha256=rtLwOE8rShmi1dJdxyBpAV5ZjLBGG9vptMiSzMxGuIA,318
120
120
  autocoder/regex_project/__init__.py,sha256=EBZeCL5ORyD_9_5u_UuG4s7XtpXOu0y1sWDmxWFtufE,6781
121
121
  autocoder/regexproject/__init__.py,sha256=cEr-ZOaQjLD5sx7T7F2DhD5ips03HcJ02rded9EpSXc,9693
122
- autocoder/suffixproject/__init__.py,sha256=cmP54Y01ditZ83tiJqw5wle0I-uJBC0aZbZ7lYNSVO8,11080
122
+ autocoder/suffixproject/__init__.py,sha256=VcXjUbGf3uQrpoqVCItDvGG9DoeHJ_qEmghKwrVNw9w,11058
123
123
  autocoder/tsproject/__init__.py,sha256=yloVzkGLnbTd4Hcj9fMO-rcjNTTx4wI3Ga41LWOSYrY,11747
124
124
  autocoder/utils/__init__.py,sha256=KtcGElFNBgZPF7dEL8zF9JpXkCAjoyDrzaREJBhJrcs,994
125
125
  autocoder/utils/_markitdown.py,sha256=RU88qn4eZfYIy0GDrPxlI8oYXIypbi63VRJjdlnE0VU,47431
@@ -134,15 +134,15 @@ autocoder/utils/print_table.py,sha256=ZMRhCA9DD0FUfKyJBWd5bDdj1RrtPtgOMWSJwtvZcL
134
134
  autocoder/utils/queue_communicate.py,sha256=buyEzdvab1QA4i2QKbq35rG5v_9x9PWVLWWMTznWcYM,6832
135
135
  autocoder/utils/request_event_queue.py,sha256=r3lo5qGsB1dIjzVQ05dnr0z_9Z3zOkBdP1vmRciKdi4,2095
136
136
  autocoder/utils/request_queue.py,sha256=nwp6PMtgTCiuwJI24p8OLNZjUiprC-TsefQrhMI-yPE,3889
137
- autocoder/utils/rest.py,sha256=opE_kBEdNQdxh350M5lUTMk5TViRfpuKP_qWc0B1lks,8861
137
+ autocoder/utils/rest.py,sha256=hLBhr78y-WVnV0oQf9Rxc22EwqF78KINkScvYa1MuYA,6435
138
138
  autocoder/utils/tests.py,sha256=BqphrwyycGAvs-5mhH8pKtMZdObwhFtJ5MC_ZAOiLq8,1340
139
139
  autocoder/utils/types.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
140
140
  autocoder/utils/auto_coder_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
141
- autocoder/utils/auto_coder_utils/chat_stream_out.py,sha256=6D_SIa5hHSwIHC1poO_ztK7IVugAqNHu-jQySd7EnfQ,4181
141
+ autocoder/utils/auto_coder_utils/chat_stream_out.py,sha256=yzh3QYJdYC1CPcdhSTn0fmFHtqV8iSXeH0drV3HjN5A,9053
142
142
  autocoder/utils/chat_auto_coder_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
143
- auto_coder-0.1.242.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
144
- auto_coder-0.1.242.dist-info/METADATA,sha256=FWP2bnOYAaDc-zY3f72Tcfadcnv8vk_v1p-4cQ2yWPU,2616
145
- auto_coder-0.1.242.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
146
- auto_coder-0.1.242.dist-info/entry_points.txt,sha256=0nzHtHH4pNcM7xq4EBA2toS28Qelrvcbrr59GqD_0Ak,350
147
- auto_coder-0.1.242.dist-info/top_level.txt,sha256=Jqc0_uJSw2GwoFQAa9iJxYns-2mWla-9ok_Y3Gcznjk,10
148
- auto_coder-0.1.242.dist-info/RECORD,,
143
+ auto_coder-0.1.244.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
144
+ auto_coder-0.1.244.dist-info/METADATA,sha256=EVj3424BKEVPU6GAnoHC-NQ4J2VQFT7kVt3ANVby28A,2616
145
+ auto_coder-0.1.244.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
146
+ auto_coder-0.1.244.dist-info/entry_points.txt,sha256=0nzHtHH4pNcM7xq4EBA2toS28Qelrvcbrr59GqD_0Ak,350
147
+ auto_coder-0.1.244.dist-info/top_level.txt,sha256=Jqc0_uJSw2GwoFQAa9iJxYns-2mWla-9ok_Y3Gcznjk,10
148
+ auto_coder-0.1.244.dist-info/RECORD,,
autocoder/auto_coder.py CHANGED
@@ -692,6 +692,23 @@ def main(input_args: Optional[List[str]] = None):
692
692
  )
693
693
  llm.setup_sub_client("vl_model", vl_model)
694
694
 
695
+ if args.index_model:
696
+ model_name = args.index_model.strip()
697
+ model_info = models_module.get_model_by_name(model_name)
698
+ index_model = byzerllm.SimpleByzerLLM(default_model_name=model_name)
699
+ index_model.deploy(
700
+ model_path="",
701
+ pretrained_model_type="saas/openai",
702
+ udf_name=model_name,
703
+ infer_params={
704
+ "saas.base_url": model_info["base_url"],
705
+ "saas.api_key": model_info["api_key"],
706
+ "saas.model": model_info["model_name"],
707
+ "saas.is_reasoning": model_info["is_reasoning"]
708
+ }
709
+ )
710
+ llm.setup_sub_client("index_model", index_model)
711
+
695
712
  if args.sd_model:
696
713
  model_name = args.sd_model.strip()
697
714
  model_info = models_module.get_model_by_name(model_name)
@@ -1112,7 +1129,7 @@ def main(input_args: Optional[List[str]] = None):
1112
1129
  json.dump(chat_history, f, ensure_ascii=False)
1113
1130
  console.print(
1114
1131
  Panel(
1115
- "New session started. Previous chat history has been archived.",
1132
+ get_message("new_session_started"),
1116
1133
  title="Session Status",
1117
1134
  expand=False,
1118
1135
  border_style="green",
@@ -1002,6 +1002,51 @@ def load_memory():
1002
1002
  completer.update_current_files(memory["current_files"]["files"])
1003
1003
 
1004
1004
 
1005
+ def print_conf(content:Dict[str,Any]):
1006
+ """Display configuration dictionary in a Rich table format with enhanced visual styling.
1007
+
1008
+ Args:
1009
+ conf (Dict[str, Any]): Configuration dictionary to display
1010
+ """
1011
+ console = Console()
1012
+
1013
+ # Create a styled table with rounded borders
1014
+ table = Table(
1015
+ show_header=True,
1016
+ header_style="bold magenta",
1017
+ title=get_message("conf_title"),
1018
+ title_style="bold blue",
1019
+ border_style="blue",
1020
+ show_lines=True
1021
+ )
1022
+
1023
+ # Add columns with explicit width and alignment
1024
+ table.add_column(get_message("conf_key"), style="cyan", justify="right", width=30, no_wrap=False)
1025
+ table.add_column(get_message("conf_value"), style="green", justify="left", width=50, no_wrap=False)
1026
+
1027
+ # Sort keys for consistent display
1028
+ for key in sorted(content.keys()):
1029
+ value = content[key]
1030
+ # Format value based on type
1031
+ if isinstance(value, (dict, list)):
1032
+ formatted_value = Text(json.dumps(value, indent=2), style="yellow")
1033
+ elif isinstance(value, bool):
1034
+ formatted_value = Text(str(value), style="bright_green" if value else "red")
1035
+ elif isinstance(value, (int, float)):
1036
+ formatted_value = Text(str(value), style="bright_cyan")
1037
+ else:
1038
+ formatted_value = Text(str(value), style="green")
1039
+
1040
+ table.add_row(str(key), formatted_value)
1041
+
1042
+ # Add padding and print with a panel
1043
+ console.print(Panel(
1044
+ table,
1045
+ padding=(1, 2),
1046
+ subtitle=f"[italic]{get_message('conf_subtitle')}[/italic]",
1047
+ border_style="blue"
1048
+ ))
1049
+
1005
1050
  def revert():
1006
1051
  last_yaml_file = get_last_yaml_file("actions")
1007
1052
  if last_yaml_file:
@@ -1560,8 +1605,8 @@ def code_next(query: str):
1560
1605
  if os.path.exists(temp_yaml):
1561
1606
  os.remove(temp_yaml)
1562
1607
 
1563
- llm = byzerllm.ByzerLLM.from_default_model(
1564
- args.inference_model or args.model)
1608
+ product_mode = conf.get("product_mode", "lite")
1609
+ llm = get_single_llm(args.chat_model or args.model, product_mode=product_mode)
1565
1610
 
1566
1611
  auto_guesser = AutoGuessQuery(
1567
1612
  llm=llm, project_dir=os.getcwd(), skip_diff=True)
@@ -2123,6 +2168,11 @@ def manage_models(params, query: str):
2123
2168
  if "/add" in query:
2124
2169
  subcmd = "/add"
2125
2170
  query = query.replace("/add", "", 1).strip()
2171
+
2172
+ # alias to /add
2173
+ if "/activate" in query:
2174
+ subcmd = "/add"
2175
+ query = query.replace("/activate", "", 1).strip()
2126
2176
 
2127
2177
  if "/remove" in query:
2128
2178
  subcmd = "/remove"
@@ -2141,7 +2191,7 @@ def manage_models(params, query: str):
2141
2191
  )
2142
2192
  table.add_column("Name", style="cyan", width=40, no_wrap=False)
2143
2193
  table.add_column("Model Name", style="magenta", width=30, overflow="fold")
2144
- table.add_column("Description", style="white", width=50, overflow="fold")
2194
+ table.add_column("Base URL", style="white", width=50, overflow="fold")
2145
2195
  for m in models_data:
2146
2196
  # Check if api_key_path exists and file exists
2147
2197
  api_key_path = m.get("api_key_path", "")
@@ -2154,7 +2204,7 @@ def manage_models(params, query: str):
2154
2204
  table.add_row(
2155
2205
  name,
2156
2206
  m.get("model_name", ""),
2157
- m.get("description", "")
2207
+ m.get("base_url", "")
2158
2208
  )
2159
2209
  console.print(table)
2160
2210
  else:
@@ -2366,10 +2416,7 @@ def execute_shell_command(command: str):
2366
2416
  if process.returncode != 0:
2367
2417
  console.print(
2368
2418
  f"[bold red]Command failed with return code {process.returncode}[/bold red]"
2369
- )
2370
- else:
2371
- console.print(
2372
- "[bold green]Command completed successfully[/bold green]")
2419
+ )
2373
2420
 
2374
2421
  except FileNotFoundError:
2375
2422
  console.print(
@@ -2705,7 +2752,7 @@ def main():
2705
2752
  elif user_input.startswith("/conf"):
2706
2753
  conf = user_input[len("/conf"):].strip()
2707
2754
  if not conf:
2708
- print(memory["conf"])
2755
+ print_conf(memory["conf"])
2709
2756
  else:
2710
2757
  configure(conf)
2711
2758
  elif user_input.startswith("/revert"):
@@ -1,4 +1,5 @@
1
1
  import locale
2
+ from byzerllm.utils import format_str_jinja2
2
3
 
3
4
  MESSAGES = {
4
5
  "en": {
@@ -75,6 +76,10 @@ MESSAGES = {
75
76
  "shell_desc": "Execute a shell command",
76
77
  "voice_input_desc": "Convert voice input to text",
77
78
  "mode_desc": "Switch input mode",
79
+ "conf_key": "Key",
80
+ "conf_value": "Value",
81
+ "conf_title": "Configuration Settings",
82
+ "conf_subtitle": "Use /conf <key>:<value> to modify these settings",
78
83
  "lib_desc": "Manage libraries",
79
84
  "exit_desc": "Exit the program",
80
85
  "design_desc": "Generate SVG image based on the provided description",
@@ -187,6 +192,10 @@ MESSAGES = {
187
192
  "design_desc": "根据需求设计SVG图片",
188
193
  "commit_desc": "根据用户人工修改的代码自动生成yaml文件并提交更改",
189
194
  "models_desc": "管理模型配置,仅在lite模式下可用",
195
+ "conf_key": "键",
196
+ "conf_value": "值",
197
+ "conf_title": "配置设置",
198
+ "conf_subtitle": "使用 /conf <key>:<value> 修改这些设置",
190
199
  "models_usage": "用法: /models /list|/add|/add_model|/remove ...",
191
200
  "models_added": "成功添加/更新模型 '{{name}}'。",
192
201
  "models_add_failed": "添加模型 '{{name}}' 失败。在默认模型中未找到该模型。",
@@ -228,3 +237,7 @@ def get_system_language():
228
237
  def get_message(key):
229
238
  lang = get_system_language()
230
239
  return MESSAGES.get(lang, MESSAGES['en']).get(key, MESSAGES['en'][key])
240
+
241
+
242
+ def get_message_with_format(msg_key: str, **kwargs):
243
+ return format_str_jinja2(get_message(msg_key), **kwargs)
@@ -350,6 +350,7 @@ class AutoCoderArgs(pydantic.BaseModel):
350
350
  skip_events: Optional[bool] = False
351
351
  data_cells_max_num: Optional[int] = 2000
352
352
  generate_times_same_model: Optional[int] = 1
353
+ rank_times_same_model: Optional[int] = 1
353
354
 
354
355
  action: List[str] = []
355
356
  enable_global_memory: Optional[bool] = True
@@ -1,8 +1,13 @@
1
1
  import locale
2
+ from byzerllm.utils import format_str_jinja2
2
3
 
3
4
  MESSAGES = {
4
5
  "en": {
6
+ "model_not_found": "Model {{model_name}} not found",
7
+ "new_session_started": "New session started. Previous chat history has been archived.",
5
8
  "memory_save_success": "✅ Saved to your memory",
9
+ "file_decode_error": "Failed to decode file: {{file_path}}. Tried encodings: {{encodings}}",
10
+ "file_write_error": "Failed to write file: {{file_path}}. Error: {{error}}",
6
11
  "index_file_too_large": "⚠️ File {{ file_path }} is too large ({{ file_size }} > {{ max_length }}), splitting into chunks...",
7
12
  "index_update_success": "✅ Successfully updated index for {{ file_path }} (md5: {{ md5 }}) in {{ duration }}s",
8
13
  "index_build_error": "❌ Error building index for {{ file_path }}: {{ error }}",
@@ -63,10 +68,20 @@ MESSAGES = {
63
68
  "ranking_failed": "Ranking failed in {{ elapsed }}s, using original order",
64
69
  "begin_index_source_code": "🚀 Begin to index source code in {{ source_dir }}",
65
70
  "stream_out_stats": "Elapsed time {{ elapsed_time }} seconds, input tokens: {{ input_tokens }}, output tokens: {{ output_tokens }}",
66
- "upsert_file": "✅ Updated file: {{ file_path }}",
71
+ "upsert_file": "✅ Updated file: {{ file_path }}",
72
+ "unmerged_blocks_title": "Unmerged Blocks",
73
+ "unmerged_file_path": "File: {{file_path}}",
74
+ "unmerged_search_block": "Search Block({{similarity}}):",
75
+ "unmerged_replace_block": "Replace Block:",
76
+ "unmerged_blocks_total": "Total unmerged blocks: {{num_blocks}}",
77
+ "git_init_required": "⚠️ auto_merge only applies to git repositories.\n\nPlease try using git init in the source directory:\n\n```shell\ncd {{ source_dir }}\ngit init.\n```\n\nThen run auto - coder again.\nError: {{ error }}"
67
78
  },
68
79
  "zh": {
80
+ "model_not_found": "未找到模型: {{model_name}}",
81
+ "new_session_started": "新会话已开始。之前的聊天历史已存档。",
69
82
  "memory_save_success": "✅ 已保存到您的记忆中",
83
+ "file_decode_error": "无法解码文件: {{file_path}}。尝试的编码: {{encodings}}",
84
+ "file_write_error": "无法写入文件: {{file_path}}. 错误: {{error}}",
70
85
  "index_file_too_large": "⚠️ 文件 {{ file_path }} 过大 ({{ file_size }} > {{ max_length }}), 正在分块处理...",
71
86
  "index_update_success": "✅ 成功更新 {{ file_path }} 的索引 (md5: {{ md5 }}), 耗时 {{ duration }} 秒",
72
87
  "index_build_error": "❌ 构建 {{ file_path }} 索引时出错: {{ error }}",
@@ -116,12 +131,12 @@ MESSAGES = {
116
131
  "pylint_file_check_failed": "⚠️ {{ file_path }} 的 Pylint 检查失败。更改未应用。错误: {{ error_message }}",
117
132
  "merge_success": "✅ 成功合并了 {{ num_files }} 个文件中的更改 {{ num_changes }}/{{ total_blocks }} 个代码块。",
118
133
  "no_changes_made": "⚠️ 未对任何文件进行更改。",
119
- "unmerged_blocks_title": "Unmerged Blocks",
120
- "unmerged_file_path": "File: {file_path}",
121
- "unmerged_search_block": "Search Block({similarity}):",
134
+ "unmerged_blocks_title": "未合并代码块",
135
+ "unmerged_file_path": "文件: {file_path}",
136
+ "unmerged_search_block": "Search Block({{similarity}}):",
122
137
  "unmerged_replace_block": "Replace Block:",
123
- "unmerged_blocks_total": "Total unmerged blocks: {num_blocks}",
124
- "git_init_required": "⚠️ auto_merge 仅适用于 git 仓库。\n\n请尝试在源目录中使用 git init:\n\n```shell\ncd {{ source_dir }}\ngit init .\n```\n\n然后再次运行 auto-coder。\n错误: {{ error }}",
138
+ "unmerged_blocks_total": "未合并代码块数量: {{num_blocks}}",
139
+ "git_init_required": "⚠️ auto_merge 仅适用于 git 仓库。\n\n请尝试在源目录中使用 git init:\n\n```shell\ncd {{ source_dir }}\ngit init.\n```\n\n然后再次运行 auto-coder。\n错误: {{ error }}",
125
140
  "upsert_file": "✅ 更新文件: {{ file_path }}",
126
141
  "files_merged": "✅ 成功合并了 {{ total }} 个文件到项目中。",
127
142
  "merge_failed": "❌ 合并文件 {{ path }} 失败: {{ error }}",
@@ -134,7 +149,7 @@ MESSAGES = {
134
149
  "ranking_process_failed": "排序过程失败: {{ error }}",
135
150
  "ranking_failed": "排序失败,耗时 {{ elapsed }} 秒,使用原始顺序",
136
151
  "stream_out_stats": "耗时 {{ elapsed_time }} 秒,输入token数: {{ input_tokens }}, 输出token数: {{ output_tokens }}"
137
- },
152
+ },
138
153
  }
139
154
 
140
155
 
@@ -148,3 +163,6 @@ def get_system_language():
148
163
  def get_message(key):
149
164
  lang = get_system_language()
150
165
  return MESSAGES.get(lang, MESSAGES['en']).get(key, MESSAGES['en'][key])
166
+
167
+ def get_message_with_format(msg_key: str, **kwargs):
168
+ return format_str_jinja2(get_message(msg_key), **kwargs)
@@ -422,11 +422,11 @@ class CodeAutoMergeEditBlock:
422
422
  self.printer.print_in_terminal("unmerged_blocks_title", style="bold red")
423
423
  for file_path, head, update, similarity in unmerged_blocks:
424
424
  self.printer.print_str_in_terminal(
425
- f"\n{self.printer.get_message_from_key('unmerged_file_path').format(file_path=file_path)}",
425
+ f"\n{self.printer.get_message_from_key_with_format('unmerged_file_path',file_path=file_path)}",
426
426
  style="bold blue"
427
427
  )
428
428
  self.printer.print_str_in_terminal(
429
- f"\n{self.printer.get_message_from_key('unmerged_search_block').format(similarity=similarity)}",
429
+ f"\n{self.printer.get_message_from_key_with_format('unmerged_search_block',similarity=similarity)}",
430
430
  style="bold green"
431
431
  )
432
432
  syntax = Syntax(head, "python", theme="monokai", line_numbers=True)
@@ -66,8 +66,8 @@ class CodeModificationRanker:
66
66
 
67
67
  self.printer.print_in_terminal(
68
68
  "ranking_start", style="blue", count=len(generate_result.contents))
69
- generate_times = self.args.generate_times_same_model
70
- total_tasks = len(self.llms) * generate_times
69
+ rank_times = self.args.rank_times_same_model
70
+ total_tasks = len(self.llms) * rank_times
71
71
 
72
72
  query = self._rank_modifications.prompt(generate_result)
73
73
  input_tokens_count = 0
@@ -78,7 +78,7 @@ class CodeModificationRanker:
78
78
  # Submit tasks for each model and generate_times
79
79
  futures = []
80
80
  for llm in self.llms:
81
- for _ in range(generate_times):
81
+ for _ in range(rank_times):
82
82
  futures.append(
83
83
  executor.submit(
84
84
  chat_with_continue,
autocoder/common/files.py CHANGED
@@ -1,3 +1,6 @@
1
+ from autocoder.common.auto_coder_lang import get_message_with_format
2
+ from typing import List, Dict, Union
3
+
1
4
  def read_file(file_path):
2
5
  """Read a file with automatic encoding detection.
3
6
 
@@ -23,4 +26,33 @@ def read_file(file_path):
23
26
  except UnicodeDecodeError:
24
27
  continue
25
28
 
26
- raise ValueError(f"无法解码文件: {file_path}。尝试的编码: {', '.join(encodings)}")
29
+ raise ValueError(get_message_with_format("file_decode_error",
30
+ file_path=file_path,
31
+ encodings=", ".join(encodings)))
32
+
33
+
34
+
35
+ def save_file(file_path: str, content: Union[str, List[str]]) -> None:
36
+ """Save content to a file using UTF-8 encoding.
37
+
38
+ Args:
39
+ file_path (str): Path to the file to write
40
+ content (Union[str, List[str]]): Content to write to the file.
41
+ Can be a string or list of strings (will be joined with newlines)
42
+
43
+ Raises:
44
+ IOError: If the file cannot be written
45
+ TypeError: If content is neither str nor List[str]
46
+ """
47
+ try:
48
+ with open(file_path, 'w', encoding='utf-8') as f:
49
+ if isinstance(content, str):
50
+ f.write(content)
51
+ elif isinstance(content, list):
52
+ f.write('\n'.join(content))
53
+ else:
54
+ raise TypeError("Content must be either str or List[str]")
55
+ except IOError as e:
56
+ raise IOError(get_message_with_format("file_write_error",
57
+ file_path=file_path,
58
+ error=str(e)))
@@ -46,5 +46,5 @@ class Printer:
46
46
 
47
47
  def print_panel(self, content: str, text_options:Dict[str,Any], panel_options:Dict[str,Any]):
48
48
  panel = Panel(Text(content, **text_options), **panel_options)
49
- self.console.print(panel)
50
-
49
+ self.console.print(panel)
50
+
@@ -57,7 +57,7 @@ def stream_chat_with_continue(
57
57
  count = 0
58
58
  temp_conversations = conversations
59
59
  current_metadata = None
60
-
60
+ metadatas = {}
61
61
  while True:
62
62
  # 使用流式接口获取生成内容
63
63
  stream_generator = llm.stream_chat_oai(
@@ -67,17 +67,20 @@ def stream_chat_with_continue(
67
67
  )
68
68
 
69
69
  current_content = ""
70
+
70
71
  for res in stream_generator:
71
72
  content = res[0]
72
73
  current_content += content
73
74
  if current_metadata is None:
74
75
  current_metadata = res[1]
75
76
  else:
76
- current_metadata.generated_tokens_count += res[1].generated_tokens_count
77
- current_metadata.input_tokens_count += res[1].input_tokens_count
78
- current_metadata.finish_reason = res[1].finish_reason
77
+ metadatas[count] = res[1]
78
+ current_metadata.finish_reason = res[1].finish_reason
79
+ current_metadata.reasoning_content = res[1].reasoning_content
79
80
 
80
81
  # Yield 当前的 StreamChatWithContinueResult
82
+ current_metadata.generated_tokens_count = sum([v.generated_tokens_count for _, v in metadatas.items()])
83
+ current_metadata.input_tokens_count = sum([v.input_tokens_count for _, v in metadatas.items()])
81
84
  yield (content,current_metadata)
82
85
 
83
86
  # 更新对话历史
autocoder/index/index.py CHANGED
@@ -130,6 +130,7 @@ class IndexManager:
130
130
  如果有符号,按如下格式返回:
131
131
 
132
132
  ```
133
+ 用途:主要用于提供自动实现函数模板的功能。
133
134
  {符号类型}: {符号名称}, {符号名称}, ...
134
135
  ```
135
136
 
autocoder/models.py CHANGED
@@ -36,6 +36,22 @@ default_models_list = [
36
36
  }
37
37
  ]
38
38
 
39
+ def process_api_key_path(base_url: str) -> str:
40
+ """
41
+ 从 base_url 中提取 host 部分并处理特殊字符
42
+ 例如: https://api.example.com:8080/v1 -> api.example.com_8080
43
+ """
44
+ if not base_url:
45
+ return ""
46
+
47
+ parsed = urlparse(base_url)
48
+ host = parsed.netloc
49
+
50
+ # 将冒号替换为下划线
51
+ host = host.replace(":", "_")
52
+
53
+ return host
54
+
39
55
  def load_models() -> List[Dict]:
40
56
  """
41
57
  Load models from ~/.auto-coder/keys/models.json and merge with default_models_list.
@@ -73,7 +89,7 @@ def load_models() -> List[Dict]:
73
89
  api_key_file = os.path.join(api_key_dir, model["api_key_path"])
74
90
  if os.path.exists(api_key_file):
75
91
  with open(api_key_file, "r") as f:
76
- model["api_key"] = f.read()
92
+ model["api_key"] = f.read()
77
93
  return target_models
78
94
 
79
95
  def save_models(models: List[Dict]) -> None:
@@ -85,22 +101,6 @@ def save_models(models: List[Dict]) -> None:
85
101
  json.dump(models, f, indent=2, ensure_ascii=False)
86
102
 
87
103
 
88
- def process_api_key_path(base_url: str) -> str:
89
- """
90
- 从 base_url 中提取 host 部分并处理特殊字符
91
- 例如: https://api.example.com:8080/v1 -> api.example.com_8080
92
- """
93
- if not base_url:
94
- return ""
95
-
96
- parsed = urlparse(base_url)
97
- host = parsed.netloc
98
-
99
- # 将冒号替换为下划线
100
- host = host.replace(":", "_")
101
-
102
- return host
103
-
104
104
  def get_model_by_name(name: str) -> Dict:
105
105
  """
106
106
  根据模型名称查找模型
@@ -109,7 +109,8 @@ def get_model_by_name(name: str) -> Dict:
109
109
  v = [m for m in models if m["name"] == name.strip()]
110
110
 
111
111
  if len(v) == 0:
112
- raise Exception(f"Model {name} not found")
112
+ from autocoder.common.auto_coder_lang import get_message_with_format
113
+ raise Exception(get_message_with_format("model_not_found", model_name=name))
113
114
  return v[0]
114
115
 
115
116
  def update_model_with_api_key(name: str, api_key: str) -> Dict:
@@ -135,9 +136,8 @@ def update_model_with_api_key(name: str, api_key: str) -> Dict:
135
136
 
136
137
  if not found_model:
137
138
  return None
138
-
139
- # base_url 中提取并处理 host
140
- api_key_path = process_api_key_path(found_model["base_url"])
139
+
140
+ api_key_path = name
141
141
  if api_key_path:
142
142
  found_model["api_key_path"] = api_key_path
143
143
 
@@ -36,9 +36,8 @@ class SuffixProject:
36
36
  self.target_file = args.target_file
37
37
  self.project_type = args.project_type
38
38
  self.suffixs = [
39
- f".{suffix.strip()}" if not suffix.startswith(".") else suffix.strip()
40
- for suffix in self.project_type.split(",")
41
- if suffix.strip() != ""
39
+ suffix.strip() if suffix.startswith(".") else f".{suffix.strip()}"
40
+ for suffix in self.project_type.split(",") if suffix.strip()
42
41
  ]
43
42
  self.file_filter = file_filter
44
43
  self.sources = []
@@ -2,12 +2,142 @@ from rich.console import Console
2
2
  from rich.live import Live
3
3
  from rich.panel import Panel
4
4
  from rich.markdown import Markdown
5
- from typing import Generator, List, Dict, Any, Optional, Tuple
5
+ from rich.layout import Layout
6
+ from threading import Thread, Lock
7
+ from queue import Queue, Empty
8
+ from typing import Generator, List, Dict, Any, Optional, Tuple, Literal
6
9
  from autocoder.utils.request_queue import RequestValue, RequestOption, StreamValue
7
10
  from autocoder.utils.request_queue import request_queue
11
+ import time
8
12
 
9
13
  MAX_HISTORY_LINES = 40 # 最大保留历史行数
10
14
 
15
+ class StreamRenderer:
16
+ def __init__(self, title: str):
17
+ self.title = title
18
+ self.content = ""
19
+ self.lock = Lock()
20
+ self.is_complete = False
21
+
22
+ def update(self, content: str):
23
+ with self.lock:
24
+ self.content += content
25
+
26
+ def get_content(self) -> str:
27
+ with self.lock:
28
+ return self.content
29
+
30
+ def complete(self):
31
+ with self.lock:
32
+ self.is_complete = True
33
+
34
+ class MultiStreamRenderer:
35
+ def __init__(self, stream_titles: List[str], layout: str = "horizontal", console: Optional[Console] = None):
36
+ """
37
+ Initialize multi-stream renderer
38
+
39
+ Args:
40
+ stream_titles: List of titles for each stream
41
+ layout: "horizontal" or "vertical"
42
+ console: Rich console instance
43
+ """
44
+ if console is None:
45
+ console = Console(force_terminal=True, color_system="auto")
46
+
47
+ self.console = console
48
+ self.layout_type = layout
49
+ self.streams = [StreamRenderer(title) for title in stream_titles]
50
+ self.layout = Layout()
51
+
52
+ # Create named layouts for each stream
53
+ self.stream_layouts = [Layout(name=f"stream{i}") for i in range(len(stream_titles))]
54
+
55
+ # Configure layout
56
+ if layout == "horizontal":
57
+ self.layout.split_row(*self.stream_layouts)
58
+ else:
59
+ self.layout.split_column(*self.stream_layouts)
60
+
61
+ def _process_stream(self,
62
+ stream_idx: int,
63
+ stream_generator: Generator[Tuple[str, Dict[str, Any]], None, None]):
64
+ """Process a single stream in a separate thread"""
65
+ stream = self.streams[stream_idx]
66
+ try:
67
+ for content, meta in stream_generator:
68
+ if content:
69
+ stream.update(content)
70
+ finally:
71
+ stream.complete()
72
+
73
+ def render_streams(self,
74
+ stream_generators: List[Generator[Tuple[str, Dict[str, Any]], None, None]]) -> List[str]:
75
+ """
76
+ Render multiple streams simultaneously
77
+
78
+ Args:
79
+ stream_generators: List of stream generators to render
80
+
81
+ Returns:
82
+ List of final content from each stream
83
+ """
84
+ assert len(stream_generators) == len(self.streams), "Number of generators must match number of streams"
85
+
86
+ # Start processing threads
87
+ threads = []
88
+ for i, generator in enumerate(stream_generators):
89
+ thread = Thread(target=self._process_stream, args=(i, generator))
90
+ thread.daemon = True
91
+ thread.start()
92
+ threads.append(thread)
93
+
94
+ try:
95
+ with Live(self.layout, console=self.console, refresh_per_second=10) as live:
96
+ while any(not stream.is_complete for stream in self.streams):
97
+ # Update all panels
98
+ for i, stream in enumerate(self.streams):
99
+ panel = Panel(
100
+ Markdown(stream.get_content() or "Waiting..."),
101
+ title=stream.title,
102
+ border_style="green" if not stream.is_complete else "blue"
103
+ )
104
+
105
+ # Update appropriate layout section
106
+ self.stream_layouts[i].update(panel)
107
+
108
+ time.sleep(0.1) # Prevent excessive CPU usage
109
+
110
+ except KeyboardInterrupt:
111
+ print("\nStopping streams...")
112
+
113
+ # Wait for all threads to complete
114
+ for thread in threads:
115
+ thread.join()
116
+
117
+ return [stream.get_content() for stream in self.streams]
118
+
119
+ def multi_stream_out(
120
+ stream_generators: List[Generator[Tuple[str, Dict[str, Any]], None, None]],
121
+ titles: List[str],
122
+ layout: str = "horizontal",
123
+ console: Optional[Console] = None
124
+ ) -> List[str]:
125
+ """
126
+ Render multiple streams with Rich
127
+
128
+ Args:
129
+ stream_generators: List of stream generators
130
+ titles: List of titles for each stream
131
+ layout: "horizontal" or "vertical"
132
+ console: Optional Rich console instance
133
+
134
+ Returns:
135
+ List of final content from each stream
136
+ """
137
+ renderer = MultiStreamRenderer(titles, layout, console)
138
+ return renderer.render_streams(stream_generators)
139
+
140
+
11
141
  def stream_out(
12
142
  stream_generator: Generator[Tuple[str, Dict[str, Any]], None, None],
13
143
  request_id: Optional[str] = None,
@@ -41,10 +171,17 @@ def stream_out(
41
171
  for res in stream_generator:
42
172
  last_meta = res[1]
43
173
  content = res[0]
174
+ reasoning_content = last_meta.reasoning_content
175
+
176
+ if reasoning_content == "" and content == "":
177
+ continue
178
+
44
179
  assistant_response += content
180
+
181
+ display_delta = reasoning_content if reasoning_content else content
45
182
 
46
183
  # 处理所有行
47
- parts = (current_line + content).split("\n")
184
+ parts = (current_line + display_delta).split("\n")
48
185
 
49
186
  # 最后一部分是未完成的新行
50
187
  if len(parts) > 1:
autocoder/utils/rest.py CHANGED
@@ -1,16 +1,22 @@
1
1
  import requests
2
2
  from bs4 import BeautifulSoup
3
- from typing import List,Dict,Type,Optional
3
+ from typing import List,Dict,Union,Optional
4
4
  from autocoder.common import SourceCode
5
5
  import byzerllm
6
- from bs4 import BeautifulSoup
7
6
  from loguru import logger
8
7
  import os
9
8
  from pathlib import Path
10
9
  from autocoder.common import files as FileUtils
10
+ import traceback
11
+ from autocoder.rag.loaders import (
12
+ extract_text_from_pdf,
13
+ extract_text_from_docx,
14
+ extract_text_from_ppt,
15
+ extract_text_from_excel
16
+ )
11
17
 
12
18
  class HttpDoc:
13
- def __init__(self, args, llm: byzerllm.ByzerLLM,urls:Optional[List[str]]=None):
19
+ def __init__(self, args, llm: Union[byzerllm.ByzerLLM, byzerllm.SimpleByzerLLM],urls:Optional[List[str]]=None):
14
20
  self.args = args
15
21
  urls_from_args = self.args.urls
16
22
  if urls_from_args:
@@ -41,104 +47,50 @@ class HttpDoc:
41
47
  {{ html }}
42
48
 
43
49
  输出的内容请以 "<MARKER></MARKER> 标签对包裹。
44
- """
45
-
46
- def is_binary_file(self,filepath):
47
- try:
48
- with open(filepath, 'rb') as file:
49
- chunk = file.read(1024*8) # Read first 1024 bytes
50
- if b'\x00' in chunk: # Binary files often contain null bytes
51
- return True
52
- # Attempt to decode as UTF-8 (or any encoding you expect your text files to be in)
53
- chunk.decode('utf-8')
54
- return False
55
- except UnicodeDecodeError:
56
- return True
50
+ """
57
51
 
58
- def get_file_extractor(self):
52
+ def _process_local_file(self, file_path: str) -> List[SourceCode]:
53
+ """统一处理本地文件,返回标准化的 SourceCode 列表"""
54
+ results = []
59
55
  try:
60
- from llama_index.core.readers.base import BaseReader
61
- from fsspec import AbstractFileSystem
62
- from llama_index.core.schema import Document
63
- from llama_index.core.readers.file.base import get_default_fs
64
- from llama_index.readers.file import (
65
- DocxReader,
66
- EpubReader,
67
- HWPReader,
68
- ImageReader,
69
- IPYNBReader,
70
- MarkdownReader,
71
- MboxReader,
72
- PandasCSVReader,
73
- PDFReader,
74
- PptxReader,
75
- VideoAudioReader,
76
- ) # pants: no-infer-dep
77
- except ImportError as e:
78
- raise ImportError(f"`llama-index-readers-file` package not found. {e}")
56
+ ext = os.path.splitext(file_path)[1].lower()
57
+
58
+ # 分发到不同 loader
59
+ if ext == '.pdf':
60
+ content = extract_text_from_pdf(file_path)
61
+ results.append(SourceCode(module_name=file_path, source_code=content))
62
+ elif ext == '.docx':
63
+ content = extract_text_from_docx(file_path)
64
+ results.append(SourceCode(module_name=file_path, source_code=content))
65
+ elif ext in ('.pptx', '.ppt'):
66
+ for slide_id, slide_content in extract_text_from_ppt(file_path):
67
+ results.append(SourceCode(module_name=f"{file_path}#{slide_id}", source_code=slide_content))
68
+ elif ext in ('.xlsx', '.xls'):
69
+ for sheet_name, sheet_content in extract_text_from_excel(file_path):
70
+ results.append(SourceCode(module_name=f"{file_path}#{sheet_name}", source_code=sheet_content))
71
+ else:
72
+ content = FileUtils.read_file(file_path)
73
+ results.append(SourceCode(module_name=file_path, source_code=content))
79
74
 
80
- default_file_reader_cls: Dict[str, BaseReader] = {
81
- ".hwp": HWPReader(),
82
- ".pdf": PDFReader(return_full_document=True),
83
- ".docx": DocxReader(),
84
- # ".pptx": PptxReader(),
85
- # ".ppt": PptxReader(),
86
- # ".pptm": PptxReader(),
87
- # ".jpg": ImageReader(),
88
- # ".png": ImageReader(),
89
- # ".jpeg": ImageReader(),
90
- # ".mp3": VideoAudioReader(),
91
- # ".mp4": VideoAudioReader(),
92
- # ".csv": PandasCSVReader(),
93
- ".epub": EpubReader(),
94
- ".mbox": MboxReader(),
95
- ".ipynb": IPYNBReader(),
96
- }
97
- return default_file_reader_cls
75
+ except Exception as e:
76
+ logger.error(f"Failed to process {file_path}: {str(e)}")
77
+ traceback.print_exc()
78
+
79
+ return results
98
80
 
99
81
  def crawl_urls(self) -> List[SourceCode]:
100
- source_codes = []
82
+ source_codes = []
101
83
  for url in self.urls:
102
- if not url.startswith("http://") and not url.startswith("https://"):
84
+ if not url.startswith(("http://", "https://")):
103
85
  try:
104
- from llama_index.core import SimpleDirectoryReader
105
- exts = self.get_file_extractor()
106
- documents = []
107
-
108
- def process_single_file(file_path: str,skip_binary_file_test:bool=False):
109
- temp_documents = []
110
- ext = os.path.splitext(file_path)[1].lower()
111
- if not skip_binary_file_test and self.is_binary_file(file_path):
112
- logger.warning(f"Skipping binary file: {file_path}")
113
- return temp_documents
114
-
115
- if ext not in exts.keys():
116
- main_content = FileUtils.read_file(file_path)
117
- source_code = SourceCode(module_name=file_path, source_code=main_content)
118
- source_codes.append(source_code)
86
+ if os.path.isdir(url):
87
+ for root, _, files in os.walk(url, followlinks=True):
88
+ for file in files:
89
+ source_codes.extend(self._process_local_file(os.path.join(root, file)))
119
90
  else:
120
- temp_documents = SimpleDirectoryReader(input_files=[url],file_extractor=exts).load_data()
121
- return temp_documents
122
-
123
- if os.path.isdir(url):
124
- for root, dirs, files in os.walk(url,followlinks=True):
125
- dirs[:] = [d for d in dirs if d not in ['.git',"node_modules"]] # Exclude .git directory
126
- for file in files:
127
- file_path = os.path.join(root, file)
128
- documents.extend(process_single_file(file_path))
129
-
130
- else:
131
- documents.extend(process_single_file(url,skip_binary_file_test=True))
132
-
133
- for document in documents:
134
- source_code = SourceCode(module_name=document.metadata["file_path"], source_code=document.get_content())
135
- source_codes.append(source_code)
136
-
137
- except ImportError as e:
138
- logger.warning(f"Failed to import llama_index. Please install it using 'pip install llama_index' {e}")
139
- main_content = FileUtils.read_file(url)
140
- source_code = SourceCode(module_name=url, source_code=main_content)
141
- source_codes.append(source_code)
91
+ source_codes.extend(self._process_local_file(url))
92
+ except Exception as e:
93
+ logger.error(f"Error accessing path {url}: {str(e)}")
142
94
  else:
143
95
  if self.args.urls_use_model:
144
96
  from autocoder.common.screenshots import gen_screenshots
autocoder/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.242"
1
+ __version__ = "0.1.244"