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 CHANGED
@@ -1,3 +1,3 @@
1
1
  """Jarvis AI Assistant"""
2
2
 
3
- __version__ = "0.1.148"
3
+ __version__ = "0.1.149"
@@ -1,7 +1,6 @@
1
1
  import argparse
2
2
  import yaml
3
3
  import os
4
- from typing import Optional, List
5
4
  from jarvis.jarvis_agent import Agent
6
5
  from jarvis.jarvis_utils.input import get_multiline_input
7
6
  from jarvis.jarvis_utils.output import PrettyOutput, OutputType
@@ -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
- PrettyOutput.print(f"恢复文件失败: {str(e)}", OutputType.ERROR)
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
- subprocess.run(['git', 'reset', '--hard', 'HEAD'], check=True)
258
- subprocess.run(['git', 'clean', '-fd'], check=True)
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=True,
291
+ text=False,
271
292
  check=True
272
293
  )
273
- ret = result.stdout
274
- subprocess.run(['git', "reset", "--mixed", "HEAD"], check=True)
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:
@@ -4,7 +4,6 @@ import os
4
4
  import re
5
5
  import tempfile
6
6
 
7
- from httpx import get
8
7
  from yaspin import yaspin
9
8
  from jarvis.jarvis_platform.registry import PlatformRegistry
10
9
  from jarvis.jarvis_tools.read_code import ReadCodeTool
@@ -3,7 +3,6 @@ import shlex
3
3
  import subprocess
4
4
  from typing import Dict, Any, Optional
5
5
  import tempfile
6
- from click import Option
7
6
  import yaml
8
7
  from yaspin import yaspin
9
8
  from jarvis.jarvis_platform.registry import PlatformRegistry
jarvis/jarvis_lsp/base.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from abc import ABC, abstractmethod
2
- from typing import List, Dict, Optional, Tuple, Any, Union
2
+ from typing import List, Dict, Any, Union
3
3
 
4
4
  class BaseLSP(ABC):
