auto-coder 0.1.392__py3-none-any.whl → 0.1.395__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.392
3
+ Version: 0.1.395
4
4
  Summary: AutoCoder: AutoCoder
5
5
  Author: allwefantasy
6
6
  Classifier: Programming Language :: Python :: 3.10
@@ -1,6 +1,6 @@
1
1
  autocoder/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  autocoder/auto_coder.py,sha256=7602L3tG0JErNxh8vkLAmGUgv2c-DGPzPCkmWIQt9bs,69757
3
- autocoder/auto_coder_rag.py,sha256=9PeW7m1bdZx9Q4yw6ULeBKuJQ2EZyO2MepTofl9RxA4,41376
3
+ autocoder/auto_coder_rag.py,sha256=r018fdFWn857cVgCHD1poNCCe70-UU-m9CpzMjSH-YY,43650
4
4
  autocoder/auto_coder_runner.py,sha256=3kjlxvCgnOd-_P7VqPVcBYU_xqTdW515c-XFwuXUgdI,115789
5
5
  autocoder/auto_coder_server.py,sha256=bLORGEclcVdbBVfM140JCI8WtdrU0jbgqdJIVVupiEU,20578
6
6
  autocoder/benchmark.py,sha256=Ypomkdzd1T3GE6dRICY3Hj547dZ6_inqJbBJIp5QMco,4423
@@ -10,8 +10,9 @@ autocoder/command_args.py,sha256=HxflngkYtTrV17Vfgk6lyUyiG68jP2ftSc7FYr9AXwY,305
10
10
  autocoder/command_parser.py,sha256=fx1g9E6GaM273lGTcJqaFQ-hoksS_Ik2glBMnVltPCE,10013
11
11
  autocoder/lang.py,sha256=PFtATuOhHRnfpqHQkXr6p4C893JvpsgwTMif3l-GEi0,14321
12
12
  autocoder/models.py,sha256=pD5u6gcMKRwWaLxeVin18g25k-ERyeHOFsRpOgO_Ae0,13788
13
+ autocoder/rags.py,sha256=1iVKH6GpgDYpE1LawehXoZNEupiHXlX5x6HmWJg83Vg,10555
13
14
  autocoder/run_context.py,sha256=IUfSO6_gp2Wt1blFWAmOpN0b0nDrTTk4LmtCYUBIoro,1643
14
- autocoder/version.py,sha256=ZTsw_XcFB4V267Rc6_tT3BTknX9GxJaf4Wj3R2S4z0U,24
15
+ autocoder/version.py,sha256=UfvK7YT61h8sNTKGWY8Hq7WLTpHKsyefTENtiRbkDys,24
15
16
  autocoder/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
17
  autocoder/agent/agentic_filter.py,sha256=zlInIRhawKIYTJjCiJBWqPCOV5UtMbh5VnvszfTy2vo,39824
17
18
  autocoder/agent/auto_demand_organizer.py,sha256=URAq0gSEiHeV_W4zwhOI_83kHz0Ryfj1gcfh5jwCv_w,6501
@@ -40,7 +41,7 @@ autocoder/agent/base_agentic/tools/ask_followup_question_tool_resolver.py,sha256
40
41
  autocoder/agent/base_agentic/tools/attempt_completion_tool_resolver.py,sha256=9a_qPihfm45Q22kmxmFwYrZrtNsgtEyBePL8D4SXfes,1487
41
42
  autocoder/agent/base_agentic/tools/base_tool_resolver.py,sha256=Y0PmRPhBLLdZpr2DNV0W5goGfAqylM5m1bHxa3T6vAY,1009
42
43
  autocoder/agent/base_agentic/tools/example_tool_resolver.py,sha256=8WBIqEH_76S0iBHBM3RhLkk14UpJ28lRAw6dNUT-0no,1388
