jarvis-ai-assistant 0.7.16__py3-none-any.whl → 1.0.2__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.
Files changed (279) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +567 -222
  3. jarvis/jarvis_agent/agent_manager.py +19 -12
  4. jarvis/jarvis_agent/builtin_input_handler.py +79 -11
  5. jarvis/jarvis_agent/config_editor.py +7 -2
  6. jarvis/jarvis_agent/event_bus.py +24 -13
  7. jarvis/jarvis_agent/events.py +19 -1
  8. jarvis/jarvis_agent/file_context_handler.py +67 -64
  9. jarvis/jarvis_agent/file_methodology_manager.py +38 -24
  10. jarvis/jarvis_agent/jarvis.py +186 -114
  11. jarvis/jarvis_agent/language_extractors/__init__.py +8 -1
  12. jarvis/jarvis_agent/language_extractors/c_extractor.py +7 -4
  13. jarvis/jarvis_agent/language_extractors/cpp_extractor.py +9 -4
  14. jarvis/jarvis_agent/language_extractors/go_extractor.py +7 -4
  15. jarvis/jarvis_agent/language_extractors/java_extractor.py +27 -20
  16. jarvis/jarvis_agent/language_extractors/javascript_extractor.py +22 -17
  17. jarvis/jarvis_agent/language_extractors/python_extractor.py +7 -4
  18. jarvis/jarvis_agent/language_extractors/rust_extractor.py +7 -4
  19. jarvis/jarvis_agent/language_extractors/typescript_extractor.py +22 -17
  20. jarvis/jarvis_agent/language_support_info.py +250 -219
  21. jarvis/jarvis_agent/main.py +19 -23
  22. jarvis/jarvis_agent/memory_manager.py +9 -6
  23. jarvis/jarvis_agent/methodology_share_manager.py +21 -15
  24. jarvis/jarvis_agent/output_handler.py +4 -2
  25. jarvis/jarvis_agent/prompt_builder.py +7 -6
  26. jarvis/jarvis_agent/prompt_manager.py +113 -8
  27. jarvis/jarvis_agent/prompts.py +317 -85
  28. jarvis/jarvis_agent/protocols.py +5 -2
  29. jarvis/jarvis_agent/run_loop.py +192 -32
  30. jarvis/jarvis_agent/session_manager.py +7 -3
  31. jarvis/jarvis_agent/share_manager.py +23 -13
  32. jarvis/jarvis_agent/shell_input_handler.py +12 -8
  33. jarvis/jarvis_agent/stdio_redirect.py +25 -26
  34. jarvis/jarvis_agent/task_analyzer.py +29 -23
  35. jarvis/jarvis_agent/task_list.py +869 -0
  36. jarvis/jarvis_agent/task_manager.py +26 -23
  37. jarvis/jarvis_agent/tool_executor.py +6 -5
  38. jarvis/jarvis_agent/tool_share_manager.py +24 -14
  39. jarvis/jarvis_agent/user_interaction.py +3 -3
  40. jarvis/jarvis_agent/utils.py +9 -1
  41. jarvis/jarvis_agent/web_bridge.py +37 -17
  42. jarvis/jarvis_agent/web_output_sink.py +5 -2
  43. jarvis/jarvis_agent/web_server.py +165 -36
  44. jarvis/jarvis_c2rust/__init__.py +1 -1
  45. jarvis/jarvis_c2rust/cli.py +260 -141
  46. jarvis/jarvis_c2rust/collector.py +37 -18
  47. jarvis/jarvis_c2rust/constants.py +60 -0
  48. jarvis/jarvis_c2rust/library_replacer.py +242 -1010
  49. jarvis/jarvis_c2rust/library_replacer_checkpoint.py +133 -0
  50. jarvis/jarvis_c2rust/library_replacer_llm.py +287 -0
  51. jarvis/jarvis_c2rust/library_replacer_loader.py +191 -0
  52. jarvis/jarvis_c2rust/library_replacer_output.py +134 -0
  53. jarvis/jarvis_c2rust/library_replacer_prompts.py +124 -0
  54. jarvis/jarvis_c2rust/library_replacer_utils.py +188 -0
  55. jarvis/jarvis_c2rust/llm_module_agent.py +98 -1044
  56. jarvis/jarvis_c2rust/llm_module_agent_apply.py +170 -0
  57. jarvis/jarvis_c2rust/llm_module_agent_executor.py +288 -0
  58. jarvis/jarvis_c2rust/llm_module_agent_loader.py +170 -0
  59. jarvis/jarvis_c2rust/llm_module_agent_prompts.py +268 -0
  60. jarvis/jarvis_c2rust/llm_module_agent_types.py +57 -0
  61. jarvis/jarvis_c2rust/llm_module_agent_utils.py +150 -0
  62. jarvis/jarvis_c2rust/llm_module_agent_validator.py +119 -0
  63. jarvis/jarvis_c2rust/loaders.py +28 -10
  64. jarvis/jarvis_c2rust/models.py +5 -2
  65. jarvis/jarvis_c2rust/optimizer.py +192 -1974
  66. jarvis/jarvis_c2rust/optimizer_build_fix.py +286 -0
  67. jarvis/jarvis_c2rust/optimizer_clippy.py +766 -0
  68. jarvis/jarvis_c2rust/optimizer_config.py +49 -0
  69. jarvis/jarvis_c2rust/optimizer_docs.py +183 -0
  70. jarvis/jarvis_c2rust/optimizer_options.py +48 -0
  71. jarvis/jarvis_c2rust/optimizer_progress.py +469 -0
  72. jarvis/jarvis_c2rust/optimizer_report.py +52 -0
  73. jarvis/jarvis_c2rust/optimizer_unsafe.py +309 -0
  74. jarvis/jarvis_c2rust/optimizer_utils.py +469 -0
  75. jarvis/jarvis_c2rust/optimizer_visibility.py +185 -0
  76. jarvis/jarvis_c2rust/scanner.py +229 -166
  77. jarvis/jarvis_c2rust/transpiler.py +531 -2732
  78. jarvis/jarvis_c2rust/transpiler_agents.py +503 -0
  79. jarvis/jarvis_c2rust/transpiler_build.py +1294 -0
  80. jarvis/jarvis_c2rust/transpiler_codegen.py +204 -0
  81. jarvis/jarvis_c2rust/transpiler_compile.py +146 -0
  82. jarvis/jarvis_c2rust/transpiler_config.py +178 -0
  83. jarvis/jarvis_c2rust/transpiler_context.py +122 -0
  84. jarvis/jarvis_c2rust/transpiler_executor.py +516 -0
  85. jarvis/jarvis_c2rust/transpiler_generation.py +278 -0
  86. jarvis/jarvis_c2rust/transpiler_git.py +163 -0
  87. jarvis/jarvis_c2rust/transpiler_mod_utils.py +225 -0
  88. jarvis/jarvis_c2rust/transpiler_modules.py +336 -0
  89. jarvis/jarvis_c2rust/transpiler_planning.py +394 -0
  90. jarvis/jarvis_c2rust/transpiler_review.py +1196 -0
  91. jarvis/jarvis_c2rust/transpiler_symbols.py +176 -0
  92. jarvis/jarvis_c2rust/utils.py +269 -79
  93. jarvis/jarvis_code_agent/after_change.py +233 -0
  94. jarvis/jarvis_code_agent/build_validation_config.py +37 -30
  95. jarvis/jarvis_code_agent/builtin_rules.py +68 -0
  96. jarvis/jarvis_code_agent/code_agent.py +976 -1517
  97. jarvis/jarvis_code_agent/code_agent_build.py +227 -0
  98. jarvis/jarvis_code_agent/code_agent_diff.py +246 -0
  99. jarvis/jarvis_code_agent/code_agent_git.py +525 -0
  100. jarvis/jarvis_code_agent/code_agent_impact.py +177 -0
  101. jarvis/jarvis_code_agent/code_agent_lint.py +283 -0
  102. jarvis/jarvis_code_agent/code_agent_llm.py +159 -0
  103. jarvis/jarvis_code_agent/code_agent_postprocess.py +105 -0
  104. jarvis/jarvis_code_agent/code_agent_prompts.py +46 -0
  105. jarvis/jarvis_code_agent/code_agent_rules.py +305 -0
  106. jarvis/jarvis_code_agent/code_analyzer/__init__.py +52 -48
  107. jarvis/jarvis_code_agent/code_analyzer/base_language.py +12 -10
  108. jarvis/jarvis_code_agent/code_analyzer/build_validator/__init__.py +12 -11
  109. jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +16 -12
  110. jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +26 -17
  111. jarvis/jarvis_code_agent/code_analyzer/build_validator/detector.py +558 -104
  112. jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +27 -16
  113. jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +22 -18
  114. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +21 -16
  115. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +20 -16
  116. jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +27 -16
  117. jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +47 -23
  118. jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +71 -37
  119. jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +162 -35
  120. jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +111 -57
  121. jarvis/jarvis_code_agent/code_analyzer/build_validator.py +18 -12
  122. jarvis/jarvis_code_agent/code_analyzer/context_manager.py +185 -183
  123. jarvis/jarvis_code_agent/code_analyzer/context_recommender.py +2 -1
  124. jarvis/jarvis_code_agent/code_analyzer/dependency_analyzer.py +24 -15
  125. jarvis/jarvis_code_agent/code_analyzer/file_ignore.py +227 -141
  126. jarvis/jarvis_code_agent/code_analyzer/impact_analyzer.py +321 -247
  127. jarvis/jarvis_code_agent/code_analyzer/language_registry.py +37 -29
  128. jarvis/jarvis_code_agent/code_analyzer/language_support.py +21 -13
  129. jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +15 -9
  130. jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +75 -45
  131. jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +87 -52
  132. jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +84 -51
  133. jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +94 -64
  134. jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +109 -71
  135. jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +97 -63
  136. jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +103 -69
  137. jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +271 -268
  138. jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +76 -64
  139. jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +92 -19
  140. jarvis/jarvis_code_agent/diff_visualizer.py +998 -0
  141. jarvis/jarvis_code_agent/lint.py +223 -524
  142. jarvis/jarvis_code_agent/rule_share_manager.py +158 -0
  143. jarvis/jarvis_code_agent/rules/clean_code.md +144 -0
  144. jarvis/jarvis_code_agent/rules/code_review.md +115 -0
  145. jarvis/jarvis_code_agent/rules/documentation.md +165 -0
  146. jarvis/jarvis_code_agent/rules/generate_rules.md +52 -0
  147. jarvis/jarvis_code_agent/rules/performance.md +158 -0
  148. jarvis/jarvis_code_agent/rules/refactoring.md +139 -0
  149. jarvis/jarvis_code_agent/rules/security.md +160 -0
  150. jarvis/jarvis_code_agent/rules/tdd.md +78 -0
  151. jarvis/jarvis_code_agent/test_rules/cpp_test.md +118 -0
  152. jarvis/jarvis_code_agent/test_rules/go_test.md +98 -0
  153. jarvis/jarvis_code_agent/test_rules/java_test.md +99 -0
  154. jarvis/jarvis_code_agent/test_rules/javascript_test.md +113 -0
  155. jarvis/jarvis_code_agent/test_rules/php_test.md +117 -0
  156. jarvis/jarvis_code_agent/test_rules/python_test.md +91 -0
  157. jarvis/jarvis_code_agent/test_rules/ruby_test.md +102 -0
  158. jarvis/jarvis_code_agent/test_rules/rust_test.md +86 -0
  159. jarvis/jarvis_code_agent/utils.py +36 -26
  160. jarvis/jarvis_code_analysis/checklists/loader.py +21 -21
  161. jarvis/jarvis_code_analysis/code_review.py +64 -33
  162. jarvis/jarvis_data/config_schema.json +285 -192
  163. jarvis/jarvis_git_squash/main.py +8 -6
  164. jarvis/jarvis_git_utils/git_commiter.py +53 -76
  165. jarvis/jarvis_mcp/__init__.py +5 -2
  166. jarvis/jarvis_mcp/sse_mcp_client.py +40 -30
  167. jarvis/jarvis_mcp/stdio_mcp_client.py +27 -19
  168. jarvis/jarvis_mcp/streamable_mcp_client.py +35 -26
  169. jarvis/jarvis_memory_organizer/memory_organizer.py +78 -55
  170. jarvis/jarvis_methodology/main.py +48 -39
  171. jarvis/jarvis_multi_agent/__init__.py +56 -23
  172. jarvis/jarvis_multi_agent/main.py +15 -18
  173. jarvis/jarvis_platform/base.py +179 -111
  174. jarvis/jarvis_platform/human.py +27 -16
  175. jarvis/jarvis_platform/kimi.py +52 -45
  176. jarvis/jarvis_platform/openai.py +101 -40
  177. jarvis/jarvis_platform/registry.py +51 -33
  178. jarvis/jarvis_platform/tongyi.py +68 -38
  179. jarvis/jarvis_platform/yuanbao.py +59 -43
  180. jarvis/jarvis_platform_manager/main.py +68 -76
  181. jarvis/jarvis_platform_manager/service.py +24 -14
  182. jarvis/jarvis_rag/README_CONFIG.md +314 -0
  183. jarvis/jarvis_rag/README_DYNAMIC_LOADING.md +311 -0
  184. jarvis/jarvis_rag/README_ONLINE_MODELS.md +230 -0
  185. jarvis/jarvis_rag/__init__.py +57 -4
  186. jarvis/jarvis_rag/cache.py +3 -1
  187. jarvis/jarvis_rag/cli.py +48 -68
  188. jarvis/jarvis_rag/embedding_interface.py +39 -0
  189. jarvis/jarvis_rag/embedding_manager.py +7 -230
  190. jarvis/jarvis_rag/embeddings/__init__.py +41 -0
  191. jarvis/jarvis_rag/embeddings/base.py +114 -0
  192. jarvis/jarvis_rag/embeddings/cohere.py +66 -0
  193. jarvis/jarvis_rag/embeddings/edgefn.py +117 -0
  194. jarvis/jarvis_rag/embeddings/local.py +260 -0
  195. jarvis/jarvis_rag/embeddings/openai.py +62 -0
  196. jarvis/jarvis_rag/embeddings/registry.py +293 -0
  197. jarvis/jarvis_rag/llm_interface.py +8 -6
  198. jarvis/jarvis_rag/query_rewriter.py +8 -9
  199. jarvis/jarvis_rag/rag_pipeline.py +61 -52
  200. jarvis/jarvis_rag/reranker.py +7 -75
  201. jarvis/jarvis_rag/reranker_interface.py +32 -0
  202. jarvis/jarvis_rag/rerankers/__init__.py +41 -0
  203. jarvis/jarvis_rag/rerankers/base.py +109 -0
  204. jarvis/jarvis_rag/rerankers/cohere.py +67 -0
  205. jarvis/jarvis_rag/rerankers/edgefn.py +140 -0
  206. jarvis/jarvis_rag/rerankers/jina.py +79 -0
  207. jarvis/jarvis_rag/rerankers/local.py +89 -0
  208. jarvis/jarvis_rag/rerankers/registry.py +293 -0
  209. jarvis/jarvis_rag/retriever.py +58 -43
  210. jarvis/jarvis_sec/__init__.py +66 -141
  211. jarvis/jarvis_sec/agents.py +21 -17
  212. jarvis/jarvis_sec/analysis.py +80 -33
  213. jarvis/jarvis_sec/checkers/__init__.py +7 -13
  214. jarvis/jarvis_sec/checkers/c_checker.py +356 -164
  215. jarvis/jarvis_sec/checkers/rust_checker.py +47 -29
  216. jarvis/jarvis_sec/cli.py +43 -21
  217. jarvis/jarvis_sec/clustering.py +430 -272
  218. jarvis/jarvis_sec/file_manager.py +99 -55
  219. jarvis/jarvis_sec/parsers.py +9 -6
  220. jarvis/jarvis_sec/prompts.py +4 -3
  221. jarvis/jarvis_sec/report.py +44 -22
  222. jarvis/jarvis_sec/review.py +180 -107
  223. jarvis/jarvis_sec/status.py +50 -41
  224. jarvis/jarvis_sec/types.py +3 -0
  225. jarvis/jarvis_sec/utils.py +160 -83
  226. jarvis/jarvis_sec/verification.py +411 -181
  227. jarvis/jarvis_sec/workflow.py +132 -21
  228. jarvis/jarvis_smart_shell/main.py +28 -41
  229. jarvis/jarvis_stats/cli.py +14 -12
  230. jarvis/jarvis_stats/stats.py +28 -19
  231. jarvis/jarvis_stats/storage.py +14 -8
  232. jarvis/jarvis_stats/visualizer.py +12 -7
  233. jarvis/jarvis_tools/base.py +5 -2
  234. jarvis/jarvis_tools/clear_memory.py +13 -9
  235. jarvis/jarvis_tools/cli/main.py +23 -18
  236. jarvis/jarvis_tools/edit_file.py +572 -873
  237. jarvis/jarvis_tools/execute_script.py +10 -7
  238. jarvis/jarvis_tools/file_analyzer.py +7 -8
  239. jarvis/jarvis_tools/meta_agent.py +287 -0
  240. jarvis/jarvis_tools/methodology.py +5 -3
  241. jarvis/jarvis_tools/read_code.py +305 -1438
  242. jarvis/jarvis_tools/read_symbols.py +50 -17
  243. jarvis/jarvis_tools/read_webpage.py +19 -18
  244. jarvis/jarvis_tools/registry.py +435 -156
  245. jarvis/jarvis_tools/retrieve_memory.py +16 -11
  246. jarvis/jarvis_tools/save_memory.py +8 -6
  247. jarvis/jarvis_tools/search_web.py +31 -31
  248. jarvis/jarvis_tools/sub_agent.py +32 -28
  249. jarvis/jarvis_tools/sub_code_agent.py +44 -60
  250. jarvis/jarvis_tools/task_list_manager.py +1811 -0
  251. jarvis/jarvis_tools/virtual_tty.py +29 -19
  252. jarvis/jarvis_utils/__init__.py +4 -0
  253. jarvis/jarvis_utils/builtin_replace_map.py +2 -1
  254. jarvis/jarvis_utils/clipboard.py +9 -8
  255. jarvis/jarvis_utils/collections.py +331 -0
  256. jarvis/jarvis_utils/config.py +699 -194
  257. jarvis/jarvis_utils/dialogue_recorder.py +294 -0
  258. jarvis/jarvis_utils/embedding.py +6 -3
  259. jarvis/jarvis_utils/file_processors.py +7 -1
  260. jarvis/jarvis_utils/fzf.py +9 -3
  261. jarvis/jarvis_utils/git_utils.py +71 -42
  262. jarvis/jarvis_utils/globals.py +116 -32
  263. jarvis/jarvis_utils/http.py +6 -2
  264. jarvis/jarvis_utils/input.py +318 -83
  265. jarvis/jarvis_utils/jsonnet_compat.py +119 -104
  266. jarvis/jarvis_utils/methodology.py +37 -28
  267. jarvis/jarvis_utils/output.py +201 -44
  268. jarvis/jarvis_utils/utils.py +986 -628
  269. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/METADATA +49 -33
  270. jarvis_ai_assistant-1.0.2.dist-info/RECORD +304 -0
  271. jarvis/jarvis_code_agent/code_analyzer/structured_code.py +0 -556
  272. jarvis/jarvis_tools/generate_new_tool.py +0 -205
  273. jarvis/jarvis_tools/lsp_client.py +0 -1552
  274. jarvis/jarvis_tools/rewrite_file.py +0 -105
  275. jarvis_ai_assistant-0.7.16.dist-info/RECORD +0 -218
  276. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/WHEEL +0 -0
  277. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/entry_points.txt +0 -0
  278. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/licenses/LICENSE +0 -0
  279. {jarvis_ai_assistant-0.7.16.dist-info → jarvis_ai_assistant-1.0.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,140 @@
1
+ """
2
+ EdgeFn 重排模型实现。
3
+ """
4
+
5
+ from typing import List
6
+ from typing import Optional
7
+
8
+ from .base import OnlineReranker
9
+
10
+
11
+ class EdgeFnReranker(OnlineReranker):
12
+ """
13
+ EdgeFn 重排模型的实现。
14
+
15
+ 使用 EdgeFn 的 rerank API。
16
+ """
17
+
18
+ def __init__(
19
+ self,
20
+ api_key: Optional[str] = None,
21
+ model_name: str = "bge-reranker-v2-m3",
22
+ base_url: str = "https://api.edgefn.net/v1/rerank",
23
+ **kwargs,
24
+ ):
25
+ """
26
+ 初始化 EdgeFn 重排模型。
27
+
28
+ 参数:
29
+ api_key: EdgeFn API密钥。如果为None,将从EDGEFN_API_KEY环境变量读取。
30
+ model_name: 要使用的模型名称(如 'bge-reranker-v2-m3')。
31
+ base_url: API的基础URL。
32
+ **kwargs: 传递给父类的其他参数。
33
+ """
34
+ super().__init__(
35
+ api_key=api_key,
36
+ api_key_env="EDGEFN_API_KEY",
37
+ base_url=base_url,
38
+ model_name=model_name,
39
+ **kwargs,
40
+ )
41
+
42
+ def _call_api(self, query: str, documents: List[str]) -> List[tuple[int, float]]:
43
+ """
44
+ 调用 EdgeFn API 获取重排分数。
45
+
46
+ 参数:
47
+ query: 查询文本。
48
+ documents: 文档文本列表。
49
+
50
+ 返回:
51
+ 包含 (索引, 分数) 元组的列表,按分数降序排序。
52
+ """
53
+ try:
54
+ import requests
55
+
56
+ headers = {
57
+ "Authorization": f"Bearer {self.api_key}",
58
+ "Content-Type": "application/json",
59
+ }
60
+
61
+ payload = {
62
+ "model": self.model_name,
63
+ "query": query,
64
+ "documents": documents,
65
+ }
66
+
67
+ response = requests.post(
68
+ self.base_url, json=payload, headers=headers, timeout=60
69
+ )
70
+ response.raise_for_status()
71
+
72
+ data = response.json()
73
+
74
+ # EdgeFn API 返回格式可能是多种形式,需要处理不同的格式
75
+ # 可能的格式:
76
+ # 1. {"results": [{"index": 0, "score": 0.95}, ...]}
77
+ # 2. {"results": [{"index": 0, "relevance_score": 0.95}, ...]}
78
+ # 3. {"data": [{"index": 0, "score": 0.95}, ...]}
79
+ # 4. 直接返回列表: [{"index": 0, "score": 0.95}, ...]
80
+
81
+ results = []
82
+ if "results" in data:
83
+ # 格式1和2: 使用 results 字段
84
+ for item in data["results"]:
85
+ index = item.get("index", item.get("rank", 0))
86
+ # 尝试不同的分数字段名
87
+ score = item.get(
88
+ "score",
89
+ item.get("relevance_score", item.get("relevance", 0.0)),
90
+ )
91
+ results.append((index, float(score)))
92
+ elif "data" in data:
93
+ # 格式3: 使用 data 字段
94
+ for item in data["data"]:
95
+ index = item.get("index", item.get("rank", 0))
96
+ score = item.get(
97
+ "score",
98
+ item.get("relevance_score", item.get("relevance", 0.0)),
99
+ )
100
+ results.append((index, float(score)))
101
+ elif isinstance(data, list):
102
+ # 格式4: 直接是列表
103
+ for item in data:
104
+ if isinstance(item, dict):
105
+ index = item.get("index", item.get("rank", 0))
106
+ score = item.get(
107
+ "score",
108
+ item.get("relevance_score", item.get("relevance", 0.0)),
109
+ )
110
+ if score is None:
111
+ score = 0.0
112
+ results.append((index, float(score)))
113
+ elif isinstance(item, (int, float)):
114
+ # 如果直接是分数列表,使用索引作为位置
115
+ results.append((len(results), float(item)))
116
+ else:
117
+ raise ValueError(
118
+ f"EdgeFn API 返回了意外的格式。响应键: {list(data.keys()) if isinstance(data, dict) else '非字典类型'}"
119
+ )
120
+
121
+ # 按分数降序排序
122
+ results.sort(key=lambda x: x[1], reverse=True)
123
+
124
+ return results
125
+
126
+ except ImportError:
127
+ raise ImportError(
128
+ "使用 EdgeFnReranker 需要安装 requests 包: pip install requests"
129
+ )
130
+ except requests.exceptions.RequestException as e:
131
+ error_msg = str(e)
132
+ if hasattr(e, "response") and e.response is not None:
133
+ try:
134
+ error_detail = e.response.json()
135
+ error_msg = f"{error_msg} - 详情: {error_detail}"
136
+ except Exception:
137
+ error_msg = f"{error_msg} - 响应状态码: {e.response.status_code}"
138
+ raise RuntimeError(f"调用 EdgeFn API 时出错: {error_msg}")
139
+ except Exception as e:
140
+ raise RuntimeError(f"处理 EdgeFn API 响应时出错: {e}")
@@ -0,0 +1,79 @@
1
+ """
2
+ Jina 重排模型实现。
3
+ """
4
+
5
+ from typing import List
6
+ from typing import Optional
7
+
8
+ from .base import OnlineReranker
9
+
10
+
11
+ class JinaReranker(OnlineReranker):
12
+ """
13
+ Jina 重排模型的实现。
14
+
15
+ 使用 Jina 的 rerank API。
16
+ """
17
+
18
+ def __init__(
19
+ self,
20
+ api_key: Optional[str] = None,
21
+ model_name: str = "jina-reranker-v1-base-en",
22
+ base_url: str = "https://api.jina.ai/v1/rerank",
23
+ **kwargs,
24
+ ):
25
+ """
26
+ 初始化 Jina 重排模型。
27
+
28
+ 参数:
29
+ api_key: Jina API密钥。如果为None,将从JINA_API_KEY环境变量读取。
30
+ model_name: 要使用的模型名称。
31
+ base_url: API的基础URL。
32
+ **kwargs: 传递给父类的其他参数。
33
+ """
34
+ super().__init__(
35
+ api_key=api_key,
36
+ api_key_env="JINA_API_KEY",
37
+ base_url=base_url,
38
+ model_name=model_name,
39
+ **kwargs,
40
+ )
41
+
42
+ def _call_api(self, query: str, documents: List[str]) -> List[tuple[int, float]]:
43
+ """
44
+ 调用 Jina API 获取重排分数。
45
+ """
46
+ try:
47
+ import requests
48
+
49
+ headers = {
50
+ "Content-Type": "application/json",
51
+ "Authorization": f"Bearer {self.api_key}",
52
+ }
53
+
54
+ payload = {
55
+ "model": self.model_name,
56
+ "query": query,
57
+ "documents": documents,
58
+ "top_n": len(documents),
59
+ }
60
+
61
+ response = requests.post(self.base_url, json=payload, headers=headers)
62
+ response.raise_for_status()
63
+
64
+ data = response.json()
65
+
66
+ # Jina API 返回格式: {"results": [{"index": 0, "relevance_score": 0.95}, ...]}
67
+ results = [
68
+ (item["index"], item["relevance_score"])
69
+ for item in data.get("results", [])
70
+ ]
71
+ results.sort(key=lambda x: x[1], reverse=True)
72
+
73
+ return results
74
+ except ImportError:
75
+ raise ImportError(
76
+ "使用 JinaReranker 需要安装 requests 包: pip install requests"
77
+ )
78
+ except Exception as e:
79
+ raise RuntimeError(f"调用 Jina API 时出错: {e}")
@@ -0,0 +1,89 @@
1
+ """
2
+ 本地重排模型实现。
3
+ """
4
+
5
+ from jarvis.jarvis_utils.output import PrettyOutput
6
+
7
+ import os
8
+ from typing import List
9
+ from typing import Optional
10
+
11
+ from huggingface_hub import snapshot_download
12
+ from langchain.docstore.document import Document
13
+ from sentence_transformers.cross_encoder import CrossEncoder
14
+
15
+ from ..reranker_interface import RerankerInterface
16
+
17
+
18
+ class LocalReranker(RerankerInterface):
19
+ """
20
+ 一个重排器类,使用Cross-Encoder模型根据文档与给定查询的相关性
21
+ 对文档进行重新评分和排序。
22
+
23
+ 这是 RerankerInterface 的本地实现,使用 sentence-transformers CrossEncoder。
24
+ """
25
+
26
+ def __init__(self, model_name: str, max_length: Optional[int] = None):
27
+ """
28
+ 初始化重排器。
29
+
30
+ 参数:
31
+ model_name (str): 要使用的Cross-Encoder模型的名称。
32
+ max_length: 模型的最大输入长度(token数),用于文档处理。
33
+ """
34
+ self.max_length = max_length
35
+ PrettyOutput.auto_print(f"ℹ️ 正在初始化重排模型: {model_name}...")
36
+ try:
37
+ local_dir = None
38
+
39
+ if os.path.isdir(model_name):
40
+ self.model = CrossEncoder(model_name)
41
+ PrettyOutput.auto_print("✅ 重排模型初始化成功。")
42
+ return
43
+ try:
44
+ # Prefer local cache; avoid any network access
45
+ local_dir = snapshot_download(repo_id=model_name, local_files_only=True)
46
+ except Exception:
47
+ local_dir = None
48
+
49
+ if local_dir:
50
+ self.model = CrossEncoder(local_dir)
51
+ else:
52
+ self.model = CrossEncoder(model_name)
53
+
54
+ PrettyOutput.auto_print("✅ 重排模型初始化成功。")
55
+ except Exception as e:
56
+ PrettyOutput.auto_print(f"❌ 初始化重排模型失败: {e}")
57
+ raise
58
+
59
+ def rerank(
60
+ self, query: str, documents: List[Document], top_n: int = 5
61
+ ) -> List[Document]:
62
+ """
63
+ 根据文档与查询的相关性对文档列表进行重排。
64
+
65
+ 参数:
66
+ query (str): 用户的查询。
67
+ documents (List[Document]): 从初始搜索中检索到的文档列表。
68
+ top_n (int): 重排后要返回的顶部文档数。
69
+
70
+ 返回:
71
+ List[Document]: 一个已排序的最相关文档列表。
72
+ """
73
+ if not documents:
74
+ return []
75
+
76
+ # 创建 [查询, 文档内容] 对用于评分
77
+ pairs = [[query, doc.page_content] for doc in documents]
78
+
79
+ # 从Cross-Encoder模型获取分数
80
+ scores = self.model.predict(pairs)
81
+
82
+ # 将文档与它们的分数结合并排序
83
+ doc_with_scores = list(zip(documents, scores))
84
+ doc_with_scores.sort(key=lambda x: x[1], reverse=True)
85
+
86
+ # 返回前N个文档
87
+ reranked_docs = [doc for doc, score in doc_with_scores[:top_n]]
88
+
89
+ return reranked_docs
@@ -0,0 +1,293 @@
1
+ """
2
+ 重排模型注册表,支持动态加载自定义重排模型实现。
3
+ """
4
+
5
+ import importlib
6
+ import inspect
7
+
8
+ from jarvis.jarvis_utils.output import PrettyOutput
9
+
10
+ # -*- coding: utf-8 -*-
11
+ import os
12
+ import sys
13
+ from typing import Dict
14
+ from typing import List
15
+ from typing import Optional
16
+ from typing import Type
17
+
18
+ from jarvis.jarvis_utils.config import get_data_dir
19
+
20
+ from ..reranker_interface import RerankerInterface
21
+
22
+
23
+ class RerankerRegistry:
24
+ """重排模型注册表,支持动态加载自定义重排模型实现"""
25
+
26
+ global_registry: Optional["RerankerRegistry"] = None
27
+
28
+ @staticmethod
29
+ def get_reranker_dir() -> str:
30
+ """获取用户自定义重排模型目录"""
31
+ reranker_dir = os.path.join(get_data_dir(), "rerankers")
32
+ if not os.path.exists(reranker_dir):
33
+ try:
34
+ os.makedirs(reranker_dir)
35
+ # 创建 __init__.py 使其成为 Python 包
36
+ with open(
37
+ os.path.join(reranker_dir, "__init__.py"), "w", errors="ignore"
38
+ ):
39
+ pass
40
+ except Exception as e:
41
+ PrettyOutput.auto_print(f"❌ 创建重排模型目录失败: {str(e)}")
42
+ return ""
43
+ return reranker_dir
44
+
45
+ @staticmethod
46
+ def check_reranker_implementation(
47
+ reranker_class: Type[RerankerInterface],
48
+ ) -> bool:
49
+ """检查重排模型类是否实现了所有必需的方法
50
+
51
+ 参数:
52
+ reranker_class: 要检查的重排模型类
53
+
54
+ 返回:
55
+ bool: 是否实现了所有必需的方法
56
+ """
57
+ required_methods = [
58
+ ("rerank", ["query", "documents", "top_n"]),
59
+ ]
60
+
61
+ missing_methods = []
62
+
63
+ for method_name, params in required_methods:
64
+ if not hasattr(reranker_class, method_name):
65
+ missing_methods.append(method_name)
66
+ continue
67
+
68
+ method = getattr(reranker_class, method_name)
69
+ if not callable(method):
70
+ missing_methods.append(method_name)
71
+ continue
72
+
73
+ # 检查方法参数(允许有默认值)
74
+ sig = inspect.signature(method)
75
+ method_params = [p for p in sig.parameters if p != "self"]
76
+ # 检查必需参数数量(不考虑有默认值的参数)
77
+ required_params = [
78
+ p
79
+ for p in method_params
80
+ if sig.parameters[p].default == inspect.Parameter.empty
81
+ ]
82
+ # rerank 方法需要至少 2 个必需参数(query 和 documents),top_n 可以有默认值
83
+ if method_name == "rerank":
84
+ if len(required_params) < 2:
85
+ missing_methods.append(f"{method_name}(parameter mismatch)")
86
+ elif len(required_params) < len(params):
87
+ missing_methods.append(f"{method_name}(parameter mismatch)")
88
+
89
+ if missing_methods:
90
+ PrettyOutput.auto_print(
91
+ f"⚠️ 重排模型 {reranker_class.__name__} 缺少必要的方法: {', '.join(missing_methods)}"
92
+ )
93
+ return False
94
+
95
+ return True
96
+
97
+ @staticmethod
98
+ def load_rerankers_from_dir(
99
+ directory: str,
100
+ ) -> Dict[str, Type[RerankerInterface]]:
101
+ """从指定目录加载重排模型
102
+
103
+ 参数:
104
+ directory: 重排模型目录路径
105
+
106
+ 返回:
107
+ Dict[str, Type[RerankerInterface]]: 重排模型名称到类的映射
108
+ """
109
+ rerankers: Dict[str, Type[RerankerInterface]] = {}
110
+
111
+ # 确保目录存在
112
+ if not os.path.exists(directory):
113
+ PrettyOutput.auto_print(f"⚠️ 重排模型目录不存在: {directory}")
114
+ return rerankers
115
+
116
+ # 获取目录的包名
117
+ package_name = None
118
+ if directory == os.path.dirname(__file__):
119
+ package_name = "jarvis.jarvis_rag.rerankers"
120
+
121
+ # 添加目录到Python路径
122
+ if directory not in sys.path:
123
+ sys.path.append(directory)
124
+
125
+ error_lines = []
126
+ # 遍历目录下的所有.py文件
127
+ for filename in os.listdir(directory):
128
+ if filename.endswith(".py") and not filename.startswith("__"):
129
+ module_name = filename[:-3] # 移除.py后缀
130
+ try:
131
+ # 导入模块
132
+ if package_name:
133
+ module = importlib.import_module(
134
+ f"{package_name}.{module_name}"
135
+ )
136
+ else:
137
+ module = importlib.import_module(module_name)
138
+
139
+ # 遍历模块中的所有类
140
+ for _, obj in inspect.getmembers(module):
141
+ # 检查是否是RerankerInterface的子类,但不是RerankerInterface本身
142
+ if (
143
+ inspect.isclass(obj)
144
+ and issubclass(obj, RerankerInterface)
145
+ and obj != RerankerInterface
146
+ ):
147
+ # 检查重排模型实现
148
+ if not RerankerRegistry.check_reranker_implementation(obj):
149
+ continue
150
+ try:
151
+ # 使用类名作为注册名(可以后续扩展为使用类方法获取名称)
152
+ reranker_name = obj.__name__
153
+ rerankers[reranker_name] = obj
154
+ except Exception as e:
155
+ error_lines.append(
156
+ f"注册重排模型失败 {obj.__name__}: {str(e)}"
157
+ )
158
+ except Exception as e:
159
+ error_lines.append(f"加载重排模型 {module_name} 失败: {str(e)}")
160
+
161
+ if error_lines:
162
+ joined_errors = "\n".join(error_lines)
163
+ PrettyOutput.auto_print(f"❌ {joined_errors}")
164
+ return rerankers
165
+
166
+ @staticmethod
167
+ def get_global_registry() -> "RerankerRegistry":
168
+ """获取全局重排模型注册表"""
169
+ if RerankerRegistry.global_registry is None:
170
+ RerankerRegistry.global_registry = RerankerRegistry()
171
+ return RerankerRegistry.global_registry
172
+
173
+ def __init__(self) -> None:
174
+ """初始化重排模型注册表"""
175
+ self.rerankers: Dict[str, Type[RerankerInterface]] = {}
176
+
177
+ # 从用户自定义目录加载额外重排模型
178
+ reranker_dir = RerankerRegistry.get_reranker_dir()
179
+ if reranker_dir and os.path.exists(reranker_dir):
180
+ for (
181
+ reranker_name,
182
+ reranker_class,
183
+ ) in RerankerRegistry.load_rerankers_from_dir(reranker_dir).items():
184
+ self.register_reranker(reranker_name, reranker_class)
185
+
186
+ # 从内置目录加载重排模型
187
+ reranker_dir = os.path.dirname(__file__)
188
+ if reranker_dir and os.path.exists(reranker_dir):
189
+ for (
190
+ reranker_name,
191
+ reranker_class,
192
+ ) in RerankerRegistry.load_rerankers_from_dir(reranker_dir).items():
193
+ self.register_reranker(reranker_name, reranker_class)
194
+
195
+ def register_reranker(
196
+ self, name: str, reranker_class: Type[RerankerInterface]
197
+ ) -> None:
198
+ """注册重排模型类
199
+
200
+ 参数:
201
+ name: 重排模型名称
202
+ reranker_class: 重排模型类
203
+ """
204
+ self.rerankers[name] = reranker_class
205
+
206
+ def create_reranker(
207
+ self, name: str, *args, **kwargs
208
+ ) -> Optional[RerankerInterface]:
209
+ """创建重排模型实例
210
+
211
+ 参数:
212
+ name: 重排模型名称
213
+ *args: 传递给构造函数的参数
214
+ **kwargs: 传递给构造函数的关键字参数
215
+
216
+ 返回:
217
+ RerankerInterface: 重排模型实例
218
+ """
219
+ if name not in self.rerankers:
220
+ PrettyOutput.auto_print(f"⚠️ 未找到重排模型: {name}")
221
+ return None
222
+
223
+ try:
224
+ reranker = self.rerankers[name](*args, **kwargs)
225
+ return reranker
226
+ except Exception as e:
227
+ PrettyOutput.auto_print(f"❌ 创建重排模型失败: {str(e)}")
228
+ return None
229
+
230
+ def get_available_rerankers(self) -> List[str]:
231
+ """获取可用的重排模型列表"""
232
+ return list(self.rerankers.keys())
233
+
234
+ @staticmethod
235
+ def create_from_config() -> Optional[RerankerInterface]:
236
+ """从配置创建重排模型实例
237
+
238
+ 从配置系统读取reranker_type、rerank_model和reranker_config,
239
+ 然后创建相应的重排模型实例。
240
+
241
+ 返回:
242
+ Optional[RerankerInterface]: 重排模型实例,如果创建失败则返回None
243
+ """
244
+ from jarvis.jarvis_utils.config import get_rag_rerank_model
245
+ from jarvis.jarvis_utils.config import get_rag_reranker_config
246
+ from jarvis.jarvis_utils.config import get_rag_reranker_type
247
+
248
+ reranker_type = get_rag_reranker_type()
249
+ model_name = get_rag_rerank_model()
250
+ reranker_config = get_rag_reranker_config()
251
+
252
+ registry = RerankerRegistry.get_global_registry()
253
+
254
+ from jarvis.jarvis_utils.config import get_rag_reranker_max_length
255
+
256
+ # 构建创建参数
257
+ create_kwargs = {"model_name": model_name}
258
+ create_kwargs.update(reranker_config)
259
+
260
+ # 将配置中的键名映射到 api_key 参数
261
+ # 支持的键名:cohere_api_key, edgefn_api_key, jina_api_key
262
+ api_key_mapping = {
263
+ "cohere_api_key": "api_key",
264
+ "edgefn_api_key": "api_key",
265
+ "jina_api_key": "api_key",
266
+ }
267
+ for config_key, param_key in api_key_mapping.items():
268
+ if config_key in create_kwargs:
269
+ # 如果还没有设置 api_key,则使用配置中的值
270
+ if param_key not in create_kwargs:
271
+ create_kwargs[param_key] = create_kwargs.pop(config_key)
272
+ else:
273
+ # 如果已经设置了 api_key,移除配置中的键
274
+ create_kwargs.pop(config_key)
275
+
276
+ # 同样处理 base_url
277
+ base_url_mapping = {
278
+ "cohere_api_base": "base_url",
279
+ "edgefn_api_base": "base_url",
280
+ "jina_api_base": "base_url",
281
+ }
282
+ for config_key, param_key in base_url_mapping.items():
283
+ if config_key in create_kwargs:
284
+ if param_key not in create_kwargs:
285
+ create_kwargs[param_key] = create_kwargs.pop(config_key)
286
+ else:
287
+ create_kwargs.pop(config_key)
288
+
289
+ # 添加max_length(如果配置中没有指定,使用配置系统的默认值)
290
+ if "max_length" not in create_kwargs:
291
+ create_kwargs["max_length"] = str(get_rag_reranker_max_length())
292
+
293
+ return registry.create_reranker(reranker_type, **create_kwargs)