jarvis-ai-assistant 0.2.1__py3-none-any.whl → 0.2.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- jarvis/__init__.py +1 -1
- jarvis/jarvis_agent/jarvis.py +61 -59
- jarvis/jarvis_agent/main.py +42 -40
- jarvis/jarvis_code_agent/code_agent.py +35 -31
- jarvis/jarvis_code_analysis/code_review.py +73 -39
- jarvis/jarvis_git_squash/main.py +16 -12
- jarvis/jarvis_git_utils/git_commiter.py +25 -20
- jarvis/jarvis_methodology/main.py +34 -49
- jarvis/jarvis_multi_agent/main.py +28 -23
- jarvis/jarvis_platform/ai8.py +31 -22
- jarvis/jarvis_platform/kimi.py +31 -61
- jarvis/jarvis_platform/tongyi.py +62 -76
- jarvis/jarvis_platform/yuanbao.py +44 -50
- jarvis/jarvis_platform_manager/main.py +55 -90
- jarvis/jarvis_smart_shell/main.py +58 -87
- jarvis/jarvis_tools/cli/main.py +120 -153
- jarvis/jarvis_tools/registry.py +1 -7
- jarvis/jarvis_tools/search_web.py +12 -10
- jarvis/jarvis_utils/http.py +58 -79
- jarvis/jarvis_utils/output.py +1 -1
- jarvis_ai_assistant-0.2.2.dist-info/METADATA +228 -0
- {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.2.dist-info}/RECORD +26 -29
- {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.2.dist-info}/entry_points.txt +0 -2
- jarvis/jarvis_git_details/__init__.py +0 -0
- jarvis/jarvis_git_details/main.py +0 -265
- jarvis/jarvis_platform/oyi.py +0 -357
- jarvis_ai_assistant-0.2.1.dist-info/METADATA +0 -845
- {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.2.dist-info}/WHEEL +0 -0
- {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.2.dist-info}/licenses/LICENSE +0 -0
- {jarvis_ai_assistant-0.2.1.dist-info → jarvis_ai_assistant-0.2.2.dist-info}/top_level.txt +0 -0
jarvis/jarvis_platform/tongyi.py
CHANGED
@@ -8,9 +8,9 @@ from typing import Any, Dict, Generator, List, Tuple
|
|
8
8
|
from jarvis.jarvis_platform.base import BasePlatform
|
9
9
|
from jarvis.jarvis_utils import http
|
10
10
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
11
|
+
from jarvis.jarvis_utils.tag import ot, ct
|
11
12
|
from jarvis.jarvis_utils.utils import while_success
|
12
13
|
|
13
|
-
|
14
14
|
class TongyiPlatform(BasePlatform):
|
15
15
|
"""Tongyi platform implementation"""
|
16
16
|
|
@@ -168,88 +168,74 @@ class TongyiPlatform(BasePlatform):
|
|
168
168
|
thinking_content = ""
|
169
169
|
text_content = ""
|
170
170
|
in_thinking = False
|
171
|
-
response_data = b""
|
172
171
|
|
173
172
|
# 处理流式响应
|
174
|
-
for
|
175
|
-
|
176
|
-
|
177
|
-
# 尝试解析SSE格式的数据
|
178
|
-
try:
|
179
|
-
# 查找完整的数据行
|
180
|
-
lines = response_data.decode("utf-8").split("\n")
|
181
|
-
response_data = b"" # 重置缓冲区
|
182
|
-
|
183
|
-
for line in lines:
|
184
|
-
if not line.strip():
|
185
|
-
continue
|
186
|
-
|
187
|
-
# SSE格式的行通常以"data: "开头
|
188
|
-
if line.startswith("data: "):
|
189
|
-
try:
|
190
|
-
data = json.loads(line[6:])
|
191
|
-
# 记录消息ID和会话ID
|
192
|
-
if "msgId" in data:
|
193
|
-
msg_id = data["msgId"]
|
194
|
-
if "sessionId" in data:
|
195
|
-
session_id = data["sessionId"]
|
196
|
-
|
197
|
-
if "contents" in data and len(data["contents"]) > 0:
|
198
|
-
for content in data["contents"]:
|
199
|
-
if content.get("contentType") == "think":
|
200
|
-
if not in_thinking:
|
201
|
-
yield "<think>\n\n"
|
202
|
-
in_thinking = True
|
203
|
-
if content.get("incremental"):
|
204
|
-
tmp_content = json.loads(
|
205
|
-
content.get("content")
|
206
|
-
)["content"]
|
207
|
-
thinking_content += tmp_content
|
208
|
-
yield tmp_content
|
209
|
-
else:
|
210
|
-
tmp_content = json.loads(
|
211
|
-
content.get("content")
|
212
|
-
)["content"]
|
213
|
-
if len(thinking_content) < len(
|
214
|
-
tmp_content
|
215
|
-
):
|
216
|
-
yield tmp_content[
|
217
|
-
len(thinking_content) :
|
218
|
-
]
|
219
|
-
thinking_content = tmp_content
|
220
|
-
else:
|
221
|
-
yield "\r\n</think>\n"[
|
222
|
-
len(thinking_content)
|
223
|
-
- len(tmp_content) :
|
224
|
-
]
|
225
|
-
thinking_content = tmp_content
|
226
|
-
in_thinking = False
|
227
|
-
elif content.get("contentType") == "text":
|
228
|
-
if in_thinking:
|
229
|
-
continue
|
230
|
-
if content.get("incremental"):
|
231
|
-
tmp_content = content.get("content")
|
232
|
-
text_content += tmp_content
|
233
|
-
yield tmp_content
|
234
|
-
else:
|
235
|
-
tmp_content = content.get("content")
|
236
|
-
if len(text_content) < len(tmp_content):
|
237
|
-
yield tmp_content[
|
238
|
-
len(text_content) :
|
239
|
-
]
|
240
|
-
text_content = tmp_content
|
241
|
-
|
242
|
-
except json.JSONDecodeError:
|
243
|
-
continue
|
244
|
-
|
245
|
-
except UnicodeDecodeError:
|
246
|
-
# 如果解码失败,继续累积数据
|
173
|
+
for line in response_stream:
|
174
|
+
if not line.strip():
|
247
175
|
continue
|
248
176
|
|
177
|
+
# SSE格式的行通常以"data: "开头
|
178
|
+
if line.startswith("data: "):
|
179
|
+
try:
|
180
|
+
data = json.loads(line[6:])
|
181
|
+
# 记录消息ID和会话ID
|
182
|
+
if "msgId" in data:
|
183
|
+
msg_id = data["msgId"]
|
184
|
+
if "sessionId" in data:
|
185
|
+
session_id = data["sessionId"]
|
186
|
+
|
187
|
+
if "contents" in data and len(data["contents"]) > 0:
|
188
|
+
for content in data["contents"]:
|
189
|
+
if content.get("contentType") == "think":
|
190
|
+
if not in_thinking:
|
191
|
+
yield f"{ot('think')}\n\n"
|
192
|
+
in_thinking = True
|
193
|
+
if content.get("incremental"):
|
194
|
+
tmp_content = json.loads(
|
195
|
+
content.get("content")
|
196
|
+
)["content"]
|
197
|
+
thinking_content += tmp_content
|
198
|
+
yield tmp_content
|
199
|
+
else:
|
200
|
+
tmp_content = json.loads(
|
201
|
+
content.get("content")
|
202
|
+
)["content"]
|
203
|
+
if len(thinking_content) < len(
|
204
|
+
tmp_content
|
205
|
+
):
|
206
|
+
yield tmp_content[
|
207
|
+
len(thinking_content) :
|
208
|
+
]
|
209
|
+
thinking_content = tmp_content
|
210
|
+
else:
|
211
|
+
yield f"\r\n{ct('think')}\n"[
|
212
|
+
len(thinking_content)
|
213
|
+
- len(tmp_content) :
|
214
|
+
]
|
215
|
+
thinking_content = tmp_content
|
216
|
+
in_thinking = False
|
217
|
+
elif content.get("contentType") == "text":
|
218
|
+
if in_thinking:
|
219
|
+
continue
|
220
|
+
if content.get("incremental"):
|
221
|
+
tmp_content = content.get("content")
|
222
|
+
text_content += tmp_content
|
223
|
+
yield tmp_content
|
224
|
+
else:
|
225
|
+
tmp_content = content.get("content")
|
226
|
+
if len(text_content) < len(tmp_content):
|
227
|
+
yield tmp_content[
|
228
|
+
len(text_content) :
|
229
|
+
]
|
230
|
+
text_content = tmp_content
|
231
|
+
|
232
|
+
except json.JSONDecodeError:
|
233
|
+
continue
|
234
|
+
|
249
235
|
self.msg_id = msg_id
|
250
236
|
self.session_id = session_id
|
251
237
|
|
252
|
-
return
|
238
|
+
return
|
253
239
|
|
254
240
|
except Exception as e:
|
255
241
|
raise Exception(f"Chat failed: {str(e)}")
|
@@ -12,6 +12,7 @@ from PIL import Image # type: ignore
|
|
12
12
|
from jarvis.jarvis_platform.base import BasePlatform
|
13
13
|
from jarvis.jarvis_utils import http
|
14
14
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
15
|
+
from jarvis.jarvis_utils.tag import ot, ct
|
15
16
|
from jarvis.jarvis_utils.utils import while_success
|
16
17
|
|
17
18
|
|
@@ -474,61 +475,54 @@ class YuanbaoPlatform(BasePlatform):
|
|
474
475
|
)
|
475
476
|
|
476
477
|
in_thinking = False
|
477
|
-
response_data = b""
|
478
478
|
|
479
479
|
# 处理流式响应
|
480
|
-
for
|
481
|
-
|
482
|
-
|
483
|
-
# 尝试解析SSE格式的数据
|
484
|
-
try:
|
485
|
-
# 查找完整的数据行
|
486
|
-
lines = response_data.decode("utf-8").split("\n")
|
487
|
-
response_data = b"" # 重置缓冲区
|
488
|
-
|
489
|
-
for line in lines:
|
490
|
-
if not line.strip():
|
491
|
-
continue
|
492
|
-
|
493
|
-
# SSE格式的行通常以"data: "开头
|
494
|
-
if line.startswith("data: "):
|
495
|
-
try:
|
496
|
-
data_str = line[6:] # 移除"data: "前缀
|
497
|
-
|
498
|
-
# 检查结束标志
|
499
|
-
if data_str == "[DONE]":
|
500
|
-
self.first_chat = False
|
501
|
-
return None
|
502
|
-
|
503
|
-
data = json.loads(data_str)
|
504
|
-
|
505
|
-
# 处理文本类型的消息
|
506
|
-
if data.get("type") == "text":
|
507
|
-
if in_thinking:
|
508
|
-
yield "</think>\n"
|
509
|
-
in_thinking = False
|
510
|
-
msg = data.get("msg", "")
|
511
|
-
if msg:
|
512
|
-
yield msg
|
513
|
-
|
514
|
-
# 处理思考中的消息
|
515
|
-
elif data.get("type") == "think":
|
516
|
-
if not in_thinking:
|
517
|
-
yield "<think>\n"
|
518
|
-
in_thinking = True
|
519
|
-
think_content = data.get("content", "")
|
520
|
-
if think_content:
|
521
|
-
yield think_content
|
522
|
-
|
523
|
-
except json.JSONDecodeError:
|
524
|
-
pass
|
525
|
-
|
526
|
-
except UnicodeDecodeError:
|
527
|
-
# 如果解码失败,继续累积数据
|
480
|
+
for line in response_stream:
|
481
|
+
if not line.strip():
|
528
482
|
continue
|
529
483
|
|
484
|
+
# SSE格式的行通常以"data: "开头
|
485
|
+
if line.startswith("data: "):
|
486
|
+
try:
|
487
|
+
data_str = line[6:] # 移除"data: "前缀
|
488
|
+
|
489
|
+
# 检查结束标志
|
490
|
+
if data_str == "[DONE]":
|
491
|
+
self.first_chat = False
|
492
|
+
return
|
493
|
+
|
494
|
+
data = json.loads(data_str)
|
495
|
+
|
496
|
+
# 处理文本类型的消息
|
497
|
+
if data.get("type") == "text":
|
498
|
+
if in_thinking:
|
499
|
+
yield f"{ct('think')}\n"
|
500
|
+
in_thinking = False
|
501
|
+
msg = data.get("msg", "")
|
502
|
+
if msg:
|
503
|
+
yield msg
|
504
|
+
|
505
|
+
# 处理思考中的消息
|
506
|
+
elif data.get("type") == "think":
|
507
|
+
if not in_thinking:
|
508
|
+
yield f"{ot('think')}\n"
|
509
|
+
in_thinking = True
|
510
|
+
think_content = data.get("content", "")
|
511
|
+
if think_content:
|
512
|
+
yield think_content
|
513
|
+
|
514
|
+
except json.JSONDecodeError:
|
515
|
+
pass
|
516
|
+
else:
|
517
|
+
try:
|
518
|
+
data = json.loads(line)
|
519
|
+
if "msg" in data:
|
520
|
+
yield data["msg"]
|
521
|
+
except json.JSONDecodeError:
|
522
|
+
pass
|
523
|
+
|
530
524
|
self.first_chat = False
|
531
|
-
return
|
525
|
+
return
|
532
526
|
|
533
527
|
except Exception as e:
|
534
528
|
raise Exception(f"对话失败: {str(e)}")
|
@@ -3,17 +3,22 @@
|
|
3
3
|
|
4
4
|
该模块提供了Jarvis平台管理器的主要入口点。
|
5
5
|
"""
|
6
|
-
import argparse
|
7
6
|
import os
|
7
|
+
import sys
|
8
8
|
from typing import Any, Dict, List, Optional
|
9
9
|
|
10
|
+
import typer
|
11
|
+
|
10
12
|
from jarvis.jarvis_platform.registry import PlatformRegistry
|
11
13
|
from jarvis.jarvis_utils.input import get_multiline_input, get_single_line_input
|
12
14
|
from jarvis.jarvis_utils.output import OutputType, PrettyOutput
|
13
15
|
from jarvis.jarvis_utils.utils import init_env
|
14
16
|
from jarvis.jarvis_platform_manager.service import start_service
|
15
17
|
|
18
|
+
app = typer.Typer(help="Jarvis AI 平台")
|
19
|
+
|
16
20
|
|
21
|
+
@app.command("info")
|
17
22
|
def list_platforms() -> None:
|
18
23
|
"""列出所有支持的平台和模型。"""
|
19
24
|
registry = PlatformRegistry.get_global_platform_registry()
|
@@ -291,8 +296,11 @@ def chat_with_model(platform_name: str, model_name: str, system_prompt: str) ->
|
|
291
296
|
except Exception as exc:
|
292
297
|
PrettyOutput.print(f"聊天失败: {str(exc)}", OutputType.ERROR)
|
293
298
|
|
299
|
+
except typer.Exit:
|
300
|
+
raise
|
294
301
|
except Exception as exc:
|
295
302
|
PrettyOutput.print(f"初始化会话失败: {str(exc)}", OutputType.ERROR)
|
303
|
+
sys.exit(1)
|
296
304
|
finally:
|
297
305
|
# Clean up resources
|
298
306
|
try:
|
@@ -301,16 +309,17 @@ def chat_with_model(platform_name: str, model_name: str, system_prompt: str) ->
|
|
301
309
|
pass
|
302
310
|
|
303
311
|
|
304
|
-
def validate_platform_model(
|
312
|
+
def validate_platform_model(platform: Optional[str], model: Optional[str]) -> bool:
|
305
313
|
"""验证平台和模型参数。
|
306
314
|
|
307
315
|
参数:
|
308
|
-
|
316
|
+
platform: 平台名称。
|
317
|
+
model: 模型名称。
|
309
318
|
|
310
319
|
返回:
|
311
320
|
bool: 如果平台和模型有效返回True,否则返回False。
|
312
321
|
"""
|
313
|
-
if not
|
322
|
+
if not platform or not model:
|
314
323
|
PrettyOutput.print(
|
315
324
|
"请指定平台和模型。使用 'jarvis info' 查看可用平台和模型。",
|
316
325
|
OutputType.WARNING,
|
@@ -319,38 +328,30 @@ def validate_platform_model(args: argparse.Namespace) -> bool:
|
|
319
328
|
return True
|
320
329
|
|
321
330
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
"""
|
328
|
-
if not validate_platform_model(
|
331
|
+
@app.command("chat")
|
332
|
+
def chat_command(
|
333
|
+
platform: Optional[str] = typer.Option(None, "--platform", "-p", help="指定要使用的平台"),
|
334
|
+
model: Optional[str] = typer.Option(None, "--model", "-m", help="指定要使用的模型"),
|
335
|
+
) -> None:
|
336
|
+
"""与指定平台和模型聊天。"""
|
337
|
+
if not validate_platform_model(platform, model):
|
329
338
|
return
|
330
|
-
chat_with_model(
|
339
|
+
chat_with_model(platform, model, "") # type: ignore
|
331
340
|
|
332
341
|
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
args: 命令行参数。
|
347
|
-
"""
|
348
|
-
start_service(
|
349
|
-
host=args.host,
|
350
|
-
port=args.port,
|
351
|
-
default_platform=args.platform,
|
352
|
-
default_model=args.model,
|
353
|
-
)
|
342
|
+
@app.command("service")
|
343
|
+
def service_command(
|
344
|
+
host: str = typer.Option("127.0.0.1", help="服务主机地址 (默认: 127.0.0.1)"),
|
345
|
+
port: int = typer.Option(8000, help="服务端口 (默认: 8000)"),
|
346
|
+
platform: Optional[str] = typer.Option(
|
347
|
+
None, "-p", "--platform", help="指定默认平台,当客户端未指定平台时使用"
|
348
|
+
),
|
349
|
+
model: Optional[str] = typer.Option(
|
350
|
+
None, "-m", "--model", help="指定默认模型,当客户端未指定平台时使用"
|
351
|
+
),
|
352
|
+
) -> None:
|
353
|
+
"""启动OpenAI兼容的API服务。"""
|
354
|
+
start_service(host=host, port=port, default_platform=platform, default_model=model)
|
354
355
|
|
355
356
|
|
356
357
|
def load_role_config(config_path: str) -> Dict[str, Any]:
|
@@ -377,13 +378,24 @@ def load_role_config(config_path: str) -> Dict[str, Any]:
|
|
377
378
|
return {}
|
378
379
|
|
379
380
|
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
381
|
+
@app.command("role")
|
382
|
+
def role_command(
|
383
|
+
config_file: str = typer.Option(
|
384
|
+
"~/.jarvis/roles.yaml",
|
385
|
+
"--config",
|
386
|
+
"-c",
|
387
|
+
help="角色配置文件路径(YAML格式,默认: ~/.jarvis/roles.yaml)",
|
388
|
+
),
|
389
|
+
platform: Optional[str] = typer.Option(
|
390
|
+
None, "--platform", "-p", help="指定要使用的平台,覆盖角色配置"
|
391
|
+
),
|
392
|
+
model: Optional[str] = typer.Option(
|
393
|
+
None, "--model", "-m", help="指定要使用的模型,覆盖角色配置"
|
394
|
+
),
|
395
|
+
) -> None:
|
396
|
+
"""加载角色配置文件并开始对话。"""
|
397
|
+
config_path = os.path.expanduser(config_file)
|
398
|
+
config = load_role_config(config_path)
|
387
399
|
if not config or "roles" not in config:
|
388
400
|
PrettyOutput.print("无效的角色配置文件", OutputType.ERROR)
|
389
401
|
return
|
@@ -407,8 +419,8 @@ def role_command(args: argparse.Namespace) -> None:
|
|
407
419
|
return
|
408
420
|
|
409
421
|
# 初始化平台和模型
|
410
|
-
platform_name =
|
411
|
-
model_name =
|
422
|
+
platform_name = platform or selected_role["platform"]
|
423
|
+
model_name = model or selected_role["model"]
|
412
424
|
system_prompt = selected_role.get("system_prompt", "")
|
413
425
|
|
414
426
|
# 开始对话
|
@@ -419,54 +431,7 @@ def role_command(args: argparse.Namespace) -> None:
|
|
419
431
|
def main() -> None:
|
420
432
|
"""Jarvis平台管理器的主入口点。"""
|
421
433
|
init_env("欢迎使用 Jarvis-PlatformManager,您的平台管理助手已准备就绪!")
|
422
|
-
|
423
|
-
parser = argparse.ArgumentParser(description="Jarvis AI 平台")
|
424
|
-
subparsers = parser.add_subparsers(dest="command", help="可用子命令")
|
425
|
-
|
426
|
-
# info subcommand
|
427
|
-
info_parser = subparsers.add_parser("info", help="显示支持的平台和模型信息")
|
428
|
-
info_parser.set_defaults(func=info_command)
|
429
|
-
|
430
|
-
# chat subcommand
|
431
|
-
chat_parser = subparsers.add_parser("chat", help="与指定平台和模型聊天")
|
432
|
-
chat_parser.add_argument("--platform", "-p", help="指定要使用的平台")
|
433
|
-
chat_parser.add_argument("--model", "-m", help="指定要使用的模型")
|
434
|
-
chat_parser.set_defaults(func=chat_command)
|
435
|
-
|
436
|
-
# service subcommand
|
437
|
-
service_parser = subparsers.add_parser("service", help="启动OpenAI兼容的API服务")
|
438
|
-
service_parser.add_argument(
|
439
|
-
"--host", default="127.0.0.1", help="服务主机地址 (默认: 127.0.0.1)"
|
440
|
-
)
|
441
|
-
service_parser.add_argument(
|
442
|
-
"--port", type=int, default=8000, help="服务端口 (默认: 8000)"
|
443
|
-
)
|
444
|
-
service_parser.add_argument(
|
445
|
-
"--platform", "-p", help="指定默认平台,当客户端未指定平台时使用"
|
446
|
-
)
|
447
|
-
service_parser.add_argument(
|
448
|
-
"--model", "-m", help="指定默认模型,当客户端未指定平台时使用"
|
449
|
-
)
|
450
|
-
service_parser.set_defaults(func=service_command)
|
451
|
-
|
452
|
-
# role subcommand
|
453
|
-
role_parser = subparsers.add_parser("role", help="加载角色配置文件并开始对话")
|
454
|
-
role_parser.add_argument(
|
455
|
-
"--config",
|
456
|
-
"-c",
|
457
|
-
default="~/.jarvis/roles.yaml",
|
458
|
-
help="角色配置文件路径(YAML格式,默认: ~/.jarvis/roles.yaml)",
|
459
|
-
)
|
460
|
-
role_parser.add_argument("--platform", "-p", help="指定要使用的平台,覆盖角色配置")
|
461
|
-
role_parser.add_argument("--model", "-m", help="指定要使用的模型,覆盖角色配置")
|
462
|
-
role_parser.set_defaults(func=role_command)
|
463
|
-
|
464
|
-
args = parser.parse_args()
|
465
|
-
|
466
|
-
if hasattr(args, "func"):
|
467
|
-
args.func(args)
|
468
|
-
else:
|
469
|
-
parser.print_help()
|
434
|
+
app()
|
470
435
|
|
471
436
|
|
472
437
|
if __name__ == "__main__":
|