43
- autocoder/agent/base_agentic/tools/execute_command_tool_resolver.py,sha256=UL7eQz7Im4BhpglIxUDmEBZ9xwM_hhk1J9iY228uvPU,3691
44
+ autocoder/agent/base_agentic/tools/execute_command_tool_resolver.py,sha256=w-_8NCtT2TRlBi8ZcU4gKksbbQFicZ4vAakCC0HOziQ,3223
44
45
  autocoder/agent/base_agentic/tools/list_files_tool_resolver.py,sha256=SCAYAiqmgwuCLMwRwroUQFfVS_hbcuAoG9-jIJxiB1c,8061
45
46
  autocoder/agent/base_agentic/tools/plan_mode_respond_tool_resolver.py,sha256=hiLdMRknR_Aljd7Ic2bOWZKs11aFHdhkRTKTlP3IIgw,1461
46
47
  autocoder/agent/base_agentic/tools/read_file_tool_resolver.py,sha256=egcxrXv32stvhB3QawE2k62-9W5U3TNuY3qoTyKKhs0,5076
@@ -97,7 +98,7 @@ autocoder/common/global_cancel.py,sha256=EYMIzdIJHQjoYP4grxhBxSIT3tCJOy3ESULNd-c
97
98
  autocoder/common/image_to_page.py,sha256=yWiTJQ49Lm3j0FngiJhQ9u7qayqE_bOGb8Rk0TmSWx0,14123
98
99
  autocoder/common/index_import_export.py,sha256=h758AYY1df6JMTKUXYmMkSgxItfymDt82XT7O-ygEuw,4565
99
100
  autocoder/common/interpreter.py,sha256=62-dIakOunYB4yjmX8SHC0Gdy2h8NtxdgbpdqRZJ5vk,2833
100
- autocoder/common/llm_friendly_package.py,sha256=j44Wqco8-5sA2Yz05ZEidA1HwTbVGnbevbALCoasTtM,14760
101
+ autocoder/common/llm_friendly_package.py,sha256=hrRoGxkHH91by-rQKJqNzDeUVvmG5HrS2eESCo3rLvI,16121
101
102
  autocoder/common/llm_friendly_package_example.py,sha256=NXUiz6j7gpfzExC-2jmppnZaZaTuu4oGMCDneV7FC_k,4647
102
103
  autocoder/common/llm_friendly_package_test.py,sha256=FhbzdNPEceuEBIxNvek2OYDFVlJlYJpkskZ7_PB4YSg,1930
103
104
  autocoder/common/mcp_hub.py,sha256=grf51bZbZDXQIqlruIxXZjfat8MoVwK7NvHTHMaxKrg,23614
@@ -158,6 +159,8 @@ autocoder/common/ignorefiles/test_ignore_file_utils.py,sha256=EydHG6E2iPsnbt-Jt8
158
159
  autocoder/common/mcp_servers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
159
160
  autocoder/common/mcp_servers/mcp_server_gpt4o_mini_search.py,sha256=TApShxgoozLluobXHOK1-oAE1zm0-9jdRoPLQB1qwMI,5688
160
161
  autocoder/common/mcp_servers/mcp_server_perplexity.py,sha256=CIC26UkfH1lYoVCjfyY5xGGYVx8h0oz0Uj1c7YJ3OPw,5560
162
+ autocoder/common/rag_manager/__init__.py,sha256=PR2LIdyFdF3XOFewd2VYuEFNp5ZUMrwAstYn8OOJX-Y,77
163
+ autocoder/common/rag_manager/rag_manager.py,sha256=l4tVztPOYTyHKWCsWOXyxzf5oxjEBx8rTDk6Q49dc6Y,6022
161
164
  autocoder/common/rulefiles/__init__.py,sha256=babSbPdFaXk1NvdHtH2zrJLb_tWd7d2ELIyS8NApY_Y,221
162
165
  autocoder/common/rulefiles/autocoderrules_utils.py,sha256=TvzKt41wa1uPnYXHkUaJRCuxCJL9IB-Zx6FsEwdSExg,19454
163
166
  autocoder/common/v2/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -175,10 +178,10 @@ autocoder/common/v2/code_editblock_manager.py,sha256=DMwJw-FAM6VyaBQV3p4xespHpgZ
