feat(engine): 添加GLM-ASR语音识别引擎支持

- 新增GLM-ASR云端语音识别引擎实现
- 扩展配置界面添加GLM相关参数设置
- Ollama支持自定义域名和Apikey以支持云端和其他LLM
- 修改音频处理逻辑以支持新引擎
- 更新依赖项和构建配置
- 修复Ollama翻译功能相关问题
This commit is contained in:
nocmt
2026-01-10 16:02:24 +08:00
parent 383e582a2d
commit 0825e48902
19 changed files with 519 additions and 91 deletions

7
.gitignore vendored
View File

@@ -8,7 +8,14 @@ __pycache__
.venv .venv
test.py test.py
engine/build engine/build
engine/dist
engine/.venv
engine/__pycache__
engine/portaudio
package-lock.json
engine/pyinstaller_cache
engine/models engine/models
engine/notebook engine/notebook
.repomap .repomap
.virtualme .virtualme
engine/main.spec

View File

@@ -8,5 +8,9 @@
<true/> <true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key> <key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/> <true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.device.audio-input</key>
<true/>
</dict> </dict>
</plist> </plist>

View File

@@ -1,3 +1,4 @@
from .gummy import GummyRecognizer from .gummy import GummyRecognizer
from .vosk import VoskRecognizer from .vosk import VoskRecognizer
from .sosv import SosvRecognizer from .sosv import SosvRecognizer
from .glm import GlmRecognizer

163
engine/audio2text/glm.py Normal file
View File

@@ -0,0 +1,163 @@
import threading
import io
import wave
import struct
import math
import audioop
import requests
from datetime import datetime
from utils import shared_data
from utils import stdout_cmd, stdout_obj, google_translate, ollama_translate
class GlmRecognizer:
"""
使用 GLM-ASR 引擎处理音频数据,并在标准输出中输出 Auto Caption 软件可读取的 JSON 字符串数据
初始化参数:
url: GLM-ASR API URL
model: GLM-ASR 模型名称
api_key: GLM-ASR API Key
source: 源语言
target: 目标语言
trans_model: 翻译模型名称
ollama_name: Ollama 模型名称
"""
def __init__(self, url: str, model: str, api_key: str, source: str, target: str | None, trans_model: str, ollama_name: str, ollama_url: str = '', ollama_api_key: str = ''):
self.url = url
self.model = model
self.api_key = api_key
self.source = source
self.target = target
if trans_model == 'google':
self.trans_func = google_translate
else:
self.trans_func = ollama_translate
self.ollama_name = ollama_name
self.ollama_url = ollama_url
self.ollama_api_key = ollama_api_key
self.audio_buffer = []
self.is_speech = False
self.silence_frames = 0
self.speech_start_time = None
self.time_str = ''
self.cur_id = 0
# VAD settings (假设 16k 16bit, chunk size 1024 or similar)
# 16bit = 2 bytes per sample.
# RMS threshold needs tuning. 500 is a conservative guess for silence.
self.threshold = 500
self.silence_limit = 15 # frames (approx 0.5-1s depending on chunk size)
self.min_speech_frames = 10 # frames
def start(self):
"""启动 GLM 引擎"""
stdout_cmd('info', 'GLM-ASR recognizer started.')
def stop(self):
"""停止 GLM 引擎"""
stdout_cmd('info', 'GLM-ASR recognizer stopped.')
def process_audio(self, chunk):
# chunk is bytes (int16)
rms = audioop.rms(chunk, 2)
if rms > self.threshold:
if not self.is_speech:
self.is_speech = True
self.time_str = datetime.now().strftime('%H:%M:%S.%f')[:-3]
self.audio_buffer = []
self.audio_buffer.append(chunk)
self.silence_frames = 0
else:
if self.is_speech:
self.audio_buffer.append(chunk)
self.silence_frames += 1
if self.silence_frames > self.silence_limit:
# Speech ended
if len(self.audio_buffer) > self.min_speech_frames:
self.recognize(self.audio_buffer, self.time_str)
self.is_speech = False
self.audio_buffer = []
self.silence_frames = 0
def recognize(self, audio_frames, time_s):
audio_bytes = b''.join(audio_frames)
wav_io = io.BytesIO()
with wave.open(wav_io, 'wb') as wav_file:
wav_file.setnchannels(1)
wav_file.setsampwidth(2)
wav_file.setframerate(16000)
wav_file.writeframes(audio_bytes)
wav_io.seek(0)
threading.Thread(
target=self._do_request,
args=(wav_io.read(), time_s, self.cur_id)
).start()
self.cur_id += 1
def _do_request(self, audio_content, time_s, index):
try:
files = {
'file': ('audio.wav', audio_content, 'audio/wav')
}
data = {
'model': self.model,
'stream': 'false'
}
headers = {
'Authorization': f'Bearer {self.api_key}'
}
response = requests.post(self.url, headers=headers, data=data, files=files, timeout=15)
if response.status_code == 200:
res_json = response.json()
text = res_json.get('text', '')
if text:
self.output_caption(text, time_s, index)
else:
try:
err_msg = response.json()
stdout_cmd('error', f"GLM API Error: {err_msg}")
except:
stdout_cmd('error', f"GLM API Error: {response.text}")
except Exception as e:
stdout_cmd('error', f"GLM Request Failed: {str(e)}")
def output_caption(self, text, time_s, index):
caption = {
'command': 'caption',
'index': index,
'time_s': time_s,
'time_t': datetime.now().strftime('%H:%M:%S.%f')[:-3],
'text': text,
'translation': ''
}
if self.target:
if self.trans_func == ollama_translate:
th = threading.Thread(
target=self.trans_func,
args=(self.ollama_name, self.target, caption['text'], time_s, self.ollama_url, self.ollama_api_key),
daemon=True
)
else:
th = threading.Thread(
target=self.trans_func,
args=(self.ollama_name, self.target, caption['text'], time_s),
daemon=True
)
th.start()
stdout_obj(caption)
def translate(self):
global shared_data
while shared_data.status == 'running':
chunk = shared_data.chunk_queue.get()
self.process_audio(chunk)

View File

@@ -29,7 +29,7 @@ class SosvRecognizer:
trans_model: 翻译模型名称 trans_model: 翻译模型名称
ollama_name: Ollama 模型名称 ollama_name: Ollama 模型名称
""" """
def __init__(self, model_path: str, source: str, target: str | None, trans_model: str, ollama_name: str): def __init__(self, model_path: str, source: str, target: str | None, trans_model: str, ollama_name: str, ollama_url: str = '', ollama_api_key: str = ''):
if model_path.startswith('"'): if model_path.startswith('"'):
model_path = model_path[1:] model_path = model_path[1:]
if model_path.endswith('"'): if model_path.endswith('"'):
@@ -45,6 +45,8 @@ class SosvRecognizer:
else: else:
self.trans_func = ollama_translate self.trans_func = ollama_translate
self.ollama_name = ollama_name self.ollama_name = ollama_name
self.ollama_url = ollama_url
self.ollama_api_key = ollama_api_key
self.time_str = '' self.time_str = ''
self.cur_id = 0 self.cur_id = 0
self.prev_content = '' self.prev_content = ''
@@ -152,7 +154,7 @@ class SosvRecognizer:
if self.target: if self.target:
th = threading.Thread( th = threading.Thread(
target=self.trans_func, target=self.trans_func,
args=(self.ollama_name, self.target, caption['text'], self.time_str), args=(self.ollama_name, self.target, caption['text'], self.time_str, self.ollama_url, self.ollama_api_key),
daemon=True daemon=True
) )
th.start() th.start()

