jarvis-ai-assistant 0.1.58__py3-none-any.whl → 0.1.74__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/agent.py +132 -63
- jarvis/jarvis_codebase/__init__.py +0 -0
- jarvis/jarvis_codebase/main.py +636 -0
- jarvis/jarvis_coder/__init__.py +0 -0
- jarvis/jarvis_coder/main.py +249 -384
- jarvis/main.py +0 -2
- jarvis/models/ai8.py +2 -3
- jarvis/models/base.py +1 -5
- jarvis/models/kimi.py +2 -0
- jarvis/models/openai.py +1 -2
- jarvis/models/oyi.py +2 -5
- jarvis/models/registry.py +8 -7
- jarvis/tools/__init__.py +1 -0
- jarvis/tools/codebase_qa.py +74 -0
- jarvis/tools/coder.py +69 -0
- jarvis/tools/methodology.py +16 -16
- jarvis/tools/registry.py +1 -1
- jarvis/tools/search.py +33 -1
- jarvis/utils.py +8 -1
- {jarvis_ai_assistant-0.1.58.dist-info → jarvis_ai_assistant-0.1.74.dist-info}/METADATA +94 -39
- jarvis_ai_assistant-0.1.74.dist-info/RECORD +33 -0
- {jarvis_ai_assistant-0.1.58.dist-info → jarvis_ai_assistant-0.1.74.dist-info}/entry_points.txt +1 -0
- jarvis/tools/bing_search.py +0 -38
- jarvis_ai_assistant-0.1.58.dist-info/RECORD +0 -29
- {jarvis_ai_assistant-0.1.58.dist-info → jarvis_ai_assistant-0.1.74.dist-info}/LICENSE +0 -0
- {jarvis_ai_assistant-0.1.58.dist-info → jarvis_ai_assistant-0.1.74.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.1.58.dist-info → jarvis_ai_assistant-0.1.74.dist-info}/top_level.txt +0 -0
jarvis/main.py
CHANGED
|
@@ -117,7 +117,6 @@ def main():
|
|
|
117
117
|
PlatformRegistry.get_global_platform_registry().set_global_platform_name(platform)
|
|
118
118
|
|
|
119
119
|
if args.model:
|
|
120
|
-
PrettyOutput.print(f"用户传入了模型参数,更换模型: {args.model}", OutputType.USER)
|
|
121
120
|
os.environ["JARVIS_MODEL"] = args.model
|
|
122
121
|
|
|
123
122
|
try:
|
|
@@ -126,7 +125,6 @@ def main():
|
|
|
126
125
|
|
|
127
126
|
# 如果用户传入了模型参数,则更换当前模型为用户指定的模型
|
|
128
127
|
if args.model:
|
|
129
|
-
PrettyOutput.print(f"用户传入了模型参数,更换模型: {args.model}", OutputType.USER)
|
|
130
128
|
agent.model.set_model_name(args.model)
|
|
131
129
|
|
|
132
130
|
# 欢迎信息
|
jarvis/models/ai8.py
CHANGED
|
@@ -64,15 +64,14 @@ class AI8Model(BasePlatform):
|
|
|
64
64
|
|
|
65
65
|
PrettyOutput.print("使用AI8_MODEL环境变量配置模型", OutputType.SUCCESS)
|
|
66
66
|
|
|
67
|
-
self.model_name = os.getenv("
|
|
67
|
+
self.model_name = os.getenv("JARVIS_MODEL") or "deepseek-chat"
|
|
68
68
|
if self.model_name not in self.models:
|
|
69
69
|
PrettyOutput.print(f"警告: 当前选择的模型 {self.model_name} 不在可用列表中", OutputType.WARNING)
|
|
70
70
|
|
|
71
|
-
PrettyOutput.print(f"当前使用模型: {self.model_name}", OutputType.SYSTEM)
|
|
72
71
|
|
|
73
72
|
def set_model_name(self, model_name: str):
|
|
74
73
|
"""设置模型名称"""
|
|
75
|
-
|
|
74
|
+
|
|
76
75
|
self.model_name = model_name
|
|
77
76
|
|
|
78
77
|
def create_conversation(self) -> bool:
|
jarvis/models/base.py
CHANGED
jarvis/models/kimi.py
CHANGED
jarvis/models/openai.py
CHANGED
|
@@ -33,7 +33,6 @@ class OpenAIModel(BasePlatform):
|
|
|
33
33
|
self.base_url = os.getenv("OPENAI_API_BASE", "https://api.deepseek.com")
|
|
34
34
|
self.model_name = os.getenv("OPENAI_MODEL_NAME") or os.getenv("JARVIS_MODEL") or "deepseek-chat"
|
|
35
35
|
|
|
36
|
-
PrettyOutput.print(f"当前使用模型: {self.model_name}", OutputType.SYSTEM)
|
|
37
36
|
|
|
38
37
|
self.client = OpenAI(
|
|
39
38
|
api_key=self.api_key,
|
|
@@ -44,7 +43,7 @@ class OpenAIModel(BasePlatform):
|
|
|
44
43
|
|
|
45
44
|
def set_model_name(self, model_name: str):
|
|
46
45
|
"""设置模型名称"""
|
|
47
|
-
|
|
46
|
+
|
|
48
47
|
self.model_name = model_name
|
|
49
48
|
|
|
50
49
|
def set_system_message(self, message: str):
|
jarvis/models/oyi.py
CHANGED
|
@@ -25,8 +25,6 @@ class OyiModel(BasePlatform):
|
|
|
25
25
|
else:
|
|
26
26
|
PrettyOutput.print("获取模型列表失败", OutputType.WARNING)
|
|
27
27
|
|
|
28
|
-
PrettyOutput.print("使用OYI_MODEL环境变量配置模型", OutputType.SUCCESS)
|
|
29
|
-
|
|
30
28
|
self.messages = []
|
|
31
29
|
self.system_message = ""
|
|
32
30
|
self.conversation = None
|
|
@@ -37,15 +35,14 @@ class OyiModel(BasePlatform):
|
|
|
37
35
|
if not self.token:
|
|
38
36
|
raise Exception("OYI_API_KEY is not set")
|
|
39
37
|
|
|
40
|
-
self.model_name = os.getenv("
|
|
38
|
+
self.model_name = os.getenv("JARVIS_MODEL") or "deepseek-chat"
|
|
41
39
|
if self.model_name not in [m.split()[0] for m in available_models]:
|
|
42
40
|
PrettyOutput.print(f"警告: 当前选择的模型 {self.model_name} 不在可用列表中", OutputType.WARNING)
|
|
43
41
|
|
|
44
|
-
PrettyOutput.print(f"当前使用模型: {self.model_name}", OutputType.SYSTEM)
|
|
45
42
|
|
|
46
43
|
def set_model_name(self, model_name: str):
|
|
47
44
|
"""设置模型名称"""
|
|
48
|
-
|
|
45
|
+
|
|
49
46
|
self.model_name = model_name
|
|
50
47
|
|
|
51
48
|
|
jarvis/models/registry.py
CHANGED
|
@@ -29,7 +29,8 @@ class PlatformRegistry:
|
|
|
29
29
|
# 创建 __init__.py 使其成为 Python 包
|
|
30
30
|
with open(os.path.join(user_platform_dir, "__init__.py"), "w") as f:
|
|
31
31
|
pass
|
|
32
|
-
|
|
32
|
+
|
|
33
|
+
pass
|
|
33
34
|
except Exception as e:
|
|
34
35
|
PrettyOutput.print(f"创建平台目录失败: {str(e)}", OutputType.ERROR)
|
|
35
36
|
return ""
|
|
@@ -81,7 +82,7 @@ class PlatformRegistry:
|
|
|
81
82
|
directory: 平台目录路径
|
|
82
83
|
|
|
83
84
|
Returns:
|
|
84
|
-
Dict[str, Type[
|
|
85
|
+
Dict[str, Type[BasePlatform]]: 平台名称到平台类的映射
|
|
85
86
|
"""
|
|
86
87
|
platforms = {}
|
|
87
88
|
|
|
@@ -112,7 +113,7 @@ class PlatformRegistry:
|
|
|
112
113
|
|
|
113
114
|
# 遍历模块中的所有类
|
|
114
115
|
for name, obj in inspect.getmembers(module):
|
|
115
|
-
# 检查是否是
|
|
116
|
+
# 检查是否是BasePlatform的子类,但不是BasePlatform本身
|
|
116
117
|
if (inspect.isclass(obj) and
|
|
117
118
|
issubclass(obj, BasePlatform) and
|
|
118
119
|
obj != BasePlatform and
|
|
@@ -120,8 +121,8 @@ class PlatformRegistry:
|
|
|
120
121
|
# 检查平台实现
|
|
121
122
|
if not PlatformRegistry.check_platform_implementation(obj):
|
|
122
123
|
continue
|
|
124
|
+
PrettyOutput.print(f"从 {os.path.join(directory, filename)} 加载平台:{obj.platform_name}", OutputType.SUCCESS)
|
|
123
125
|
platforms[obj.platform_name] = obj
|
|
124
|
-
PrettyOutput.print(f"从 {directory} 加载平台: {obj.platform_name}", OutputType.INFO)
|
|
125
126
|
break
|
|
126
127
|
except Exception as e:
|
|
127
128
|
PrettyOutput.print(f"加载平台 {module_name} 失败: {str(e)}", OutputType.ERROR)
|
|
@@ -159,6 +160,7 @@ class PlatformRegistry:
|
|
|
159
160
|
raise Exception(f"Failed to create platform: {PlatformRegistry.global_platform_name}")
|
|
160
161
|
return platform
|
|
161
162
|
|
|
163
|
+
|
|
162
164
|
def register_platform(self, name: str, platform_class: Type[BasePlatform]):
|
|
163
165
|
"""注册平台类
|
|
164
166
|
|
|
@@ -167,7 +169,6 @@ class PlatformRegistry:
|
|
|
167
169
|
model_class: 平台类
|
|
168
170
|
"""
|
|
169
171
|
self.platforms[name] = platform_class
|
|
170
|
-
PrettyOutput.print(f"已注册平台: {name}", OutputType.INFO)
|
|
171
172
|
|
|
172
173
|
def create_platform(self, name: str) -> Optional[BasePlatform]:
|
|
173
174
|
"""创建平台实例
|
|
@@ -176,15 +177,15 @@ class PlatformRegistry:
|
|
|
176
177
|
name: 平台名称
|
|
177
178
|
|
|
178
179
|
Returns:
|
|
179
|
-
|
|
180
|
+
BasePlatform: 平台实例
|
|
180
181
|
"""
|
|
181
182
|
if name not in self.platforms:
|
|
182
183
|
PrettyOutput.print(f"未找到平台: {name}", OutputType.ERROR)
|
|
183
184
|
return None
|
|
184
185
|
|
|
185
186
|
try:
|
|
187
|
+
|
|
186
188
|
platform = self.platforms[name]()
|
|
187
|
-
PrettyOutput.print(f"已创建平台实例: {name}", OutputType.INFO)
|
|
188
189
|
return platform
|
|
189
190
|
except Exception as e:
|
|
190
191
|
PrettyOutput.print(f"创建平台失败: {str(e)}", OutputType.ERROR)
|
jarvis/tools/__init__.py
CHANGED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Any, Dict
|
|
3
|
+
from jarvis.jarvis_codebase.main import CodeBase
|
|
4
|
+
from jarvis.utils import find_git_root, PrettyOutput, OutputType
|
|
5
|
+
|
|
6
|
+
class CodebaseQATool:
|
|
7
|
+
"""代码库问答工具,用于回答关于代码库的问题"""
|
|
8
|
+
|
|
9
|
+
name = "codebase_qa"
|
|
10
|
+
description = "回答关于代码库的问题,可以查询和理解代码的功能、结构和实现细节"
|
|
11
|
+
parameters = {
|
|
12
|
+
"type": "object",
|
|
13
|
+
"properties": {
|
|
14
|
+
"dir": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"description": "项目根目录"
|
|
17
|
+
},
|
|
18
|
+
"question": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"description": "关于代码库的问题"
|
|
21
|
+
},
|
|
22
|
+
"top_k": {
|
|
23
|
+
"type": "integer",
|
|
24
|
+
"description": "搜索相关文件的数量",
|
|
25
|
+
"default": 5
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"required": ["question"]
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
def execute(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
|
32
|
+
"""执行代码问答"""
|
|
33
|
+
try:
|
|
34
|
+
dir = params.get("dir")
|
|
35
|
+
question = params["question"]
|
|
36
|
+
top_k = params.get("top_k", 5)
|
|
37
|
+
|
|
38
|
+
# 初始化代码库
|
|
39
|
+
current_dir = os.getcwd()
|
|
40
|
+
root_dir = find_git_root(dir or current_dir)
|
|
41
|
+
if not root_dir:
|
|
42
|
+
return {
|
|
43
|
+
"success": False,
|
|
44
|
+
"stdout": "",
|
|
45
|
+
"stderr": "错误:当前目录不在Git仓库中",
|
|
46
|
+
"error": "NotInGitRepository"
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
os.chdir(root_dir)
|
|
50
|
+
codebase = CodeBase(root_dir)
|
|
51
|
+
# 生成索引
|
|
52
|
+
|
|
53
|
+
codebase.generate_codebase(force=True)
|
|
54
|
+
# 执行问答
|
|
55
|
+
response = codebase.ask_codebase(question, top_k)
|
|
56
|
+
os.chdir(current_dir)
|
|
57
|
+
return {
|
|
58
|
+
"success": True,
|
|
59
|
+
"stdout": response,
|
|
60
|
+
"stderr": "",
|
|
61
|
+
"error": None
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
except Exception as e:
|
|
65
|
+
PrettyOutput.print(f"代码问答出错: {str(e)}", output_type=OutputType.ERROR)
|
|
66
|
+
return {
|
|
67
|
+
"success": False,
|
|
68
|
+
"stdout": "",
|
|
69
|
+
"stderr": f"执行代码问答时发生错误: {str(e)}",
|
|
70
|
+
"error": str(type(e).__name__)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
def register():
|
|
74
|
+
return CodebaseQATool()
|
jarvis/tools/coder.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Dict, Any, Optional
|
|
3
|
+
from jarvis.jarvis_coder.main import JarvisCoder
|
|
4
|
+
from jarvis.utils import PrettyOutput, OutputType
|
|
5
|
+
|
|
6
|
+
class CoderTool:
|
|
7
|
+
"""代码修改工具"""
|
|
8
|
+
|
|
9
|
+
name = "coder"
|
|
10
|
+
description = "用于自动修改和生成代码的工具"
|
|
11
|
+
parameters = {
|
|
12
|
+
"feature": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"description": "要实现的功能描述",
|
|
15
|
+
"required": True
|
|
16
|
+
},
|
|
17
|
+
"dir": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"description": "项目根目录",
|
|
20
|
+
"required": False
|
|
21
|
+
},
|
|
22
|
+
"language": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"description": "编程语言",
|
|
25
|
+
"required": False
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
def __init__(self):
|
|
30
|
+
self._coder = None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _init_coder(self, dir: Optional[str] = None, language: Optional[str] = "python") -> None:
|
|
34
|
+
"""初始化JarvisCoder实例"""
|
|
35
|
+
if not self._coder:
|
|
36
|
+
import os
|
|
37
|
+
work_dir = dir or os.getcwd()
|
|
38
|
+
self._coder = JarvisCoder(work_dir, language)
|
|
39
|
+
|
|
40
|
+
def execute(self, args: Dict) -> Dict[str, Any]:
|
|
41
|
+
"""执行代码修改
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
feature: 要实现的功能描述
|
|
45
|
+
dir: 可选,项目根目录
|
|
46
|
+
language: 可选,编程语言
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
Dict[str, Any]: 执行结果
|
|
50
|
+
"""
|
|
51
|
+
feature = args.get("feature")
|
|
52
|
+
dir = args.get("dir")
|
|
53
|
+
language = args.get("language", "python")
|
|
54
|
+
|
|
55
|
+
try:
|
|
56
|
+
self.current_dir = os.getcwd()
|
|
57
|
+
self._init_coder(dir, language)
|
|
58
|
+
result = self._coder.execute(feature)
|
|
59
|
+
return result
|
|
60
|
+
except Exception as e:
|
|
61
|
+
PrettyOutput.print(f"代码修改失败: {str(e)}", OutputType.ERROR)
|
|
62
|
+
return {
|
|
63
|
+
"success": False,
|
|
64
|
+
"stdout": "",
|
|
65
|
+
"stderr": f"执行失败: {str(e)}",
|
|
66
|
+
"error": e
|
|
67
|
+
}
|
|
68
|
+
finally:
|
|
69
|
+
os.chdir(self.current_dir)
|
jarvis/tools/methodology.py
CHANGED
|
@@ -8,7 +8,7 @@ class MethodologyTool:
|
|
|
8
8
|
"""经验管理工具"""
|
|
9
9
|
|
|
10
10
|
name = "methodology"
|
|
11
|
-
description = "
|
|
11
|
+
description = "管理问题处理方法论,支持添加、更新、删除操作"
|
|
12
12
|
parameters = {
|
|
13
13
|
"type": "object",
|
|
14
14
|
"properties": {
|
|
@@ -23,7 +23,7 @@ class MethodologyTool:
|
|
|
23
23
|
},
|
|
24
24
|
"content": {
|
|
25
25
|
"type": "string",
|
|
26
|
-
"description": "
|
|
26
|
+
"description": "方法论内容 (update/add 时必需)",
|
|
27
27
|
"optional": True
|
|
28
28
|
}
|
|
29
29
|
},
|
|
@@ -36,39 +36,39 @@ class MethodologyTool:
|
|
|
36
36
|
self._ensure_file_exists()
|
|
37
37
|
|
|
38
38
|
def _ensure_file_exists(self):
|
|
39
|
-
"""
|
|
39
|
+
"""确保方法论文件存在"""
|
|
40
40
|
if not os.path.exists(self.methodology_file):
|
|
41
41
|
try:
|
|
42
42
|
with open(self.methodology_file, 'w', encoding='utf-8') as f:
|
|
43
43
|
yaml.safe_dump({}, f, allow_unicode=True)
|
|
44
44
|
except Exception as e:
|
|
45
|
-
PrettyOutput.print(f"
|
|
45
|
+
PrettyOutput.print(f"创建方法论文件失败: {str(e)}", OutputType.ERROR)
|
|
46
46
|
|
|
47
47
|
def _load_methodologies(self) -> Dict:
|
|
48
|
-
"""
|
|
48
|
+
"""加载所有方法论"""
|
|
49
49
|
try:
|
|
50
50
|
with open(self.methodology_file, 'r', encoding='utf-8') as f:
|
|
51
51
|
return yaml.safe_load(f) or {}
|
|
52
52
|
except Exception as e:
|
|
53
|
-
PrettyOutput.print(f"
|
|
53
|
+
PrettyOutput.print(f"加载方法论失败: {str(e)}", OutputType.ERROR)
|
|
54
54
|
return {}
|
|
55
55
|
|
|
56
56
|
def _save_methodologies(self, methodologies: Dict):
|
|
57
|
-
"""
|
|
57
|
+
"""保存所有方法论"""
|
|
58
58
|
try:
|
|
59
59
|
with open(self.methodology_file, 'w', encoding='utf-8') as f:
|
|
60
60
|
yaml.safe_dump(methodologies, f, allow_unicode=True)
|
|
61
61
|
except Exception as e:
|
|
62
|
-
PrettyOutput.print(f"
|
|
62
|
+
PrettyOutput.print(f"保存方法论失败: {str(e)}", OutputType.ERROR)
|
|
63
63
|
|
|
64
64
|
def execute(self, args: Dict[str, Any]) -> Dict[str, Any]:
|
|
65
|
-
"""
|
|
65
|
+
"""执行方法论管理操作
|
|
66
66
|
|
|
67
67
|
Args:
|
|
68
68
|
args: 包含操作参数的字典
|
|
69
69
|
- operation: 操作类型 (delete/update/add)
|
|
70
70
|
- problem_type: 问题类型
|
|
71
|
-
- content:
|
|
71
|
+
- content: 方法论内容 (update/add 时必需)
|
|
72
72
|
|
|
73
73
|
Returns:
|
|
74
74
|
Dict[str, Any]: 包含执行结果的字典
|
|
@@ -92,19 +92,19 @@ class MethodologyTool:
|
|
|
92
92
|
self._save_methodologies(methodologies)
|
|
93
93
|
return {
|
|
94
94
|
"success": True,
|
|
95
|
-
"stdout": f"已删除问题类型 '{problem_type}'
|
|
95
|
+
"stdout": f"已删除问题类型 '{problem_type}' 的方法论"
|
|
96
96
|
}
|
|
97
97
|
else:
|
|
98
98
|
return {
|
|
99
99
|
"success": False,
|
|
100
|
-
"error": f"未找到问题类型 '{problem_type}'
|
|
100
|
+
"error": f"未找到问题类型 '{problem_type}' 的方法论"
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
elif operation in ["update", "add"]:
|
|
104
104
|
if not content:
|
|
105
105
|
return {
|
|
106
106
|
"success": False,
|
|
107
|
-
"error": "
|
|
107
|
+
"error": "需要提供方法论内容"
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
methodologies[problem_type] = content
|
|
@@ -113,7 +113,7 @@ class MethodologyTool:
|
|
|
113
113
|
action = "更新" if problem_type in methodologies else "添加"
|
|
114
114
|
return {
|
|
115
115
|
"success": True,
|
|
116
|
-
"stdout": f"已{action}问题类型 '{problem_type}'
|
|
116
|
+
"stdout": f"已{action}问题类型 '{problem_type}' 的方法论"
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
else:
|
|
@@ -129,13 +129,13 @@ class MethodologyTool:
|
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
def get_methodology(self, problem_type: str) -> Optional[str]:
|
|
132
|
-
"""
|
|
132
|
+
"""获取指定问题类型的方法论
|
|
133
133
|
|
|
134
134
|
Args:
|
|
135
135
|
problem_type: 问题类型
|
|
136
136
|
|
|
137
137
|
Returns:
|
|
138
|
-
Optional[str]:
|
|
138
|
+
Optional[str]: 方法论内容,如果不存在则返回 None
|
|
139
139
|
"""
|
|
140
140
|
methodologies = self._load_methodologies()
|
|
141
141
|
return methodologies.get(problem_type)
|
jarvis/tools/registry.py
CHANGED
|
@@ -99,7 +99,7 @@ class ToolRegistry:
|
|
|
99
99
|
parameters=tool_instance.parameters,
|
|
100
100
|
func=tool_instance.execute
|
|
101
101
|
)
|
|
102
|
-
PrettyOutput.print(f"从 {file_path} 加载工具: {tool_instance.name}: {tool_instance.description}", OutputType.
|
|
102
|
+
PrettyOutput.print(f"从 {file_path} 加载工具: {tool_instance.name}: {tool_instance.description}", OutputType.SUCCESS)
|
|
103
103
|
tool_found = True
|
|
104
104
|
break
|
|
105
105
|
|
jarvis/tools/search.py
CHANGED
|
@@ -2,7 +2,39 @@ from typing import Dict, Any, List
|
|
|
2
2
|
from jarvis.models.registry import PlatformRegistry
|
|
3
3
|
from jarvis.utils import PrettyOutput, OutputType
|
|
4
4
|
from jarvis.tools.webpage import WebpageTool
|
|
5
|
-
from
|
|
5
|
+
from playwright.sync_api import sync_playwright
|
|
6
|
+
from urllib.parse import quote
|
|
7
|
+
|
|
8
|
+
def bing_search(query):
|
|
9
|
+
try:
|
|
10
|
+
with sync_playwright() as p:
|
|
11
|
+
browser = p.chromium.launch()
|
|
12
|
+
page = browser.new_page()
|
|
13
|
+
page.goto(
|
|
14
|
+
f"https://www.bing.com/search?form=QBRE&q={quote(query)}&cc=US"
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
page.wait_for_selector("#b_results", timeout=10000)
|
|
18
|
+
|
|
19
|
+
summaries = page.evaluate("""() => {
|
|
20
|
+
const liElements = Array.from(
|
|
21
|
+
document.querySelectorAll("#b_results > .b_algo")
|
|
22
|
+
);
|
|
23
|
+
return liElements.map((li) => {
|
|
24
|
+
const abstractElement = li.querySelector(".b_caption > p");
|
|
25
|
+
const linkElement = li.querySelector("a");
|
|
26
|
+
const href = linkElement.getAttribute("href");
|
|
27
|
+
const title = linkElement.textContent;
|
|
28
|
+
const abstract = abstractElement ? abstractElement.textContent : "";
|
|
29
|
+
return { href, title, abstract };
|
|
30
|
+
});
|
|
31
|
+
}""")
|
|
32
|
+
|
|
33
|
+
browser.close()
|
|
34
|
+
print(summaries)
|
|
35
|
+
return summaries
|
|
36
|
+
except Exception as error:
|
|
37
|
+
print("An error occurred:", error)
|
|
6
38
|
|
|
7
39
|
class SearchTool:
|
|
8
40
|
name = "search"
|
jarvis/utils.py
CHANGED
|
@@ -158,7 +158,7 @@ def get_multiline_input(tip: str) -> str:
|
|
|
158
158
|
lines.append(line)
|
|
159
159
|
|
|
160
160
|
except KeyboardInterrupt:
|
|
161
|
-
PrettyOutput.print("\n输入已取消", OutputType.
|
|
161
|
+
PrettyOutput.print("\n输入已取消", OutputType.INFO)
|
|
162
162
|
return "__interrupt__"
|
|
163
163
|
|
|
164
164
|
return "\n".join(lines)
|
|
@@ -200,3 +200,10 @@ def while_true(func, sleep_time: float = 0.1):
|
|
|
200
200
|
PrettyOutput.print(f"执行失败,{sleep_time}s后重试...", OutputType.WARNING)
|
|
201
201
|
time.sleep(sleep_time)
|
|
202
202
|
return ret
|
|
203
|
+
|
|
204
|
+
def find_git_root(dir="."):
|
|
205
|
+
curr_dir = os.getcwd()
|
|
206
|
+
os.chdir(dir)
|
|
207
|
+
ret = os.popen("git rev-parse --show-toplevel").read().strip()
|
|
208
|
+
os.chdir(curr_dir)
|
|
209
|
+
return ret
|