175
178
  autocoder/common/v2/code_manager.py,sha256=C403bS-f6urixwitlKHcml-J03hci-UyNwHJOqBiY6Q,9182
176
179
  autocoder/common/v2/code_strict_diff_manager.py,sha256=Bys7tFAq4G03R1zUZuxrszBTvP4QB96jIw2y5BDLyRM,9424
177
180
  autocoder/common/v2/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
178
- autocoder/common/v2/agent/agentic_edit.py,sha256=f9GxvaOvgirxyPCEiGxFi7u8X4ZB3do72PGldxCzpAI,115291
179
- autocoder/common/v2/agent/agentic_edit_types.py,sha256=nEcZc2MOZ_fQLaJX-YDha_x9Iim22ao4tykYM2iIy4k,4908
181
+ autocoder/common/v2/agent/agentic_edit.py,sha256=iy7jqzLcjc37sHHqTXI5Nbhx_w2UGaAGE6KQay94EEc,130191
182
+ autocoder/common/v2/agent/agentic_edit_types.py,sha256=rN3MuPES2Gwp8b5vrpp9v4eUkAlLA4AY7PEZ7LoUgvQ,5005
180
183
  autocoder/common/v2/agent/agentic_tool_display.py,sha256=-a-JTQLc4q03E_rdIILKMI0B6DHN-5gcGlrqq-mBYK4,7239
181
- autocoder/common/v2/agent/agentic_edit_tools/__init__.py,sha256=RbPZZcZg_VnGssL577GxSyFrYrxQ_LopJ4G_-mY3z_Q,1337
184
+ autocoder/common/v2/agent/agentic_edit_tools/__init__.py,sha256=5I_N3xeekdGQJtOI6TxZ4LkwwtP0CQ7stu6SBaF9UeQ,1417
182
185
  autocoder/common/v2/agent/agentic_edit_tools/ask_followup_question_tool_resolver.py,sha256=-HFXo3RR6CH8xXjDaE2mYV4XasTLAmvXe6WutL7qbwA,3208
183
186
  autocoder/common/v2/agent/agentic_edit_tools/attempt_completion_tool_resolver.py,sha256=82ZGKeRBSDKeead_XVBW4FxpiE-5dS7tBOk_3RZ6B5s,1511
184
187
  autocoder/common/v2/agent/agentic_edit_tools/base_tool_resolver.py,sha256=Zid2m1uZd-2wVFGc_n_KAViXZyNjbdLSpI5n7ut1RUQ,1036
@@ -195,6 +198,7 @@ autocoder/common/v2/agent/agentic_edit_tools/test_execute_command_tool_resolver.
195
198
  autocoder/common/v2/agent/agentic_edit_tools/test_search_files_tool_resolver.py,sha256=9eBo3WLkrr77iNotwIwVmH1ZL3UY0JQgLpdAIc9wTTM,6127
196
199
  autocoder/common/v2/agent/agentic_edit_tools/test_write_to_file_tool_resolver.py,sha256=ZWRPsJny_My4UMzovrB8J2_x5N0rEW-xx3DVI-kDRFI,15870
197
200
  autocoder/common/v2/agent/agentic_edit_tools/use_mcp_tool_resolver.py,sha256=wM2Xy4bcnD0TSLEmcM8rvvyyWenN5_KQnJMO6hJ8lTE,1716
201
+ autocoder/common/v2/agent/agentic_edit_tools/use_rag_tool_resolver.py,sha256=frVkXws__fDO2kXETi4NI7eKR_lz2i0C26MPsoYftp8,3901
198
202
  autocoder/common/v2/agent/agentic_edit_tools/write_to_file_tool_resolver.py,sha256=lPESPLoe9P_bEXXNqqHAkVlqMrIH0XziJ6XeILIejUo,8084
199
203
  autocoder/compilers/__init__.py,sha256=C0HOms70QA747XD0uZEMmGtRFcIPenohyqECNStv0Bw,1647
200
204
  autocoder/compilers/base_compiler.py,sha256=dsTzMO4H_RoqWfE-SntIk2B52hWuvSlWVLtkdCbHgGs,3244