View File

@@ -18,7 +18,7 @@ class VoskRecognizer:
trans_model: 翻译模型名称 trans_model: 翻译模型名称
ollama_name: Ollama 模型名称 ollama_name: Ollama 模型名称
""" """
def __init__(self, model_path: str, target: str | None, trans_model: str, ollama_name: str): def __init__(self, model_path: str, target: str | None, trans_model: str, ollama_name: str, ollama_url: str = '', ollama_api_key: str = ''):
SetLogLevel(-1) SetLogLevel(-1)
if model_path.startswith('"'): if model_path.startswith('"'):
model_path = model_path[1:] model_path = model_path[1:]
@@ -31,6 +31,8 @@ class VoskRecognizer:
else: else:
self.trans_func = ollama_translate self.trans_func = ollama_translate
self.ollama_name = ollama_name self.ollama_name = ollama_name
self.ollama_url = ollama_url
self.ollama_api_key = ollama_api_key
self.time_str = '' self.time_str = ''
self.cur_id = 0 self.cur_id = 0
self.prev_content = '' self.prev_content = ''
@@ -66,7 +68,7 @@ class VoskRecognizer:
if self.target: if self.target:
th = threading.Thread( th = threading.Thread(
target=self.trans_func, target=self.trans_func,
args=(self.ollama_name, self.target, caption['text'], self.time_str), args=(self.ollama_name, self.target, caption['text'], self.time_str, self.ollama_url, self.ollama_api_key),
daemon=True daemon=True
) )
th.start() th.start()

View File

