myagent-ai 1.23.49 → 1.23.51
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/stt.py +24 -1
- package/package.json +1 -1
- package/web/ui/chat/chat_main.js +9 -8
- package/web/ui/chat/flow_engine.js +3 -3
- package/web/ui/chat/groupchat.js +29 -0
package/core/stt.py
CHANGED
|
@@ -68,6 +68,29 @@ async def _stt_sensevoice(audio_data: bytes, audio_format: Optional[str] = None)
|
|
|
68
68
|
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
|
|
69
69
|
'models', 'sensevoice',
|
|
70
70
|
)
|
|
71
|
+
# [v1.23.49] 首次加载:将 ModelScope 缓存复制到本地 model_dir,后续不再联网
|
|
72
|
+
if not os.path.isdir(model_dir) or not os.listdir(model_dir):
|
|
73
|
+
import shutil
|
|
74
|
+
ms_cache = os.path.expanduser("~/.cache/modelscope/hub/models/iic/SenseVoiceSmall")
|
|
75
|
+
if os.path.isdir(ms_cache) and os.listdir(ms_cache):
|
|
76
|
+
os.makedirs(model_dir, exist_ok=True)
|
|
77
|
+
logger.info(f"复制 SenseVoice 模型: {ms_cache} -> {model_dir}")
|
|
78
|
+
# 复制模型文件(排除缓存元数据)
|
|
79
|
+
for item in os.listdir(ms_cache):
|
|
80
|
+
if item.endswith('.tmp') or item in ('.lock', '__pycache__'):
|
|
81
|
+
continue
|
|
82
|
+
src = os.path.join(ms_cache, item)
|
|
83
|
+
dst = os.path.join(model_dir, item)
|
|
84
|
+
if os.path.isdir(src):
|
|
85
|
+
if os.path.exists(dst):
|
|
86
|
+
shutil.rmtree(dst)
|
|
87
|
+
shutil.copytree(src, dst)
|
|
88
|
+
else:
|
|
89
|
+
shutil.copy2(src, dst)
|
|
90
|
+
else:
|
|
91
|
+
# ModelScope 缓存也没有,首次下载到本地
|
|
92
|
+
os.makedirs(model_dir, exist_ok=True)
|
|
93
|
+
logger.info("SenseVoice 模型首次下载到本地...")
|
|
71
94
|
_sensevoice_model = AutoModel(
|
|
72
95
|
model="iic/SenseVoiceSmall",
|
|
73
96
|
model_dir=model_dir,
|
|
@@ -75,7 +98,7 @@ async def _stt_sensevoice(audio_data: bytes, audio_format: Optional[str] = None)
|
|
|
75
98
|
disable_pbar=True,
|
|
76
99
|
disable_update=True,
|
|
77
100
|
)
|
|
78
|
-
logger.info("SenseVoice 模型已加载 (iic/SenseVoiceSmall, CPU)")
|
|
101
|
+
logger.info("SenseVoice 模型已加载 (iic/SenseVoiceSmall, CPU, 本地缓存)")
|
|
79
102
|
|
|
80
103
|
# [v1.23.2] 增强: pydub 转换失败记录警告、WAV 头验证、音频长度检查
|
|
81
104
|
wav_data = _convert_to_wav(audio_data, audio_format)
|
package/package.json
CHANGED
package/web/ui/chat/chat_main.js
CHANGED
|
@@ -351,11 +351,11 @@ async function initChat() {
|
|
|
351
351
|
// [v1.16.12] 初始化附件上传 UI
|
|
352
352
|
initAttachmentUI();
|
|
353
353
|
|
|
354
|
-
// URL 参数处理: ?
|
|
354
|
+
// URL 参数处理: ?a=xxx&mode=exec&s=xxx&popout=1(agent/session 使用 UrlCodec 编码)
|
|
355
355
|
const urlParams = new URLSearchParams(window.location.search);
|
|
356
|
-
const urlAgent = urlParams.get('agent');
|
|
356
|
+
const urlAgent = UrlCodec.decode(urlParams.get('a') || '') || UrlCodec.decode(urlParams.get('agent') || '');
|
|
357
357
|
const urlMode = urlParams.get('mode');
|
|
358
|
-
const urlSession = urlParams.get('session');
|
|
358
|
+
const urlSession = UrlCodec.decode(urlParams.get('s') || '') || UrlCodec.decode(urlParams.get('session') || '');
|
|
359
359
|
const isPopout = urlParams.get('popout') === '1';
|
|
360
360
|
if (urlMode === 'chat' || urlMode === 'exec') {
|
|
361
361
|
state.chatMode = urlMode;
|
|
@@ -1977,7 +1977,7 @@ async function loadSessions() {
|
|
|
1977
1977
|
// Auto-select most recent session if none selected
|
|
1978
1978
|
// 优先级: URL session 参数 > localStorage 持久化的 session > 最新 session
|
|
1979
1979
|
const urlParams = new URLSearchParams(window.location.search);
|
|
1980
|
-
const urlSession = urlParams.get('session');
|
|
1980
|
+
const urlSession = UrlCodec.decode(urlParams.get('s') || '') || UrlCodec.decode(urlParams.get('session') || '');
|
|
1981
1981
|
var targetSessionId = null;
|
|
1982
1982
|
|
|
1983
1983
|
if (urlSession && state.sessions.some(s => s.id === urlSession)) {
|
|
@@ -1994,7 +1994,7 @@ async function loadSessions() {
|
|
|
1994
1994
|
// 更新 URL 为 canonical ID,避免下次刷新再走 fallback
|
|
1995
1995
|
try {
|
|
1996
1996
|
var _fixUrl = new URL(window.location.href);
|
|
1997
|
-
_fixUrl.searchParams.set('
|
|
1997
|
+
_fixUrl.searchParams.set('s', UrlCodec.encode(prefixMatch.id));
|
|
1998
1998
|
window.history.replaceState({}, '', _fixUrl.toString());
|
|
1999
1999
|
} catch (_) {}
|
|
2000
2000
|
}
|
|
@@ -2135,8 +2135,9 @@ function newChat() {
|
|
|
2135
2135
|
// ── 更新 URL(新对话移除 session 参数) ──
|
|
2136
2136
|
try {
|
|
2137
2137
|
const url = new URL(window.location.href);
|
|
2138
|
+
url.searchParams.delete('s');
|
|
2138
2139
|
url.searchParams.delete('session');
|
|
2139
|
-
url.searchParams.set('
|
|
2140
|
+
url.searchParams.set('a', UrlCodec.encode(state.activeAgent || 'default'));
|
|
2140
2141
|
window.history.replaceState({}, '', url.toString());
|
|
2141
2142
|
} catch (_) {}
|
|
2142
2143
|
state.messages = [];
|
|
@@ -2263,8 +2264,8 @@ async function selectSession(id) {
|
|
|
2263
2264
|
// ── 更新 URL 参数,保留会话 ID(刷新页面可恢复会话) ──
|
|
2264
2265
|
try {
|
|
2265
2266
|
const url = new URL(window.location.href);
|
|
2266
|
-
url.searchParams.set('
|
|
2267
|
-
url.searchParams.set('
|
|
2267
|
+
url.searchParams.set('s', UrlCodec.encode(id));
|
|
2268
|
+
url.searchParams.set('a', UrlCodec.encode(state.activeAgent || 'default'));
|
|
2268
2269
|
if (state.chatMode) url.searchParams.set('mode', state.chatMode);
|
|
2269
2270
|
window.history.replaceState({}, '', url.toString());
|
|
2270
2271
|
} catch (_) {}
|
|
@@ -1619,8 +1619,8 @@ async function sendMessage(opts) {
|
|
|
1619
1619
|
// ── 更新 URL 参数,携带会话 ID(刷新页面可恢复) ──
|
|
1620
1620
|
try {
|
|
1621
1621
|
const url = new URL(window.location.href);
|
|
1622
|
-
url.searchParams.set('
|
|
1623
|
-
url.searchParams.set('
|
|
1622
|
+
url.searchParams.set('s', UrlCodec.encode(sessionId));
|
|
1623
|
+
url.searchParams.set('a', UrlCodec.encode(state.activeAgent || 'default'));
|
|
1624
1624
|
window.history.replaceState({}, '', url.toString());
|
|
1625
1625
|
} catch (_) {}
|
|
1626
1626
|
}
|
|
@@ -1770,7 +1770,7 @@ async function sendMessage(opts) {
|
|
|
1770
1770
|
// ── 更新 URL 参数(后端返回的 session ID 可能与前端不同) ──
|
|
1771
1771
|
try {
|
|
1772
1772
|
const _url = new URL(window.location.href);
|
|
1773
|
-
_url.searchParams.set('
|
|
1773
|
+
_url.searchParams.set('s', UrlCodec.encode(evt.session_id));
|
|
1774
1774
|
window.history.replaceState({}, '', _url.toString());
|
|
1775
1775
|
} catch (_) {}
|
|
1776
1776
|
} else if (evt.type === 'user_files') {
|
package/web/ui/chat/groupchat.js
CHANGED
|
@@ -1,3 +1,32 @@
|
|
|
1
|
+
// ══════════════════════════════════════════════════════
|
|
2
|
+
// ── URL Codec(避免 agent/session 明文暴露在 URL) ──
|
|
3
|
+
// [v1.23.50] 放在最先加载的文件中,供所有模块使用
|
|
4
|
+
// ══════════════════════════════════════════════════════
|
|
5
|
+
var UrlCodec = (function() {
|
|
6
|
+
var _p = 'x';
|
|
7
|
+
function _encode(str) {
|
|
8
|
+
if (!str) return '';
|
|
9
|
+
try {
|
|
10
|
+
var bytes = new TextEncoder().encode(str);
|
|
11
|
+
var bin = '';
|
|
12
|
+
for (var i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]);
|
|
13
|
+
return _p + btoa(bin).replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
|
|
14
|
+
} catch(e) { return str; }
|
|
15
|
+
}
|
|
16
|
+
function _decode(encoded) {
|
|
17
|
+
if (!encoded || encoded[0] !== _p) return encoded;
|
|
18
|
+
try {
|
|
19
|
+
var b64 = encoded.substring(1).replace(/-/g, '+').replace(/_/g, '/');
|
|
20
|
+
while (b64.length % 4) b64 += '=';
|
|
21
|
+
var bin = atob(b64);
|
|
22
|
+
var bytes = new Uint8Array(bin.length);
|
|
23
|
+
for (var i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
|
|
24
|
+
return new TextDecoder().decode(bytes);
|
|
25
|
+
} catch(e) { return encoded; }
|
|
26
|
+
}
|
|
27
|
+
return { encode: _encode, decode: _decode };
|
|
28
|
+
})();
|
|
29
|
+
|
|
1
30
|
// ══════════════════════════════════════════════════════
|
|
2
31
|
// ── Group Chat: 群聊模块 ──
|
|
3
32
|
// ── 负责群聊的创建、管理、消息渲染与发送 ──
|