@@ -341,9 +345,9 @@ autocoder/utils/types.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
341
345
  autocoder/utils/auto_coder_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
342
346
  autocoder/utils/auto_coder_utils/chat_stream_out.py,sha256=t902pKxQ5xM7zgIHiAOsTPLwxhE6VuvXAqPy751S7fg,14096
343
347
  autocoder/utils/chat_auto_coder_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
344
- auto_coder-0.1.392.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
345
- auto_coder-0.1.392.dist-info/METADATA,sha256=CI2kK7M_kEPPdkrzIufAAYs5PaKCS4AM4FhrzMDePcY,2796
346
- auto_coder-0.1.392.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
347
- auto_coder-0.1.392.dist-info/entry_points.txt,sha256=0nzHtHH4pNcM7xq4EBA2toS28Qelrvcbrr59GqD_0Ak,350
348
- auto_coder-0.1.392.dist-info/top_level.txt,sha256=Jqc0_uJSw2GwoFQAa9iJxYns-2mWla-9ok_Y3Gcznjk,10
349
- auto_coder-0.1.392.dist-info/RECORD,,
348
+ auto_coder-0.1.395.dist-info/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
349
+ auto_coder-0.1.395.dist-info/METADATA,sha256=sAecYPtZ_CLwD9kc0ChW_nHRlJNQhCQvCoI7Fia_xdE,2796
350
+ auto_coder-0.1.395.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
351
+ auto_coder-0.1.395.dist-info/entry_points.txt,sha256=0nzHtHH4pNcM7xq4EBA2toS28Qelrvcbrr59GqD_0Ak,350
352
+ auto_coder-0.1.395.dist-info/top_level.txt,sha256=Jqc0_uJSw2GwoFQAa9iJxYns-2mWla-9ok_Y3Gcznjk,10
353
+ auto_coder-0.1.395.dist-info/RECORD,,
@@ -21,15 +21,7 @@ class ExecuteCommandToolResolver(BaseToolResolver):
21
21
  def resolve(self) -> ToolResult:
22
22
  command = self.tool.command
23
23
  requires_approval = self.tool.requires_approval
24
- source_dir = self.args.source_dir or "."
25
-
26
- # Basic security check (can be expanded)
27
- if ";" in command or "&&" in command or "|" in command or "`" in command:
28
- # Allow && for cd chaining, but be cautious
29
- if not command.strip().startswith("cd ") and " && " in command:
30
- pass # Allow cd chaining like 'cd subdir && command'
31
- else:
32
- return ToolResult(success=False, message=f"Command '{command}' contains potentially unsafe characters.")
24
+ source_dir = self.args.source_dir or "."
33
25
 
34
26
  # Approval mechanism (simplified)
35
27
  if requires_approval:
@@ -35,6 +35,7 @@ import pkg_resources
35
35
  from autocoder.rag.token_counter import TokenCounter
36
36
  from autocoder.rag.types import RAGServiceInfo
37
37
  from autocoder.version import __version__
38
+ from autocoder.rags import get_rag_config
38
39
 
39
40
  if platform.system() == "Windows":
40
41
  from colorama import init
@@ -169,6 +170,40 @@ def initialize_system(args):
169
170
  print_status(get_message("init_complete_final"), "success")
170
171
 
171
172
 
173
+ def merge_args_with_config(args, config, arg_class, parser):
174
+ """
175
+ 合并命令行参数和配置文件参数,优先级如下:
176
+ 1. 命令行参数非默认值,以命令行为准
177
+ 2. 命令行参数为默认值,且配置文件有值,以配置文件为准
178
+ 3. 否则用命令行参数
179
+ """
180
+ merged = {}
181
+ for arg in vars(arg_class()):
182
+ # 获取默认值
183
+ try:
184
+ default = parser.get_default(arg)
185
+ except Exception:
186
+ default = None
187
+
188
+
189
+ if not hasattr(args,arg) and arg not in config:
190
+ continue
191
+
192
+ cli_value = getattr(args, arg, None)
193
+ config_value = config.get(arg, None)
194
+
195
+
196
+ # 判断优先级
197
+ if cli_value != default:
198
+ merged[arg] = cli_value
199
+ elif config_value is not None:
200
+ merged[arg] = config_value
201
+ else:
202
+ merged[arg] = cli_value
203
+
204
+ return arg_class(**merged)
205
+
206
+
172
207
  def main(input_args: Optional[List[str]] = None):