@@ -8,6 +8,7 @@ from utils import merge_chunk_channels, resample_chunk_mono
from audio2text import GummyRecognizer from audio2text import GummyRecognizer
from audio2text import VoskRecognizer from audio2text import VoskRecognizer
from audio2text import SosvRecognizer from audio2text import SosvRecognizer
from audio2text import GlmRecognizer
from sysaudio import AudioStream from sysaudio import AudioStream
@@ -74,7 +75,7 @@ def main_gummy(s: str, t: str, a: int, c: int, k: str, r: bool, rp: str):
engine.stop() engine.stop()
def main_vosk(a: int, c: int, vosk: str, t: str, tm: str, omn: str, r: bool, rp: str): def main_vosk(a: int, c: int, vosk: str, t: str, tm: str, omn: str, ourl: str, okey: str, r: bool, rp: str):
""" """
Parameters: Parameters:
a: Audio source: 0 for output, 1 for input a: Audio source: 0 for output, 1 for input
@@ -83,14 +84,16 @@ def main_vosk(a: int, c: int, vosk: str, t: str, tm: str, omn: str, r: bool, rp:
t: Target language t: Target language
tm: Translation model type, ollama or google tm: Translation model type, ollama or google
omn: Ollama model name omn: Ollama model name
ourl: Ollama Base URL
okey: Ollama API Key
r: Whether to record the audio r: Whether to record the audio
rp: Path to save the recorded audio rp: Path to save the recorded audio
""" """
stream = AudioStream(a, c) stream = AudioStream(a, c)
if t == 'none': if t == 'none':
engine = VoskRecognizer(vosk, None, tm, omn) engine = VoskRecognizer(vosk, None, tm, omn, ourl, okey)
else: else:
engine = VoskRecognizer(vosk, t, tm, omn) engine = VoskRecognizer(vosk, t, tm, omn, ourl, okey)
engine.start() engine.start()
stream_thread = threading.Thread( stream_thread = threading.Thread(
@@ -106,7 +109,7 @@ def main_vosk(a: int, c: int, vosk: str, t: str, tm: str, omn: str, r: bool, rp:
engine.stop() engine.stop()
def main_sosv(a: int, c: int, sosv: str, s: str, t: str, tm: str, omn: str, r: bool, rp: str): def main_sosv(a: int, c: int, sosv: str, s: str, t: str, tm: str, omn: str, ourl: str, okey: str, r: bool, rp: str):
""" """
Parameters: Parameters:
a: Audio source: 0 for output, 1 for input a: Audio source: 0 for output, 1 for input
@@ -116,14 +119,16 @@ def main_sosv(a: int, c: int, sosv: str, s: str, t: str, tm: str, omn: str, r: b
t: Target language t: Target language
tm: Translation model type, ollama or google tm: Translation model type, ollama or google
omn: Ollama model name omn: Ollama model name
ourl: Ollama API URL
okey: Ollama API Key
r: Whether to record the audio r: Whether to record the audio
rp: Path to save the recorded audio rp: Path to save the recorded audio
""" """
stream = AudioStream(a, c) stream = AudioStream(a, c)
if t == 'none': if t == 'none':
engine = SosvRecognizer(sosv, s, None, tm, omn) engine = SosvRecognizer(sosv, s, None, tm, omn, ourl, okey)
else: else:
engine = SosvRecognizer(sosv, s, t, tm, omn) engine = SosvRecognizer(sosv, s, t, tm, omn, ourl, okey)
engine.start() engine.start()
stream_thread = threading.Thread( stream_thread = threading.Thread(
@@ -139,16 +144,54 @@ def main_sosv(a: int, c: int, sosv: str, s: str, t: str, tm: str, omn: str, r: b
engine.stop() engine.stop()
def main_glm(a: int, c: int, url: str, model: str, key: str, s: str, t: str, tm: str, omn: str, ourl: str, okey: str, r: bool, rp: str):
"""
Parameters:
a: Audio source
c: Chunk rate
url: GLM API URL
model: GLM Model Name
key: GLM API Key
s: Source language
t: Target language
tm: Translation model
omn: Ollama model name
ourl: Ollama API URL
okey: Ollama API Key
r: Record
rp: Record path
"""
stream = AudioStream(a, c)
if t == 'none':
engine = GlmRecognizer(url, model, key, s, None, tm, omn, ourl, okey)
else:
engine = GlmRecognizer(url, model, key, s, t, tm, omn, ourl, okey)
engine.start()
stream_thread = threading.Thread(
target=audio_recording,
args=(stream, True, r, rp),
daemon=True
)
stream_thread.start()
try:
engine.translate()
except KeyboardInterrupt:
stdout("Keyboard interrupt detected. Exiting...")
engine.stop()
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Convert system audio stream to text') parser = argparse.ArgumentParser(description='Convert system audio stream to text')
# all # all
parser.add_argument('-e', '--caption_engine', default='gummy', help='Caption engine: gummy or vosk or sosv') parser.add_argument('-e', '--caption_engine', default='gummy', help='Caption engine: gummy or vosk or sosv')
parser.add_argument('-a', '--audio_type', default=0, help='Audio stream source: 0 for output, 1 for input') parser.add_argument('-a', '--audio_type', type=int, default=0, help='Audio stream source: 0 for output, 1 for input')
parser.add_argument('-c', '--chunk_rate', default=10, help='Number of audio stream chunks collected per second') parser.add_argument('-c', '--chunk_rate', type=int, default=10, help='Number of audio stream chunks collected per second')
parser.add_argument('-p', '--port', default=0, help='The port to run the server on, 0 for no server') parser.add_argument('-p', '--port', type=int, default=0, help='The port to run the server on, 0 for no server')
parser.add_argument('-d', '--display_caption', default=0, help='Display caption on terminal, 0 for no display, 1 for display') parser.add_argument('-d', '--display_caption', type=int, default=0, help='Display caption on terminal, 0 for no display, 1 for display')
parser.add_argument('-t', '--target_language', default='none', help='Target language code, "none" for no translation') parser.add_argument('-t', '--target_language', default='none', help='Target language code, "none" for no translation')
parser.add_argument('-r', '--record', default=0, help='Whether to record the audio, 0 for no recording, 1 for recording') parser.add_argument('-r', '--record', type=int, default=0, help='Whether to record the audio, 0 for no recording, 1 for recording')
parser.add_argument('-rp', '--record_path', default='', help='Path to save the recorded audio') parser.add_argument('-rp', '--record_path', default='', help='Path to save the recorded audio')
# gummy and sosv # gummy and sosv
parser.add_argument('-s', '--source_language', default='auto', help='Source language code') parser.add_argument('-s', '--source_language', default='auto', help='Source language code')
@@ -157,20 +200,24 @@ if __name__ == "__main__":
# vosk and sosv # vosk and sosv
parser.add_argument('-tm', '--translation_model', default='ollama', help='Model for translation: ollama or google') parser.add_argument('-tm', '--translation_model', default='ollama', help='Model for translation: ollama or google')
parser.add_argument('-omn', '--ollama_name', default='', help='Ollama model name for translation') parser.add_argument('-omn', '--ollama_name', default='', help='Ollama model name for translation')
parser.add_argument('-ourl', '--ollama_url', default='', help='Ollama API URL')
parser.add_argument('-okey', '--ollama_api_key', default='', help='Ollama API Key')
# vosk only # vosk only
parser.add_argument('-vosk', '--vosk_model', default='', help='The path to the vosk model.') parser.add_argument('-vosk', '--vosk_model', default='', help='The path to the vosk model.')
# sosv only # sosv only
parser.add_argument('-sosv', '--sosv_model', default=None, help='The SenseVoice model path') parser.add_argument('-sosv', '--sosv_model', default=None, help='The SenseVoice model path')
# glm only
parser.add_argument('-gurl', '--glm_url', default='https://open.bigmodel.cn/api/paas/v4/audio/transcriptions', help='GLM API URL')
parser.add_argument('-gmodel', '--glm_model', default='glm-asr-2512', help='GLM Model Name')
parser.add_argument('-gkey', '--glm_api_key', default='', help='GLM API Key')
args = parser.parse_args() args = parser.parse_args()
if int(args.port) == 0:
shared_data.status = "running"
else:
start_server(int(args.port))
if int(args.display_caption) != 0: if args.port != 0:
threading.Thread(target=start_server, args=(args.port,), daemon=True).start()
if args.display_caption == '1':
change_caption_display(True) change_caption_display(True)
print("Caption will be displayed on terminal")
if args.caption_engine == 'gummy': if args.caption_engine == 'gummy':
main_gummy( main_gummy(
@@ -179,7 +226,7 @@ if __name__ == "__main__":
int(args.audio_type), int(args.audio_type),
int(args.chunk_rate), int(args.chunk_rate),
args.api_key, args.api_key,
True if int(args.record) == 1 else False, bool(int(args.record)),
args.record_path args.record_path
) )
elif args.caption_engine == 'vosk': elif args.caption_engine == 'vosk':
@@ -190,7 +237,9 @@ if __name__ == "__main__":
args.target_language, args.target_language,
args.translation_model, args.translation_model,
args.ollama_name, args.ollama_name,
True if int(args.record) == 1 else False, args.ollama_url,
args.ollama_api_key,
bool(int(args.record)),
args.record_path args.record_path
) )
elif args.caption_engine == 'sosv': elif args.caption_engine == 'sosv':
@@ -202,7 +251,25 @@ if __name__ == "__main__":
args.target_language, args.target_language,
args.translation_model, args.translation_model,
args.ollama_name, args.ollama_name,
True if int(args.record) == 1 else False, args.ollama_url,
args.ollama_api_key,
bool(int(args.record)),
args.record_path
)
elif args.caption_engine == 'glm':
main_glm(
int(args.audio_type),
int(args.chunk_rate),
args.glm_url,
args.glm_model,
args.glm_api_key,
args.source_language,
args.target_language,
args.translation_model,
args.ollama_name,
args.ollama_url,
args.ollama_api_key,
bool(int(args.record)),
args.record_path args.record_path
) )
else: else:

View File

@@ -6,11 +6,17 @@ import sys
if sys.platform == 'win32': if sys.platform == 'win32':
vosk_path = str(Path('./.venv/Lib/site-packages/vosk').resolve()) vosk_path = str(Path('./.venv/Lib/site-packages/vosk').resolve())
else: else:
vosk_path = str(Path('./.venv/lib/python3.12/site-packages/vosk').resolve()) venv_lib = Path('./.venv/lib')
python_dirs = list(venv_lib.glob('python*'))
if python_dirs:
vosk_path = str((python_dirs[0] / 'site-packages' / 'vosk').resolve())
else:
vosk_path = str(Path('./.venv/lib/python3.12/site-packages/vosk').resolve())
a = Analysis( a = Analysis(
['main.py'], ['main.py'],
pathex=[], pathex=[],
# binaries=[('portaudio/lib/.libs/libportaudio.2.dylib', '.')],
binaries=[], binaries=[],
datas=[(vosk_path, 'vosk')], datas=[(vosk_path, 'vosk')],
hiddenimports=[], hiddenimports=[],
@@ -27,21 +33,27 @@ pyz = PYZ(a.pure)
exe = EXE( exe = EXE(
pyz, pyz,
a.scripts, a.scripts,
a.binaries,
a.datas,
[], [],
exclude_binaries=True,
name='main', name='main',
debug=False, debug=False,
bootloader_ignore_signals=False, bootloader_ignore_signals=False,
strip=False, strip=False,
upx=True, upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True, console=True,
disable_windowed_traceback=False, disable_windowed_traceback=False,
argv_emulation=False, argv_emulation=False,
target_arch=None, target_arch=None,
codesign_identity=None, codesign_identity=None,
entitlements_file=None, entitlements_file=None,
onefile=True, )
coll = COLLECT(
exe,
a.binaries,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='main',
) )

View File

@@ -8,3 +8,5 @@ pyaudiowpatch; sys_platform == 'win32'
googletrans googletrans
ollama ollama
sherpa_onnx sherpa_onnx
requests
openai

View File

@@ -47,7 +47,6 @@ def translation_display(obj):
def stdout_obj(obj): def stdout_obj(obj):
global display_caption global display_caption
print(obj['command'], display_caption)
if obj['command'] == 'caption' and display_caption: if obj['command'] == 'caption' and display_caption:
caption_display(obj) caption_display(obj)
return return

View File

@@ -1,5 +1,9 @@
from ollama import chat from ollama import chat, Client
from ollama import ChatResponse from ollama import ChatResponse
try:
from openai import OpenAI
except ImportError:
OpenAI = None
import asyncio import asyncio
from googletrans import Translator from googletrans import Translator
from .sysout import stdout_cmd, stdout_obj from .sysout import stdout_cmd, stdout_obj
@@ -17,15 +21,43 @@ lang_map = {
'zh-cn': 'Chinese' 'zh-cn': 'Chinese'
} }
def ollama_translate(model: str, target: str, text: str, time_s: str): def ollama_translate(model: str, target: str, text: str, time_s: str, url: str = '', key: str = ''):
response: ChatResponse = chat( content = ""
model=model, try:
messages=[ if url:
{"role": "system", "content": f"/no_think Translate the following content into {lang_map[target]}, and do not output any additional information."}, if OpenAI:
{"role": "user", "content": text} client = OpenAI(base_url=url, api_key=key if key else "ollama")
] response = client.chat.completions.create(
) model=model,
content = response.message.content or "" messages=[
{"role": "system", "content": f"/no_think Translate the following content into {lang_map[target]}, and do not output any additional information."},
{"role": "user", "content": text}
]
)
content = response.choices[0].message.content or ""
else:
client = Client(host=url)
response: ChatResponse = client.chat(
model=model,
messages=[
{"role": "system", "content": f"/no_think Translate the following content into {lang_map[target]}, and do not output any additional information."},
{"role": "user", "content": text}
]
)
content = response.message.content or ""
else:
response: ChatResponse = chat(
model=model,
messages=[
{"role": "system", "content": f"/no_think Translate the following content into {lang_map[target]}, and do not output any additional information."},
{"role": "user", "content": text}
]
)
content = response.message.content or ""
except Exception as e:
stdout_cmd("warn", f"Translation failed: {str(e)}")
return
if content.startswith('<think>'): if content.startswith('<think>'):
index = content.find('</think>') index = content.find('</think>')
if index != -1: if index != -1:

67
package-lock.json generated
View File

@@ -110,6 +110,7 @@
"integrity": "sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==", "integrity": "sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@ampproject/remapping": "^2.2.0", "@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.27.1", "@babel/code-frame": "^7.27.1",
@@ -2274,6 +2275,7 @@
"resolved": "https://registry.npmmirror.com/@types/node/-/node-22.15.17.tgz", "resolved": "https://registry.npmmirror.com/@types/node/-/node-22.15.17.tgz",
"integrity": "sha512-wIX2aSZL5FE+MR0JlvF87BNVrtFWf6AE6rxSE9X7OwnVvoyCQjpzSRJ+M87se/4QCkCiebQAqrJ0y6fwIyi7nw==", "integrity": "sha512-wIX2aSZL5FE+MR0JlvF87BNVrtFWf6AE6rxSE9X7OwnVvoyCQjpzSRJ+M87se/4QCkCiebQAqrJ0y6fwIyi7nw==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"undici-types": "~6.21.0" "undici-types": "~6.21.0"
} }
@@ -2360,6 +2362,7 @@
"integrity": "sha512-B2MdzyWxCE2+SqiZHAjPphft+/2x2FlO9YBx7eKE1BCb+rqBlQdhtAEhzIEdozHd55DXPmxBdpMygFJjfjjA9A==", "integrity": "sha512-B2MdzyWxCE2+SqiZHAjPphft+/2x2FlO9YBx7eKE1BCb+rqBlQdhtAEhzIEdozHd55DXPmxBdpMygFJjfjjA9A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.32.0", "@typescript-eslint/scope-manager": "8.32.0",
"@typescript-eslint/types": "8.32.0", "@typescript-eslint/types": "8.32.0",
@@ -2791,6 +2794,7 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
}, },
@@ -2851,6 +2855,7 @@
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"fast-deep-equal": "^3.1.1", "fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0", "fast-json-stable-stringify": "^2.0.0",
@@ -3064,7 +3069,6 @@
"integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"archiver-utils": "^2.1.0", "archiver-utils": "^2.1.0",
"async": "^3.2.4", "async": "^3.2.4",
@@ -3084,7 +3088,6 @@
"integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"glob": "^7.1.4", "glob": "^7.1.4",
"graceful-fs": "^4.2.0", "graceful-fs": "^4.2.0",
@@ -3107,7 +3110,6 @@
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"core-util-is": "~1.0.0", "core-util-is": "~1.0.0",
"inherits": "~2.0.3", "inherits": "~2.0.3",
@@ -3123,8 +3125,7 @@
"resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz", "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT"
"peer": true
}, },
"node_modules/archiver-utils/node_modules/string_decoder": { "node_modules/archiver-utils/node_modules/string_decoder": {
"version": "1.1.1", "version": "1.1.1",
@@ -3132,7 +3133,6 @@
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"safe-buffer": "~5.1.0" "safe-buffer": "~5.1.0"
} }
@@ -3351,6 +3351,7 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"caniuse-lite": "^1.0.30001716", "caniuse-lite": "^1.0.30001716",
"electron-to-chromium": "^1.5.149", "electron-to-chromium": "^1.5.149",
@@ -3848,7 +3849,6 @@
"integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"buffer-crc32": "^0.2.13", "buffer-crc32": "^0.2.13",
"crc32-stream": "^4.0.2", "crc32-stream": "^4.0.2",
@@ -3994,7 +3994,6 @@
"integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"bin": { "bin": {
"crc32": "bin/crc32.njs" "crc32": "bin/crc32.njs"
}, },
@@ -4008,7 +4007,6 @@
"integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"crc-32": "^1.2.0", "crc-32": "^1.2.0",
"readable-stream": "^3.4.0" "readable-stream": "^3.4.0"
@@ -4248,6 +4246,7 @@
"integrity": "sha512-NoXo6Liy2heSklTI5OIZbCgXC1RzrDQsZkeEwXhdOro3FT1VBOvbubvscdPnjVuQ4AMwwv61oaH96AbiYg9EnQ==", "integrity": "sha512-NoXo6Liy2heSklTI5OIZbCgXC1RzrDQsZkeEwXhdOro3FT1VBOvbubvscdPnjVuQ4AMwwv61oaH96AbiYg9EnQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"app-builder-lib": "25.1.8", "app-builder-lib": "25.1.8",
"builder-util": "25.1.7", "builder-util": "25.1.7",
@@ -4410,6 +4409,7 @@
"integrity": "sha512-6dLslJrQYB1qvqVPYRv1PhAA/uytC66nUeiTcq2JXiBzrmTWCHppqtGUjZhvnSRVatBCT5/SFdizdzcBiEiYUg==", "integrity": "sha512-6dLslJrQYB1qvqVPYRv1PhAA/uytC66nUeiTcq2JXiBzrmTWCHppqtGUjZhvnSRVatBCT5/SFdizdzcBiEiYUg==",
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@electron/get": "^2.0.0", "@electron/get": "^2.0.0",
"@types/node": "^22.7.7", "@types/node": "^22.7.7",
@@ -4454,7 +4454,6 @@
"integrity": "sha512-2ntkJ+9+0GFP6nAISiMabKt6eqBB0kX1QqHNWFWAXgi0VULKGisM46luRFpIBiU3u/TDmhZMM8tzvo2Abn3ayg==", "integrity": "sha512-2ntkJ+9+0GFP6nAISiMabKt6eqBB0kX1QqHNWFWAXgi0VULKGisM46luRFpIBiU3u/TDmhZMM8tzvo2Abn3ayg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"app-builder-lib": "25.1.8", "app-builder-lib": "25.1.8",
"archiver": "^5.3.1", "archiver": "^5.3.1",
@@ -4468,7 +4467,6 @@
"integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"graceful-fs": "^4.2.0", "graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1", "jsonfile": "^6.0.1",
@@ -4484,7 +4482,6 @@
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"universalify": "^2.0.0" "universalify": "^2.0.0"
}, },
@@ -4498,7 +4495,6 @@
"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">= 10.0.0" "node": ">= 10.0.0"
} }
@@ -4813,6 +4809,7 @@
"integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==", "integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1", "@eslint-community/regexpp": "^4.12.1",
@@ -4874,6 +4871,7 @@
"integrity": "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==", "integrity": "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"eslint-config-prettier": "bin/cli.js" "eslint-config-prettier": "bin/cli.js"
}, },
@@ -5351,8 +5349,7 @@
"resolved": "https://registry.npmmirror.com/fs-constants/-/fs-constants-1.0.0.tgz", "resolved": "https://registry.npmmirror.com/fs-constants/-/fs-constants-1.0.0.tgz",
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT"
"peer": true
}, },
"node_modules/fs-extra": { "node_modules/fs-extra": {
"version": "8.1.0", "version": "8.1.0",
@@ -6108,8 +6105,7 @@
"resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz", "resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT"
"peer": true
}, },
"node_modules/isbinaryfile": { "node_modules/isbinaryfile": {
"version": "5.0.4", "version": "5.0.4",
@@ -6300,7 +6296,6 @@
"integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"readable-stream": "^2.0.5" "readable-stream": "^2.0.5"
}, },
@@ -6314,7 +6309,6 @@
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"core-util-is": "~1.0.0", "core-util-is": "~1.0.0",
"inherits": "~2.0.3", "inherits": "~2.0.3",
@@ -6330,8 +6324,7 @@
"resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz", "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT"
"peer": true
}, },
"node_modules/lazystream/node_modules/string_decoder": { "node_modules/lazystream/node_modules/string_decoder": {
"version": "1.1.1", "version": "1.1.1",
@@ -6339,7 +6332,6 @@
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"safe-buffer": "~5.1.0" "safe-buffer": "~5.1.0"
} }
@@ -6391,32 +6383,28 @@
"resolved": "https://registry.npmmirror.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz", "resolved": "https://registry.npmmirror.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT"
"peer": true
}, },
"node_modules/lodash.difference": { "node_modules/lodash.difference": {
"version": "4.5.0", "version": "4.5.0",
"resolved": "https://registry.npmmirror.com/lodash.difference/-/lodash.difference-4.5.0.tgz", "resolved": "https://registry.npmmirror.com/lodash.difference/-/lodash.difference-4.5.0.tgz",
"integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT"
"peer": true
}, },
"node_modules/lodash.flatten": { "node_modules/lodash.flatten": {
"version": "4.4.0", "version": "4.4.0",
"resolved": "https://registry.npmmirror.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz", "resolved": "https://registry.npmmirror.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
"integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT"
"peer": true
}, },
"node_modules/lodash.isplainobject": { "node_modules/lodash.isplainobject": {
"version": "4.0.6", "version": "4.0.6",
"resolved": "https://registry.npmmirror.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", "resolved": "https://registry.npmmirror.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT"
"peer": true
}, },
"node_modules/lodash.merge": { "node_modules/lodash.merge": {
"version": "4.6.2", "version": "4.6.2",
@@ -6430,8 +6418,7 @@
"resolved": "https://registry.npmmirror.com/lodash.union/-/lodash.union-4.6.0.tgz", "resolved": "https://registry.npmmirror.com/lodash.union/-/lodash.union-4.6.0.tgz",
"integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT"
"peer": true
}, },
"node_modules/log-symbols": { "node_modules/log-symbols": {
"version": "4.1.0", "version": "4.1.0",
@@ -6984,7 +6971,6 @@
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
@@ -7408,6 +7394,7 @@
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"prettier": "bin/prettier.cjs" "prettier": "bin/prettier.cjs"
}, },
@@ -7436,8 +7423,7 @@
"resolved": "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "resolved": "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT"
"peer": true
}, },
"node_modules/progress": { "node_modules/progress": {
"version": "2.0.3", "version": "2.0.3",
@@ -7556,7 +7542,6 @@
"integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"dependencies": { "dependencies": {
"minimatch": "^5.1.0" "minimatch": "^5.1.0"
} }
@@ -7567,7 +7552,6 @@
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
"dev": true, "dev": true,
"license": "ISC", "license": "ISC",
"peer": true,
"dependencies": { "dependencies": {
"brace-expansion": "^2.0.1" "brace-expansion": "^2.0.1"
}, },
@@ -8235,7 +8219,6 @@
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"bl": "^4.0.3", "bl": "^4.0.3",
"end-of-stream": "^1.4.1", "end-of-stream": "^1.4.1",
@@ -8360,6 +8343,7 @@
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
@@ -8462,6 +8446,7 @@
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
"devOptional": true, "devOptional": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
@@ -8611,6 +8596,7 @@
"integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"esbuild": "^0.25.0", "esbuild": "^0.25.0",
"fdir": "^6.4.4", "fdir": "^6.4.4",
@@ -8701,6 +8687,7 @@
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
@@ -8720,6 +8707,7 @@
"resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.13.tgz", "resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.13.tgz",
"integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==", "integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@vue/compiler-dom": "3.5.13", "@vue/compiler-dom": "3.5.13",
"@vue/compiler-sfc": "3.5.13", "@vue/compiler-sfc": "3.5.13",
@@ -8742,6 +8730,7 @@
"integrity": "sha512-dbCBnd2e02dYWsXoqX5yKUZlOt+ExIpq7hmHKPb5ZqKcjf++Eo0hMseFTZMLKThrUk61m+Uv6A2YSBve6ZvuDQ==", "integrity": "sha512-dbCBnd2e02dYWsXoqX5yKUZlOt+ExIpq7hmHKPb5ZqKcjf++Eo0hMseFTZMLKThrUk61m+Uv6A2YSBve6ZvuDQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"debug": "^4.4.0", "debug": "^4.4.0",
"eslint-scope": "^8.2.0", "eslint-scope": "^8.2.0",
@@ -9046,7 +9035,6 @@
"integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"archiver-utils": "^3.0.4", "archiver-utils": "^3.0.4",
"compress-commons": "^4.1.2", "compress-commons": "^4.1.2",
@@ -9062,7 +9050,6 @@
"integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"glob": "^7.2.3", "glob": "^7.2.3",
"graceful-fs": "^4.2.0", "graceful-fs": "^4.2.0",

