jarvis-ai-assistant 0.1.132__py3-none-any.whl → 0.1.138__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 jarvis-ai-assistant might be problematic. Click here for more details.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/__init__.py +330 -347
- jarvis/jarvis_agent/builtin_input_handler.py +16 -6
- jarvis/jarvis_agent/file_input_handler.py +9 -9
- jarvis/jarvis_agent/jarvis.py +143 -0
- jarvis/jarvis_agent/main.py +12 -13
- jarvis/jarvis_agent/output_handler.py +3 -3
- jarvis/jarvis_agent/patch.py +92 -64
- jarvis/jarvis_agent/shell_input_handler.py +5 -3
- jarvis/jarvis_code_agent/code_agent.py +263 -177
- jarvis/jarvis_code_agent/file_select.py +24 -24
- jarvis/jarvis_dev/main.py +45 -59
- jarvis/jarvis_git_details/__init__.py +0 -0
- jarvis/jarvis_git_details/main.py +179 -0
- jarvis/jarvis_git_squash/main.py +7 -7
- jarvis/jarvis_lsp/base.py +11 -53
- jarvis/jarvis_lsp/cpp.py +13 -28
- jarvis/jarvis_lsp/go.py +13 -28
- jarvis/jarvis_lsp/python.py +8 -27
- jarvis/jarvis_lsp/registry.py +21 -83
- jarvis/jarvis_lsp/rust.py +15 -30
- jarvis/jarvis_methodology/main.py +101 -0
- jarvis/jarvis_multi_agent/__init__.py +10 -51
- jarvis/jarvis_multi_agent/main.py +43 -0
- jarvis/jarvis_platform/__init__.py +1 -1
- jarvis/jarvis_platform/ai8.py +67 -89
- jarvis/jarvis_platform/base.py +14 -13
- jarvis/jarvis_platform/kimi.py +25 -28
- jarvis/jarvis_platform/ollama.py +24 -26
- jarvis/jarvis_platform/openai.py +15 -19
- jarvis/jarvis_platform/oyi.py +48 -50
- jarvis/jarvis_platform/registry.py +29 -44
- jarvis/jarvis_platform/yuanbao.py +39 -43
- jarvis/jarvis_platform_manager/main.py +81 -81
- jarvis/jarvis_platform_manager/openai_test.py +21 -21
- jarvis/jarvis_rag/file_processors.py +18 -18
- jarvis/jarvis_rag/main.py +262 -278
- jarvis/jarvis_smart_shell/main.py +12 -12
- jarvis/jarvis_tools/ask_codebase.py +85 -78
- jarvis/jarvis_tools/ask_user.py +8 -8
- jarvis/jarvis_tools/base.py +4 -4
- jarvis/jarvis_tools/chdir.py +9 -9
- jarvis/jarvis_tools/code_review.py +40 -21
- jarvis/jarvis_tools/create_code_agent.py +15 -15
- jarvis/jarvis_tools/create_sub_agent.py +0 -1
- jarvis/jarvis_tools/execute_python_script.py +3 -3
- jarvis/jarvis_tools/execute_shell.py +11 -11
- jarvis/jarvis_tools/execute_shell_script.py +3 -3
- jarvis/jarvis_tools/file_analyzer.py +116 -105
- jarvis/jarvis_tools/file_operation.py +22 -20
- jarvis/jarvis_tools/find_caller.py +105 -40
- jarvis/jarvis_tools/find_methodolopy.py +65 -0
- jarvis/jarvis_tools/find_symbol.py +123 -39
- jarvis/jarvis_tools/function_analyzer.py +140 -57
- jarvis/jarvis_tools/git_commiter.py +10 -10
- jarvis/jarvis_tools/lsp_get_diagnostics.py +19 -19
- jarvis/jarvis_tools/methodology.py +22 -67
- jarvis/jarvis_tools/project_analyzer.py +137 -53
- jarvis/jarvis_tools/rag.py +15 -20
- jarvis/jarvis_tools/read_code.py +25 -23
- jarvis/jarvis_tools/read_webpage.py +31 -31
- jarvis/jarvis_tools/registry.py +72 -52
- jarvis/jarvis_tools/search_web.py +23 -353
- jarvis/jarvis_tools/tool_generator.py +19 -19
- jarvis/jarvis_utils/config.py +36 -96
- jarvis/jarvis_utils/embedding.py +83 -83
- jarvis/jarvis_utils/git_utils.py +20 -20
- jarvis/jarvis_utils/globals.py +18 -6
- jarvis/jarvis_utils/input.py +10 -9
- jarvis/jarvis_utils/methodology.py +141 -140
- jarvis/jarvis_utils/output.py +13 -13
- jarvis/jarvis_utils/utils.py +23 -71
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/METADATA +6 -15
- jarvis_ai_assistant-0.1.138.dist-info/RECORD +85 -0
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/entry_points.txt +4 -3
- jarvis/jarvis_tools/lsp_find_definition.py +0 -150
- jarvis/jarvis_tools/lsp_find_references.py +0 -127
- jarvis/jarvis_tools/select_code_files.py +0 -62
- jarvis_ai_assistant-0.1.132.dist-info/RECORD +0 -82
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.132.dist-info → jarvis_ai_assistant-0.1.138.dist-info}/top_level.txt +0 -0
|
@@ -18,7 +18,6 @@ import faiss
|
|
|
18
18
|
from typing import Dict, Any, List, Tuple, Optional
|
|
19
19
|
from jarvis.jarvis_utils.output import PrettyOutput, OutputType
|
|
20
20
|
from jarvis.jarvis_utils.embedding import load_embedding_model
|
|
21
|
-
from jarvis.jarvis_utils.config import dont_use_local_model
|
|
22
21
|
|
|
23
22
|
# 全局缓存,避免重复计算嵌入向量
|
|
24
23
|
_methodology_embeddings_cache = {}
|
|
@@ -27,7 +26,7 @@ _methodology_index_cache: Optional[Tuple[faiss.IndexIDMap, List[Dict[str, str]],
|
|
|
27
26
|
def _get_cache_directory() -> str:
|
|
28
27
|
"""
|
|
29
28
|
获取缓存目录路径,如果不存在则创建
|
|
30
|
-
|
|
29
|
+
|
|
31
30
|
返回:
|
|
32
31
|
str: 缓存目录的路径
|
|
33
32
|
"""
|
|
@@ -42,7 +41,7 @@ def _get_cache_directory() -> str:
|
|
|
42
41
|
def _get_embeddings_cache_path() -> str:
|
|
43
42
|
"""
|
|
44
43
|
获取嵌入向量缓存文件的路径
|
|
45
|
-
|
|
44
|
+
|
|
46
45
|
返回:
|
|
47
46
|
str: 嵌入向量缓存文件的路径
|
|
48
47
|
"""
|
|
@@ -51,7 +50,7 @@ def _get_embeddings_cache_path() -> str:
|
|
|
51
50
|
def _get_index_cache_path() -> str:
|
|
52
51
|
"""
|
|
53
52
|
获取索引缓存文件的路径
|
|
54
|
-
|
|
53
|
+
|
|
55
54
|
返回:
|
|
56
55
|
str: 索引缓存文件的路径
|
|
57
56
|
"""
|
|
@@ -60,7 +59,7 @@ def _get_index_cache_path() -> str:
|
|
|
60
59
|
def _get_index_metadata_path() -> str:
|
|
61
60
|
"""
|
|
62
61
|
获取索引元数据文件的路径
|
|
63
|
-
|
|
62
|
+
|
|
64
63
|
返回:
|
|
65
64
|
str: 索引元数据文件的路径
|
|
66
65
|
"""
|
|
@@ -69,14 +68,14 @@ def _get_index_metadata_path() -> str:
|
|
|
69
68
|
def _load_embeddings_cache() -> Dict[int, np.ndarray]:
|
|
70
69
|
"""
|
|
71
70
|
从文件系统加载嵌入向量缓存
|
|
72
|
-
|
|
71
|
+
|
|
73
72
|
返回:
|
|
74
73
|
Dict[int, np.ndarray]: 嵌入向量缓存字典
|
|
75
74
|
"""
|
|
76
75
|
cache_path = _get_embeddings_cache_path()
|
|
77
76
|
if not os.path.exists(cache_path):
|
|
78
77
|
return {}
|
|
79
|
-
|
|
78
|
+
|
|
80
79
|
try:
|
|
81
80
|
with open(cache_path, "rb") as f:
|
|
82
81
|
embeddings_cache = pickle.load(f)
|
|
@@ -87,18 +86,18 @@ def _load_embeddings_cache() -> Dict[int, np.ndarray]:
|
|
|
87
86
|
def _save_embeddings_cache(cache: Dict[int, np.ndarray]) -> bool:
|
|
88
87
|
"""
|
|
89
88
|
将嵌入向量缓存保存到文件系统
|
|
90
|
-
|
|
89
|
+
|
|
91
90
|
参数:
|
|
92
91
|
cache: 要保存的嵌入向量缓存字典
|
|
93
|
-
|
|
92
|
+
|
|
94
93
|
返回:
|
|
95
94
|
bool: 保存是否成功
|
|
96
95
|
"""
|
|
97
96
|
if not cache:
|
|
98
97
|
return False
|
|
99
|
-
|
|
98
|
+
|
|
100
99
|
cache_path = _get_embeddings_cache_path()
|
|
101
|
-
|
|
100
|
+
|
|
102
101
|
try:
|
|
103
102
|
with open(cache_path, "wb") as f:
|
|
104
103
|
pickle.dump(cache, f)
|
|
@@ -110,62 +109,62 @@ def _save_embeddings_cache(cache: Dict[int, np.ndarray]) -> bool:
|
|
|
110
109
|
def _load_index_cache() -> Optional[Tuple[faiss.IndexIDMap, List[Dict[str, str]], str]]:
|
|
111
110
|
"""
|
|
112
111
|
从文件系统加载索引缓存
|
|
113
|
-
|
|
112
|
+
|
|
114
113
|
返回:
|
|
115
114
|
Optional[Tuple[faiss.IndexIDMap, List[Dict[str, str]], str]]: 索引缓存元组
|
|
116
115
|
"""
|
|
117
116
|
index_path = _get_index_cache_path()
|
|
118
117
|
metadata_path = _get_index_metadata_path()
|
|
119
|
-
|
|
118
|
+
|
|
120
119
|
if not os.path.exists(index_path) or not os.path.exists(metadata_path):
|
|
121
120
|
return None
|
|
122
|
-
|
|
121
|
+
|
|
123
122
|
try:
|
|
124
123
|
# 加载索引
|
|
125
124
|
index = faiss.read_index(index_path)
|
|
126
|
-
|
|
125
|
+
|
|
127
126
|
# 加载元数据
|
|
128
127
|
with open(metadata_path, "rb") as f:
|
|
129
128
|
metadata = pickle.load(f)
|
|
130
|
-
|
|
129
|
+
|
|
131
130
|
methodology_data = metadata.get("methodology_data", [])
|
|
132
131
|
methodology_hash = metadata.get("methodology_hash", "")
|
|
133
|
-
|
|
132
|
+
|
|
134
133
|
if isinstance(index, faiss.IndexIDMap) and methodology_data and methodology_hash:
|
|
135
134
|
return index, methodology_data, methodology_hash
|
|
136
135
|
except Exception as e:
|
|
137
136
|
PrettyOutput.print(f"加载索引缓存失败: {str(e)}", OutputType.WARNING)
|
|
138
|
-
|
|
137
|
+
|
|
139
138
|
return None
|
|
140
139
|
|
|
141
140
|
def _save_index_cache(index: faiss.IndexIDMap, methodology_data: List[Dict[str, str]], methodology_hash: str) -> bool:
|
|
142
141
|
"""
|
|
143
142
|
将索引缓存保存到文件系统
|
|
144
|
-
|
|
143
|
+
|
|
145
144
|
参数:
|
|
146
145
|
index: FAISS索引
|
|
147
146
|
methodology_data: 方法论数据列表
|
|
148
147
|
methodology_hash: 方法论文件哈希值
|
|
149
|
-
|
|
148
|
+
|
|
150
149
|
返回:
|
|
151
150
|
bool: 保存是否成功
|
|
152
151
|
"""
|
|
153
152
|
index_path = _get_index_cache_path()
|
|
154
153
|
metadata_path = _get_index_metadata_path()
|
|
155
|
-
|
|
154
|
+
|
|
156
155
|
try:
|
|
157
156
|
# 保存索引
|
|
158
157
|
faiss.write_index(index, index_path)
|
|
159
|
-
|
|
158
|
+
|
|
160
159
|
# 保存元数据
|
|
161
160
|
metadata = {
|
|
162
161
|
"methodology_data": methodology_data,
|
|
163
162
|
"methodology_hash": methodology_hash
|
|
164
163
|
}
|
|
165
|
-
|
|
164
|
+
|
|
166
165
|
with open(metadata_path, "wb") as f:
|
|
167
166
|
pickle.dump(metadata, f)
|
|
168
|
-
|
|
167
|
+
|
|
169
168
|
return True
|
|
170
169
|
except Exception as e:
|
|
171
170
|
PrettyOutput.print(f"保存索引缓存失败: {str(e)}", OutputType.WARNING)
|
|
@@ -174,11 +173,11 @@ def _save_index_cache(index: faiss.IndexIDMap, methodology_data: List[Dict[str,
|
|
|
174
173
|
def _create_methodology_embedding(embedding_model: Any, methodology_text: str) -> np.ndarray:
|
|
175
174
|
"""
|
|
176
175
|
为方法论文本创建嵌入向量。
|
|
177
|
-
|
|
176
|
+
|
|
178
177
|
参数:
|
|
179
178
|
embedding_model: 使用的嵌入模型
|
|
180
179
|
methodology_text: 要创建嵌入的文本
|
|
181
|
-
|
|
180
|
+
|
|
182
181
|
返回:
|
|
183
182
|
np.ndarray: 嵌入向量
|
|
184
183
|
"""
|
|
@@ -187,21 +186,21 @@ def _create_methodology_embedding(embedding_model: Any, methodology_text: str) -
|
|
|
187
186
|
cache_key = hash(methodology_text)
|
|
188
187
|
if cache_key in _methodology_embeddings_cache:
|
|
189
188
|
return _methodology_embeddings_cache[cache_key]
|
|
190
|
-
|
|
189
|
+
|
|
191
190
|
# 截断长文本
|
|
192
191
|
max_length = 512
|
|
193
192
|
text = ' '.join(methodology_text.split()[:max_length])
|
|
194
|
-
|
|
193
|
+
|
|
195
194
|
# 使用sentence_transformers模型获取嵌入向量
|
|
196
|
-
embedding = embedding_model.encode([text],
|
|
195
|
+
embedding = embedding_model.encode([text],
|
|
197
196
|
convert_to_tensor=True,
|
|
198
197
|
normalize_embeddings=True)
|
|
199
198
|
vector = np.array(embedding.cpu().numpy(), dtype=np.float32)
|
|
200
199
|
result = vector[0] # 返回第一个向量,因为我们只编码了一个文本
|
|
201
|
-
|
|
200
|
+
|
|
202
201
|
# 缓存嵌入向量以便后续使用
|
|
203
202
|
_methodology_embeddings_cache[cache_key] = result
|
|
204
|
-
|
|
203
|
+
|
|
205
204
|
return result
|
|
206
205
|
except Exception as e:
|
|
207
206
|
PrettyOutput.print(f"创建方法论嵌入向量失败: {str(e)}", OutputType.ERROR)
|
|
@@ -210,14 +209,14 @@ def _create_methodology_embedding(embedding_model: Any, methodology_text: str) -
|
|
|
210
209
|
def make_methodology_prompt(data: Dict[str, str]) -> str:
|
|
211
210
|
"""
|
|
212
211
|
从方法论数据生成格式化提示
|
|
213
|
-
|
|
212
|
+
|
|
214
213
|
参数:
|
|
215
214
|
data: 方法论数据字典
|
|
216
|
-
|
|
215
|
+
|
|
217
216
|
返回:
|
|
218
217
|
str: 格式化后的提示字符串
|
|
219
218
|
"""
|
|
220
|
-
ret = """这是处理以往问题的标准方法论,如果当前任务类似,可以参考使用,如果不相关,请忽略:\n"""
|
|
219
|
+
ret = """这是处理以往问题的标准方法论,如果当前任务类似,可以参考使用,如果不相关,请忽略:\n"""
|
|
221
220
|
for key, value in data.items():
|
|
222
221
|
ret += f"问题: {key}\n方法论: {value}\n"
|
|
223
222
|
return ret
|
|
@@ -225,7 +224,7 @@ def make_methodology_prompt(data: Dict[str, str]) -> str:
|
|
|
225
224
|
def _get_methodology_directory() -> str:
|
|
226
225
|
"""
|
|
227
226
|
获取方法论目录路径,如果不存在则创建
|
|
228
|
-
|
|
227
|
+
|
|
229
228
|
返回:
|
|
230
229
|
str: 方法论目录的路径
|
|
231
230
|
"""
|
|
@@ -240,46 +239,46 @@ def _get_methodology_directory() -> str:
|
|
|
240
239
|
def _get_methodology_files_hash() -> str:
|
|
241
240
|
"""
|
|
242
241
|
计算所有方法论文件的组合哈希值,用于检测文件变化
|
|
243
|
-
|
|
242
|
+
|
|
244
243
|
返回:
|
|
245
244
|
str: 所有方法论文件的组合哈希值
|
|
246
245
|
"""
|
|
247
246
|
methodology_dir = _get_methodology_directory()
|
|
248
247
|
if not os.path.exists(methodology_dir):
|
|
249
248
|
return ""
|
|
250
|
-
|
|
249
|
+
|
|
251
250
|
# 获取所有方法论文件的路径和修改时间
|
|
252
251
|
files_data = []
|
|
253
252
|
for filepath in glob.glob(os.path.join(methodology_dir, "*.json")):
|
|
254
253
|
mtime = os.path.getmtime(filepath)
|
|
255
254
|
files_data.append((filepath, mtime))
|
|
256
|
-
|
|
255
|
+
|
|
257
256
|
# 按路径排序,保证哈希值的一致性
|
|
258
257
|
files_data.sort(key=lambda x: x[0])
|
|
259
|
-
|
|
258
|
+
|
|
260
259
|
# 计算组合哈希值
|
|
261
260
|
if not files_data:
|
|
262
261
|
return ""
|
|
263
|
-
|
|
262
|
+
|
|
264
263
|
hasher = hashlib.md5()
|
|
265
264
|
for filepath, mtime in files_data:
|
|
266
265
|
hasher.update(f"{filepath}:{mtime}".encode("utf-8"))
|
|
267
|
-
|
|
266
|
+
|
|
268
267
|
return hasher.hexdigest()
|
|
269
268
|
|
|
270
269
|
def _load_all_methodologies() -> Dict[str, str]:
|
|
271
270
|
"""
|
|
272
271
|
加载所有方法论文件
|
|
273
|
-
|
|
272
|
+
|
|
274
273
|
返回:
|
|
275
274
|
Dict[str, str]: 方法论字典,键为问题类型,值为方法论内容
|
|
276
275
|
"""
|
|
277
276
|
methodology_dir = _get_methodology_directory()
|
|
278
277
|
all_methodologies = {}
|
|
279
|
-
|
|
278
|
+
|
|
280
279
|
if not os.path.exists(methodology_dir):
|
|
281
280
|
return all_methodologies
|
|
282
|
-
|
|
281
|
+
|
|
283
282
|
for filepath in glob.glob(os.path.join(methodology_dir, "*.json")):
|
|
284
283
|
try:
|
|
285
284
|
with open(filepath, "r", encoding="utf-8", errors="ignore") as f:
|
|
@@ -291,7 +290,7 @@ def _load_all_methodologies() -> Dict[str, str]:
|
|
|
291
290
|
except Exception as e:
|
|
292
291
|
filename = os.path.basename(filepath)
|
|
293
292
|
PrettyOutput.print(f"加载方法论文件 {filename} 失败: {str(e)}", OutputType.WARNING)
|
|
294
|
-
|
|
293
|
+
|
|
295
294
|
return all_methodologies
|
|
296
295
|
|
|
297
296
|
def _migrate_from_old_format():
|
|
@@ -301,34 +300,34 @@ def _migrate_from_old_format():
|
|
|
301
300
|
old_format_file = os.path.expanduser("~/.jarvis/methodology")
|
|
302
301
|
if not os.path.exists(old_format_file):
|
|
303
302
|
return
|
|
304
|
-
|
|
303
|
+
|
|
305
304
|
try:
|
|
306
305
|
# 加载旧格式文件
|
|
307
306
|
with open(old_format_file, "r", encoding="utf-8", errors="ignore") as f:
|
|
308
307
|
old_data = yaml.safe_load(f) or {}
|
|
309
|
-
|
|
308
|
+
|
|
310
309
|
if not old_data:
|
|
311
310
|
return
|
|
312
|
-
|
|
311
|
+
|
|
313
312
|
# 创建新目录
|
|
314
313
|
methodology_dir = _get_methodology_directory()
|
|
315
|
-
|
|
314
|
+
|
|
316
315
|
# 迁移每个方法论
|
|
317
316
|
migrated_count = 0
|
|
318
317
|
for problem_type, content in old_data.items():
|
|
319
318
|
# 为每个方法论创建文件名(使用问题类型的MD5哈希作为文件名)
|
|
320
319
|
safe_filename = hashlib.md5(problem_type.encode('utf-8')).hexdigest()
|
|
321
320
|
file_path = os.path.join(methodology_dir, f"{safe_filename}.json")
|
|
322
|
-
|
|
321
|
+
|
|
323
322
|
# 保存为新格式
|
|
324
323
|
with open(file_path, "w", encoding="utf-8", errors="ignore") as f:
|
|
325
324
|
json.dump({
|
|
326
325
|
"problem_type": problem_type,
|
|
327
326
|
"content": content
|
|
328
327
|
}, f, ensure_ascii=False, indent=2)
|
|
329
|
-
|
|
328
|
+
|
|
330
329
|
migrated_count += 1
|
|
331
|
-
|
|
330
|
+
|
|
332
331
|
if migrated_count > 0:
|
|
333
332
|
# 备份旧文件
|
|
334
333
|
backup_path = old_format_file + ".bak"
|
|
@@ -343,15 +342,15 @@ def _migrate_from_old_format():
|
|
|
343
342
|
def load_methodology(user_input: str) -> str:
|
|
344
343
|
"""
|
|
345
344
|
加载方法论并构建向量索引以进行相似性搜索。
|
|
346
|
-
|
|
345
|
+
|
|
347
346
|
参数:
|
|
348
347
|
user_input: 要搜索方法论的输入文本
|
|
349
|
-
|
|
348
|
+
|
|
350
349
|
返回:
|
|
351
350
|
str: 相关的方法论提示,如果未找到方法论则返回空字符串
|
|
352
351
|
"""
|
|
353
352
|
from yaspin import yaspin
|
|
354
|
-
|
|
353
|
+
|
|
355
354
|
# 加载嵌入向量缓存
|
|
356
355
|
global _methodology_embeddings_cache
|
|
357
356
|
if not _methodology_embeddings_cache:
|
|
@@ -359,29 +358,22 @@ def load_methodology(user_input: str) -> str:
|
|
|
359
358
|
_methodology_embeddings_cache = _load_embeddings_cache()
|
|
360
359
|
spinner.text = f"加载嵌入向量缓存完成 ({len(_methodology_embeddings_cache)} 个向量)"
|
|
361
360
|
spinner.ok("✅")
|
|
362
|
-
|
|
361
|
+
|
|
363
362
|
# 检查是否需要从旧格式迁移
|
|
364
363
|
with yaspin(text="检查方法论格式...", color="yellow") as spinner:
|
|
365
364
|
_migrate_from_old_format()
|
|
366
365
|
spinner.text = "检查方法论格式完成"
|
|
367
366
|
spinner.ok("✅")
|
|
368
|
-
|
|
367
|
+
|
|
369
368
|
# 获取方法论目录
|
|
370
369
|
methodology_dir = _get_methodology_directory()
|
|
371
370
|
if not os.path.exists(methodology_dir) or not glob.glob(os.path.join(methodology_dir, "*.json")):
|
|
372
371
|
return ""
|
|
373
|
-
|
|
372
|
+
|
|
374
373
|
try:
|
|
375
374
|
# 获取文件的修改时间戳组合哈希,用于检测文件是否被修改
|
|
376
375
|
methodology_hash = _get_methodology_files_hash()
|
|
377
|
-
|
|
378
|
-
with yaspin(text="加载方法论文件...", color="yellow") as spinner:
|
|
379
|
-
data = _load_all_methodologies()
|
|
380
|
-
if dont_use_local_model():
|
|
381
|
-
spinner.text = "加载方法论文件完成"
|
|
382
|
-
spinner.ok("✅")
|
|
383
|
-
return make_methodology_prompt(data)
|
|
384
|
-
|
|
376
|
+
|
|
385
377
|
# 检查缓存的索引是否可用且方法论文件未被修改
|
|
386
378
|
global _methodology_index_cache
|
|
387
379
|
if _methodology_index_cache is None:
|
|
@@ -394,7 +386,7 @@ def load_methodology(user_input: str) -> str:
|
|
|
394
386
|
else:
|
|
395
387
|
spinner.text = "没有可用的索引缓存"
|
|
396
388
|
spinner.fail("❌")
|
|
397
|
-
|
|
389
|
+
|
|
398
390
|
if _methodology_index_cache is not None:
|
|
399
391
|
cached_index, cached_data, cache_hash = _methodology_index_cache
|
|
400
392
|
if cache_hash == methodology_hash:
|
|
@@ -404,12 +396,12 @@ def load_methodology(user_input: str) -> str:
|
|
|
404
396
|
methodology_data = cached_data
|
|
405
397
|
spinner.text = "使用缓存的方法论索引完成"
|
|
406
398
|
spinner.ok("✅")
|
|
407
|
-
|
|
399
|
+
|
|
408
400
|
with yaspin(text="加载嵌入模型...", color="yellow") as spinner:
|
|
409
401
|
embedding_model = load_embedding_model()
|
|
410
402
|
spinner.text = "加载嵌入模型完成"
|
|
411
403
|
spinner.ok("✅")
|
|
412
|
-
|
|
404
|
+
|
|
413
405
|
with yaspin(text="执行搜索...", color="yellow") as spinner:
|
|
414
406
|
# 使用缓存构造输入文本的嵌入
|
|
415
407
|
query_embedding = _create_methodology_embedding(embedding_model, user_input)
|
|
@@ -419,7 +411,7 @@ def load_methodology(user_input: str) -> str:
|
|
|
419
411
|
) # type: ignore
|
|
420
412
|
spinner.text = "执行搜索完成"
|
|
421
413
|
spinner.ok("✅")
|
|
422
|
-
|
|
414
|
+
|
|
423
415
|
with yaspin(text="处理搜索结果...", color="yellow") as spinner:
|
|
424
416
|
relevant_methodologies = {}
|
|
425
417
|
for dist, idx in zip(distances[0], indices[0]):
|
|
@@ -430,11 +422,12 @@ def load_methodology(user_input: str) -> str:
|
|
|
430
422
|
relevant_methodologies[methodology["key"]] = methodology["value"]
|
|
431
423
|
spinner.text = "处理搜索结果完成"
|
|
432
424
|
spinner.ok("✅")
|
|
433
|
-
|
|
425
|
+
|
|
434
426
|
if relevant_methodologies:
|
|
427
|
+
spinner.text = f"找到相关方法论: {', '.join(relevant_methodologies.keys())}"
|
|
428
|
+
spinner.ok("✅")
|
|
435
429
|
return make_methodology_prompt(relevant_methodologies)
|
|
436
|
-
|
|
437
|
-
|
|
430
|
+
|
|
438
431
|
# 如果缓存无效,从头构建索引
|
|
439
432
|
with yaspin(text="初始化数据结构...", color="yellow") as spinner:
|
|
440
433
|
methodology_data: List[Dict[str, str]] = []
|
|
@@ -442,77 +435,85 @@ def load_methodology(user_input: str) -> str:
|
|
|
442
435
|
ids: List[int] = []
|
|
443
436
|
spinner.text = "初始化数据结构完成"
|
|
444
437
|
spinner.ok("✅")
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
438
|
+
|
|
439
|
+
with yaspin(text="加载嵌入模型...", color="yellow") as spinner:
|
|
440
|
+
embedding_model = load_embedding_model()
|
|
441
|
+
spinner.text = "加载嵌入模型完成"
|
|
442
|
+
spinner.ok("✅")
|
|
443
|
+
|
|
444
|
+
with yaspin(text="创建测试嵌入...", color="yellow") as spinner:
|
|
445
|
+
test_embedding = _create_methodology_embedding(embedding_model, "test")
|
|
446
|
+
embedding_dimension = len(test_embedding)
|
|
447
|
+
spinner.text = "创建测试嵌入完成"
|
|
448
|
+
spinner.ok("✅")
|
|
449
|
+
|
|
450
|
+
with yaspin(text="加载方法论文件...", color="yellow") as spinner:
|
|
451
|
+
data = _load_all_methodologies()
|
|
452
|
+
spinner.text = "加载方法论文件完成"
|
|
453
|
+
spinner.ok("✅")
|
|
454
|
+
|
|
455
|
+
with yaspin(text="处理方法论数据...", color="yellow") as spinner:
|
|
456
|
+
for i, (key, value) in enumerate(data.items()):
|
|
457
|
+
methodology_text = f"{key}\n{value}"
|
|
458
|
+
embedding = _create_methodology_embedding(embedding_model, methodology_text)
|
|
459
|
+
vectors.append(embedding)
|
|
460
|
+
ids.append(i)
|
|
461
|
+
methodology_data.append({"key": key, "value": value})
|
|
462
|
+
spinner.text = "处理方法论数据完成"
|
|
463
|
+
spinner.ok("✅")
|
|
464
|
+
|
|
465
|
+
if vectors:
|
|
466
|
+
with yaspin(text="构建索引...", color="yellow") as spinner:
|
|
467
|
+
vectors_array = np.vstack(vectors)
|
|
468
|
+
hnsw_index = faiss.IndexHNSWFlat(embedding_dimension, 16)
|
|
469
|
+
hnsw_index.hnsw.efConstruction = 40
|
|
470
|
+
hnsw_index.hnsw.efSearch = 16
|
|
471
|
+
methodology_index = faiss.IndexIDMap(hnsw_index)
|
|
472
|
+
methodology_index.add_with_ids(vectors_array, np.array(ids)) # type: ignore
|
|
473
|
+
# 缓存构建好的索引和数据以及时间戳哈希
|
|
474
|
+
_methodology_index_cache = (methodology_index, methodology_data, methodology_hash)
|
|
475
|
+
|
|
476
|
+
# 将索引和嵌入向量缓存保存到文件系统
|
|
477
|
+
_save_index_cache(methodology_index, methodology_data, methodology_hash)
|
|
478
|
+
|
|
479
|
+
spinner.text = "构建索引完成"
|
|
449
480
|
spinner.ok("✅")
|
|
450
|
-
|
|
451
|
-
with yaspin(text="
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
481
|
+
|
|
482
|
+
with yaspin(text="执行搜索...", color="yellow") as spinner:
|
|
483
|
+
query_embedding = _create_methodology_embedding(embedding_model, user_input)
|
|
484
|
+
k = min(10, len(methodology_data))
|
|
485
|
+
distances, indices = methodology_index.search(
|
|
486
|
+
query_embedding.reshape(1, -1), k
|
|
487
|
+
) # type: ignore
|
|
488
|
+
spinner.text = "执行搜索完成"
|
|
455
489
|
spinner.ok("✅")
|
|
456
|
-
|
|
457
|
-
with yaspin(text="
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
490
|
+
|
|
491
|
+
with yaspin(text="处理搜索结果...", color="yellow") as spinner:
|
|
492
|
+
relevant_methodologies = {}
|
|
493
|
+
for dist, idx in zip(distances[0], indices[0]):
|
|
494
|
+
if idx >= 0:
|
|
495
|
+
similarity = 1.0 / (1.0 + float(dist))
|
|
496
|
+
methodology = methodology_data[idx]
|
|
497
|
+
if similarity >= 0.5:
|
|
498
|
+
relevant_methodologies[methodology["key"]] = methodology["value"]
|
|
499
|
+
spinner.text = "处理搜索结果完成"
|
|
465
500
|
spinner.ok("✅")
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
hnsw_index.hnsw.efConstruction = 40
|
|
472
|
-
hnsw_index.hnsw.efSearch = 16
|
|
473
|
-
methodology_index = faiss.IndexIDMap(hnsw_index)
|
|
474
|
-
methodology_index.add_with_ids(vectors_array, np.array(ids)) # type: ignore
|
|
475
|
-
# 缓存构建好的索引和数据以及时间戳哈希
|
|
476
|
-
_methodology_index_cache = (methodology_index, methodology_data, methodology_hash)
|
|
477
|
-
|
|
478
|
-
# 将索引和嵌入向量缓存保存到文件系统
|
|
479
|
-
_save_index_cache(methodology_index, methodology_data, methodology_hash)
|
|
480
|
-
|
|
481
|
-
spinner.text = "构建索引完成"
|
|
482
|
-
spinner.ok("✅")
|
|
483
|
-
|
|
484
|
-
with yaspin(text="执行搜索...", color="yellow") as spinner:
|
|
485
|
-
query_embedding = _create_methodology_embedding(embedding_model, user_input)
|
|
486
|
-
k = min(3, len(methodology_data))
|
|
487
|
-
distances, indices = methodology_index.search(
|
|
488
|
-
query_embedding.reshape(1, -1), k
|
|
489
|
-
) # type: ignore
|
|
490
|
-
spinner.text = "执行搜索完成"
|
|
491
|
-
spinner.ok("✅")
|
|
492
|
-
|
|
493
|
-
with yaspin(text="处理搜索结果...", color="yellow") as spinner:
|
|
494
|
-
relevant_methodologies = {}
|
|
495
|
-
for dist, idx in zip(distances[0], indices[0]):
|
|
496
|
-
if idx >= 0:
|
|
497
|
-
similarity = 1.0 / (1.0 + float(dist))
|
|
498
|
-
methodology = methodology_data[idx]
|
|
499
|
-
if similarity >= 0.5:
|
|
500
|
-
relevant_methodologies[methodology["key"]] = methodology["value"]
|
|
501
|
-
spinner.text = "处理搜索结果完成"
|
|
501
|
+
|
|
502
|
+
# 保存嵌入向量缓存到文件系统
|
|
503
|
+
with yaspin(text="保存嵌入向量缓存...", color="yellow") as spinner:
|
|
504
|
+
if _save_embeddings_cache(_methodology_embeddings_cache):
|
|
505
|
+
spinner.text = f"保存嵌入向量缓存完成 ({len(_methodology_embeddings_cache)} 个向量)"
|
|
502
506
|
spinner.ok("✅")
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
if relevant_methodologies:
|
|
514
|
-
return make_methodology_prompt(relevant_methodologies)
|
|
515
|
-
return make_methodology_prompt(data)
|
|
507
|
+
else:
|
|
508
|
+
spinner.text = "保存嵌入向量缓存失败"
|
|
509
|
+
spinner.fail("❌")
|
|
510
|
+
|
|
511
|
+
if relevant_methodologies:
|
|
512
|
+
spinner.write(f"找到相关方法论: {', '.join(relevant_methodologies.keys())}")
|
|
513
|
+
return make_methodology_prompt(relevant_methodologies)
|
|
514
|
+
spinner.write(f"未找到相关的方法论")
|
|
515
|
+
spinner.fail("❌")
|
|
516
|
+
return ""
|
|
516
517
|
except Exception as e:
|
|
517
518
|
PrettyOutput.print(f"加载方法论失败: {str(e)}", OutputType.ERROR)
|
|
518
519
|
return ""
|
jarvis/jarvis_utils/output.py
CHANGED
|
@@ -17,11 +17,11 @@ from rich.syntax import Syntax
|
|
|
17
17
|
from rich.style import Style as RichStyle
|
|
18
18
|
from pygments.lexers import guess_lexer
|
|
19
19
|
from pygments.util import ClassNotFound
|
|
20
|
-
from .globals import console, get_agent_list
|
|
20
|
+
from jarvis.jarvis_utils.globals import console, get_agent_list
|
|
21
21
|
class OutputType(Enum):
|
|
22
22
|
"""
|
|
23
23
|
输出类型枚举,用于分类和样式化不同类型的消息。
|
|
24
|
-
|
|
24
|
+
|
|
25
25
|
属性:
|
|
26
26
|
SYSTEM: AI助手消息
|
|
27
27
|
CODE: 代码相关输出
|
|
@@ -51,7 +51,7 @@ class OutputType(Enum):
|
|
|
51
51
|
class PrettyOutput:
|
|
52
52
|
"""
|
|
53
53
|
使用rich库格式化和显示富文本输出的类。
|
|
54
|
-
|
|
54
|
+
|
|
55
55
|
提供以下方法:
|
|
56
56
|
- 使用适当的样式格式化不同类型的输出
|
|
57
57
|
- 代码块的语法高亮
|
|
@@ -110,11 +110,11 @@ class PrettyOutput:
|
|
|
110
110
|
def _detect_language(text: str, default_lang: str = 'markdown') -> str:
|
|
111
111
|
"""
|
|
112
112
|
检测给定文本的编程语言。
|
|
113
|
-
|
|
113
|
+
|
|
114
114
|
参数:
|
|
115
115
|
text: 要分析的文本
|
|
116
116
|
default_lang: 如果检测失败,默认返回的语言
|
|
117
|
-
|
|
117
|
+
|
|
118
118
|
返回:
|
|
119
119
|
str: 检测到的语言名称
|
|
120
120
|
"""
|
|
@@ -128,11 +128,11 @@ class PrettyOutput:
|
|
|
128
128
|
def _format(output_type: OutputType, timestamp: bool = True) -> Text:
|
|
129
129
|
"""
|
|
130
130
|
使用时间戳和图标格式化输出头。
|
|
131
|
-
|
|
131
|
+
|
|
132
132
|
参数:
|
|
133
133
|
output_type: 输出类型
|
|
134
134
|
timestamp: 是否包含时间戳
|
|
135
|
-
|
|
135
|
+
|
|
136
136
|
返回:
|
|
137
137
|
Text: 格式化后的rich Text对象
|
|
138
138
|
"""
|
|
@@ -149,7 +149,7 @@ class PrettyOutput:
|
|
|
149
149
|
def print(text: str, output_type: OutputType, timestamp: bool = True, lang: Optional[str] = None, traceback: bool = False):
|
|
150
150
|
"""
|
|
151
151
|
使用样式和语法高亮打印格式化输出。
|
|
152
|
-
|
|
152
|
+
|
|
153
153
|
参数:
|
|
154
154
|
text: 要打印的文本内容
|
|
155
155
|
output_type: 输出类型(影响样式)
|
|
@@ -186,13 +186,13 @@ class PrettyOutput:
|
|
|
186
186
|
)
|
|
187
187
|
console.print()
|
|
188
188
|
console.print(panel)
|
|
189
|
-
if traceback:
|
|
189
|
+
if traceback or output_type == OutputType.ERROR:
|
|
190
190
|
console.print_exception()
|
|
191
191
|
@staticmethod
|
|
192
192
|
def section(title: str, output_type: OutputType = OutputType.INFO):
|
|
193
193
|
"""
|
|
194
194
|
在样式化面板中打印章节标题。
|
|
195
|
-
|
|
195
|
+
|
|
196
196
|
参数:
|
|
197
197
|
title: 章节标题文本
|
|
198
198
|
output_type: 输出类型(影响样式)
|
|
@@ -208,7 +208,7 @@ class PrettyOutput:
|
|
|
208
208
|
def print_stream(text: str, is_thinking: bool = False):
|
|
209
209
|
"""
|
|
210
210
|
打印流式输出,不带换行符。
|
|
211
|
-
|
|
211
|
+
|
|
212
212
|
参数:
|
|
213
213
|
text: 要打印的文本
|
|
214
214
|
"""
|
|
@@ -228,10 +228,10 @@ class PrettyOutput:
|
|
|
228
228
|
def _get_style(output_type: OutputType) -> RichStyle:
|
|
229
229
|
"""
|
|
230
230
|
获取预定义的RichStyle用于输出类型。
|
|
231
|
-
|
|
231
|
+
|
|
232
232
|
参数:
|
|
233
233
|
output_type: 要获取样式的输出类型
|
|
234
|
-
|
|
234
|
+
|
|
235
235
|
返回:
|
|
236
236
|
RichStyle: 对应的样式
|
|
237
237
|
"""
|