173
208
  print(
174
209
  f"""
@@ -297,6 +332,7 @@ def main(input_args: Optional[List[str]] = None):
297
332
  serve_parser.add_argument("--source_dir", default=".", help="")
298
333
  serve_parser.add_argument("--host", default="", help="")
299
334
  serve_parser.add_argument("--port", type=int, default=8000, help="")
335
+ serve_parser.add_argument("--name", default="", help="RAG服务的名称(可选)")
300
336
  serve_parser.add_argument("--workers", type=int, default=4, help="")
301
337
  serve_parser.add_argument("--uvicorn_log_level", default="info", help="")
302
338
  serve_parser.add_argument("--allow_credentials", action="store_true", help="")
@@ -565,29 +601,40 @@ def main(input_args: Optional[List[str]] = None):
565
601
  benchmark_byzerllm(args.model, args.parallel, args.rounds, args.query)
566
602
 
567
603
  elif args.command == "serve":
568
- # Handle lite/pro flags
569
- if args.lite:
570
- args.product_mode = "lite"
571
- elif args.pro:
604
+ # 如果用户传递了 --name 参数,则加载已保存的配置并与命令行参数合并
605
+ server_args_config = {}
606
+ auto_coder_args_config = {}
607
+ if args.name:
608
+ saved_config = get_rag_config(args.name)
609
+ if saved_config:
610
+ logger.info(f"加载已保存的RAG配置: {args.name}")
611
+ # 将保存的配置合并到 args 中(命令行参数优先)
612
+ for key, value in saved_config.items():
613
+ # 跳过一些不应该被合并的字段
614
+ skip_fields = {'name', 'status', 'created_at', 'updated_at', 'process_id', 'stdout_fd', 'stderr_fd', 'cache_build_task_id'}
615
+ if key in skip_fields:
616
+ continue
617
+ server_args_config[key] = value
618
+ # 特殊处理 infer_params 字段
619
+ if 'infer_params' in saved_config and saved_config['infer_params']:
620
+ for infer_key, infer_value in saved_config['infer_params'].items():
621
+ auto_coder_args_config[infer_key] = infer_value
622
+ logger.info(f"配置合并完成,使用文档目录: {getattr(args, 'doc_dir', 'N/A')}")
623
+ else:
624
+ logger.warning(f"未找到名为 '{args.name}' 的RAG配置")
625
+
626
+ # Handle lite/pro flags
627
+ if args.pro:
572
628
  args.product_mode = "pro"
573
-
629
+ else:
630
+ args.product_mode = "lite"
631
+
574
632
  if not args.quick:
575
633
  initialize_system(args)
576
-
577
- server_args = ServerArgs(
578
- **{
579
- arg: getattr(args, arg)
580
- for arg in vars(ServerArgs())
581
- if hasattr(args, arg)
582
- }
583
- )
584
- auto_coder_args = AutoCoderArgs(
585
- **{
586
- arg: getattr(args, arg)
587
- for arg in vars(AutoCoderArgs())
588
- if hasattr(args, arg)
589
- }
590
- )
634
+
635
+ # 使用新的合并逻辑
636
+ server_args = merge_args_with_config(args, server_args_config, ServerArgs, serve_parser)
637
+ auto_coder_args = merge_args_with_config(args, server_args_config, AutoCoderArgs, serve_parser)
591
638
  # 设置本地图床的地址
592
639
  if args.enable_local_image_host:
593
640
  host = server_args.host or "127.0.0.1"
@@ -178,6 +178,41 @@ class LLMFriendlyPackageManager:
178
178
 
179
179
  return docs
180
180
 
181
+ def get_package_path(self, package_name: str) -> Optional[str]:
182
+ """
183
+ Get the full path of a package by its name
184
+
185
+ Args:
186
+ package_name: Package name (can be just lib_name or username/lib_name)
187
+
188
+ Returns:
189
+ Full path to the package directory, or None if not found
190
+ """
191
+ if not os.path.exists(self.llm_friendly_packages_dir):
192
+ return None
193
+
194
+ for domain in os.listdir(self.llm_friendly_packages_dir):
195
+ domain_path = os.path.join(self.llm_friendly_packages_dir, domain)
196
+ if not os.path.isdir(domain_path):
197
+ continue
198
+
199
+ for username in os.listdir(domain_path):
200
+ username_path = os.path.join(domain_path, username)
201
+ if not os.path.isdir(username_path):
202
+ continue
203
+
204
+ for lib_name in os.listdir(username_path):
205
+ lib_path = os.path.join(username_path, lib_name)
206
+ if not os.path.isdir(lib_path):
207
+ continue
208
+
209
+ # Check if this matches the requested package
210
+ if (lib_name == package_name or
211
+ package_name == os.path.join(username, lib_name)):
212
+ return lib_path
213
+
214
+ return None
215
+
181
216
  def list_added_libraries(self) -> List[str]:
182
217
  """List all added libraries"""
183
218
  memory = self._load_memory()
@@ -405,6 +440,4 @@ class LLMFriendlyPackageManager:
405
440
  table.add_column("File Path", style="cyan")
406
441
 
407
442
  for doc in docs:
408
- table.add_row(doc)
409
-
410
- self.console.print(table)
443
+ table.add_row(doc)
@@ -0,0 +1,4 @@
1
+ # flake8: noqa
2
+ from .rag_manager import RAGManager
3
+
4
+ __all__ = ["RAGManager"]
@@ -0,0 +1,144 @@
1
+ import os
2
+ import json
3
+ from typing import List, Dict, Any, Optional
4
+ from pydantic import BaseModel
5
+ from autocoder.common import AutoCoderArgs
6
+ from loguru import logger
7
+
8
+
9
+ class RAGConfig(BaseModel):
10
+ """RAG 配置项模型"""
11
+ name: str
12
+ server_name: str # 实际的服务器地址,如 http://127.0.0.1:8107/v1
13
+ api_key: Optional[str] = None
14
+ description: Optional[str] = None
15
+
16
+
17
+ class RAGManager:
18
+ """RAG 管理器,用于读取和管理 RAG 服务器配置"""
19
+
20
+ def __init__(self, args: AutoCoderArgs):
21
+ self.args = args
22
+ self.configs: List[RAGConfig] = []
23
+ self._load_configs()
24
+
25
+ def _load_configs(self):
26
+ """加载 RAG 配置,优先从项目配置,然后从全局配置"""
27
+ # 优先读取项目级别配置
28
+ project_config_path = os.path.join(
29
+ self.args.source_dir,
30
+ ".auto-coder",
31
+ "auto-coder.web",
32
+ "rags",
33
+ "rags.json"
34
+ )
35
+
36
+ if os.path.exists(project_config_path):
37
+ logger.info(f"正在加载项目级别 RAG 配置: {project_config_path}")
38
+ self._load_project_config(project_config_path)
39
+ else:
40
+ logger.info("未找到项目级别 RAG 配置,尝试加载全局配置")
41
+ # 读取全局配置
42
+ global_config_path = os.path.expanduser("~/.auto-coder/keys/rags.json")
43
+ if os.path.exists(global_config_path):
44
+ logger.info(f"正在加载全局 RAG 配置: {global_config_path}")
45
+ self._load_global_config(global_config_path)
46
+ else:
47
+ logger.warning("未找到任何 RAG 配置文件")
48
+
49
+ def _load_project_config(self, config_path: str):
50
+ """加载项目级别的 RAG 配置"""
51
+ try:
52
+ with open(config_path, 'r', encoding='utf-8') as f:
53
+ config_data = json.load(f)
54
+
55
+ if "data" in config_data and isinstance(config_data["data"], list):
56
+ for item in config_data["data"]:
57
+ try:
58
+ rag_config = RAGConfig(
59
+ name=item.get("name", ""),
60
+ server_name=item.get("base_url", ""),
61
+ api_key=item.get("api_key"),
62
+ description=item.get("description")
63
+ )
64
+ self.configs.append(rag_config)
65
+ logger.info(f"已加载 RAG 配置: {rag_config.name} -> {rag_config.server_name}")
66
+ except Exception as e:
67
+ logger.error(f"解析项目级别 RAG 配置项时出错: {e}, 配置项: {item}")
68
+ else:
69
+ logger.error(f"项目级别 RAG 配置格式错误,缺少 'data' 字段或 'data' 不是列表")
70
+
71
+ except json.JSONDecodeError as e:
72
+ logger.error(f"项目级别 RAG 配置文件 JSON 格式错误: {e}")
73
+ except Exception as e:
74
+ logger.error(f"读取项目级别 RAG 配置文件时出错: {e}")
75
+
76
+ def _load_global_config(self, config_path: str):
77
+ """加载全局级别的 RAG 配置"""
78
+ try:
79
+ with open(config_path, 'r', encoding='utf-8') as f:
80
+ config_data = json.load(f)
81
+
82
+ for key, item in config_data.items():
83
+ try:
84
+ # 构造 server_name: http://host:port/v1
85
+ host = item.get("host", "127.0.0.1")
86
+ port = item.get("port", 8080)
87
+ server_name = f"http://{host}:{port}/v1"
88
+
89
+ rag_config = RAGConfig(
90
+ name=item.get("name", key),
91
+ server_name=server_name,
92
+ api_key=None, # 全局配置中没有 api_key
93
+ description=item.get("description", f"{key} RAG 服务")
94
+ )
95
+ self.configs.append(rag_config)
96
+ logger.info(f"已加载 RAG 配置: {rag_config.name} -> {rag_config.server_name}")
97
+ except Exception as e:
98
+ logger.error(f"解析全局 RAG 配置项时出错: {e}, 配置项: {item}")
99
+
100
+ except json.JSONDecodeError as e:
101
+ logger.error(f"全局 RAG 配置文件 JSON 格式错误: {e}")
102
+ except Exception as e:
103
+ logger.error(f"读取全局 RAG 配置文件时出错: {e}")
104
+
105
+ def get_all_configs(self) -> List[RAGConfig]:
106
+ """获取所有 RAG 配置"""
107
+ return self.configs
108
+
109
+ def get_config_by_name(self, name: str) -> Optional[RAGConfig]:
110
+ """根据名称获取特定的 RAG 配置"""
111
+ for config in self.configs:
112
+ if config.name == name:
113
+ return config
114
+ return None
115
+
116
+ def get_server_names(self) -> List[str]:
117
+ """获取所有服务器名称列表"""
118
+ return [config.server_name for config in self.configs]
119
+
120
+ def get_config_info(self) -> str:
121
+ """获取格式化的配置信息,用于显示"""
122
+ if not self.configs:
123
+ return "未找到可用的 RAG 服务器配置"
124
+
125
+ info_lines = []
126
+ info_lines.append("可用的 RAG 服务器配置")
127
+
128
+ for i, config in enumerate(self.configs, 1):
129
+ info_lines.append(f"\n{i}. 配置名称: {config.name}")
130
+ info_lines.append(f" 服务器地址: {config.server_name}")
131
+
132
+ if config.description:
133
+ info_lines.append(f" 描述信息: {config.description}")
134
+ else:
135
+ info_lines.append(f" 描述信息: 无")
136
+
137
+ if i < len(self.configs):
138
+ info_lines.append("-" * 30)
139
+
140
+ return "\n".join(info_lines)
141
+
142
+ def has_configs(self) -> bool:
143
+ """检查是否有可用的配置"""
144
+ return len(self.configs) > 0