View File

@@ -8,6 +8,8 @@ export interface Controls {
targetLang: string, targetLang: string,
transModel: string, transModel: string,
ollamaName: string, ollamaName: string,
ollamaUrl: string,
ollamaApiKey: string,
engine: string, engine: string,
audio: 0 | 1, audio: 0 | 1,
translation: boolean, translation: boolean,
@@ -15,6 +17,9 @@ export interface Controls {
API_KEY: string, API_KEY: string,
voskModelPath: string, voskModelPath: string,
sosvModelPath: string, sosvModelPath: string,
glmUrl: string,
glmModel: string,
glmApiKey: string,
recordingPath: string, recordingPath: string,
customized: boolean, customized: boolean,
customizedApp: string, customizedApp: string,

View File

@@ -6,7 +6,7 @@ import { Log } from './Log'
import { app, BrowserWindow } from 'electron' import { app, BrowserWindow } from 'electron'
import * as path from 'path' import * as path from 'path'
import * as fs from 'fs' import * as fs from 'fs'
import os from 'os' import * as os from 'os'
interface CaptionTranslation { interface CaptionTranslation {
time_s: string, time_s: string,
@@ -44,13 +44,18 @@ const defaultControls: Controls = {
sourceLang: 'en', sourceLang: 'en',
targetLang: 'zh', targetLang: 'zh',
transModel: 'ollama', transModel: 'ollama',
ollamaName: '', ollamaName: 'qwen2.5:0.5b',
ollamaUrl: 'http://localhost:11434',
ollamaApiKey: '',
engine: 'gummy', engine: 'gummy',
audio: 0, audio: 0,
engineEnabled: false, engineEnabled: false,
API_KEY: '', API_KEY: '',
voskModelPath: '', voskModelPath: '',
sosvModelPath: '', sosvModelPath: '',
glmUrl: 'https://open.bigmodel.cn/api/paas/v4/audio/transcriptions',
glmModel: 'glm-asr-2512',
glmApiKey: '',
recordingPath: getDesktopPath(), recordingPath: getDesktopPath(),
translation: true, translation: true,
recording: false, recording: false,

View File

@@ -1,8 +1,8 @@
import { exec, spawn } from 'child_process' import { exec, spawn } from 'child_process'
import { app } from 'electron' import { app } from 'electron'
import { is } from '@electron-toolkit/utils' import { is } from '@electron-toolkit/utils'
import path from 'path' import * as path from 'path'
import net from 'net' import * as net from 'net'
import { controlWindow } from '../ControlWindow' import { controlWindow } from '../ControlWindow'
import { allConfig } from './AllConfig' import { allConfig } from './AllConfig'
import { i18n } from '../i18n' import { i18n } from '../i18n'
@@ -60,7 +60,7 @@ export class CaptionEngine {
this.appPath = path.join(process.resourcesPath, 'engine', 'main.exe') this.appPath = path.join(process.resourcesPath, 'engine', 'main.exe')
} }
else { else {
this.appPath = path.join(process.resourcesPath, 'engine', 'main') this.appPath = path.join(process.resourcesPath, 'engine', 'main', 'main')
} }
} }
this.command.push('-a', allConfig.controls.audio ? '1' : '0') this.command.push('-a', allConfig.controls.audio ? '1' : '0')
@@ -87,6 +87,8 @@ export class CaptionEngine {
this.command.push('-vosk', `"${allConfig.controls.voskModelPath}"`) this.command.push('-vosk', `"${allConfig.controls.voskModelPath}"`)
this.command.push('-tm', allConfig.controls.transModel) this.command.push('-tm', allConfig.controls.transModel)
this.command.push('-omn', allConfig.controls.ollamaName) this.command.push('-omn', allConfig.controls.ollamaName)
if(allConfig.controls.ollamaUrl) this.command.push('-ourl', allConfig.controls.ollamaUrl)
if(allConfig.controls.ollamaApiKey) this.command.push('-okey', allConfig.controls.ollamaApiKey)
} }
else if(allConfig.controls.engine === 'sosv'){ else if(allConfig.controls.engine === 'sosv'){
this.command.push('-e', 'sosv') this.command.push('-e', 'sosv')
@@ -94,10 +96,25 @@ export class CaptionEngine {
this.command.push('-sosv', `"${allConfig.controls.sosvModelPath}"`) this.command.push('-sosv', `"${allConfig.controls.sosvModelPath}"`)
this.command.push('-tm', allConfig.controls.transModel) this.command.push('-tm', allConfig.controls.transModel)
this.command.push('-omn', allConfig.controls.ollamaName) this.command.push('-omn', allConfig.controls.ollamaName)
if(allConfig.controls.ollamaUrl) this.command.push('-ourl', allConfig.controls.ollamaUrl)
if(allConfig.controls.ollamaApiKey) this.command.push('-okey', allConfig.controls.ollamaApiKey)
}
else if(allConfig.controls.engine === 'glm'){
this.command.push('-e', 'glm')
this.command.push('-s', allConfig.controls.sourceLang)
this.command.push('-gurl', allConfig.controls.glmUrl)
this.command.push('-gmodel', allConfig.controls.glmModel)
if(allConfig.controls.glmApiKey) {
this.command.push('-gkey', allConfig.controls.glmApiKey)
}
this.command.push('-tm', allConfig.controls.transModel)
this.command.push('-omn', allConfig.controls.ollamaName)
if(allConfig.controls.ollamaUrl) this.command.push('-ourl', allConfig.controls.ollamaUrl)
if(allConfig.controls.ollamaApiKey) this.command.push('-okey', allConfig.controls.ollamaApiKey)
} }
} }
Log.info('Engine Path:', this.appPath) Log.info('Engine Path:', this.appPath)
if(this.command.length > 2 && this.command.at(-2) === '-k') { if(this.command.length > 2 && this.command[this.command.length - 2] === '-k') {
const _command = [...this.command] const _command = [...this.command]
_command[_command.length -1] = _command[_command.length -1].replace(/./g, '*') _command[_command.length -1] = _command[_command.length -1].replace(/./g, '*')
Log.info('Engine Command:', _command) Log.info('Engine Command:', _command)

View File

@@ -52,6 +52,44 @@
v-model:value="currentOllamaName" v-model:value="currentOllamaName"
></a-input> ></a-input>
</div> </div>
<div class="input-item" v-if="transModel && currentTransModel === 'ollama'">
<span class="input-label">Ollama Domain</span>
<a-input
class="input-area"
v-model:value="currentOllamaUrl"
placeholder="http://localhost:11434"
></a-input>
</div>
<div class="input-item" v-if="transModel && currentTransModel === 'ollama'">
<span class="input-label">Ollama API Key</span>
<a-input-password
class="input-area"
v-model:value="currentOllamaApiKey"
></a-input-password>
</div>
<div class="input-item" v-if="currentEngine === 'glm'">
<span class="input-label">GLM API URL</span>
<a-input
class="input-area"
v-model:value="currentGlmUrl"
placeholder="https://open.bigmodel.cn/api/paas/v4/audio/transcriptions"
></a-input>
</div>
<div class="input-item" v-if="currentEngine === 'glm'">
<span class="input-label">GLM Model Name</span>
<a-input
class="input-area"
v-model:value="currentGlmModel"
placeholder="glm-asr-2512"
></a-input>
</div>
<div class="input-item" v-if="currentEngine === 'glm'">
<span class="input-label">GLM API Key</span>
<a-input-password
class="input-area"
v-model:value="currentGlmApiKey"
></a-input-password>
</div>
<div class="input-item"> <div class="input-item">
<span class="input-label">{{ $t('engine.audioType') }}</span> <span class="input-label">{{ $t('engine.audioType') }}</span>
<a-select <a-select
@@ -239,9 +277,14 @@ const currentTranslation = ref<boolean>(true)
const currentRecording = ref<boolean>(false) const currentRecording = ref<boolean>(false)
const currentTransModel = ref('ollama') const currentTransModel = ref('ollama')
const currentOllamaName = ref('') const currentOllamaName = ref('')
const currentOllamaUrl = ref('')
const currentOllamaApiKey = ref('')
const currentAPI_KEY = ref<string>('') const currentAPI_KEY = ref<string>('')
const currentVoskModelPath = ref<string>('') const currentVoskModelPath = ref<string>('')
const currentSosvModelPath = ref<string>('') const currentSosvModelPath = ref<string>('')
const currentGlmUrl = ref<string>('')
const currentGlmModel = ref<string>('')
const currentGlmApiKey = ref<string>('')
const currentRecordingPath = ref<string>('') const currentRecordingPath = ref<string>('')
const currentCustomized = ref<boolean>(false) const currentCustomized = ref<boolean>(false)
const currentCustomizedApp = ref('') const currentCustomizedApp = ref('')
@@ -294,12 +337,17 @@ function applyChange(){
engineControl.transModel = currentTransModel.value engineControl.transModel = currentTransModel.value
engineControl.ollamaName = currentOllamaName.value engineControl.ollamaName = currentOllamaName.value
engineControl.engine = currentEngine.value engineControl.engine = currentEngine.value
engineControl.ollamaUrl = currentOllamaUrl.value ?? "http://localhost:11434"
engineControl.ollamaApiKey = currentOllamaApiKey.value
engineControl.audio = currentAudio.value engineControl.audio = currentAudio.value
engineControl.translation = currentTranslation.value engineControl.translation = currentTranslation.value
engineControl.recording = currentRecording.value engineControl.recording = currentRecording.value
engineControl.API_KEY = currentAPI_KEY.value engineControl.API_KEY = currentAPI_KEY.value
engineControl.voskModelPath = currentVoskModelPath.value engineControl.voskModelPath = currentVoskModelPath.value
engineControl.sosvModelPath = currentSosvModelPath.value engineControl.sosvModelPath = currentSosvModelPath.value
engineControl.glmUrl = currentGlmUrl.value ?? "https://open.bigmodel.cn/api/paas/v4/audio/transcriptions"
engineControl.glmModel = currentGlmModel.value ?? "glm-asr-2512"
engineControl.glmApiKey = currentGlmApiKey.value
engineControl.recordingPath = currentRecordingPath.value engineControl.recordingPath = currentRecordingPath.value
engineControl.customized = currentCustomized.value engineControl.customized = currentCustomized.value
engineControl.customizedApp = currentCustomizedApp.value engineControl.customizedApp = currentCustomizedApp.value
@@ -320,6 +368,8 @@ function cancelChange(){
currentTargetLang.value = engineControl.targetLang currentTargetLang.value = engineControl.targetLang
currentTransModel.value = engineControl.transModel currentTransModel.value = engineControl.transModel
currentOllamaName.value = engineControl.ollamaName currentOllamaName.value = engineControl.ollamaName
currentOllamaUrl.value = engineControl.ollamaUrl
currentOllamaApiKey.value = engineControl.ollamaApiKey
currentEngine.value = engineControl.engine currentEngine.value = engineControl.engine
currentAudio.value = engineControl.audio currentAudio.value = engineControl.audio
currentTranslation.value = engineControl.translation currentTranslation.value = engineControl.translation
@@ -327,6 +377,9 @@ function cancelChange(){
currentAPI_KEY.value = engineControl.API_KEY currentAPI_KEY.value = engineControl.API_KEY
currentVoskModelPath.value = engineControl.voskModelPath currentVoskModelPath.value = engineControl.voskModelPath
currentSosvModelPath.value = engineControl.sosvModelPath currentSosvModelPath.value = engineControl.sosvModelPath
currentGlmUrl.value = engineControl.glmUrl
currentGlmModel.value = engineControl.glmModel
currentGlmApiKey.value = engineControl.glmApiKey
currentRecordingPath.value = engineControl.recordingPath currentRecordingPath.value = engineControl.recordingPath
currentCustomized.value = engineControl.customized currentCustomized.value = engineControl.customized
currentCustomizedApp.value = engineControl.customizedApp currentCustomizedApp.value = engineControl.customizedApp

View File

@@ -58,6 +58,21 @@ export const engines = {
{ value: 'ollama', label: 'Ollama 本地模型' }, { value: 'ollama', label: 'Ollama 本地模型' },
{ value: 'google', label: 'Google API 调用' }, { value: 'google', label: 'Google API 调用' },
] ]
},
{
value: 'glm',
label: '云端 / 智谱AI / GLM-ASR',
languages: [
{ value: 'auto', type: -1, label: '自动检测' },
{ value: 'en', type: 0, label: '英语' },
{ value: 'zh', type: 0, label: '中文' },
{ value: 'ja', type: 0, label: '日语' },
{ value: 'ko', type: 0, label: '韩语' },
],
transModel: [
{ value: 'ollama', label: 'Ollama 本地模型' },
{ value: 'google', label: 'Google API 调用' },
]
} }
], ],
en: [ en: [
@@ -118,6 +133,21 @@ export const engines = {
{ value: 'ollama', label: 'Ollama Local Model' }, { value: 'ollama', label: 'Ollama Local Model' },
{ value: 'google', label: 'Google API Call' }, { value: 'google', label: 'Google API Call' },
] ]
},
{
value: 'glm',
label: 'Cloud / Zhipu AI / GLM-ASR',
languages: [
{ value: 'auto', type: -1, label: 'Auto Detect' },
{ value: 'en', type: 0, label: 'English' },
{ value: 'zh', type: 0, label: 'Chinese' },
{ value: 'ja', type: 0, label: 'Japanese' },
{ value: 'ko', type: 0, label: 'Korean' },
],
transModel: [
{ value: 'ollama', label: 'Ollama Local Model' },
{ value: 'google', label: 'Google API Call' },
]
} }
], ],
ja: [ ja: [
@@ -178,6 +208,21 @@ export const engines = {
{ value: 'ollama', label: 'Ollama ローカルモデル' }, { value: 'ollama', label: 'Ollama ローカルモデル' },
{ value: 'google', label: 'Google API 呼び出し' }, { value: 'google', label: 'Google API 呼び出し' },
] ]
},
{
value: 'glm',
label: 'クラウド / 智譜AI / GLM-ASR',
languages: [
{ value: 'auto', type: -1, label: '自動検出' },
{ value: 'en', type: 0, label: '英語' },
{ value: 'zh', type: 0, label: '中国語' },
{ value: 'ja', type: 0, label: '日本語' },
{ value: 'ko', type: 0, label: '韓国語' },
],
transModel: [
{ value: 'ollama', label: 'Ollama ローカルモデル' },
{ value: 'google', label: 'Google API 呼び出し' },
]
} }
] ]
} }

