myagent-ai 1.18.7 → 1.18.8
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.
- package/core/deps_checker.py +3 -1
- package/package.json +1 -1
- package/skills/base.py +7 -3
- package/skills/xlsx_skill.py +16 -5
- package/web/api_server.py +64 -8
package/core/deps_checker.py
CHANGED
|
@@ -100,8 +100,10 @@ DEPENDENCIES: List[DepInfo] = [
|
|
|
100
100
|
DepInfo("edge_tts", "edge-tts", "6.1.0", "tts", "all"),
|
|
101
101
|
|
|
102
102
|
# ── 语音识别 (STT) ──
|
|
103
|
+
DepInfo("funasr", "funasr", "1.1.0", "stt", "all",
|
|
104
|
+
note="[v1.18.7] SenseVoice 中文语音识别(推荐,需 torch+torchaudio)"),
|
|
103
105
|
DepInfo("faster_whisper", "faster-whisper", "1.0.0", "stt", "all",
|
|
104
|
-
note="本地语音识别引擎 (需要 C++ 编译)"),
|
|
106
|
+
note="Whisper 本地语音识别引擎 (需要 C++ 编译)"),
|
|
105
107
|
DepInfo("speech_recognition", "SpeechRecognition", "3.10.0", "stt", "all",
|
|
106
108
|
note="在线语音识别 (Google API,纯 Python 无需编译,Termux 兼容)"),
|
|
107
109
|
|
package/package.json
CHANGED
package/skills/base.py
CHANGED
|
@@ -94,10 +94,14 @@ class Skill(ABC):
|
|
|
94
94
|
pass
|
|
95
95
|
|
|
96
96
|
def validate_params(self, params: Dict[str, Any]) -> tuple[bool, str]:
|
|
97
|
-
"""
|
|
97
|
+
"""校验参数是否合法。有默认值的必需参数在缺失时自动填充。"""
|
|
98
98
|
for p in self.parameters:
|
|
99
|
-
if p.
|
|
100
|
-
|
|
99
|
+
if p.name not in params:
|
|
100
|
+
# [v1.18.7] 有默认值的必需参数:自动填充而非报错
|
|
101
|
+
if p.default is not None:
|
|
102
|
+
params[p.name] = p.default
|
|
103
|
+
elif p.required:
|
|
104
|
+
return False, f"缺少必需参数: {p.name}"
|
|
101
105
|
if p.name in params and p.enum and params[p.name] not in p.enum:
|
|
102
106
|
return False, f"参数 {p.name} 值无效,可选: {p.enum}"
|
|
103
107
|
return True, ""
|
package/skills/xlsx_skill.py
CHANGED
|
@@ -8,6 +8,7 @@ from __future__ import annotations
|
|
|
8
8
|
|
|
9
9
|
import json
|
|
10
10
|
import os
|
|
11
|
+
import time
|
|
11
12
|
from pathlib import Path
|
|
12
13
|
from typing import Any, Dict, List, Optional
|
|
13
14
|
|
|
@@ -29,18 +30,19 @@ class XLSXCreateSkill(Skill):
|
|
|
29
30
|
"""
|
|
30
31
|
name = "xlsx_create"
|
|
31
32
|
description = (
|
|
32
|
-
"生成 Excel (XLSX)
|
|
33
|
+
"生成 Excel (XLSX) 电子表格文件。支持多工作表、表头、数据行、公式、"
|
|
33
34
|
"冻结窗格、自动筛选、列宽设置。"
|
|
34
|
-
"sheets
|
|
35
|
+
"参数 sheets 必须是 JSON 字符串,格式为 {\"工作表名\": {\"headers\":[...], \"rows\":[[...]]}}。"
|
|
36
|
+
"参数 output_path 指定输出文件路径,默认为工作目录下。"
|
|
35
37
|
)
|
|
36
38
|
category = "doc"
|
|
37
39
|
dangerous = True
|
|
38
40
|
parameters = [
|
|
39
41
|
SkillParameter("sheets", "string",
|
|
40
|
-
"
|
|
41
|
-
"示例: {\"Sheet1\":{\"headers\":[\"
|
|
42
|
+
"工作表数据,JSON 字符串。key=工作表名, value包含 headers(列名数组) 和 rows(数据行二维数组)。"
|
|
43
|
+
"示例: '{\"Sheet1\":{\"headers\":[\"姓名\",\"分数\"],\"rows\":[[\"Alice\",95]]}}'",
|
|
42
44
|
required=True),
|
|
43
|
-
SkillParameter("output_path", "string", "
|
|
45
|
+
SkillParameter("output_path", "string", "输出文件路径(如 /tmp/report.xlsx)", required=False, default=""),
|
|
44
46
|
SkillParameter("title", "string", "文档标题", required=False, default=""),
|
|
45
47
|
]
|
|
46
48
|
|
|
@@ -62,6 +64,15 @@ class XLSXCreateSkill(Skill):
|
|
|
62
64
|
|
|
63
65
|
try:
|
|
64
66
|
out = Path(output_path).expanduser().resolve()
|
|
67
|
+
if not output_path.strip():
|
|
68
|
+
# [v1.18.7] 默认输出路径:工作目录/data/workspace下
|
|
69
|
+
from core.context_manager import get_active_context
|
|
70
|
+
try:
|
|
71
|
+
ctx = get_active_context()
|
|
72
|
+
work_dir = Path(ctx.work_dir) if ctx and ctx.work_dir else Path.cwd()
|
|
73
|
+
except Exception:
|
|
74
|
+
work_dir = Path.cwd()
|
|
75
|
+
out = work_dir / f"report_{int(time.time())}.xlsx"
|
|
65
76
|
out.parent.mkdir(parents=True, exist_ok=True)
|
|
66
77
|
|
|
67
78
|
wb = openpyxl.Workbook()
|
package/web/api_server.py
CHANGED
|
@@ -1545,13 +1545,15 @@ window.toggleFullscreen = function() {{
|
|
|
1545
1545
|
return web.json_response({"error": str(e)}, status=500)
|
|
1546
1546
|
|
|
1547
1547
|
async def handle_voice_stt(self, request):
|
|
1548
|
-
"""POST /api/voice-stt -
|
|
1548
|
+
"""POST /api/voice-stt - 本地语音转文字
|
|
1549
1549
|
|
|
1550
1550
|
接受音频文件(WAV/WEBM/OGG),使用本地 STT 引擎转录。
|
|
1551
1551
|
支持的引擎(按优先级):
|
|
1552
|
-
1.
|
|
1553
|
-
2.
|
|
1554
|
-
|
|
1552
|
+
1. [v1.18.7] SenseVoice(推荐,中文识别最佳,需:pip install funasr torch torchaudio)
|
|
1553
|
+
2. faster-whisper(备选,需安装:pip install faster-whisper)
|
|
1554
|
+
3. vosk(备选,需安装:pip install vosk)
|
|
1555
|
+
4. LLM API Whisper 兼容端点
|
|
1556
|
+
5. SpeechRecognition(Google,需外网)
|
|
1555
1557
|
"""
|
|
1556
1558
|
try:
|
|
1557
1559
|
reader = await request.multipart()
|
|
@@ -1584,6 +1586,59 @@ window.toggleFullscreen = function() {{
|
|
|
1584
1586
|
|
|
1585
1587
|
import io
|
|
1586
1588
|
|
|
1589
|
+
# ── [v1.18.7] 首选: SenseVoice(阿里达摩院,中文识别极佳) ──
|
|
1590
|
+
try:
|
|
1591
|
+
sv_model = getattr(self, '_sensevoice_model', None)
|
|
1592
|
+
if sv_model is None:
|
|
1593
|
+
os.environ.setdefault("HF_HUB_DISABLE_TELEMETRY", "1")
|
|
1594
|
+
os.environ.setdefault("HF_HUB_DISABLE_PROGRESS_BARS", "1")
|
|
1595
|
+
from funasr import AutoModel
|
|
1596
|
+
model_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'models', 'sensevoice')
|
|
1597
|
+
sv_model = AutoModel(model="iic/SenseVoiceSmall", model_dir=model_dir,
|
|
1598
|
+
device="cpu", disable_pbar=True, disable_update=True)
|
|
1599
|
+
self._sensevoice_model = sv_model
|
|
1600
|
+
logger.info("SenseVoice 模型已加载 (iic/SenseVoiceSmall, CPU)")
|
|
1601
|
+
|
|
1602
|
+
# SenseVoice 接受 16kHz WAV
|
|
1603
|
+
wav_path = f"/tmp/myagent_stt_{id(audio_data) % 100000}.wav"
|
|
1604
|
+
wav_buf = io.BytesIO()
|
|
1605
|
+
try:
|
|
1606
|
+
from pydub import AudioSegment
|
|
1607
|
+
audio_buf = io.BytesIO(audio_data)
|
|
1608
|
+
seg = AudioSegment.from_file(audio_buf, format=audio_format or "webm")
|
|
1609
|
+
seg = seg.set_channels(1).set_frame_rate(16000).set_sample_width(2)
|
|
1610
|
+
seg.export(wav_buf, format="wav")
|
|
1611
|
+
except Exception:
|
|
1612
|
+
wav_buf = io.BytesIO(audio_data)
|
|
1613
|
+
wav_buf.seek(0)
|
|
1614
|
+
with open(wav_path, 'wb') as f:
|
|
1615
|
+
f.write(wav_buf.read())
|
|
1616
|
+
|
|
1617
|
+
# SenseVoice 推理
|
|
1618
|
+
res = sv_model.generate(input=wav_path, cache={},
|
|
1619
|
+
language="auto", # 自动检测语言
|
|
1620
|
+
use_itn=True, # 逆文本标准化(数字/日期等)
|
|
1621
|
+
batch_size_s=300)
|
|
1622
|
+
if res and len(res) > 0 and len(res[0]) > 0:
|
|
1623
|
+
text = res[0][0]["text"] if isinstance(res[0][0], dict) else str(res[0][0])
|
|
1624
|
+
# SenseVoice 可能输出带 <|zh|><|en|><|EMO|> 等特殊 token,清理掉
|
|
1625
|
+
import re
|
|
1626
|
+
text = re.sub(r'<\|[^|]+\|>', '', text).strip()
|
|
1627
|
+
if text:
|
|
1628
|
+
try:
|
|
1629
|
+
os.remove(wav_path)
|
|
1630
|
+
except Exception:
|
|
1631
|
+
pass
|
|
1632
|
+
return web.json_response({"text": text, "engine": "sensevoice"})
|
|
1633
|
+
try:
|
|
1634
|
+
os.remove(wav_path)
|
|
1635
|
+
except Exception:
|
|
1636
|
+
pass
|
|
1637
|
+
except ImportError:
|
|
1638
|
+
logger.debug("SenseVoice (funasr) 未安装,跳过。安装: pip install funasr torch torchaudio")
|
|
1639
|
+
except Exception as e:
|
|
1640
|
+
logger.warning(f"SenseVoice 转录失败: {e}")
|
|
1641
|
+
|
|
1587
1642
|
# ── 尝试 faster-whisper ──
|
|
1588
1643
|
try:
|
|
1589
1644
|
whisper_model = self._whisper_model
|
|
@@ -1815,10 +1870,11 @@ window.toggleFullscreen = function() {{
|
|
|
1815
1870
|
# ── 没有可用的 STT 引擎 ──
|
|
1816
1871
|
return web.json_response({
|
|
1817
1872
|
"error": "未检测到可用的 STT 引擎。请尝试以下方案:\n"
|
|
1818
|
-
" 1.
|
|
1819
|
-
" 2.
|
|
1820
|
-
" 3. pip install
|
|
1821
|
-
" 4. pip install
|
|
1873
|
+
" 1. pip install funasr torch torchaudio (SenseVoice,中文最佳,推荐)\n"
|
|
1874
|
+
" 2. 配置支持 Whisper 的 LLM API(自动使用,无需安装)\n"
|
|
1875
|
+
" 3. pip install faster-whisper (离线本地,需 C++ 编译环境)\n"
|
|
1876
|
+
" 4. pip install vosk (离线本地,需下载模型)\n"
|
|
1877
|
+
" 5. pip install SpeechRecognition (需外网,国内不可用)",
|
|
1822
1878
|
"available": False,
|
|
1823
1879
|
}, status=503)
|
|
1824
1880
|
|