5
5
  """Base class for Language Server Protocol integration.
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, Tuple, Any
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, Tuple, Any
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
@@ -1,4 +1,4 @@
1
- from typing import List, Dict, Optional, Tuple, Any
1
+ from typing import List, Dict, Any
2
2
  import jedi
3
3
  from jarvis.jarvis_lsp.base import BaseLSP
4
4
 
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, Tuple, Any
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
@@ -1,6 +1,6 @@
1
1
  from abc import ABC, abstractmethod
2
2
  import re
3
- from typing import Dict, List, Tuple
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
@@ -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"""
@@ -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
  """用于代码修改规划和需求分析的工具
@@ -1,4 +1,4 @@
1
- from typing import Dict, Any, List
1
+ from typing import Dict, Any
2
2
  import os
3
3
 
4
4
  from jarvis.jarvis_platform.registry import PlatformRegistry
@@ -1,7 +1,6 @@
1
1
  from typing import Dict, Any
2
2
  import os
3
3
 
4
- from pkg_resources import add_activation_listener
5
4
  from yaspin import yaspin
6
5
 
7
6
  from jarvis.jarvis_utils.globals import add_read_file_record
@@ -1,5 +1,4 @@
1
1
  import os
2
- import statistics
3
2
  from typing import Any, Dict
4
3
  from jarvis.jarvis_platform.registry import PlatformRegistry
5
4
 
@@ -1,12 +1,8 @@
1
1
  import os
2
- import numpy as np
3
- import torch
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
  # 全局缓存,避免重复加载模型
@@ -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=True
77
+ text=False # 禁用自动文本解码
78
78
  )
79
79
  if result.returncode != 0:
80
- PrettyOutput.print(f"获取commit历史失败: {result.stderr}", OutputType.ERROR)
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 result.stdout.splitlines():
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=True
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]]:
@@ -11,7 +11,6 @@ from enum import Enum
11
11
  from datetime import datetime
12
12
  from typing import Optional
13
13
  from rich.panel import Panel
14
- from rich.box import HEAVY
15
14
  from rich.text import Text
16
15
  from rich.syntax import Syntax
17
16
  from rich.style import Style as RichStyle
@@ -2,8 +2,7 @@ import os
2
2
  import time
3
3
  import hashlib
4
4
  from pathlib import Path
5
- from typing import Union, List, Dict, Any, Callable, cast
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
- # Check if ~/.jarvis directory exists
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
- """Loop execution function, until the function returns True"""
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
- """Calculate the MD5 hash of a file's content.
64
+ """计算文件内容的MD5哈希值
66
65
 
67
- Args:
68
- filepath: Path to the file to hash
66
+ 参数:
67
+ filepath: 要计算哈希的文件路径
69
68
 
70
- Returns:
71
- str: MD5 hash of the file's content
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
- """Prompt the user for confirmation with a yes/no question.
74
+ """提示用户确认是/否问题
76
75
 
77
- Args:
78
- tip: The message to show to the user
79
- default: The default response if user hits enter
76
+ 参数:
77
+ tip: 显示给用户的消息
78
+ default: 用户直接回车时的默认响应
80
79
 
81
- Returns:
82
- bool: True if user confirmed, False otherwise
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
- """Count the number of lines in a file.
88
+ """计算文件中的行数
90
89
 
91
- Args:
92
- filename: Path to the file to count lines for
90
+ 参数:
91
+ filename: 要计算行数的文件路径
93
92
 
94
- Returns:
95
- int: Number of lines in the file, 0 if file cannot be read
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.148
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>=2.25.1
44
- Requires-Dist: pyyaml>=5.1
45
- Requires-Dist: colorama>=0.4.6
46
- Requires-Dist: prompt-toolkit>=3.0.0
47
- Requires-Dist: openai>=1.20.0
48
- Requires-Dist: numpy>=1.19.5
49
- Requires-Dist: faiss-cpu>=1.8.0
50
- Requires-Dist: sentence-transformers>=2.2.2
51
- Requires-Dist: bs4>=0.0.1
52
- Requires-Dist: PyMuPDF>=1.21.0
53
- Requires-Dist: python-docx>=0.8.11
54
- Requires-Dist: tiktoken>=0.3.0
55
- Requires-Dist: tqdm>=4.65.0
56
- Requires-Dist: docx>=0.2.4
57
- Requires-Dist: yaspin>=2.4.0
58
- Requires-Dist: rich>=13.3.1
59
- Requires-Dist: pygments>=2.15.0
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
+ [![视频介绍](docs/images/intro.png)](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=IPKJ58S3CymSi9qPAmkE8Ov4uPiG-oVEYfh-4wsuyaM,50
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=Hx1cavfGkrGVEk_HrOJX6FNE0fEh2CDLy7Efr_VSiKI,2636
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=L1Ejz2P_0sH2zaeHt3pkAPCo55RV3JAjBf4EijjBVk0,21343
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=nS_GeT3RhkzeF6xvOdncqufMKG8OKDhYbLsnOiX1WcQ,29289
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=mBmrsbN6NrjdVPqa_tW7zLgx1vRWzYM2OMU__iACifw,10805
39
- jarvis/jarvis_lsp/base.py,sha256=CWfiqiQ6ZBc_lrW64Y1YAsFQeNPGoWcgTBGKgOrPVQg,2047
40
- jarvis/jarvis_lsp/cpp.py,sha256=SOXFhpipvbdhlwUZ7Rh0hdWGXWnrNOxZVsmTN6ZXoZk,3148
41
- jarvis/jarvis_lsp/go.py,sha256=h7vA0ArGSq9rhLZcrPXg5HdnEbKwnjVr322IkYI1jHw,3465
42
- jarvis/jarvis_lsp/python.py,sha256=xMqSVJn8w6CZEquSIO2I-6TJ7-YOABgpt3SjNOV6UAk,1860
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=9UOiYTUwMwz2raj1G8Uec0aB5Oun7wMiWYGDhC4JMpI,3693
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=Ge-UgZGCHICFWOqrHzg-_qXQXjS1I2lZSxfYs5Angwo,3234
50
- jarvis/jarvis_platform/kimi.py,sha256=tytHhRSddPTNwkaPYPr59rBZfGMo7616QMcnFQxLRic,16494
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=6FtKFumGnjxCMK8VSBlgQsneu45gKhN2hnxzTSh9Cf8,7776
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=g_mjECrq4gUCJTNrUG8SQN2BUzwaWjbCRo6HsYJDDaw,4820
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=ET6cR3Pm5hAeweXJ1yxHj5V-CVVuisN3wBVFmbd6G24,6091
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=75qpUwSw4NwT62y-owbdg8z1Oq_QEnhWpkLP-phwObs,1351
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=NjbhqoUrSH0p0upQCalGO3O34CyXQ8MMvF1eQTRn5JQ,7129
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=XOadeSlKoRA9aKYuxcCGKoawRUrnUC5C0TT2gAQN3wc,5083
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=EUJQ1pnCj7PcD9-gXIXMFNrxAwyZBeUd8X-fNEJYJ1k,8443
86
- jarvis/jarvis_utils/utils.py,sha256=ZYclSrkrHBxatxYQkoNpAgIupO0j9CjiLIp8xBijWXc,12164
87
- jarvis_ai_assistant-0.1.148.dist-info/LICENSE,sha256=AGgVgQmTqFvaztRtCAXsAMryUymB18gZif7_l2e1XOg,1063
88
- jarvis_ai_assistant-0.1.148.dist-info/METADATA,sha256=k0RYd3fze2ujx1-ipW6wetXOdmRtfUGd_zH9xSGgdFI,11257
89
- jarvis_ai_assistant-0.1.148.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
90
- jarvis_ai_assistant-0.1.148.dist-info/entry_points.txt,sha256=4ZS8kq6jahnmfDyXFSx39HRi-Tkbp0uFc6cTXt3QIHA,929
91
- jarvis_ai_assistant-0.1.148.dist-info/top_level.txt,sha256=1BOxyWfzOP_ZXj8rVTDnNCJ92bBGB0rwq8N1PCpoMIs,7
92
- jarvis_ai_assistant-0.1.148.dist-info/RECORD,,
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())