View File

@@ -21,6 +21,8 @@ export const useEngineControlStore = defineStore('engineControl', () => {
const targetLang = ref<string>('zh') const targetLang = ref<string>('zh')
const transModel = ref<string>('ollama') const transModel = ref<string>('ollama')
const ollamaName = ref<string>('') const ollamaName = ref<string>('')
const ollamaUrl = ref<string>('')
const ollamaApiKey = ref<string>('')
const engine = ref<string>('gummy') const engine = ref<string>('gummy')
const audio = ref<0 | 1>(0) const audio = ref<0 | 1>(0)
const translation = ref<boolean>(true) const translation = ref<boolean>(true)
@@ -28,6 +30,9 @@ export const useEngineControlStore = defineStore('engineControl', () => {
const API_KEY = ref<string>('') const API_KEY = ref<string>('')
const voskModelPath = ref<string>('') const voskModelPath = ref<string>('')
const sosvModelPath = ref<string>('') const sosvModelPath = ref<string>('')
const glmUrl = ref<string>('https://open.bigmodel.cn/api/paas/v4/audio/transcriptions')
const glmModel = ref<string>('glm-asr-2512')
const glmApiKey = ref<string>('')
const recordingPath = ref<string>('') const recordingPath = ref<string>('')
const customized = ref<boolean>(false) const customized = ref<boolean>(false)
const customizedApp = ref<string>('') const customizedApp = ref<string>('')
@@ -44,6 +49,8 @@ export const useEngineControlStore = defineStore('engineControl', () => {
targetLang: targetLang.value, targetLang: targetLang.value,
transModel: transModel.value, transModel: transModel.value,
ollamaName: ollamaName.value, ollamaName: ollamaName.value,
ollamaUrl: ollamaUrl.value,
ollamaApiKey: ollamaApiKey.value,
engine: engine.value, engine: engine.value,
audio: audio.value, audio: audio.value,
translation: translation.value, translation: translation.value,
@@ -51,6 +58,9 @@ export const useEngineControlStore = defineStore('engineControl', () => {
API_KEY: API_KEY.value, API_KEY: API_KEY.value,
voskModelPath: voskModelPath.value, voskModelPath: voskModelPath.value,
sosvModelPath: sosvModelPath.value, sosvModelPath: sosvModelPath.value,
glmUrl: glmUrl.value,
glmModel: glmModel.value,
glmApiKey: glmApiKey.value,
recordingPath: recordingPath.value, recordingPath: recordingPath.value,
customized: customized.value, customized: customized.value,
customizedApp: customizedApp.value, customizedApp: customizedApp.value,
@@ -80,6 +90,8 @@ export const useEngineControlStore = defineStore('engineControl', () => {
targetLang.value = controls.targetLang targetLang.value = controls.targetLang
transModel.value = controls.transModel transModel.value = controls.transModel
ollamaName.value = controls.ollamaName ollamaName.value = controls.ollamaName
ollamaUrl.value = controls.ollamaUrl
ollamaApiKey.value = controls.ollamaApiKey
engine.value = controls.engine engine.value = controls.engine
audio.value = controls.audio audio.value = controls.audio
engineEnabled.value = controls.engineEnabled engineEnabled.value = controls.engineEnabled
@@ -88,6 +100,9 @@ export const useEngineControlStore = defineStore('engineControl', () => {
API_KEY.value = controls.API_KEY API_KEY.value = controls.API_KEY
voskModelPath.value = controls.voskModelPath voskModelPath.value = controls.voskModelPath
sosvModelPath.value = controls.sosvModelPath sosvModelPath.value = controls.sosvModelPath
glmUrl.value = controls.glmUrl || 'https://open.bigmodel.cn/api/paas/v4/audio/transcriptions'
glmModel.value = controls.glmModel || 'glm-asr-2512'
glmApiKey.value = controls.glmApiKey
recordingPath.value = controls.recordingPath recordingPath.value = controls.recordingPath
customized.value = controls.customized customized.value = controls.customized
customizedApp.value = controls.customizedApp customizedApp.value = controls.customizedApp
@@ -150,6 +165,8 @@ export const useEngineControlStore = defineStore('engineControl', () => {
targetLang, // 目标语言 targetLang, // 目标语言
transModel, // 翻译模型 transModel, // 翻译模型
ollamaName, // Ollama 模型 ollamaName, // Ollama 模型
ollamaUrl,
ollamaApiKey,
engine, // 字幕引擎 engine, // 字幕引擎
audio, // 选择音频 audio, // 选择音频
translation, // 是否启用翻译 translation, // 是否启用翻译
@@ -157,6 +174,9 @@ export const useEngineControlStore = defineStore('engineControl', () => {
API_KEY, // API KEY API_KEY, // API KEY
voskModelPath, // vosk 模型路径 voskModelPath, // vosk 模型路径
sosvModelPath, // sosv 模型路径 sosvModelPath, // sosv 模型路径
glmUrl, // GLM API URL
glmModel, // GLM 模型名称
glmApiKey, // GLM API Key
recordingPath, // 录音保存路径 recordingPath, // 录音保存路径
customized, // 是否使用自定义字幕引擎 customized, // 是否使用自定义字幕引擎
customizedApp, // 自定义字幕引擎的应用程序 customizedApp, // 自定义字幕引擎的应用程序

View File

@@ -8,6 +8,8 @@ export interface Controls {
targetLang: string, targetLang: string,
transModel: string, transModel: string,
ollamaName: string, ollamaName: string,
ollamaUrl: string,
ollamaApiKey: string,
engine: string, engine: string,
audio: 0 | 1, audio: 0 | 1,
translation: boolean, translation: boolean,
@@ -15,6 +17,9 @@ export interface Controls {
API_KEY: string, API_KEY: string,
voskModelPath: string, voskModelPath: string,
sosvModelPath: string, sosvModelPath: string,
glmUrl: string,
glmModel: string,
glmApiKey: string,
recordingPath: string, recordingPath: string,
customized: boolean, customized: boolean,
customizedApp: string, customizedApp: string,