jarvis-ai-assistant 0.1.148__py3-none-any.whl → 0.1.149__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/main.py +0 -1
- jarvis/jarvis_agent/patch.py +42 -7
- jarvis/jarvis_code_analysis/code_review.py +0 -1
- jarvis/jarvis_git_utils/git_commiter.py +0 -1
- jarvis/jarvis_lsp/base.py +1 -1
- jarvis/jarvis_lsp/cpp.py +1 -1
- jarvis/jarvis_lsp/go.py +1 -1
- jarvis/jarvis_lsp/python.py +1 -1
- jarvis/jarvis_lsp/rust.py +1 -1
- jarvis/jarvis_platform/base.py +1 -1
- jarvis/jarvis_platform/kimi.py +0 -1
- jarvis/jarvis_tools/code_plan.py +0 -1
- jarvis/jarvis_tools/file_analyzer.py +1 -1
- jarvis/jarvis_tools/read_code.py +0 -1
- jarvis/jarvis_tools/search_web.py +0 -1
- jarvis/jarvis_utils/embedding.py +2 -6
- jarvis/jarvis_utils/git_utils.py +19 -8
- jarvis/jarvis_utils/output.py +0 -1
- jarvis/jarvis_utils/utils.py +19 -217
- {jarvis_ai_assistant-0.1.148.dist-info → jarvis_ai_assistant-0.1.149.dist-info}/METADATA +24 -27
- {jarvis_ai_assistant-0.1.148.dist-info → jarvis_ai_assistant-0.1.149.dist-info}/RECORD +26 -27
- jarvis/jarvis_platform_manager/openai_test.py +0 -138
- {jarvis_ai_assistant-0.1.148.dist-info → jarvis_ai_assistant-0.1.149.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.148.dist-info → jarvis_ai_assistant-0.1.149.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.148.dist-info → jarvis_ai_assistant-0.1.149.dist-info}/entry_points.txt +0 -0
- {jarvis_ai_assistant-0.1.148.dist-info → jarvis_ai_assistant-0.1.149.dist-info}/top_level.txt +0 -0
jarvis/__init__.py
CHANGED
jarvis/jarvis_agent/main.py
CHANGED
jarvis/jarvis_agent/patch.py
CHANGED
|
@@ -238,7 +238,8 @@ def revert_file(filepath: str):
|
|
|
238
238
|
# 检查文件是否在版本控制中
|
|
239
239
|
result = subprocess.run(
|
|
240
240
|
['git', 'ls-files', '--error-unmatch', filepath],
|
|
241
|
-
stderr=subprocess.PIPE
|
|
241
|
+
stderr=subprocess.PIPE,
|
|
242
|
+
text=False # 禁用自动文本解码
|
|
242
243
|
)
|
|
243
244
|
if result.returncode == 0:
|
|
244
245
|
subprocess.run(['git', 'checkout', 'HEAD',
|
|
@@ -248,33 +249,67 @@ def revert_file(filepath: str):
|
|
|
248
249
|
os.remove(filepath)
|
|
249
250
|
subprocess.run(['git', 'clean', '-f', '--', filepath], check=True)
|
|
250
251
|
except subprocess.CalledProcessError as e:
|
|
251
|
-
|
|
252
|
+
error_msg = e.stderr.decode('utf-8', errors='replace') if e.stderr else str(e)
|
|
253
|
+
PrettyOutput.print(f"恢复文件失败: {error_msg}", OutputType.ERROR)
|
|
252
254
|
# 修改后的恢复函数
|
|
253
255
|
|
|
254
256
|
|
|
255
257
|
def revert_change():
|
|
258
|
+
"""恢复所有未提交的修改到HEAD状态"""
|
|
256
259
|
import subprocess
|
|
257
|
-
|
|
258
|
-
|
|
260
|
+
try:
|
|
261
|
+
# 检查是否为空仓库
|
|
262
|
+
head_check = subprocess.run(
|
|
263
|
+
['git', 'rev-parse', '--verify', 'HEAD'],
|
|
264
|
+
stderr=subprocess.PIPE,
|
|
265
|
+
stdout=subprocess.PIPE
|
|
266
|
+
)
|
|
267
|
+
if head_check.returncode == 0:
|
|
268
|
+
subprocess.run(['git', 'reset', '--hard', 'HEAD'], check=True)
|
|
269
|
+
subprocess.run(['git', 'clean', '-fd'], check=True)
|
|
270
|
+
except subprocess.CalledProcessError as e:
|
|
271
|
+
return f"恢复更改失败: {str(e)}"
|
|
259
272
|
# 修改后的获取差异函数
|
|
260
273
|
|
|
261
274
|
|
|
262
275
|
def get_diff() -> str:
|
|
263
276
|
"""使用git获取暂存区差异"""
|
|
264
277
|
import subprocess
|
|
278
|
+
|
|
279
|
+
# 初始化状态
|
|
280
|
+
need_reset = False
|
|
281
|
+
|
|
265
282
|
try:
|
|
283
|
+
# 暂存所有修改
|
|
266
284
|
subprocess.run(['git', 'add', '.'], check=True)
|
|
285
|
+
need_reset = True
|
|
286
|
+
|
|
287
|
+
# 获取差异
|
|
267
288
|
result = subprocess.run(
|
|
268
289
|
['git', 'diff', '--cached'],
|
|
269
290
|
capture_output=True,
|
|
270
|
-
text=
|
|
291
|
+
text=False,
|
|
271
292
|
check=True
|
|
272
293
|
)
|
|
273
|
-
|
|
274
|
-
|
|
294
|
+
|
|
295
|
+
# 解码输出
|
|
296
|
+
try:
|
|
297
|
+
ret = result.stdout.decode('utf-8')
|
|
298
|
+
except UnicodeDecodeError:
|
|
299
|
+
ret = result.stdout.decode('utf-8', errors='replace')
|
|
300
|
+
|
|
301
|
+
# 重置暂存区
|
|
302
|
+
subprocess.run(['git', "reset", "--mixed"], check=False)
|
|
275
303
|
return ret
|
|
304
|
+
|
|
276
305
|
except subprocess.CalledProcessError as e:
|
|
306
|
+
if need_reset:
|
|
307
|
+
subprocess.run(['git', "reset", "--mixed"], check=False)
|
|
277
308
|
return f"获取差异失败: {str(e)}"
|
|
309
|
+
except Exception as e:
|
|
310
|
+
if need_reset:
|
|
311
|
+
subprocess.run(['git', "reset", "--mixed"], check=False)
|
|
312
|
+
return f"发生意外错误: {str(e)}"
|
|
278
313
|
|
|
279
314
|
|
|
280
315
|
def handle_commit_workflow() -> bool:
|
jarvis/jarvis_lsp/base.py
CHANGED
jarvis/jarvis_lsp/cpp.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import shutil
|
|
3
3
|
import subprocess
|
|
4
|
-
from typing import List, Dict, Optional,
|
|
4
|
+
from typing import List, Dict, Optional, Any
|
|
5
5
|
import json
|
|
6
6
|
from jarvis.jarvis_lsp.base import BaseLSP
|
|
7
7
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
jarvis/jarvis_lsp/go.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import shutil
|
|
3
3
|
import subprocess
|
|
4
|
-
from typing import List, Dict, Optional,
|
|
4
|
+
from typing import List, Dict, Optional, Any
|
|
5
5
|
import json
|
|
6
6
|
from jarvis.jarvis_lsp.base import BaseLSP
|
|
7
7
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
jarvis/jarvis_lsp/python.py
CHANGED
jarvis/jarvis_lsp/rust.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import shutil
|
|
3
3
|
import subprocess
|
|
4
|
-
from typing import List, Dict, Optional,
|
|
4
|
+
from typing import List, Dict, Optional, Any
|
|
5
5
|
import json
|
|
6
6
|
from jarvis.jarvis_lsp.base import BaseLSP
|
|
7
7
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
jarvis/jarvis_platform/base.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
2
|
import re
|
|
3
|
-
from typing import
|
|
3
|
+
from typing import List, Tuple
|
|
4
4
|
from jarvis.jarvis_utils.globals import clear_read_file_record
|
|
5
5
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
6
6
|
from jarvis.jarvis_utils.utils import ct, ot, get_context_token_count, while_success, while_true
|
jarvis/jarvis_platform/kimi.py
CHANGED
|
@@ -7,7 +7,6 @@ import time
|
|
|
7
7
|
from jarvis.jarvis_platform.base import BasePlatform
|
|
8
8
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
9
9
|
from jarvis.jarvis_utils.utils import while_success
|
|
10
|
-
from yaspin import yaspin
|
|
11
10
|
|
|
12
11
|
class KimiModel(BasePlatform):
|
|
13
12
|
"""Kimi model implementation"""
|
jarvis/jarvis_tools/code_plan.py
CHANGED
|
@@ -15,7 +15,6 @@ from jarvis.jarvis_agent import Agent
|
|
|
15
15
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
|
16
16
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
|
17
17
|
from jarvis.jarvis_utils.git_utils import find_git_root
|
|
18
|
-
from jarvis.jarvis_utils.utils import init_env
|
|
19
18
|
|
|
20
19
|
class CodePlanTool:
|
|
21
20
|
"""用于代码修改规划和需求分析的工具
|
jarvis/jarvis_tools/read_code.py
CHANGED
jarvis/jarvis_utils/embedding.py
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import os
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
from sentence_transformers import SentenceTransformer
|
|
5
|
-
from transformers import AutoTokenizer, AutoModelForSequenceClassification
|
|
6
|
-
from typing import List, Any, Optional, Tuple
|
|
2
|
+
from transformers import AutoTokenizer
|
|
3
|
+
from typing import List
|
|
7
4
|
import functools
|
|
8
5
|
|
|
9
|
-
from yaspin.api import Yaspin
|
|
10
6
|
from jarvis.jarvis_utils.output import PrettyOutput, OutputType
|
|
11
7
|
|
|
12
8
|
# 全局缓存,避免重复加载模型
|
jarvis/jarvis_utils/git_utils.py
CHANGED
|
@@ -74,14 +74,16 @@ def get_commits_between(start_hash: str, end_hash: str) -> List[Tuple[str, str]]
|
|
|
74
74
|
['git', 'log', f'{start_hash}..{end_hash}', '--pretty=format:%H|%s'],
|
|
75
75
|
stdout=subprocess.PIPE,
|
|
76
76
|
stderr=subprocess.PIPE,
|
|
77
|
-
text=
|
|
77
|
+
text=False # 禁用自动文本解码
|
|
78
78
|
)
|
|
79
79
|
if result.returncode != 0:
|
|
80
|
-
|
|
80
|
+
error_msg = result.stderr.decode('utf-8', errors='replace')
|
|
81
|
+
PrettyOutput.print(f"获取commit历史失败: {error_msg}", OutputType.ERROR)
|
|
81
82
|
return []
|
|
82
83
|
|
|
84
|
+
output = result.stdout.decode('utf-8', errors='replace')
|
|
83
85
|
commits = []
|
|
84
|
-
for line in
|
|
86
|
+
for line in output.splitlines():
|
|
85
87
|
if '|' in line:
|
|
86
88
|
commit_hash, message = line.split('|', 1)
|
|
87
89
|
commits.append((commit_hash, message))
|
|
@@ -94,18 +96,27 @@ def get_latest_commit_hash() -> str:
|
|
|
94
96
|
"""获取当前Git仓库的最新提交哈希值
|
|
95
97
|
|
|
96
98
|
返回:
|
|
97
|
-
str: 提交哈希值,如果不在Git
|
|
99
|
+
str: 提交哈希值,如果不在Git仓库、空仓库或发生错误则返回空字符串
|
|
98
100
|
"""
|
|
99
101
|
try:
|
|
102
|
+
# 首先检查是否存在HEAD引用
|
|
103
|
+
head_check = subprocess.run(
|
|
104
|
+
['git', 'rev-parse', '--verify', 'HEAD'],
|
|
105
|
+
stdout=subprocess.PIPE,
|
|
106
|
+
stderr=subprocess.PIPE,
|
|
107
|
+
text=False
|
|
108
|
+
)
|
|
109
|
+
if head_check.returncode != 0:
|
|
110
|
+
return "" # 空仓库或无效HEAD
|
|
111
|
+
|
|
112
|
+
# 获取HEAD的完整哈希值
|
|
100
113
|
result = subprocess.run(
|
|
101
114
|
['git', 'rev-parse', 'HEAD'],
|
|
102
115
|
stdout=subprocess.PIPE,
|
|
103
116
|
stderr=subprocess.PIPE,
|
|
104
|
-
text=
|
|
117
|
+
text=False
|
|
105
118
|
)
|
|
106
|
-
if result.returncode == 0
|
|
107
|
-
return result.stdout.strip()
|
|
108
|
-
return ""
|
|
119
|
+
return result.stdout.decode('utf-8', errors='replace').strip() if result.returncode == 0 else ""
|
|
109
120
|
except Exception:
|
|
110
121
|
return ""
|
|
111
122
|
def get_modified_line_ranges() -> Dict[str, Tuple[int, int]]:
|
jarvis/jarvis_utils/output.py
CHANGED
jarvis/jarvis_utils/utils.py
CHANGED
|
@@ -2,8 +2,7 @@ import os
|
|
|
2
2
|
import time
|
|
3
3
|
import hashlib
|
|
4
4
|
from pathlib import Path
|
|
5
|
-
from typing import
|
|
6
|
-
from bs4 import BeautifulSoup, Tag
|
|
5
|
+
from typing import List, Any, Callable
|
|
7
6
|
from jarvis.jarvis_utils.config import get_max_input_token_count
|
|
8
7
|
from jarvis.jarvis_utils.embedding import get_context_token_count
|
|
9
8
|
from jarvis.jarvis_utils.input import get_single_line_input
|
|
@@ -19,7 +18,7 @@ def init_env() -> None:
|
|
|
19
18
|
jarvis_dir = Path.home() / ".jarvis"
|
|
20
19
|
env_file = jarvis_dir / "env"
|
|
21
20
|
|
|
22
|
-
#
|
|
21
|
+
# 检查~/.jarvis目录是否存在
|
|
23
22
|
if not jarvis_dir.exists():
|
|
24
23
|
jarvis_dir.mkdir(parents=True)
|
|
25
24
|
if env_file.exists():
|
|
@@ -53,7 +52,7 @@ def while_success(func: Callable[[], Any], sleep_time: float = 0.1) -> Any:
|
|
|
53
52
|
time.sleep(sleep_time)
|
|
54
53
|
continue
|
|
55
54
|
def while_true(func: Callable[[], bool], sleep_time: float = 0.1) -> Any:
|
|
56
|
-
"""
|
|
55
|
+
"""循环执行函数直到返回True"""
|
|
57
56
|
while True:
|
|
58
57
|
ret = func()
|
|
59
58
|
if ret:
|
|
@@ -62,37 +61,37 @@ def while_true(func: Callable[[], bool], sleep_time: float = 0.1) -> Any:
|
|
|
62
61
|
time.sleep(sleep_time)
|
|
63
62
|
return ret
|
|
64
63
|
def get_file_md5(filepath: str)->str:
|
|
65
|
-
"""
|
|
64
|
+
"""计算文件内容的MD5哈希值
|
|
66
65
|
|
|
67
|
-
|
|
68
|
-
filepath:
|
|
66
|
+
参数:
|
|
67
|
+
filepath: 要计算哈希的文件路径
|
|
69
68
|
|
|
70
|
-
|
|
71
|
-
str: MD5
|
|
69
|
+
返回:
|
|
70
|
+
str: 文件内容的MD5哈希值
|
|
72
71
|
"""
|
|
73
72
|
return hashlib.md5(open(filepath, "rb").read(100*1024*1024)).hexdigest()
|
|
74
73
|
def user_confirm(tip: str, default: bool = True) -> bool:
|
|
75
|
-
"""
|
|
74
|
+
"""提示用户确认是/否问题
|
|
76
75
|
|
|
77
|
-
|
|
78
|
-
tip:
|
|
79
|
-
default:
|
|
76
|
+
参数:
|
|
77
|
+
tip: 显示给用户的消息
|
|
78
|
+
default: 用户直接回车时的默认响应
|
|
80
79
|
|
|
81
|
-
|
|
82
|
-
bool: True
|
|
80
|
+
返回:
|
|
81
|
+
bool: 用户确认返回True,否则返回False
|
|
83
82
|
"""
|
|
84
83
|
suffix = "[Y/n]" if default else "[y/N]"
|
|
85
84
|
ret = get_single_line_input(f"{tip} {suffix}: ")
|
|
86
85
|
return default if ret == "" else ret.lower() == "y"
|
|
87
86
|
|
|
88
87
|
def get_file_line_count(filename: str) -> int:
|
|
89
|
-
"""
|
|
88
|
+
"""计算文件中的行数
|
|
90
89
|
|
|
91
|
-
|
|
92
|
-
filename:
|
|
90
|
+
参数:
|
|
91
|
+
filename: 要计算行数的文件路径
|
|
93
92
|
|
|
94
|
-
|
|
95
|
-
int:
|
|
93
|
+
返回:
|
|
94
|
+
int: 文件中的行数,如果文件无法读取则返回0
|
|
96
95
|
"""
|
|
97
96
|
try:
|
|
98
97
|
return len(open(filename, "r", encoding="utf-8", errors="ignore").readlines())
|
|
@@ -153,200 +152,3 @@ def ct(tag_name: str) -> str:
|
|
|
153
152
|
"""
|
|
154
153
|
return f"</{tag_name}>"
|
|
155
154
|
|
|
156
|
-
|
|
157
|
-
def create_soup_element(content: Union[str, Tag, List[Any]]) -> List[Union[Tag, str]]:
|
|
158
|
-
"""Safely create a BeautifulSoup element, ensuring it's treated as markup
|
|
159
|
-
|
|
160
|
-
Args:
|
|
161
|
-
content: Input content to convert to BeautifulSoup elements
|
|
162
|
-
Returns:
|
|
163
|
-
List of BeautifulSoup elements or strings
|
|
164
|
-
"""
|
|
165
|
-
if isinstance(content, str):
|
|
166
|
-
# Create a wrapper tag to ensure proper parsing
|
|
167
|
-
soup_div = BeautifulSoup(f"<div>{content}</div>", 'html.parser').div
|
|
168
|
-
if soup_div is not None:
|
|
169
|
-
return [cast(Union[Tag, str], el) for el in soup_div.contents]
|
|
170
|
-
return []
|
|
171
|
-
elif isinstance(content, list):
|
|
172
|
-
return content
|
|
173
|
-
return [content]
|
|
174
|
-
|
|
175
|
-
def extract_interactive_elements(html_content: str) -> List[Dict[str, Any]]:
|
|
176
|
-
"""Extract all interactive elements from HTML content with their properties.
|
|
177
|
-
|
|
178
|
-
Args:
|
|
179
|
-
html_content: HTML content to parse
|
|
180
|
-
|
|
181
|
-
Returns:
|
|
182
|
-
List of dictionaries containing element properties:
|
|
183
|
-
- xpath: XPath of the element
|
|
184
|
-
- tag: HTML tag name
|
|
185
|
-
- text: Text content
|
|
186
|
-
- is_clickable: Whether element is clickable
|
|
187
|
-
- is_input: Whether element is an input field
|
|
188
|
-
- is_select: Whether element is a select dropdown
|
|
189
|
-
"""
|
|
190
|
-
soup = BeautifulSoup(html_content, 'html.parser')
|
|
191
|
-
interactive_elements = []
|
|
192
|
-
|
|
193
|
-
# Define interactive tags
|
|
194
|
-
clickable_tags = {'a', 'button', 'input', 'select', 'textarea'}
|
|
195
|
-
input_tags = {'input', 'textarea', 'select'}
|
|
196
|
-
|
|
197
|
-
def get_xpath(element: Tag) -> str:
|
|
198
|
-
"""Generate XPath for an element"""
|
|
199
|
-
components = []
|
|
200
|
-
current = element
|
|
201
|
-
|
|
202
|
-
while current and current.name:
|
|
203
|
-
siblings = current.find_previous_siblings(current.name)
|
|
204
|
-
index = len(siblings) + 1
|
|
205
|
-
components.append(f"{current.name}[{index}]")
|
|
206
|
-
current = current.parent
|
|
207
|
-
|
|
208
|
-
return "/".join(reversed(components))
|
|
209
|
-
|
|
210
|
-
def process_element(element: Tag) -> None:
|
|
211
|
-
"""Process a single element and add it to interactive_elements if it's interactive"""
|
|
212
|
-
tag_name = element.name.lower()
|
|
213
|
-
|
|
214
|
-
# Skip non-interactive elements
|
|
215
|
-
if tag_name not in clickable_tags and not element.find_parent(clickable_tags):
|
|
216
|
-
return
|
|
217
|
-
|
|
218
|
-
# Get element properties
|
|
219
|
-
element_info = {
|
|
220
|
-
'xpath': get_xpath(element),
|
|
221
|
-
'tag': tag_name,
|
|
222
|
-
'text': element.get_text().strip(),
|
|
223
|
-
'is_clickable': tag_name in clickable_tags or bool(element.find_parent('a')) or bool(element.find_parent('button')),
|
|
224
|
-
'is_input': tag_name in input_tags,
|
|
225
|
-
'is_select': tag_name == 'select'
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
# Add additional properties for input elements
|
|
229
|
-
if element_info['is_input']:
|
|
230
|
-
element_info['input_type'] = element.get('type', 'text')
|
|
231
|
-
element_info['name'] = element.get('name', '')
|
|
232
|
-
element_info['value'] = element.get('value', '')
|
|
233
|
-
|
|
234
|
-
# Add options for select elements
|
|
235
|
-
if element_info['is_select']:
|
|
236
|
-
element_info['options'] = [
|
|
237
|
-
{'value': opt.get('value', ''), 'text': opt.get_text().strip()}
|
|
238
|
-
for opt in element.find_all('option')
|
|
239
|
-
if isinstance(opt, Tag)
|
|
240
|
-
]
|
|
241
|
-
|
|
242
|
-
interactive_elements.append(element_info)
|
|
243
|
-
|
|
244
|
-
# Process all elements
|
|
245
|
-
for element in soup.find_all():
|
|
246
|
-
if isinstance(element, Tag):
|
|
247
|
-
process_element(element)
|
|
248
|
-
|
|
249
|
-
return interactive_elements
|
|
250
|
-
|
|
251
|
-
def extract_display_elements(html_content: str) -> List[Dict[str, Any]]:
|
|
252
|
-
"""Extract all display elements from HTML content with their properties.
|
|
253
|
-
|
|
254
|
-
Args:
|
|
255
|
-
html_content: HTML content to parse
|
|
256
|
-
|
|
257
|
-
Returns:
|
|
258
|
-
List of dictionaries containing element properties:
|
|
259
|
-
- xpath: XPath of the element
|
|
260
|
-
- tag: HTML tag name
|
|
261
|
-
- text: Text content
|
|
262
|
-
- heading_level: Heading level (1-6) if the element is a heading
|
|
263
|
-
- is_list: Whether the element is a list
|
|
264
|
-
- is_list_item: Whether the element is a list item
|
|
265
|
-
- is_table: Whether the element is a table
|
|
266
|
-
- is_table_cell: Whether the element is a table cell
|
|
267
|
-
"""
|
|
268
|
-
soup = BeautifulSoup(html_content, 'html.parser')
|
|
269
|
-
display_elements = []
|
|
270
|
-
|
|
271
|
-
# Define display tags
|
|
272
|
-
display_tags = {
|
|
273
|
-
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', # Headings
|
|
274
|
-
'p', 'div', 'span', # Text containers
|
|
275
|
-
'ul', 'ol', 'li', # Lists
|
|
276
|
-
'table', 'tr', 'td', 'th', # Tables
|
|
277
|
-
'article', 'section', 'main', # Content sections
|
|
278
|
-
'header', 'footer', 'nav', # Layout sections
|
|
279
|
-
'aside', 'figure', 'figcaption' # Side content
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
# Define interactive tags to exclude
|
|
283
|
-
interactive_tags = {'a', 'button', 'input', 'select', 'textarea', 'form'}
|
|
284
|
-
|
|
285
|
-
def get_xpath(element: Tag) -> str:
|
|
286
|
-
"""Generate XPath for an element"""
|
|
287
|
-
components = []
|
|
288
|
-
current = element
|
|
289
|
-
|
|
290
|
-
while current and current.name:
|
|
291
|
-
siblings = current.find_previous_siblings(current.name)
|
|
292
|
-
index = len(siblings) + 1
|
|
293
|
-
components.append(f"{current.name}[{index}]")
|
|
294
|
-
current = current.parent
|
|
295
|
-
|
|
296
|
-
return "/".join(reversed(components))
|
|
297
|
-
|
|
298
|
-
def process_element(element: Tag) -> None:
|
|
299
|
-
"""Process a single element and add it to display_elements if it's a display element"""
|
|
300
|
-
tag_name = element.name.lower()
|
|
301
|
-
|
|
302
|
-
# Skip non-display elements and interactive elements
|
|
303
|
-
if tag_name not in display_tags or element.find_parent(interactive_tags):
|
|
304
|
-
return
|
|
305
|
-
|
|
306
|
-
# Get text content
|
|
307
|
-
text = element.get_text().strip()
|
|
308
|
-
if not text: # Skip empty elements
|
|
309
|
-
return
|
|
310
|
-
|
|
311
|
-
# Get element properties
|
|
312
|
-
element_info = {
|
|
313
|
-
'xpath': get_xpath(element),
|
|
314
|
-
'tag': tag_name,
|
|
315
|
-
'text': text,
|
|
316
|
-
'heading_level': int(tag_name[1]) if tag_name.startswith('h') and len(tag_name) == 2 else None,
|
|
317
|
-
'is_list': tag_name in {'ul', 'ol'},
|
|
318
|
-
'is_list_item': tag_name == 'li',
|
|
319
|
-
'is_table': tag_name == 'table',
|
|
320
|
-
'is_table_cell': tag_name in {'td', 'th'}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
# Add list-specific properties
|
|
324
|
-
if element_info['is_list']:
|
|
325
|
-
element_info['list_items'] = [
|
|
326
|
-
{'text': li.get_text().strip()}
|
|
327
|
-
for li in element.find_all('li')
|
|
328
|
-
if isinstance(li, Tag)
|
|
329
|
-
]
|
|
330
|
-
|
|
331
|
-
# Add table-specific properties
|
|
332
|
-
if element_info['is_table']:
|
|
333
|
-
element_info['table_rows'] = [
|
|
334
|
-
{
|
|
335
|
-
'cells': [
|
|
336
|
-
{'text': cell.get_text().strip(), 'is_header': cell.name == 'th'}
|
|
337
|
-
for cell in row.find_all(['td', 'th'])
|
|
338
|
-
if isinstance(cell, Tag)
|
|
339
|
-
]
|
|
340
|
-
}
|
|
341
|
-
for row in element.find_all('tr')
|
|
342
|
-
if isinstance(row, Tag)
|
|
343
|
-
]
|
|
344
|
-
|
|
345
|
-
display_elements.append(element_info)
|
|
346
|
-
|
|
347
|
-
# Process all elements
|
|
348
|
-
for element in soup.find_all():
|
|
349
|
-
if isinstance(element, Tag):
|
|
350
|
-
process_element(element)
|
|
351
|
-
|
|
352
|
-
return display_elements
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: jarvis-ai-assistant
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.149
|
|
4
4
|
Summary: Jarvis: An AI assistant that uses tools to interact with the system
|
|
5
5
|
Home-page: https://github.com/skyfireitdiy/Jarvis
|
|
6
6
|
Author: skyfire
|
|
@@ -40,32 +40,23 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
40
40
|
Requires-Python: >=3.8
|
|
41
41
|
Description-Content-Type: text/markdown
|
|
42
42
|
License-File: LICENSE
|
|
43
|
-
Requires-Dist: requests
|
|
44
|
-
Requires-Dist:
|
|
45
|
-
Requires-Dist:
|
|
46
|
-
Requires-Dist:
|
|
47
|
-
Requires-Dist:
|
|
48
|
-
Requires-Dist:
|
|
49
|
-
Requires-Dist:
|
|
50
|
-
Requires-Dist:
|
|
51
|
-
Requires-Dist:
|
|
52
|
-
Requires-Dist:
|
|
53
|
-
Requires-Dist:
|
|
54
|
-
Requires-Dist:
|
|
55
|
-
Requires-Dist:
|
|
56
|
-
Requires-Dist: docx
|
|
57
|
-
Requires-Dist:
|
|
58
|
-
Requires-Dist:
|
|
59
|
-
Requires-Dist:
|
|
60
|
-
Requires-Dist: fuzzywuzzy>=0.18.0
|
|
61
|
-
Requires-Dist: python-Levenshtein>=0.25.0
|
|
62
|
-
Requires-Dist: jedi>=0.17.2
|
|
63
|
-
Requires-Dist: psutil>=7.0.0
|
|
64
|
-
Requires-Dist: fastapi>=0.115.4
|
|
65
|
-
Requires-Dist: uvicorn>=0.33.0
|
|
66
|
-
Requires-Dist: python-pptx>=1.0.0
|
|
67
|
-
Requires-Dist: pandas>=2.0.0
|
|
68
|
-
Requires-Dist: html2text>=2024.2.26
|
|
43
|
+
Requires-Dist: requests==2.32.3
|
|
44
|
+
Requires-Dist: colorama==0.4.6
|
|
45
|
+
Requires-Dist: prompt-toolkit==3.0.50
|
|
46
|
+
Requires-Dist: PyMuPDF==1.24.11
|
|
47
|
+
Requires-Dist: yaspin==2.4.0
|
|
48
|
+
Requires-Dist: pygments==2.19.1
|
|
49
|
+
Requires-Dist: fuzzywuzzy==0.18.0
|
|
50
|
+
Requires-Dist: jedi==0.19.2
|
|
51
|
+
Requires-Dist: fastapi==0.115.12
|
|
52
|
+
Requires-Dist: uvicorn==0.33.0
|
|
53
|
+
Requires-Dist: pandas==2.0.3
|
|
54
|
+
Requires-Dist: rich==14.0.0
|
|
55
|
+
Requires-Dist: transformers==4.46.3
|
|
56
|
+
Requires-Dist: python-docx==1.1.2
|
|
57
|
+
Requires-Dist: python-pptx==1.0.2
|
|
58
|
+
Requires-Dist: torch==2.4.1
|
|
59
|
+
Requires-Dist: python-Levenshtein==0.25.1
|
|
69
60
|
Provides-Extra: dev
|
|
70
61
|
Requires-Dist: pytest; extra == "dev"
|
|
71
62
|
Requires-Dist: black; extra == "dev"
|
|
@@ -82,6 +73,7 @@ Requires-Dist: mypy; extra == "dev"
|
|
|
82
73
|
|
|
83
74
|
*您的智能开发和系统交互助手*
|
|
84
75
|
|
|
76
|
+
[视频介绍](#video-introduction) •
|
|
85
77
|
[快速开始](#quick-start) •
|
|
86
78
|
[配置说明](#configuration) •
|
|
87
79
|
[工具说明](#tools) •
|
|
@@ -92,6 +84,11 @@ Requires-Dist: mypy; extra == "dev"
|
|
|
92
84
|
|
|
93
85
|
---
|
|
94
86
|
|
|
87
|
+
## 📺 视频介绍<a id="video-introduction"></a>
|
|
88
|
+
|
|
89
|
+
[](https://player.bilibili.com/player.html?isOutside=true&aid=114306578382907&bvid=BV1x2dAYeEpM&cid=29314583629&p=1)
|
|
90
|
+
|
|
91
|
+
|
|
95
92
|
## 🚀 快速开始 <a id="quick-start"></a>
|
|
96
93
|
### 安装
|
|
97
94
|
```bash
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
jarvis/__init__.py,sha256=
|
|
1
|
+
jarvis/__init__.py,sha256=hxJ4Q6VJ6mt37L0_z_wpHY8wJUah6G2JMjEbeoEg-FA,50
|
|
2
2
|
jarvis/jarvis_agent/__init__.py,sha256=QtWu2kh6o5IB_XtGLoxHi5K9lA1t8XoqNUXtX-OqujY,23796
|
|
3
3
|
jarvis/jarvis_agent/builtin_input_handler.py,sha256=0SjlBYnBWKNi3eVdZ7c2NuP82tQej7DEWLAqG6bY1Rc,4357
|
|
4
4
|
jarvis/jarvis_agent/file_input_handler.py,sha256=6R68cSjLBnSJjTKJrSO2IqziRDFnxazU_Jq2t1W1ndo,3695
|
|
5
5
|
jarvis/jarvis_agent/jarvis.py,sha256=jxsk8afcBpVM1ruy4Q00UJSRc2db_Av45rH8__y1-6E,5067
|
|
6
|
-
jarvis/jarvis_agent/main.py,sha256=
|
|
6
|
+
jarvis/jarvis_agent/main.py,sha256=Jlw_Tofh2C-sMVnkeOZBrwWJOWNH3IhsKDUn-WBlgU8,2602
|
|
7
7
|
jarvis/jarvis_agent/output_handler.py,sha256=4limQ-Kf-YYvQjT5SMjJIyyvD1DVG8tINv1A_qbv4ho,405
|
|
8
|
-
jarvis/jarvis_agent/patch.py,sha256=
|
|
8
|
+
jarvis/jarvis_agent/patch.py,sha256=nhfAVHhSm4PWBMd_B9eeaUdnGDpryWTrGiJ7rMqvJ5g,22504
|
|
9
9
|
jarvis/jarvis_agent/shell_input_handler.py,sha256=9IoGQCe6FF4HA2V5S11q63AtnWDZFpNeRd3hcqCAlBw,1237
|
|
10
10
|
jarvis/jarvis_code_agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
11
|
jarvis/jarvis_code_agent/code_agent.py,sha256=XlPa764dXbHkTxs1ByG9G-2K7_NRtmogHJhTFM_Hd_k,13117
|
|
12
|
-
jarvis/jarvis_code_analysis/code_review.py,sha256=
|
|
12
|
+
jarvis/jarvis_code_analysis/code_review.py,sha256=9H0Jt0SwdDs9qdE4UALYw6Zp6SyWxmAUyXj6yXrMnIU,29267
|
|
13
13
|
jarvis/jarvis_code_analysis/checklists/__init__.py,sha256=PCjlyxLa939613cAzS7pfEPgP57setO-1RvcdzzPivw,54
|
|
14
14
|
jarvis/jarvis_code_analysis/checklists/c_cpp.py,sha256=8lfWmhImAxeTBdHPOgVXDjMllaq280Qki1ZOOSDBnvk,1293
|
|
15
15
|
jarvis/jarvis_code_analysis/checklists/csharp.py,sha256=fg35Iima2nIsirEmAjianfAybVjwRYml9BtbSQFff7w,2396
|
|
@@ -35,24 +35,23 @@ jarvis/jarvis_git_details/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
|
|
|
35
35
|
jarvis/jarvis_git_details/main.py,sha256=YowncVxYyJ3y2EvGrZhAJeR4yizXp6aB3dqvoYTepFY,6117
|
|
36
36
|
jarvis/jarvis_git_squash/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
37
37
|
jarvis/jarvis_git_squash/main.py,sha256=xBNkAl7_8_pQC-C6RcUImA1mEU4KTqhjtA57rG_mMJ8,2179
|
|
38
|
-
jarvis/jarvis_git_utils/git_commiter.py,sha256=
|
|
39
|
-
jarvis/jarvis_lsp/base.py,sha256=
|
|
40
|
-
jarvis/jarvis_lsp/cpp.py,sha256=
|
|
41
|
-
jarvis/jarvis_lsp/go.py,sha256=
|
|
42
|
-
jarvis/jarvis_lsp/python.py,sha256=
|
|
38
|
+
jarvis/jarvis_git_utils/git_commiter.py,sha256=dozU5vmodhb-uiLJBHGRPzUMU1er4xqvjClG3sqNwTA,10780
|
|
39
|
+
jarvis/jarvis_lsp/base.py,sha256=f-76xgNijfQ4G3Q0t8IfOGtCu-q2TSQ7a_in6XwDb_8,2030
|
|
40
|
+
jarvis/jarvis_lsp/cpp.py,sha256=ekci2M9_UtkCSEe9__72h26Gat93r9_knL2VmFr8X5M,3141
|
|
41
|
+
jarvis/jarvis_lsp/go.py,sha256=sSypuQSP5X2YtrVMC8XCc5nXkgfG93SO7sC89lHzoR8,3458
|
|
42
|
+
jarvis/jarvis_lsp/python.py,sha256=OJuYHLHI1aYNNWcAFayy_5GxogwyMC3A7KOYGjxN1yg,1843
|
|
43
43
|
jarvis/jarvis_lsp/registry.py,sha256=LduRCEVH5y75IODdY8lZ3ZB3OHKpgwbZnYNxuhUmA_o,6439
|
|
44
|
-
jarvis/jarvis_lsp/rust.py,sha256=
|
|
44
|
+
jarvis/jarvis_lsp/rust.py,sha256=ICmQs5UVdMZwn5KjaF1YRXBCLUMtGF8Z9IwE5rqWkrU,3686
|
|
45
45
|
jarvis/jarvis_methodology/main.py,sha256=IBv87UOmdCailgooMtWEcqZcQHmNLhZD-kkGw5jOcVg,3375
|
|
46
46
|
jarvis/jarvis_multi_agent/__init__.py,sha256=SX8lBErhltKyYRM-rymrMz3sJ0Zl3hBXrpsPdFgzkQc,4399
|
|
47
47
|
jarvis/jarvis_multi_agent/main.py,sha256=aGuUC3YQmahabqwDwZXJjfQLYsZ3KIZdf8DZDlVNMe4,1543
|
|
48
48
|
jarvis/jarvis_platform/__init__.py,sha256=WIJtD5J7lOrWLX2bsgZGkmlMcN0NOJsnh_reybmHPjg,58
|
|
49
|
-
jarvis/jarvis_platform/base.py,sha256=
|
|
50
|
-
jarvis/jarvis_platform/kimi.py,sha256=
|
|
49
|
+
jarvis/jarvis_platform/base.py,sha256=bihlnM5PowzKhi3dbxUp_eHOA14MLrHAbs_DXLe0s0g,3228
|
|
50
|
+
jarvis/jarvis_platform/kimi.py,sha256=h69kc29IB_Tv1txjEQF-k39F_C1ijUeFU7Qxw1-uQ84,16468
|
|
51
51
|
jarvis/jarvis_platform/registry.py,sha256=2kF2xwBIOlBlsw1aOzDWWyZbdITVxp96kwq01-mAWLg,7724
|
|
52
52
|
jarvis/jarvis_platform/yuanbao.py,sha256=TBn9VbJ05g45CFNUz83HQTL1Nyk00pWahTlFqiG8eQ0,21868
|
|
53
53
|
jarvis/jarvis_platform_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
54
54
|
jarvis/jarvis_platform_manager/main.py,sha256=o7UDrcCkLf9dTh2LOO-_bQVHjWf2X6RuSY5XRtCGvZs,20245
|
|
55
|
-
jarvis/jarvis_platform_manager/openai_test.py,sha256=8L9Xx-oR82X8l38NsVhkymYucICwMb-6yrH17Usk2TI,4954
|
|
56
55
|
jarvis/jarvis_smart_shell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
57
56
|
jarvis/jarvis_smart_shell/main.py,sha256=slP_8CwpfMjWFZis0At1ANRlPb3gx1KteAg1B7R7dl4,4546
|
|
58
57
|
jarvis/jarvis_tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -60,33 +59,33 @@ jarvis/jarvis_tools/ask_codebase.py,sha256=xQTcuDl7cbH6uVkWlkA1HXJAo4_3r09-3SboU
|
|
|
60
59
|
jarvis/jarvis_tools/ask_user.py,sha256=NjxTCHGKo4nthbEQD-isvPCW4PQhTcekEferjnukX70,2143
|
|
61
60
|
jarvis/jarvis_tools/base.py,sha256=vskI4czVdlhbo38ODuF9rFrnWBYQIhJSPAqAkLVcyTs,1165
|
|
62
61
|
jarvis/jarvis_tools/chdir.py,sha256=do_OdtabiH3lZcT_ynjSAX66XgH2gPl9mYiS7dMMDa8,2682
|
|
63
|
-
jarvis/jarvis_tools/code_plan.py,sha256=
|
|
62
|
+
jarvis/jarvis_tools/code_plan.py,sha256=jNa2rs4J3Fam8Q_RHE2_QvVch21TPp-Zfv-W6iQ3D_0,7729
|
|
64
63
|
jarvis/jarvis_tools/create_code_agent.py,sha256=Vl76eqERuxJWKmVR3eUSKE7ZqlG9pVhzqZqhuxZRin8,4217
|
|
65
64
|
jarvis/jarvis_tools/create_sub_agent.py,sha256=wGiHukvi58wb1AKW5beP7R8VvApOn8TOeGmtXsmcETE,3001
|
|
66
65
|
jarvis/jarvis_tools/execute_script.py,sha256=3sR_u6-SLbzmcUbXjHLN-rGjoelIj4uAefys5la_x7o,6759
|
|
67
|
-
jarvis/jarvis_tools/file_analyzer.py,sha256=
|
|
66
|
+
jarvis/jarvis_tools/file_analyzer.py,sha256=XCsFB4dZ9qy2q929hqi1rTngj6AtRtIaPx_W7lJAcpQ,4814
|
|
68
67
|
jarvis/jarvis_tools/file_operation.py,sha256=sbO2gpVyDBM2gdBnRSLp-FUQPzHo4t3Wb9TNI1EMTFo,10337
|
|
69
68
|
jarvis/jarvis_tools/find_methodology.py,sha256=FnvjWt4Za2P9B_oDPSOqkotuaQFbgjM9WCPkB_OJRzQ,2225
|
|
70
69
|
jarvis/jarvis_tools/lsp_get_diagnostics.py,sha256=IYqv8jQwSK71sZpDBRolSDnYii8t0M7fzLthhMYTeGk,5322
|
|
71
70
|
jarvis/jarvis_tools/methodology.py,sha256=wBcQF4mSupcro6mi4koJevu3w5ELNakQ0jjTRE7JP0M,5162
|
|
72
|
-
jarvis/jarvis_tools/read_code.py,sha256=
|
|
71
|
+
jarvis/jarvis_tools/read_code.py,sha256=_X6D3AIgRD9YplSDnFhXOm8wQAZMA3pkkXy31SG33l0,6041
|
|
73
72
|
jarvis/jarvis_tools/read_webpage.py,sha256=syduSZK4kXRRTPzeZ2W9Q6YH5umKiMJZyjA0cCpSF4g,2198
|
|
74
73
|
jarvis/jarvis_tools/registry.py,sha256=2yEFBZ6vrG_SUy5m2bEdHDHfeJjlLrBsdzMKribHEhw,18325
|
|
75
|
-
jarvis/jarvis_tools/search_web.py,sha256=
|
|
74
|
+
jarvis/jarvis_tools/search_web.py,sha256=kWW9K2QUR2AxPq6gcyx4Bgy-0Y4gzcdErq1DNT1EYM4,1333
|
|
76
75
|
jarvis/jarvis_tools/virtual_tty.py,sha256=Rpn9VXUG17LQsY87F_O6UCjN_opXB05mpwozxYf-xVI,16372
|
|
77
76
|
jarvis/jarvis_utils/__init__.py,sha256=KMg-KY5rZIhGTeOD5e2Xo5CU7DX1DUz4ULWAaTQ-ZNw,825
|
|
78
77
|
jarvis/jarvis_utils/config.py,sha256=aHLOVJMJz-AUvTz0L2V33J_sJLaCHCwxT3CuKMmN0IM,3104
|
|
79
|
-
jarvis/jarvis_utils/embedding.py,sha256=
|
|
78
|
+
jarvis/jarvis_utils/embedding.py,sha256=QOO36-wXabKo0GOJ_r6fYiHCcLxT24lXFLCGwo717Ak,6955
|
|
80
79
|
jarvis/jarvis_utils/file_processors.py,sha256=VchHOIXxxGWqSu5q0Q_epVWUHJTxaKz2wmqiDoRy5Ik,14324
|
|
81
|
-
jarvis/jarvis_utils/git_utils.py,sha256=
|
|
80
|
+
jarvis/jarvis_utils/git_utils.py,sha256=j_Jw6h7JD91XhMf0WD3MAH4URkLUBrrYCLnuLm1GeN4,5630
|
|
82
81
|
jarvis/jarvis_utils/globals.py,sha256=Ed2d6diWXCgI74HVV_tI4qW7yXxLpNvQKN2yG0IH9hc,3388
|
|
83
82
|
jarvis/jarvis_utils/input.py,sha256=0Xq5xV2-6yiyEvT8Dry4CYlGMHAmi5hiSFxmLkWSZFw,6643
|
|
84
83
|
jarvis/jarvis_utils/methodology.py,sha256=kEqr3BxBuy26YPUziq4GeCD0TwaEZMLwd41_ZVMesHE,6267
|
|
85
|
-
jarvis/jarvis_utils/output.py,sha256=
|
|
86
|
-
jarvis/jarvis_utils/utils.py,sha256=
|
|
87
|
-
jarvis_ai_assistant-0.1.
|
|
88
|
-
jarvis_ai_assistant-0.1.
|
|
89
|
-
jarvis_ai_assistant-0.1.
|
|
90
|
-
jarvis_ai_assistant-0.1.
|
|
91
|
-
jarvis_ai_assistant-0.1.
|
|
92
|
-
jarvis_ai_assistant-0.1.
|
|
84
|
+
jarvis/jarvis_utils/output.py,sha256=BmWdB1bmizv0xfU4Z___9p_xQodorriIcEgADVq9fk0,8416
|
|
85
|
+
jarvis/jarvis_utils/utils.py,sha256=MqENS4ldx5BEsQJOS_8tNPI7PNwZ-QnF3KUeg_AaC0U,4634
|
|
86
|
+
jarvis_ai_assistant-0.1.149.dist-info/LICENSE,sha256=AGgVgQmTqFvaztRtCAXsAMryUymB18gZif7_l2e1XOg,1063
|
|
87
|
+
jarvis_ai_assistant-0.1.149.dist-info/METADATA,sha256=UJzRWmjjNJ6SgTakma9RGTY2coCPoUsBZRYjTpQCh5U,11234
|
|
88
|
+
jarvis_ai_assistant-0.1.149.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
|
|
89
|
+
jarvis_ai_assistant-0.1.149.dist-info/entry_points.txt,sha256=4ZS8kq6jahnmfDyXFSx39HRi-Tkbp0uFc6cTXt3QIHA,929
|
|
90
|
+
jarvis_ai_assistant-0.1.149.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
|
|
91
|
+
jarvis_ai_assistant-0.1.149.dist-info/RECORD,,
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Test script for Jarvis OpenAI-compatible API service.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
import argparse
|
|
7
|
-
import sys
|
|
8
|
-
from openai import OpenAI
|
|
9
|
-
|
|
10
|
-
def test_chat(api_base, model, stream=False, interactive=False):
|
|
11
|
-
"""Test chat completion with the API."""
|
|
12
|
-
client = OpenAI(
|
|
13
|
-
api_key="dummy-key", # Not actually used by our service
|
|
14
|
-
base_url=f"{api_base}/v1"
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
print(f"Testing chat with model: {model}, stream={stream}")
|
|
18
|
-
print("=" * 50)
|
|
19
|
-
|
|
20
|
-
try:
|
|
21
|
-
# First, list available models
|
|
22
|
-
print("Available models:")
|
|
23
|
-
models = client.models.list()
|
|
24
|
-
for m in models.data:
|
|
25
|
-
print(f" - {m.id}")
|
|
26
|
-
print()
|
|
27
|
-
|
|
28
|
-
if interactive:
|
|
29
|
-
# Interactive chat mode
|
|
30
|
-
messages = [
|
|
31
|
-
{"role": "system", "content": "You are a helpful assistant."}
|
|
32
|
-
]
|
|
33
|
-
|
|
34
|
-
print("Interactive chat mode. Type 'exit' to quit.")
|
|
35
|
-
print("=" * 50)
|
|
36
|
-
|
|
37
|
-
while True:
|
|
38
|
-
# Get user input
|
|
39
|
-
user_input = input("You: ")
|
|
40
|
-
if user_input.lower() in ['exit', 'quit', 'bye']:
|
|
41
|
-
break
|
|
42
|
-
|
|
43
|
-
# Add user message to history
|
|
44
|
-
messages.append({"role": "user", "content": user_input})
|
|
45
|
-
|
|
46
|
-
# Get response
|
|
47
|
-
print("Assistant: ", end="", flush=True)
|
|
48
|
-
|
|
49
|
-
if stream:
|
|
50
|
-
response = client.chat.completions.create(
|
|
51
|
-
model=model,
|
|
52
|
-
messages=messages, # type: ignore
|
|
53
|
-
stream=True
|
|
54
|
-
) # type: ignore
|
|
55
|
-
|
|
56
|
-
# Process the streaming response
|
|
57
|
-
assistant_response = ""
|
|
58
|
-
for chunk in response:
|
|
59
|
-
if hasattr(chunk.choices[0], 'delta') and hasattr(chunk.choices[0].delta, 'content') and chunk.choices[0].delta.content:
|
|
60
|
-
content = chunk.choices[0].delta.content
|
|
61
|
-
assistant_response += content
|
|
62
|
-
print(content, end="", flush=True)
|
|
63
|
-
print()
|
|
64
|
-
else:
|
|
65
|
-
response = client.chat.completions.create(
|
|
66
|
-
model=model,
|
|
67
|
-
messages=messages # type: ignore
|
|
68
|
-
)
|
|
69
|
-
assistant_response = response.choices[0].message.content
|
|
70
|
-
print(assistant_response)
|
|
71
|
-
|
|
72
|
-
# Add assistant response to history
|
|
73
|
-
messages.append({"role": "assistant", "content": assistant_response}) # type: ignore
|
|
74
|
-
print()
|
|
75
|
-
|
|
76
|
-
print("=" * 50)
|
|
77
|
-
print("Chat session ended.")
|
|
78
|
-
|
|
79
|
-
else:
|
|
80
|
-
# Single request mode
|
|
81
|
-
print("Sending chat request...")
|
|
82
|
-
messages = [
|
|
83
|
-
{"role": "system", "content": "You are a helpful assistant."},
|
|
84
|
-
{"role": "user", "content": "Hello! Tell me a short joke."}
|
|
85
|
-
]
|
|
86
|
-
|
|
87
|
-
if stream:
|
|
88
|
-
print("Response (streaming):")
|
|
89
|
-
|
|
90
|
-
# Use the OpenAI client for streaming
|
|
91
|
-
response = client.chat.completions.create(
|
|
92
|
-
model=model,
|
|
93
|
-
messages=messages, # type: ignore
|
|
94
|
-
stream=True
|
|
95
|
-
) # type: ignore
|
|
96
|
-
|
|
97
|
-
# Process the streaming response
|
|
98
|
-
full_content = ""
|
|
99
|
-
for chunk in response:
|
|
100
|
-
if hasattr(chunk.choices[0], 'delta') and hasattr(chunk.choices[0].delta, 'content') and chunk.choices[0].delta.content:
|
|
101
|
-
content = chunk.choices[0].delta.content
|
|
102
|
-
full_content += content
|
|
103
|
-
print(content, end="", flush=True)
|
|
104
|
-
|
|
105
|
-
print("\n")
|
|
106
|
-
print(f"Full response: {full_content}")
|
|
107
|
-
else:
|
|
108
|
-
print("Response:")
|
|
109
|
-
response = client.chat.completions.create(
|
|
110
|
-
model=model,
|
|
111
|
-
messages=messages # type: ignore
|
|
112
|
-
)
|
|
113
|
-
print(response.choices[0].message.content)
|
|
114
|
-
|
|
115
|
-
print("=" * 50)
|
|
116
|
-
print("Test completed successfully!")
|
|
117
|
-
|
|
118
|
-
except Exception as e:
|
|
119
|
-
print(f"Error: {str(e)}")
|
|
120
|
-
import traceback
|
|
121
|
-
traceback.print_exc()
|
|
122
|
-
return 1
|
|
123
|
-
|
|
124
|
-
return 0
|
|
125
|
-
|
|
126
|
-
def main():
|
|
127
|
-
parser = argparse.ArgumentParser(description="Test Jarvis OpenAI-compatible API")
|
|
128
|
-
parser.add_argument("--api-base", default="http://localhost:8000", help="API base URL")
|
|
129
|
-
parser.add_argument("--model", default="gpt-3.5-turbo", help="Model to test (default: gpt-3.5-turbo)")
|
|
130
|
-
parser.add_argument("--stream", action="store_true", help="Test streaming mode")
|
|
131
|
-
parser.add_argument("--interactive", "-i", action="store_true", help="Interactive chat mode")
|
|
132
|
-
|
|
133
|
-
args = parser.parse_args()
|
|
134
|
-
|
|
135
|
-
return test_chat(args.api_base, args.model, args.stream, args.interactive)
|
|
136
|
-
|
|
137
|
-
if __name__ == "__main__":
|
|
138
|
-
sys.exit(main())
|
|
File without changes
|
|
File without changes
|
{jarvis_ai_assistant-0.1.148.dist-info → jarvis_ai_assistant-0.1.149.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{jarvis_ai_assistant-0.1.148.dist-info → jarvis_ai_assistant-0.1.149.dist-info}/top_level.txt
RENAMED
|
File without changes
|