├── .github └── workflows │ └── main.yml ├── .gitignore ├── LICENSE ├── README.md ├── doc └── img │ └── image.png ├── main.py ├── main.spec ├── requirements.txt ├── src ├── __init__.py ├── core │ ├── __init__.py │ ├── defaultConfig.py │ ├── dglab.py │ ├── logger.py │ ├── process.py │ └── startup.py ├── handler │ ├── __init__.py │ ├── base_handler.py │ └── basic.py └── module │ └── __init__.py ├── templates ├── css │ ├── app.766ca9ce.css │ └── chunk-vendors.efdeab3a.css ├── favicon.ico ├── index.html └── js │ ├── app.16fed61a.js │ ├── app.16fed61a.js.map │ ├── chunk-vendors.aeccd9a7.js │ └── chunk-vendors.aeccd9a7.js.map └── webUI ├── .gitignore ├── README.md ├── babel.config.js ├── client.json ├── jsconfig.json ├── package-lock.json ├── package.json ├── patterns.json ├── public ├── favicon.ico └── index.html ├── src ├── App.vue ├── assets │ └── logo.png ├── components │ ├── config-page.vue │ └── side-info.vue └── main.js └── vue.config.js /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Package Python Application on Windows 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' # 监听以v开头的标签,例如v1.0.0 7 | 8 | jobs: 9 | build-windows: 10 | runs-on: windows-latest # 指定Windows最新版本作为运行环境 11 | 12 | steps: 13 | - name: Checkout repository 14 | uses: actions/checkout@v4 15 | 16 | - name: Set up Python 17 | uses: actions/setup-python@v4 18 | with: 19 | python-version: '3.12' 20 | 21 | - name: Install dependencies 22 | run: | 23 | python -m pip install --upgrade pip 24 | pip install pyinstaller 25 | pip install -r requirements.txt 26 | 27 | - name: Package application with PyInstaller 28 | run: | 29 | pyinstaller .\main.spec -y 30 | 31 | - name: Upload artifact 32 | uses: actions/upload-artifact@v4 33 | with: 34 | name: "VoiceLinkDGLAB-windows-${{ github.ref_name }}" 35 | path: dist\ # 注意Windows路径使用反斜杠\ 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | qrcode.png 2 | *.log 3 | *.log.* 4 | *.spec 5 | main.bat 6 | # Byte-compiled / optimized / DLL files 7 | __pycache__/ 8 | *.py[cod] 9 | *$py.class 10 | 11 | # C extensions 12 | *.so 13 | 14 | # Distribution / packaging 15 | .Python 16 | build/ 17 | develop-eggs/ 18 | dist/ 19 | downloads/ 20 | eggs/ 21 | .eggs/ 22 | lib/ 23 | lib64/ 24 | parts/ 25 | sdist/ 26 | var/ 27 | wheels/ 28 | share/python-wheels/ 29 | *.egg-info/ 30 | .installed.cfg 31 | *.egg 32 | *.json 33 | !webUI/*.json 34 | MANIFEST 35 | !errorDict.json 36 | # PyInstaller 37 | # Usually these files are written by a python script from a template 38 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 39 | # *.manifest 40 | # *.spec 41 | 42 | # Installer logs 43 | pip-log.txt 44 | pip-delete-this-directory.txt 45 | 46 | # Unit test / coverage reports 47 | htmlcov/ 48 | .tox/ 49 | .nox/ 50 | .coverage 51 | .coverage.* 52 | .cache 53 | nosetests.xml 54 | coverage.xml 55 | *.cover 56 | *.py,cover 57 | .hypothesis/ 58 | .pytest_cache/ 59 | cover/ 60 | 61 | # Translations 62 | *.mo 63 | *.pot 64 | 65 | # Django stuff: 66 | *.log 67 | local_settings.py 68 | db.sqlite3 69 | db.sqlite3-journal 70 | 71 | # Flask stuff: 72 | instance/ 73 | .webassets-cache 74 | 75 | # Scrapy stuff: 76 | .scrapy 77 | 78 | # Sphinx documentation 79 | docs/_build/ 80 | 81 | # PyBuilder 82 | .pybuilder/ 83 | target/ 84 | 85 | # Jupyter Notebook 86 | .ipynb_checkpoints 87 | 88 | # IPython 89 | profile_default/ 90 | ipython_config.py 91 | 92 | # pyenv 93 | # For a library or package, you might want to ignore these files since the code is 94 | # intended to run in multiple environments; otherwise, check them in: 95 | # .python-version 96 | 97 | # pipenv 98 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 99 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 100 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 101 | # install all needed dependencies. 102 | #Pipfile.lock 103 | 104 | # poetry 105 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 106 | # This is especially recommended for binary packages to ensure reproducibility, and is more 107 | # commonly ignored for libraries. 108 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 109 | #poetry.lock 110 | 111 | # pdm 112 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 113 | #pdm.lock 114 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 115 | # in version control. 116 | # https://pdm.fming.dev/latest/usage/project/#working-with-version-control 117 | .pdm.toml 118 | .pdm-python 119 | .pdm-build/ 120 | 121 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 122 | __pypackages__/ 123 | 124 | # Celery stuff 125 | celerybeat-schedule 126 | celerybeat.pid 127 | 128 | # SageMath parsed files 129 | *.sage.py 130 | 131 | # Environments 132 | .env 133 | .venv 134 | env/ 135 | venv/ 136 | ENV/ 137 | env.bak/ 138 | venv.bak/ 139 | 140 | # Spyder project settings 141 | .spyderproject 142 | .spyproject 143 | 144 | # Rope project settings 145 | .ropeproject 146 | 147 | # mkdocs documentation 148 | /site 149 | 150 | # mypy 151 | .mypy_cache/ 152 | .dmypy.json 153 | dmypy.json 154 | 155 | # Pyre type checker 156 | .pyre/ 157 | 158 | # pytype static type analyzer 159 | .pytype/ 160 | 161 | # Cython debug symbols 162 | cython_debug/ 163 | 164 | # PyCharm 165 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 166 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 167 | # and can be added to the global gitignore or merged into this file. For a more nuclear 168 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 169 | #.idea/ 170 | 171 | !main.spec -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 VoiceLinkVR 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # VoiceLinkDGLAB 3 | 这是一个使用VoiceLinkVR server作为后端语音识别,并触发郊狼 (DG-LAB) 3.0 设备的控制程序。 4 | 5 | - 兼容设备:通过 WebSocket 控制 DG-LAB APP,目前只适配 DG-LAB 3.0 主机。 6 | 7 | 8 | ## 注意事项 9 | 1. 本程序及开发者不对使用该本程序产生的任何后果负责,使用程序则视为同意本条款。 10 | 2. 请遵循 DG-LAB APP 中的说明,以安全的方式使用设备,使用此程序前请根据个人情况设置合理的强度上限。 11 | 12 | 13 | 14 | ## 快速开始 15 | 16 | ### 打包文件启动 17 | 18 | 如没有python环境可以访问通过[下载链接](https://github.com/VoiceLinkVR/VoiceLinkDGLAB/releases)或者QQ群1011986554群文件下载打包后的程序 19 | 20 | 解压压缩包后双击VoiceLinkDGLAB.exe 21 | 22 | 打开后会默认启动edge或默认浏览器 23 | 24 | 界面如下 25 | 26 | ![alt text](./doc/img/image.png) 27 | 28 | ### python 启动 29 | ``` 30 | pip install -r requirements.txt 31 | 32 | python main.py 33 | ``` 34 | 35 | 36 | ## 常见问题 37 | 38 | ### 1. 麦克风无法收音 39 | 请检查系统默认麦克风 40 | 41 | ### 2. 如何将游戏内声音送入程序 42 | 可以使用voicemeeter 等虚拟声卡,将自己的话筒与系统声音同时输入虚拟麦克风 43 | -------------------------------------------------------------------------------- /doc/img/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VoiceLinkVR/VoiceLinkDGLAB/398ecbd8c28812650e77c08590957cd90ed4a932/doc/img/image.png -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request, render_template, url_for,jsonify,send_from_directory 2 | import waitress 3 | from src.core.startup import StartUp 4 | from src.core.dglab import ServerTread 5 | from multiprocessing import Process,Manager,freeze_support,Queue 6 | from src.core.process import logger_process,threaded_listen 7 | import time 8 | import json,os,io,base64 9 | import webbrowser 10 | import pyaudio 11 | 12 | queue=Queue(-1) 13 | 14 | processList=[] 15 | app = Flask(__name__,static_folder='templates') 16 | app.config['SECRET_KEY'] = 'your_secret_key' 17 | 18 | def rebootJob(): 19 | global queue,params,listener_thread,startUp,queue_a,baseurl,headers,queue_b,server 20 | queue.put({"text":"/reboot","level":"debug"}) 21 | queue.put({"text":"sound process start to complete wait for 20s|| 服务开始重启 请等待20秒 ","level":"info"}) 22 | params["running"] = False 23 | time.sleep(20) 24 | params["running"] = True 25 | params["sourceLanguage"]=startUp.config.get("sourceLanguage") 26 | startUp.setThreads(queue_a,queue_b) 27 | listener_thread = Process(target=threaded_listen,args=(baseurl,startUp.config,startUp.patterns,headers,params,queue,queue_a,queue_b)) 28 | listener_thread.start() 29 | queue.put({"text":"sound process restart complete|| 服务完成重启","level":"info"}) 30 | 31 | @app.route('/api/saveConfig', methods=['post']) 32 | def saveConfig(): 33 | global queue,params,listener_thread,startUp,sendClient,baseurl,headers 34 | data=request.get_json() 35 | queue.put({"text":"/saveandreboot","level":"debug"}) 36 | try: 37 | with open('client.json', 'r',encoding='utf8') as file, open('client-back.json', 'w', encoding="utf8") as f: 38 | f.write(file.read()) 39 | startUp.config=data["config"] 40 | with open('client.json', 'w', encoding="utf8") as f: 41 | f.write(json.dumps(startUp.config,ensure_ascii=False, indent=4)) 42 | except Exception as e: 43 | queue.put({"text":f"config saved 配置保存异常:{e}","level":"warning"}) 44 | return jsonify({"text":f"config saved 配置保存异常:{e}","level":"warning"}),401 45 | queue.put({"text":"config saved 配置保存完毕","level":"info"}) 46 | return startUp.config 47 | 48 | @app.route('/') 49 | def ui(): 50 | return render_template("index.html") 51 | 52 | @app.route('/') 53 | def send_static(path): 54 | return send_from_directory(app.static_folder, path) 55 | 56 | @app.route('/api/getQRcode', methods=['get']) 57 | def get_image(): 58 | 59 | global img 60 | 61 | # 保存图片为字节流 62 | byte_array = io.BytesIO() 63 | img.save(byte_array, format='PNG') 64 | byte_array = byte_array.getvalue() 65 | 66 | # 将字节流转换为Base64编码的字符串(可选,也可以直接发送字节流) 67 | base64_image = base64.b64encode(byte_array).decode('utf-8') 68 | 69 | # 发送Base64编码的图片字符串到前端(或者你可以使用send_file发送字节流) 70 | return jsonify({"image": base64_image}) 71 | 72 | @app.route('/api/getQRCodeURL', methods=['get']) 73 | def getQRCodeURL(): 74 | global wsurl 75 | queue.put({"text":"/getQRCodeURL","level":"debug"}) 76 | return jsonify({"wsurl":wsurl}),200 77 | 78 | # 处理表单提交 79 | @app.route('/api/getConfig', methods=['get']) 80 | def getConfig(): 81 | global startUp,queue 82 | queue.put({"text":"/getConfig","level":"debug"}) 83 | return jsonify(startUp.config),200 84 | 85 | 86 | @app.route('/api/reboot', methods=['get']) 87 | def reboot(): 88 | rebootJob() 89 | return jsonify({'message':'sound process restart complete|| 程序完成重启'}),200 90 | 91 | @app.route('/api/getMics', methods=['get']) 92 | def getMics(): 93 | global queue 94 | queue.put({"text":"/getMics","level":"debug"}) 95 | # 创建 PyAudio 实例 96 | p = pyaudio.PyAudio() 97 | host_api_count=p.get_host_api_count() 98 | 99 | # 获取设备数量 100 | device_count = p.get_device_count() 101 | 102 | microphones = [] 103 | hostapis=[] 104 | for j in range(host_api_count): 105 | hostapi=p.get_host_api_info_by_index(j) 106 | hostapis.append(hostapi["name"]) 107 | for i in range(device_count): 108 | # 获取每个设备的详细信息 109 | dev_info = p.get_device_info_by_index(i) 110 | # 检查设备是否是输入设备(麦克风) 111 | if dev_info['maxInputChannels'] > 0: 112 | microphones.append( f"{hostapis[dev_info['hostApi']]} - {dev_info['name']}") 113 | 114 | # 关闭 PyAudio 实例 115 | p.terminate() 116 | 117 | return jsonify(microphones),200 118 | 119 | # 处理表单提交 120 | @app.route('/api/saveandreboot', methods=['post']) 121 | def update_config(): 122 | data=request.get_json(silent=True) 123 | if data is None: return jsonify({'text':'no data'}),400 124 | config=saveConfig() 125 | rebootJob() 126 | return jsonify(config),200 127 | 128 | # TODO 增加获取波形接口 129 | @app.route('/api/getPatternName', methods=['get']) 130 | def getPatternName(): 131 | global startUp,queue 132 | queue.put({"text":"/getPatternName","level":"debug"}) 133 | return jsonify(list(startUp.patterns.keys())),200 134 | # 示例函数 135 | def open_web(host,port): 136 | 137 | # 定义要打开的URL 138 | url = f"http://{host}:{port}" 139 | 140 | # 获取Edge浏览器的可执行文件路径 141 | # 不同的操作系统有不同的路径 142 | edge_path = None 143 | if os.name == 'nt': # Windows系统 144 | edge_path = os.path.join(os.environ.get('ProgramFiles(x86)'), 'Microsoft', 'Edge', 'Application', 'msedge.exe') 145 | elif os.uname().sysname == 'Darwin': # macOS系统(注意:macOS上默认可能没有安装Edge) 146 | # 通常需要用户手动指定Edge的路径,或者通过其他方式获取 147 | # 例如:edge_path = '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge' 148 | pass # 这里不做处理,因为路径需要用户指定 149 | elif os.uname().sysname == 'Linux': # Linux系统 150 | # Linux上Edge的路径也可能需要用户手动指定 151 | # 例如:edge_path = '/opt/microsoft/edge/microsoft-edge' 152 | pass # 这里不做处理,因为路径需要用户指定 153 | try: 154 | # 如果找到了Edge的路径,则使用它打开网页 155 | if edge_path: 156 | # 创建一个新的Edge控制器 157 | edge = webbrowser.get(using=edge_path) 158 | # 使用Edge控制器打开网页 159 | edge.open(url) 160 | else: 161 | # 如果没有找到Edge的路径,则使用默认浏览器打开网页 162 | webbrowser.open(url) 163 | except Exception : 164 | webbrowser.open(url) 165 | 166 | 167 | 168 | if __name__ == '__main__': 169 | freeze_support() 170 | try: 171 | import logging 172 | # 获取 asyncio 的日志记录器 173 | asyncio_logger = logging.getLogger('asyncio') 174 | 175 | # 设置日志级别为 CRITICAL,这样只有严重错误才会被记录 176 | asyncio_logger.setLevel(logging.CRITICAL) 177 | 178 | logger_thread = Process(target=logger_process,daemon=True,args=(queue,)) 179 | logger_thread.start() 180 | manager = Manager() 181 | params=manager.dict() 182 | queue_a=manager.Queue(-1) 183 | queue_b=manager.Queue(-1) 184 | 185 | 186 | 187 | params["running"] = True 188 | params['dgUnbinded']=True 189 | startUp=StartUp(queue,params) 190 | headers=startUp.run() 191 | server=startUp.setDglabServer() 192 | startUp.setThreads(queue_a,queue_b) 193 | baseurl=startUp.config.get("baseurl") 194 | client=server.client 195 | wsurl =client.get_qrcode(server.get_ws_url()) 196 | img=server.create_qrcode(wsurl) 197 | img.save('qrcode.png') 198 | queue.put({'text':r''' 199 | ------------------------------------------------------------------------ 200 | __ __ __ __ __ __ 201 | / | / | / | / | / | / | 202 | $$ | $$ | ______ $$/ _______ ______ $$ | $$/ _______ $$ | __ 203 | $$ | $$ |/ \ / | / | / \ $$ | / |/ \ $$ | / | 204 | $$ \ /$$//$$$$$$ |$$ |/$$$$$$$/ /$$$$$$ |$$ | $$ |$$$$$$$ |$$ |_/$$/ 205 | $$ /$$/ $$ | $$ |$$ |$$ | $$ $$ |$$ | $$ |$$ | $$ |$$ $$< 206 | $$ $$/ $$ \__$$ |$$ |$$ \_____ $$$$$$$$/ $$ |_____ $$ |$$ | $$ |$$$$$$ \ 207 | $$$/ $$ $$/ $$ |$$ |$$ |$$ |$$ |$$ | $$ |$$ | $$ | 208 | $/ $$$$$$/ $$/ $$$$$$$/ $$$$$$$/ $$$$$$$$/ $$/ $$/ $$/ $$/ $$/ 209 | 210 | _______ ______ __ ______ _______ 211 | / \ / \ / | / \ / \ 212 | $$$$$$$ |/$$$$$$ |$$ | /$$$$$$ |$$$$$$$ | 213 | $$ | $$ |$$ | _$$/ $$ | $$ |__$$ |$$ |__$$ | 214 | $$ | $$ |$$ |/ |$$ | $$ $$ |$$ $$< 215 | $$ | $$ |$$ |$$$$ |$$ | $$$$$$$$ |$$$$$$$ | 216 | $$ |__$$ |$$ \__$$ |$$ |_____ $$ | $$ |$$ |__$$ | 217 | $$ $$/ $$ $$/ $$ |$$ | $$ |$$ $$/ 218 | $$$$$$$/ $$$$$$/ $$$$$$$$/ $$/ $$/ $$$$$$$/ 219 | 220 | 221 | '''+f'webUI: http://{startUp.config['api-ip']}:{startUp.config['api-port']}'+r''' 222 | 223 | 》》》》 《《《《 224 | 》》》》请保持本窗口持续开启《《《《 225 | 》》》》 《《《《 226 | 227 | 欢迎使用由VoiceLinkVR开发的VRCLS 228 | 本程序的开发这为boyqiu-001(boyqiu玻璃球) 229 | 欢迎大家加入qq群1011986554获取最新资讯 230 | 目前您使用的时公测账户,限制每日2000次请求 231 | 如需获取更多资源请加群 232 | ------------------------------------------------------------------------ 233 | ''','level':'info'} 234 | ) 235 | queue.put({"text":"请用 DG-Lab App 扫描二维码以连接",'level':'info'}) 236 | 237 | params["sourceLanguage"]=startUp.sourceLanguage 238 | 239 | # start listening in the background (note that we don't have to do this inside a `with` statement) 240 | # this is called from the background thread 241 | 242 | 243 | listener_thread = Process(target=threaded_listen,args=(baseurl,startUp.config,startUp.patterns,headers,params,queue,queue_a,queue_b)) 244 | listener_thread.start() 245 | 246 | # time.sleep(10) 247 | 248 | # while True:time.sleep(1) 249 | # app.run(debug=True,) 250 | queue.put({'text':"api ok||api就绪",'level':'info'}) 251 | open_web(startUp.config['api-ip'],startUp.config['api-port']) 252 | waitress.serve(app=app, host=startUp.config['api-ip'], port=startUp.config['api-port']) 253 | except Exception as e: 254 | print(f"Main thread encountered an error: {e}") 255 | finally: 256 | # 设置退出事件来通知所有子线程 257 | listener_thread.kill() 258 | -------------------------------------------------------------------------------- /main.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: python ; coding: utf-8 -*- 2 | from PyInstaller.utils.hooks import collect_all 3 | 4 | datas = [] 5 | binaries = [] 6 | hiddenimports = [] 7 | 8 | tmp_ret = collect_all('pydglab_ws') 9 | datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2] 10 | tmp_ret = collect_all('qrcode') 11 | datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2] 12 | datas.append(('templates','templates')) 13 | 14 | a = Analysis( 15 | ['main.py'], 16 | pathex=[], 17 | binaries=[], 18 | datas=datas, 19 | hiddenimports=[], 20 | hookspath=[], 21 | hooksconfig={}, 22 | runtime_hooks=[], 23 | excludes=[], 24 | noarchive=False, 25 | optimize=0, 26 | ) 27 | pyz = PYZ(a.pure) 28 | 29 | exe = EXE( 30 | pyz, 31 | a.scripts, 32 | [], 33 | exclude_binaries=True, 34 | name='VoiceLinkDGLAB', 35 | debug=False, 36 | bootloader_ignore_signals=False, 37 | strip=False, 38 | upx=True, 39 | console=True, 40 | disable_windowed_traceback=False, 41 | argv_emulation=False, 42 | target_arch=None, 43 | codesign_identity=None, 44 | entitlements_file=None, 45 | ) 46 | coll = COLLECT( 47 | exe, 48 | a.binaries, 49 | a.datas, 50 | strip=False, 51 | upx=True, 52 | upx_exclude=[], 53 | name='VoiceLinkDGLAB', 54 | ) 55 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pyaudio 2 | SpeechRecognition 3 | Flask 4 | waitress 5 | pydglab-ws 6 | qrcode[pil] 7 | requests -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VoiceLinkVR/VoiceLinkDGLAB/398ecbd8c28812650e77c08590957cd90ed4a932/src/__init__.py -------------------------------------------------------------------------------- /src/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VoiceLinkVR/VoiceLinkDGLAB/398ecbd8c28812650e77c08590957cd90ed4a932/src/core/__init__.py -------------------------------------------------------------------------------- /src/core/defaultConfig.py: -------------------------------------------------------------------------------- 1 | defaultConfig={ 2 | "userInfo": { 3 | "username": "testuser", 4 | "password": "abc123!" 5 | }, 6 | "baseurl": "https://whisper.boyqiu001.cn:7070", 7 | "api-ip":"127.0.0.1", 8 | "api-port":8980, 9 | "micIndex":-1, 10 | "sourceLanguage": "zh", 11 | "dglabServerIp":"", 12 | "dglabServerPort":56742, 13 | "activateText":"", 14 | "exitText":"退出程序", 15 | "scripts": [ 16 | { 17 | "action":"1", 18 | "text": ["测试","可以"], 19 | "patterns":[ 20 | { 21 | "name":"呼吸", 22 | "channel": "B", 23 | "intensity": 10, 24 | "time": 2 25 | }, 26 | { 27 | "name":"呼吸", 28 | "channel": "A", 29 | "intensity": 10, 30 | "time": 3 31 | } 32 | ] 33 | } 34 | ] 35 | } 36 | 37 | defaultpatterns={ 38 | '呼吸': [ 39 | ((10, 10, 10, 10), (0, 0, 0, 0)), ((10, 10, 10, 10), (0, 5, 10, 20)), 40 | ((10, 10, 10, 10), (20, 25, 30, 40)), ((10, 10, 10, 10), (40, 45, 50, 60)), 41 | ((10, 10, 10, 10), (60, 65, 70, 80)), ((10, 10, 10, 10), (100, 100, 100, 100)), 42 | ((10, 10, 10, 10), (100, 100, 100, 100)), ((10, 10, 10, 10), (100, 100, 100, 100)), 43 | ((0, 0, 0, 0), (0, 0, 0, 0)), ((0, 0, 0, 0), (0, 0, 0, 0)), ((0, 0, 0, 0), (0, 0, 0, 0)) 44 | ], 45 | '潮汐': [ 46 | ((10, 10, 10, 10), (0, 0, 0, 0)), ((10, 10, 10, 10), (0, 4, 8, 17)), 47 | ((10, 10, 10, 10), (17, 21, 25, 33)), ((10, 10, 10, 10), (50, 50, 50, 50)), 48 | ((10, 10, 10, 10), (50, 54, 58, 67)), ((10, 10, 10, 10), (67, 71, 75, 83)), 49 | ((10, 10, 10, 10), (100, 100, 100, 100)), ((10, 10, 10, 10), (100, 98, 96, 92)), 50 | ((10, 10, 10, 10), (92, 90, 88, 84)), ((10, 10, 10, 10), (84, 82, 80, 76)), 51 | ((10, 10, 10, 10), (68, 68, 68, 68)) 52 | ], 53 | '连击': [ 54 | ((10, 10, 10, 10), (100, 100, 100, 100)), ((10, 10, 10, 10), (0, 0, 0, 0)), 55 | ((10, 10, 10, 10), (100, 100, 100, 100)), ((10, 10, 10, 10), (100, 92, 84, 67)), 56 | ((10, 10, 10, 10), (67, 58, 50, 33)), ((10, 10, 10, 10), (0, 0, 0, 0)), 57 | ((10, 10, 10, 10), (0, 0, 0, 1)), ((10, 10, 10, 10), (2, 2, 2, 2)) 58 | ], 59 | '快速按捏': [ 60 | ((10, 10, 10, 10), (0, 0, 0, 0)), ((10, 10, 10, 10), (100, 100, 100, 100)), 61 | ((0, 0, 0, 0), (0, 0, 0, 0)) 62 | ], 63 | '按捏渐强': [ 64 | ((10, 10, 10, 10), (0, 0, 0, 0)), ((10, 10, 10, 10), (29, 29, 29, 29)), 65 | ((10, 10, 10, 10), (0, 0, 0, 0)), ((10, 10, 10, 10), (52, 52, 52, 52)), 66 | ((10, 10, 10, 10), (2, 2, 2, 2)), ((10, 10, 10, 10), (73, 73, 73, 73)), 67 | ((10, 10, 10, 10), (0, 0, 0, 0)), ((10, 10, 10, 10), (87, 87, 87, 87)), 68 | ((10, 10, 10, 10), (0, 0, 0, 0)), ((10, 10, 10, 10), (100, 100, 100, 100)), 69 | ((10, 10, 10, 10), (0, 0, 0, 0)) 70 | ], 71 | '心跳节奏': [ 72 | ((110, 110, 110, 110), (100, 100, 100, 100)), ((110, 110, 110, 110), (100, 100, 100, 100)), 73 | ((10, 10, 10, 10), (0, 0, 0, 0)), ((10, 10, 10, 10), (0, 0, 0, 0)), 74 | ((10, 10, 10, 10), (0, 0, 0, 0)), ((10, 10, 10, 10), (0, 0, 0, 0)), 75 | ((10, 10, 10, 10), (0, 0, 0, 0)), ((10, 10, 10, 10), (75, 75, 75, 75)), 76 | ((10, 10, 10, 10), (75, 77, 79, 83)), ((10, 10, 10, 10), (83, 85, 88, 92)), 77 | ((10, 10, 10, 10), (100, 100, 100, 100)), ((10, 10, 10, 10), (0, 0, 0, 0)), 78 | ((10, 10, 10, 10), (0, 0, 0, 0)), ((10, 10, 10, 10), (0, 0, 0, 0)), 79 | ((10, 10, 10, 10), (0, 0, 0, 0)), ((10, 10, 10, 10), (0, 0, 0, 0)) 80 | ], 81 | '压缩': [ 82 | ((25, 25, 24, 24), (100, 100, 100, 100)), ((24, 23, 23, 23), (100, 100, 100, 100)), 83 | ((22, 22, 22, 21), (100, 100, 100, 100)), ((21, 21, 20, 20), (100, 100, 100, 100)), 84 | ((20, 19, 19, 19), (100, 100, 100, 100)), ((18, 18, 18, 17), (100, 100, 100, 100)), 85 | ((17, 16, 16, 16), (100, 100, 100, 100)), ((15, 15, 15, 14), (100, 100, 100, 100)), 86 | ((14, 14, 13, 13), (100, 100, 100, 100)), ((13, 12, 12, 12), (100, 100, 100, 100)), 87 | ((11, 11, 11, 10), (100, 100, 100, 100)), ((10, 10, 10, 10), (100, 100, 100, 100)), 88 | ((10, 10, 10, 10), (100, 100, 100, 100)), ((10, 10, 10, 10), (100, 100, 100, 100)), 89 | ((10, 10, 10, 10), (100, 100, 100, 100)), ((10, 10, 10, 10), (100, 100, 100, 100)), 90 | ((10, 10, 10, 10), (100, 100, 100, 100)), ((10, 10, 10, 10), (100, 100, 100, 100)), 91 | ((10, 10, 10, 10), (100, 100, 100, 100)), ((10, 10, 10, 10), (100, 100, 100, 100)), 92 | ((10, 10, 10, 10), (100, 100, 100, 100)) 93 | ], 94 | '节奏步伐': [ 95 | ((10, 10, 10, 10), (0, 0, 0, 0)), ((10, 10, 10, 10), (0, 5, 10, 20)), 96 | ((10, 10, 10, 10), (20, 25, 30, 40)), ((10, 10, 10, 10), (40, 45, 50, 60)), 97 | ((10, 10, 10, 10), (60, 65, 70, 80)), ((10, 10, 10, 10), (100, 100, 100, 100)), 98 | ((10, 10, 10, 10), (0, 0, 0, 0)), ((10, 10, 10, 10), (0, 6, 12, 25)), 99 | ((10, 10, 10, 10), (25, 31, 38, 50)), ((10, 10, 10, 10), (50, 56, 62, 75)), 100 | ((10, 10, 10, 10), (100, 100, 100, 100)), ((10, 10, 10, 10), (0, 0, 0, 0)), 101 | ((10, 10, 10, 10), (0, 8, 16, 33)), ((10, 10, 10, 10), (33, 42, 50, 67)), 102 | ((10, 10, 10, 10), (100, 100, 100, 100)), ((10, 10, 10, 10), (0, 0, 0, 0)), 103 | ((10, 10, 10, 10), (0, 12, 25, 50)), ((10, 10, 10, 10), (100, 100, 100, 100)), 104 | ((10, 10, 10, 10), (0, 0, 0, 0)), ((10, 10, 10, 10), (100, 100, 100, 100)), 105 | ((10, 10, 10, 10), (0, 0, 0, 0)), ((10, 10, 10, 10), (100, 100, 100, 100)), 106 | ((10, 10, 10, 10), (0, 0, 0, 0)), ((10, 10, 10, 10), (100, 100, 100, 100)), 107 | ((10, 10, 10, 10), (0, 0, 0, 0)), ((10, 10, 10, 10), (100, 100, 100, 100)) 108 | ], 109 | '颗粒摩擦': [ 110 | ((10, 10, 10, 10), (100, 100, 100, 100)), ((10, 10, 10, 10), (100, 100, 100, 100)), 111 | ((10, 10, 10, 10), (100, 100, 100, 100)), ((10, 10, 10, 10), (0, 0, 0, 0)) 112 | ], 113 | '渐变弹跳': [ 114 | ((10, 10, 10, 10), (1, 1, 1, 1)), ((10, 10, 10, 10), (1, 9, 18, 34)), 115 | ((10, 10, 10, 10), (34, 42, 50, 67)), ((10, 10, 10, 10), (100, 100, 100, 100)), 116 | ((0, 0, 0, 0), (0, 0, 0, 0)), ((0, 0, 0, 0), (0, 0, 0, 0)) 117 | ], 118 | '波浪涟漪': [ 119 | ((10, 10, 10, 10), (0, 0, 0, 0)), ((10, 10, 10, 10), (0, 12, 25, 50)), 120 | ((10, 10, 10, 10), (100, 100, 100, 100)), ((10, 10, 10, 10), (73, 73, 73, 73)) 121 | ], 122 | '雨水冲刷': [ 123 | ((10, 10, 10, 10), (34, 34, 34, 34)), ((10, 10, 10, 10), (34, 42, 50, 67)), 124 | ((10, 10, 10, 10), (100, 100, 100, 100)), ((10, 10, 10, 10), (100, 100, 100, 100)), 125 | ((10, 10, 10, 10), (100, 100, 100, 100)), ((0, 0, 0, 0), (0, 0, 0, 0)), 126 | ((0, 0, 0, 0), (0, 0, 0, 0)) 127 | ], 128 | '变速敲击': [ 129 | ((10, 10, 10, 10), (100, 100, 100, 100)), ((10, 10, 10, 10), (100, 100, 100, 100)), 130 | ((10, 10, 10, 10), (100, 100, 100, 100)), ((10, 10, 10, 10), (0, 0, 0, 0)), 131 | ((10, 10, 10, 10), (0, 0, 0, 0)), ((10, 10, 10, 10), (0, 0, 0, 0)), 132 | ((10, 10, 10, 10), (0, 0, 0, 0)), ((110, 110, 110, 110), (100, 100, 100, 100)), 133 | ((110, 110, 110, 110), (100, 100, 100, 100)), ((110, 110, 110, 110), (100, 100, 100, 100)), 134 | ((110, 110, 110, 110), (100, 100, 100, 100)), ((0, 0, 0, 0), (0, 0, 0, 0)) 135 | ], 136 | '信号灯': [ 137 | ((197, 197, 197, 197), (100, 100, 100, 100)), ((197, 197, 197, 197), (100, 100, 100, 100)), 138 | ((197, 197, 197, 197), (100, 100, 100, 100)), ((197, 197, 197, 197), (100, 100, 100, 100)), 139 | ((10, 10, 10, 10), (0, 0, 0, 0)), ((10, 10, 10, 10), (0, 8, 16, 33)), 140 | ((10, 10, 10, 10), (33, 42, 50, 67)), ((10, 10, 10, 10), (100, 100, 100, 100)) 141 | ], 142 | '挑逗1': [ 143 | ((10, 10, 10, 10), (0, 0, 0, 0)), ((10, 10, 10, 10), (0, 6, 12, 25)), 144 | ((10, 10, 10, 10), (25, 31, 38, 50)), ((10, 10, 10, 10), (50, 56, 62, 75)), 145 | ((10, 10, 10, 10), (100, 100, 100, 100)), ((10, 10, 10, 10), (100, 100, 100, 100)), 146 | ((10, 10, 10, 10), (100, 100, 100, 100)), ((10, 10, 10, 10), (0, 0, 0, 0)), 147 | ((10, 10, 10, 10), (0, 0, 0, 0)), ((10, 10, 10, 10), (0, 0, 0, 0)), ((10, 10, 10, 10), (0, 0, 0, 0)), 148 | ((10, 10, 10, 10), (100, 100, 100, 100)) 149 | ], 150 | '挑逗2': [ 151 | ((10, 10, 10, 10), (1, 1, 1, 1)), ((10, 10, 10, 10), (1, 4, 6, 12)), 152 | ((10, 10, 10, 10), (12, 15, 18, 23)), ((10, 10, 10, 10), (23, 26, 28, 34)), 153 | ((10, 10, 10, 10), (34, 37, 40, 45)), ((10, 10, 10, 10), (45, 48, 50, 56)), 154 | ((10, 10, 10, 10), (56, 59, 62, 67)), ((10, 10, 10, 10), (67, 70, 72, 78)), 155 | ((10, 10, 10, 10), (78, 81, 84, 89)), ((10, 10, 10, 10), (100, 100, 100, 100)), 156 | ((10, 10, 10, 10), (100, 100, 100, 100)), ((10, 10, 10, 10), (0, 0, 0, 0)), 157 | ((0, 0, 0, 0), (0, 0, 0, 0)) 158 | ] 159 | } -------------------------------------------------------------------------------- /src/core/dglab.py: -------------------------------------------------------------------------------- 1 | 2 | import asyncio 3 | import threading 4 | from multiprocessing import Queue 5 | from pydglab_ws import FeedbackButton, RetCode,StrengthData,DGLabLocalClient,DGLabWSServer,Channel,StrengthOperationType 6 | import qrcode 7 | import socket 8 | import time 9 | class DGLabServerTread: 10 | def __init__(self,config,logger,params) -> None: 11 | self.config=config 12 | self.strengthData:StrengthData=None 13 | self.client:DGLabLocalClient=None 14 | self.loop=None 15 | self.params=params 16 | self.logger=logger 17 | 18 | def run(self): 19 | thread = threading.Thread(target=self.run_asyncio_loop,daemon=True) 20 | thread.start() 21 | return thread 22 | 23 | def run_asyncio_loop(self): 24 | self.loop = asyncio.new_event_loop() 25 | asyncio.set_event_loop(self.loop) 26 | try: 27 | self.loop.run_until_complete(self.serverStart()) 28 | except Exception as e: 29 | self.wirte_log("DGLabServerTread Error:"+str(e),"error") 30 | finally: 31 | self.wirte_log("DGLabServerTread Exit","info") 32 | 33 | def create_qrcode(self,data): 34 | qr = qrcode.QRCode( 35 | version=1, 36 | error_correction=qrcode.constants.ERROR_CORRECT_L, 37 | box_size=10, 38 | border=4, 39 | ) 40 | qr.add_data(data) 41 | qr.make(fit=True) 42 | img = qr.make_image(fill='black', back_color='white') 43 | 44 | return img 45 | 46 | def get_local_ip(self): 47 | try: 48 | # 创建一个socket对象 49 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 50 | # 利用UDP协议的特性,尝试发送无需实际传输的数据 51 | s.connect(('10.255.255.255', 1)) 52 | local_ip = s.getsockname()[0] 53 | except Exception as e: 54 | local_ip = '127.0.0.1' 55 | finally: 56 | s.close() 57 | return local_ip 58 | 59 | def get_ws_url(self): 60 | port=self.config["dglabServerPort"] 61 | return f"ws://{str(self.get_local_ip())}:{port}" 62 | 63 | def print_qrcode(self,data: str): 64 | """输出二维码到终端界面""" 65 | image=self.create_qrcode(data) 66 | image.save('qrcode.png') 67 | 68 | def wirte_log(self,text:str,level:str|None): 69 | self.logger.put({"text":text,"level":"info"if level==None else level}) 70 | 71 | 72 | async def serverStart(self): 73 | 74 | port=self.config["dglabServerPort"] 75 | if self.config["dglabServerIp"]=="":ip=str(self.get_local_ip()) 76 | else: ip=self.config["dglabServerIp"] 77 | async with DGLabWSServer(ip,port,60) as server: 78 | self.client = server.new_local_client() 79 | client=self.client 80 | 81 | # 等待绑定 82 | await client.bind() 83 | self.params['dgUnbinded']=False 84 | self.wirte_log(f"已与 App {self.client.target_id} 成功绑定","info") 85 | 86 | async for data in client.data_generator(FeedbackButton, RetCode,StrengthData): 87 | 88 | if isinstance(data,StrengthData): 89 | self.strengthData=data 90 | if self.strengthData.a_limit != self.strengthData.a: 91 | await self.client.set_strength(Channel.A,StrengthOperationType.SET_TO,self.strengthData.a_limit) 92 | if self.strengthData.b_limit != self.strengthData.b: 93 | await self.client.set_strength(Channel.B,StrengthOperationType.SET_TO,self.strengthData.b_limit) 94 | 95 | # 接收 心跳 / App 断开通知 96 | elif data == RetCode.CLIENT_DISCONNECTED: 97 | self.wirte_log("App 已断开连接,你可以尝试重新扫码进行连接绑定","info") 98 | self.params['dgUnbinded']=True 99 | await client.rebind() 100 | self.wirte_log("重新绑定成功","info") 101 | self.params['dgUnbinded']=False 102 | if self.params.get('running')==False:return 103 | 104 | 105 | 106 | class ServerTread: 107 | def __init__(self,logger,client,patterns,params,queue,channel) -> None: 108 | super().__init__() 109 | self.logger=logger 110 | self.client:DGLabLocalClient=client 111 | self.patterns=patterns 112 | self.params=params 113 | self.queue:Queue=queue 114 | self.channel=channel 115 | 116 | 117 | 118 | def run(self): 119 | thread = threading.Thread(target=self.run_asyncio_loop,daemon=True) 120 | thread.start() 121 | return thread 122 | 123 | def run_asyncio_loop(self): 124 | self.loop = asyncio.new_event_loop() 125 | asyncio.set_event_loop(self.loop) 126 | try: 127 | self.loop.run_until_complete(self.webSocketstart()) 128 | except Exception as e: 129 | self.writeLog("ServerTread Error:"+str(e),"error") 130 | finally: 131 | self.writeLog("info","ServerTread Exit") 132 | 133 | 134 | async def webSocketstart(self): 135 | while self.params.get('running'): 136 | if self.params.get("dgUnbinded"): 137 | if self.channel=="A": self.writeLog("info","waiting for dgserver bind 等待dglab socket扫码绑定") 138 | time.sleep(3) 139 | continue 140 | 141 | try: 142 | data:dict=self.queue.get() 143 | name=data.get("name") 144 | intensity= data.get("intensity") 145 | takeTime=float(data.get("time")) 146 | tickstime=await self.sendMessage(name,takeTime,intensity) 147 | await asyncio.sleep(tickstime/10-0.5) 148 | except TimeoutError: 149 | self.writeLog("warning","Timeout,Sever cannot connect to APP,please check APP||连接超时,无法连接至APP请检查APP是否处于运行状态") 150 | await asyncio.sleep(1) 151 | except ConnectionRefusedError: 152 | self.writeLog("warning","ConnectionRefused,Server cannot to APP,please check APP||无法连接致手机APP,请检查手机APP是否开启") 153 | await asyncio.sleep(1) 154 | except Exception as e: 155 | self.writeLog("error",f"unexcepted error:{e}|type:{type(e)}") 156 | await asyncio.sleep(1) 157 | continue 158 | 159 | 160 | 161 | async def sendMessage(self,pattern_name,time,intensity): 162 | pattern=self.patterns[pattern_name] 163 | intensity= 100 if intensity >100 else intensity 164 | pattern = [(a, tuple(int(b_i * intensity / 100 ) for b_i in b)) for a, b in pattern] 165 | 166 | looptime=self.getPatternLoopTime(pattern_name,time*10) 167 | 168 | await self.client.add_pulses(self.getChannel(self.channel),*(pattern*looptime)) 169 | self.writeLog("info",f"Sent|channel:{self.channel}|name:{pattern_name}|intensity:{intensity}|ticks:{time*10}|time:{len(pattern)/10*looptime} s") 170 | return len(pattern)*looptime 171 | 172 | def writeLog(self,level,text): 173 | self.logger.put({'text':text,'level':level}) 174 | 175 | def getChannel(self,value): 176 | if value=='A' or value=='a':return Channel.A 177 | if value=='B' or value=='b':return Channel.B 178 | self.writeLog("error",f"unexpected json 参数错误 channel error ") 179 | 180 | 181 | 182 | def getPatternLoopTime(self,pattern_name,ticks)->int: 183 | one_round_tick=len(self.patterns[pattern_name]) 184 | num=int(ticks/one_round_tick) 185 | return num+1 186 | 187 | 188 | if __name__ == "__main__": 189 | import time 190 | try: 191 | 192 | logger=Queue(-1) 193 | server=DGLabServerTread({"dglabServerPort":5678,"dglabServerIp":"0.0.0.0"},logger,None) 194 | thread=server.run() 195 | time.sleep(5) 196 | 197 | url =server.client.get_qrcode(server.get_ws_url()) 198 | img=server.create_qrcode(url) 199 | print(img) 200 | img.save('qrcode.png') 201 | # self.wirte_log("请用 DG-Lab App 扫描二维码以连接","info") 202 | print(123) 203 | 204 | while True: 205 | print(1) 206 | time.sleep(1) 207 | except: 208 | server.stop=True -------------------------------------------------------------------------------- /src/core/logger.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import logging.handlers 3 | from typing import Optional 4 | class MyLogger: 5 | def __init__(self): 6 | self.logger=self.getlogger() 7 | 8 | def getlogger(self,name: Optional[str] = "my_logger",filepath: Optional[str] ='VRCLS.log'): 9 | # 创建 logger 10 | logger = logging.getLogger(name) 11 | logger.setLevel(logging.DEBUG) # 设置日志级别 12 | # 日志文件路径 13 | log_file = filepath 14 | # 单个日志文件最大大小 15 | max_bytes = 1024 * 1024 # 1MB 16 | # 最多保留的日志文件数 17 | backup_count = 20 18 | # 创建 file handler 并设置日志级别 19 | fh = logging.handlers.RotatingFileHandler(log_file, maxBytes=max_bytes, backupCount=backup_count,encoding="utf-8") 20 | fh.setLevel(logging.DEBUG) 21 | 22 | # 创建 console handler 并设置日志级别 23 | ch = logging.StreamHandler() 24 | ch.setLevel(logging.INFO) 25 | 26 | # 定义 handler 的输出格式 27 | formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 28 | fh.setFormatter(formatter) 29 | ch.setFormatter(formatter) 30 | 31 | # 给 logger 添加 handler 32 | logger.addHandler(fh) 33 | logger.addHandler(ch) 34 | return logger 35 | -------------------------------------------------------------------------------- /src/core/process.py: -------------------------------------------------------------------------------- 1 | from .logger import MyLogger 2 | from ..handler.basic import BasicHandler 3 | import speech_recognition as sr 4 | import requests 5 | from multiprocessing import Process,Queue 6 | import winsound 7 | from .dglab import DGLabServerTread,ServerTread 8 | import threading 9 | import asyncio 10 | 11 | def once(audio:sr.AudioData,baseurl,config,pattern,headers,params,logger,pattern_a,pattern_b): 12 | sourceLanguage=params["sourceLanguage"] 13 | basicHandler=BasicHandler(logger,config,pattern,params,pattern_a,pattern_b) 14 | try: 15 | 16 | logger.put({"text":"音频输出完毕","level":"info"}) 17 | 18 | url=baseurl+"/whisper/multitranscription" 19 | 20 | logger.put({"text":f"url:{url}","level":"debug"}) 21 | files = {'file': ('filename', audio.get_wav_data(), 'audio/wav')} 22 | data = { 'sourceLanguage': sourceLanguage} 23 | response = requests.post(url, files=files, data=data, headers=headers) 24 | # 检查响应状态码 25 | if response.status_code != 200: 26 | logger.put({"text":f"数据接收异常:{response.text}","level":"warning"}) 27 | return 28 | # 解析JSON响应 29 | res = response.json() 30 | logger.put({"text":"你说的是: " + res["text"],"level":"info"}) 31 | if res["text"] =="": 32 | logger.put({"text":"返回值过滤","level":"debug"}) 33 | return 34 | # 执行操作 35 | basicHandler.handle(res) 36 | 37 | 38 | except requests.JSONDecodeError: 39 | logger.put({"text":"json解析异常,code:"+str(response.status_code)+" info:"+response.text,"level":"warning"}) 40 | return 41 | except Exception as e: 42 | logger.put({"text":e,"level":"warning"}) 43 | return 44 | def threaded_listen(baseurl,config,pattern,headers,params,logger,pattern_a,pattern_b): 45 | # logger=MyLogger().logger 46 | r = sr.Recognizer() 47 | m = sr.Microphone(device_index=None if config.get("micIndex")== -1 else config.get("micIndex")) 48 | logger.put({"text":"开始音量测试","level":"info"}) 49 | with m as source: 50 | r.adjust_for_ambient_noise(source) # we only need to calibrate once, before we start listening 51 | logger.put({"text":"结束音量测试","level":"info"}) 52 | logger.put({"text":"sound process started complete||音频进程启动完毕","level":"info"}) 53 | winsound.PlaySound('SystemAsterisk', winsound.SND_ALIAS) 54 | with m as s: 55 | while params["running"]: 56 | try: # listen for 1 second, then check again if the stop function has been called 57 | audio = r.listen(s, 10) 58 | except sr.WaitTimeoutError: # listening timed out, just try again 59 | pass 60 | else: 61 | if params["running"]: 62 | p = Process(target=once,daemon=True, args=(audio,baseurl,config,pattern,headers,params,logger,pattern_a,pattern_b)) 63 | p.start() 64 | 65 | logger.put({"text":"sound process exited complete||音频进程退出完毕","level":"info"}) 66 | def logger_process(queue:Queue): 67 | logger=MyLogger().logger 68 | while True: 69 | text=queue.get() 70 | if text['level']=="debug":logger.debug(text['text']) 71 | elif text['level']=="info":logger.info(text['text']) 72 | elif text['level']=="warning":logger.warning(text['text']) 73 | elif text['level']=="error":logger.error(text['text']) 74 | else :logger.warning(text) 75 | 76 | -------------------------------------------------------------------------------- /src/core/startup.py: -------------------------------------------------------------------------------- 1 | import json 2 | from .defaultConfig import defaultConfig,defaultpatterns 3 | from .dglab import DGLabServerTread,ServerTread 4 | import requests 5 | import time 6 | 7 | class StartUp: 8 | def __init__(self,logger,params): 9 | self.logger=logger 10 | self.params=params 11 | self.tragetTranslateLanguage="en" 12 | logger.put({"text":f"server start","level":"info"}) 13 | try: 14 | with open('patterns.json', 'r', encoding="utf8") as f: 15 | self.patterns = json.load(f) 16 | except FileNotFoundError: 17 | with open('patterns.json', 'w+', encoding="utf8") as f: 18 | logger.put({"text":'正在创建波形文件',"level":"info"}) 19 | f.write(json.dumps(defaultpatterns,ensure_ascii=False, indent=4)) 20 | self.patterns = defaultpatterns 21 | 22 | try: 23 | with open('client.json', 'r',encoding='utf-8') as file: 24 | self.config:dict = json.load(file) 25 | except FileNotFoundError: 26 | with open('client.json', 'w', encoding="utf8") as f: 27 | f.write(json.dumps(defaultConfig,ensure_ascii=False, indent=4)) 28 | self.config=defaultConfig 29 | except requests.exceptions.JSONDecodeError as e: 30 | self.logger.put({'text':"配置文件异常,详情:"+str(e.strerror),"level":"error"}) 31 | time.sleep(10) 32 | exit(0) 33 | 34 | def setDglabServer(self): 35 | self.dglabServer=DGLabServerTread(self.config,self.logger,self.params) 36 | self.dglabServer.run() 37 | time.sleep(5) 38 | return self.dglabServer 39 | def setThreads(self,queue_a,queue_b): 40 | self.AThread=ServerTread(self.logger,self.dglabServer.client,self.patterns,self.params,queue_a,"A") 41 | self.AThread.run() 42 | self.BThread=ServerTread(self.logger,self.dglabServer.client,self.patterns,self.params,queue_b,"B") 43 | self.BThread.run() 44 | def run(self): 45 | self.configCheck() 46 | res= self.checkAccount() 47 | return res 48 | def configCheck(self): 49 | try: 50 | with open('client.json', 'r',encoding='utf-8') as file: 51 | self.config:dict = json.load(file) 52 | configDiff=list(set(defaultConfig.keys())-set(self.config.keys())) 53 | if configDiff != []: 54 | self.logger.put({'text':"配置文件更新,增加条目:"+str(configDiff),"level":"info"}) 55 | for newConfig in configDiff: 56 | self.config[newConfig]=defaultConfig[newConfig] 57 | with open('client.json', 'w', encoding="utf8") as file: 58 | file.write(json.dumps(self.config,ensure_ascii=False, indent=4)) 59 | # configDefaultScripts=[script["action"] for script in self.config["defaultScripts"]] 60 | # defaultScriptsDiff=[script for script in defaultConfig["defaultScripts"] if script["action"] not in configDefaultScripts] 61 | # if defaultScriptsDiff != []: 62 | # self.logger.put({'text':"配置文件更新,增加默认指令条目:"+str(defaultScriptsDiff),"level":"info"}) 63 | # for newConfig in defaultScriptsDiff: 64 | # self.config["defaultScripts"].append(newConfig) 65 | # with open('client.json', 'w', encoding="utf8") as file: 66 | # file.write(json.dumps(self.config,ensure_ascii=False, indent=4)) 67 | except requests.exceptions.JSONDecodeError as e: 68 | self.logger.put({'text':"配置文件异常,详情:"+str(e.strerror),"level":"warning"}) 69 | time.sleep(10) 70 | exit(0) 71 | whisperSupportedLanguageList=["af","am","ar","as","az","ba","be","bg","bn","bo","br","bs","ca","cs","cy","da","de","el","en","es" 72 | ,"et","eu","fa","fi","fo","fr","gl","gu","ha","haw","he","hi","hr","ht","hu","hy","id","is","it", 73 | "ja","jw","ka","kk","km","kn","ko","la","lb","ln","lo","lt","lv","mg","mi","mk","ml","mn","mr","ms", 74 | "mt","my","ne","nl","nn","no","oc","pa","pl","ps","pt","ro","ru","sa","sd","si","sk","sl","sn","so","sq", 75 | "sr", "su", "sv","sw","ta", "te","tg","th","tk","tl","tr","tt","uk","ur","uz","vi","yi","yo","yue","zh"] 76 | self.sourceLanguage="zh" if self.config["sourceLanguage"] =="" else self.config["sourceLanguage"] 77 | if self.sourceLanguage not in whisperSupportedLanguageList: 78 | self.logger.put({'text':'please check your sourceLanguage in config,please choose one in following list\n 请检查sourceLanguage配置是否正确 请从下方语言列表中选择一个(中文是 zh)\n list:'+str(whisperSupportedLanguageList),"level":"warning"}) 79 | input("press any key to exit||按下任意键退出...") 80 | exit(0) 81 | def checkAccount(self): 82 | 83 | 84 | while True: 85 | time.sleep(0.1) 86 | if self.config["userInfo"]["username"] == "" or self.config["userInfo"]["password"] == "" or self.config["userInfo"]["username"] is None or self.config["userInfo"]["password"] is None: 87 | self.logger.put({'text':"userinfo empty , please enter again||无用户信息请重新输入","level":"warning"}) 88 | self.config["userInfo"]["username"] = input("请输入用户名: ") 89 | self.config["userInfo"]["password"] = input("请输入密码: ") 90 | continue 91 | baseurl=self.config["baseurl"] 92 | response = requests.post(baseurl+"/login",json=self.config["userInfo"]) 93 | if response.status_code != 200: 94 | self.logger.put({'text':response.text,"level":"debug"}) 95 | self.logger.put({'text':"password or account error , please enter again||账户或密码错误,请重新输入","level":"warning"}) 96 | self.config["userInfo"]["username"] = input("请输入用户名: ") 97 | self.config["userInfo"]["password"] = input("请输入密码: ") 98 | continue 99 | with open('client.json', 'w', encoding="utf8") as f: 100 | f.write(json.dumps(self.config,ensure_ascii=False, indent=4)) 101 | break 102 | 103 | res=response.json() 104 | return {'Authorization': 'Bearer '+res["access_token"]} -------------------------------------------------------------------------------- /src/handler/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VoiceLinkVR/VoiceLinkDGLAB/398ecbd8c28812650e77c08590957cd90ed4a932/src/handler/__init__.py -------------------------------------------------------------------------------- /src/handler/base_handler.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | from pydglab_ws import DGLabLocalClient,DGLabWSClient 3 | class BaseHandler(ABC): 4 | """处理器基类""" 5 | def __init__(self): 6 | pass 7 | @abstractmethod 8 | def handle(self, *args, **kwargs): 9 | """处理方法 10 | 11 | Args: 12 | *args: 位置参数 13 | **kwargs: 关键字参数 14 | """ 15 | pass -------------------------------------------------------------------------------- /src/handler/basic.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | from .base_handler import BaseHandler 3 | from multiprocessing import Queue 4 | import winsound 5 | import random 6 | class BasicHandler(BaseHandler): 7 | def __init__(self,logger,config,pattern,params,pattern_a,pattern_b): 8 | self.config=config 9 | self.logger=logger 10 | self.pattern=pattern 11 | self.pattern_a:Queue=pattern_a 12 | self.pattern_b:Queue=pattern_b 13 | """聊天框处理器""" 14 | 15 | def handle(self, message: str): 16 | self.controlFunction(message) 17 | 18 | 19 | def action(self,script:dict,count): 20 | for pattern in script.get("patterns"): 21 | for i in range(count): 22 | name=pattern.get("name") 23 | sendPattern={ 24 | "name":pattern.get("name"), 25 | "intensity":pattern.get("intensity"), 26 | "time":pattern.get("time") 27 | } 28 | if name=="random" or name=="随机": 29 | randomName=str(random.choice(list(self.pattern.keys()))) 30 | self.logger.put({"text":f"随机波形:{randomName}","level":"info"}) 31 | 32 | sendPattern["name"]=randomName 33 | channel=pattern.get("channel") 34 | if channel == 'random':channel=str(random.choice(["A","B"])) 35 | if channel == 'A' or channel == 'a':self.pattern_a.put(sendPattern) 36 | elif channel == 'B' or channel =='b':self.pattern_b.put(sendPattern) 37 | 38 | 39 | 40 | def controlFunction(self,res): 41 | config=self.config 42 | logger=self.logger 43 | text:str=res['text'] 44 | counter=0 45 | hasCommand=False 46 | if config["activateText"] == "": 47 | logger.put({"text":"无头操作:"+text,"level":"info"}) 48 | if text == config["exitText"]: 49 | exit(0) 50 | for script in config.get("scripts"): 51 | for command in script.get("text"): 52 | counter+=text.count(command) 53 | if counter != 0: 54 | hasCommand=True 55 | logger.put({"text":f"执行操作:{script["action"]},触发次数:{counter}次","level":"info"}) 56 | #执行命令 57 | self.action(script,counter) 58 | 59 | elif config["activateText"] in text: 60 | commandlist=text.split(config["activateText"]) 61 | command=commandlist[-1] 62 | if (config["stopText"] in command) or config["stopText"] == "": 63 | if config["stopText"] != "":command=command.split(config["stopText"])[0] 64 | logger.put({"text":"有头操作:"+command,"level":"info"}) 65 | if command == config["exitText"]: 66 | exit(0) 67 | for script in config.get("scripts"): 68 | for command in script.get("text"): 69 | counter+=text.count(command) 70 | if counter != 0: 71 | hasCommand=True 72 | logger.put({"text":f"执行操作:{script["action"]},触发次数:{counter}次","level":"info"}) 73 | #执行命令 74 | self.action(script,counter) 75 | if hasCommand:winsound.PlaySound('SystemAsterisk', winsound.SND_ALIAS) -------------------------------------------------------------------------------- /src/module/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VoiceLinkVR/VoiceLinkDGLAB/398ecbd8c28812650e77c08590957cd90ed4a932/src/module/__init__.py -------------------------------------------------------------------------------- /templates/css/app.766ca9ce.css: -------------------------------------------------------------------------------- 1 | .info-container[data-v-651f4516]{padding:20px;font-size:14px;line-height:1.5}.info-container p[data-v-651f4516]{margin:10px 0}#app{font-family:Avenir,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-align:center;color:#2c3e50}#app,body,html{width:100%;height:100%;margin:0;padding:0} -------------------------------------------------------------------------------- /templates/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VoiceLinkVR/VoiceLinkDGLAB/398ecbd8c28812650e77c08590957cd90ed4a932/templates/favicon.ico -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | VoiceLinkDGLAB
-------------------------------------------------------------------------------- /templates/js/app.16fed61a.js: -------------------------------------------------------------------------------- 1 | (function(){"use strict";var e={6527:function(e,l,a){var n=a(5130),t=a(6768);function u(e,l,a,n,u,i){const o=(0,t.g2)("configPage");return(0,t.uX)(),(0,t.Wv)(o)}a(4114);var i=a(144),o=a(4232);function b(e,l){const a=(0,t.g2)("el-text"),n=(0,t.g2)("el-link");return(0,t.uX)(),(0,t.CE)(t.FK,null,[l[3]||(l[3]=(0,t.Lk)("div",{style:{height:"100px"}},null,-1)),(0,t.bF)(a,{class:"mx-1"},{default:(0,t.k6)((()=>l[0]||(l[0]=[(0,t.eW)("欢迎使用"),(0,t.Lk)("br",null,null,-1),(0,t.eW)("由VoiceLinkVR"),(0,t.Lk)("br",null,null,-1),(0,t.eW)("开发的VoiceLinkDGLAB"),(0,t.Lk)("br",null,null,-1),(0,t.eW)("开发者:boyqiu-001"),(0,t.Lk)("br",null,null,-1),(0,t.eW)("boyqiu玻璃球"),(0,t.Lk)("br",null,null,-1),(0,t.eW)("qq群1011986554")]))),_:1}),l[4]||(l[4]=(0,t.Lk)("br",null,null,-1)),(0,t.bF)(n,{type:"primary",href:"https://github.com/VoiceLinkVR/VoiceLinkDGLAB",target:"_blank"},{default:(0,t.k6)((()=>l[1]||(l[1]=[(0,t.eW)("VoiceLinkDGLAB Github Page")]))),_:1}),l[5]||(l[5]=(0,t.Lk)("br",null,null,-1)),(0,t.bF)(n,{type:"primary",href:"https://github.com/VoiceLinkVR/VoiceLinkServer",target:"_blank"},{default:(0,t.k6)((()=>l[2]||(l[2]=[(0,t.eW)("server Github Page")]))),_:1})],64)}var r=a(1241);const c={},s=(0,r.A)(c,[["render",b]]);var d=s,p=a(4373),f=a(1219),F=a(2933),k=a(7477),g={__name:"config-page",setup(e){let l=(0,i.Kh)({local:{imageSrc:null,scriptClick:0,patternName:[],micName:[]},config:{userInfo:{username:"testuser",password:"abc123!"},baseurl:"https://whisper.boyqiu001.cn:7070","api-ip":"127.0.0.1","api-port":8980,sourceLanguage:"zh",dglabServerIp:"",dglabServerPort:56742,activateText:"",micIndex:-1,exitText:"退出程序",scripts:[{action:"1",text:["测试","可以"],patterns:[{name:"呼吸",channel:"B",intensity:10,time:2},{name:"呼吸",channel:"A",intensity:10,time:3}]}]}});function a(){p.A.get("/api/getConfig").then((e=>{l.config=e.data,(0,f.nk)({message:"配置信息获取成功",type:"success"})})),p.A.get("/api/getPatternName").then((e=>{l.local.patternName=e.data,(0,f.nk)({message:"波形名称获取成功",type:"success"})})),p.A.get("/api/getMics").then((e=>{l.local.micName=e.data,(0,f.nk)({message:"麦克风名称获取成功",type:"success"})}))}function n(){p.A.post("/api/saveConfig",{config:l.config},{headers:{"Content-Type":"application/json"}}).then((0,f.nk)({message:"配置信息保存成功",type:"success"}))}function u(){n(),b()}function b(){p.A.get("/api/reboot")}function r(){l.config.scripts[l.local.scriptClick].text.push("")}function c(e){l.config.scripts[l.local.scriptClick].text.splice(e,1)}function s(){l.config.scripts[l.local.scriptClick].patterns.push({name:"呼吸",channel:"A",intensity:0,time:2})}function g(e){l.config.scripts[l.local.scriptClick].patterns.splice(e,1)}function m(){l.config.scripts.push({action:"脚本",text:[""],patterns:[{name:"呼吸",channel:"A",intensity:0,time:2}]})}function v(){const e=l.local.scriptClick;F.s.confirm("请确认是否删除自定义脚本:"+l.config.scripts[e]["action"],"Warning",{confirmButtonText:"确定",cancelButtonText:"取消",type:"warning"}).then((()=>{0!=e||1!=l.config.scripts.length?(l.local.scriptClick=0==e?0:e-1,l.config.scripts.splice(e,1),(0,f.nk)({type:"success",message:"删除成功"})):l.config.scripts[0]={action:"脚本",text:[""],vrcActions:[{vrcPath:"",vrcValueType:"bool",vrcValue:0,sleeptime:.1}]}})).catch((()=>{(0,f.nk)({type:"info",message:"取消删除"})}))}function h(){try{p.A.get("/api/getQRcode").then((e=>{const a=e.data.image;l.local.imageSrc=`data:image/png;base64,${a}`}))}catch(e){console.error("Error fetching image:",e)}}return(0,t.sV)((()=>{a(),h()})),(e,p)=>{const f=(0,t.g2)("el-header"),F=(0,t.g2)("el-aside"),y=(0,t.g2)("el-button"),_=(0,t.g2)("el-button-group"),V=(0,t.g2)("el-input"),C=(0,t.g2)("el-form-item"),x=(0,t.g2)("el-tooltip"),R=(0,t.g2)("el-option"),L=(0,t.g2)("el-select"),w=(0,t.g2)("el-form"),W=(0,t.g2)("el-card"),A=(0,t.g2)("el-col"),S=(0,t.g2)("el-image"),U=(0,t.g2)("el-row"),I=(0,t.g2)("el-menu-item"),T=(0,t.g2)("el-scrollbar"),B=(0,t.g2)("el-menu"),P=(0,t.g2)("el-descriptions-item"),O=(0,t.g2)("el-slider"),j=(0,t.g2)("el-descriptions"),X=(0,t.g2)("el-main"),G=(0,t.g2)("el-container");return(0,t.uX)(),(0,t.Wv)(G,null,{default:(0,t.k6)((()=>[(0,t.bF)(f,null,{default:(0,t.k6)((()=>p[9]||(p[9]=[(0,t.Lk)("h1",null,"VoiceLinkDGLAB配置管理",-1)]))),_:1}),(0,t.bF)(G,null,{default:(0,t.k6)((()=>[(0,t.bF)(F,{width:"10%"},{default:(0,t.k6)((()=>[(0,t.bF)(d)])),_:1}),(0,t.bF)(X,null,{default:(0,t.k6)((()=>[(0,t.bF)(_,{style:{"margin-left":"50%","margin-bottom":"20px"}},{default:(0,t.k6)((()=>[(0,t.bF)(y,{type:"primary",onClick:a},{default:(0,t.k6)((()=>p[10]||(p[10]=[(0,t.eW)("获取配置")]))),_:1}),(0,t.bF)(y,{type:"primary",onClick:h},{default:(0,t.k6)((()=>p[11]||(p[11]=[(0,t.eW)("获取二维码")]))),_:1}),(0,t.bF)(y,{type:"primary",onClick:n},{default:(0,t.k6)((()=>p[12]||(p[12]=[(0,t.eW)("保存配置")]))),_:1}),(0,t.bF)(y,{type:"primary",onClick:u},{default:(0,t.k6)((()=>p[13]||(p[13]=[(0,t.eW)("保存配置并重启")]))),_:1}),(0,t.bF)(y,{type:"primary",onClick:b},{default:(0,t.k6)((()=>p[14]||(p[14]=[(0,t.eW)("重启服务")]))),_:1})])),_:1}),(0,t.bF)(U,{gutter:20},{default:(0,t.k6)((()=>[(0,t.bF)(A,{span:8},{default:(0,t.k6)((()=>[(0,t.bF)(W,{style:{height:"400px"}},{header:(0,t.k6)((()=>p[15]||(p[15]=[(0,t.Lk)("div",{class:"card-header"},[(0,t.Lk)("span",null,"程序配置")],-1)]))),default:(0,t.k6)((()=>[(0,t.bF)(w,{model:(0,i.R1)(l).config,"label-width":"auto"},{default:(0,t.k6)((()=>[(0,t.bF)(C,{label:"服务器URL"},{default:(0,t.k6)((()=>[(0,t.bF)(V,{modelValue:(0,i.R1)(l).config.baseurl,"onUpdate:modelValue":p[0]||(p[0]=e=>(0,i.R1)(l).config.baseurl=e)},null,8,["modelValue"])])),_:1}),(0,t.bF)(C,{label:"郊狼服务端 IP"},{default:(0,t.k6)((()=>[(0,t.bF)(x,{class:"box-item",effect:"dark",content:"修改该配置后,请关闭程序黑色窗口并重启程序",placement:"right"},{default:(0,t.k6)((()=>[(0,t.bF)(V,{modelValue:(0,i.R1)(l).config["dglabServerIp"],"onUpdate:modelValue":p[1]||(p[1]=e=>(0,i.R1)(l).config["dglabServerIp"]=e),placeholder:"局域网中扫码异常时填写"},null,8,["modelValue"])])),_:1})])),_:1}),(0,t.bF)(C,{label:"郊狼服务端 端口"},{default:(0,t.k6)((()=>[(0,t.bF)(x,{class:"box-item",effect:"dark",content:"修改该配置后,请关闭程序黑色窗口并重启程序",placement:"right"},{default:(0,t.k6)((()=>[(0,t.bF)(V,{type:"number",modelValue:(0,i.R1)(l).config["dglabServerPort"],"onUpdate:modelValue":p[2]||(p[2]=e=>(0,i.R1)(l).config["dglabServerPort"]=e)},null,8,["modelValue"])])),_:1})])),_:1}),(0,t.bF)(C,{label:"麦克风"},{default:(0,t.k6)((()=>[(0,t.bF)(L,{modelValue:(0,i.R1)(l).config.micIndex,"onUpdate:modelValue":p[3]||(p[3]=e=>(0,i.R1)(l).config.micIndex=e)},{default:(0,t.k6)((()=>[(0,t.bF)(R,{label:"系统默认麦克风",value:-1}),((0,t.uX)(!0),(0,t.CE)(t.FK,null,(0,t.pI)((0,i.R1)(l).local.micName,((e,l)=>((0,t.uX)(),(0,t.Wv)(R,{key:l,label:e,value:l},null,8,["label","value"])))),128))])),_:1},8,["modelValue"])])),_:1}),(0,t.bF)(C,{label:"识别语言"},{default:(0,t.k6)((()=>[(0,t.bF)(L,{modelValue:(0,i.R1)(l).config.sourceLanguage,"onUpdate:modelValue":p[4]||(p[4]=e=>(0,i.R1)(l).config.sourceLanguage=e)},{default:(0,t.k6)((()=>[(0,t.bF)(R,{label:"阿非利堪斯语(Afrikaans)",value:"af"}),(0,t.bF)(R,{label:"阿姆哈拉语(Amharic)",value:"am"}),(0,t.bF)(R,{label:"阿拉伯语(Arabic)",value:"ar"}),(0,t.bF)(R,{label:"阿萨姆语(Assamese)",value:"as"}),(0,t.bF)(R,{label:"阿塞拜疆语(Azerbaijani)",value:"az"}),(0,t.bF)(R,{label:"巴什基尔语(Bashkir)",value:"ba"}),(0,t.bF)(R,{label:"白俄罗斯语(Belarusian)",value:"be"}),(0,t.bF)(R,{label:"保加利亚语(Bulgarian)",value:"bg"}),(0,t.bF)(R,{label:"孟加拉语(Bengali)",value:"bn"}),(0,t.bF)(R,{label:"藏语(Tibetan)",value:"bo"}),(0,t.bF)(R,{label:"布雷顿语(Breton)",value:"br"}),(0,t.bF)(R,{label:"波斯尼亚语(Bosnian)",value:"bs"}),(0,t.bF)(R,{label:"加泰罗尼亚语(Catalan)",value:"ca"}),(0,t.bF)(R,{label:"捷克语(Czech)",value:"cs"}),(0,t.bF)(R,{label:"威尔士语(Welsh)",value:"cy"}),(0,t.bF)(R,{label:"丹麦语(Danish)",value:"da"}),(0,t.bF)(R,{label:"德语(German)",value:"de"}),(0,t.bF)(R,{label:"希腊语(Greek)",value:"el"}),(0,t.bF)(R,{label:"英语(English)",value:"en"}),(0,t.bF)(R,{label:"西班牙语(Spanish)",value:"es"}),(0,t.bF)(R,{label:"爱沙尼亚语(Estonian)",value:"et"}),(0,t.bF)(R,{label:"巴斯克语(Basque)",value:"eu"}),(0,t.bF)(R,{label:"波斯语(Persian)",value:"fa"}),(0,t.bF)(R,{label:"芬兰语(Finnish)",value:"fi"}),(0,t.bF)(R,{label:"法罗语(Faroese)",value:"fo"}),(0,t.bF)(R,{label:"法语(French)",value:"fr"}),(0,t.bF)(R,{label:"加利西亚语(Galician)",value:"gl"}),(0,t.bF)(R,{label:"古吉拉特语(Gujarati)",value:"gu"}),(0,t.bF)(R,{label:"豪萨语(Hausa)",value:"ha"}),(0,t.bF)(R,{label:"夏威夷语(Hawaiian)",value:"haw"}),(0,t.bF)(R,{label:"希伯来语(Hebrew)",value:"he"}),(0,t.bF)(R,{label:"印地语(Hindi)",value:"hi"}),(0,t.bF)(R,{label:"克罗地亚语(Croatian)",value:"hr"}),(0,t.bF)(R,{label:"海地克里奥尔语(Haitian Creole)",value:"ht"}),(0,t.bF)(R,{label:"匈牙利语(Hungarian)",value:"hu"}),(0,t.bF)(R,{label:"亚美尼亚语(Armenian)",value:"hy"}),(0,t.bF)(R,{label:"印尼语(Indonesian)",value:"id"}),(0,t.bF)(R,{label:"冰岛语(Icelandic)",value:"is"}),(0,t.bF)(R,{label:"意大利语(Italian)",value:"it"}),(0,t.bF)(R,{label:"日语(Japanese)",value:"ja"}),(0,t.bF)(R,{label:"爪哇语(Javanese)",value:"jw"}),(0,t.bF)(R,{label:"格鲁吉亚语(Georgian)",value:"ka"}),(0,t.bF)(R,{label:"哈萨克语(Kazakh)",value:"kk"}),(0,t.bF)(R,{label:"高棉语(Khmer)",value:"km"}),(0,t.bF)(R,{label:"卡纳达语(Kannada)",value:"kn"}),(0,t.bF)(R,{label:"韩语(Korean)",value:"ko"}),(0,t.bF)(R,{label:"拉丁语(Latin)",value:"la"}),(0,t.bF)(R,{label:"卢森堡语(Luxembourgish)",value:"lb"}),(0,t.bF)(R,{label:"林加拉语(Lingala)",value:"ln"}),(0,t.bF)(R,{label:"老挝语(Lao)",value:"lo"}),(0,t.bF)(R,{label:"立陶宛语(Lithuanian)",value:"lt"}),(0,t.bF)(R,{label:"拉脱维亚语(Latvian)",value:"lv"}),(0,t.bF)(R,{label:"马达加斯加语(Malagasy)",value:"mg"}),(0,t.bF)(R,{label:"毛利语(Maori)",value:"mi"}),(0,t.bF)(R,{label:"马其顿语(Macedonian)",value:"mk"}),(0,t.bF)(R,{label:"马拉雅拉姆语(Malayalam)",value:"ml"}),(0,t.bF)(R,{label:"蒙古语(Mongolian)",value:"mn"}),(0,t.bF)(R,{label:"马拉提语(Marathi)",value:"mr"}),(0,t.bF)(R,{label:"马来语(Malay)",value:"ms"}),(0,t.bF)(R,{label:"马耳他语(Maltese)",value:"mt"}),(0,t.bF)(R,{label:"缅甸语(Burmese)",value:"my"}),(0,t.bF)(R,{label:"尼泊尔语(Nepali)",value:"ne"}),(0,t.bF)(R,{label:"荷兰语(Dutch)",value:"nl"}),(0,t.bF)(R,{label:"尼诺尔斯克语(Nynorsk)",value:"nn"}),(0,t.bF)(R,{label:"挪威语(Norwegian)",value:"no"}),(0,t.bF)(R,{label:"奥克语(Occitan)",value:"oc"}),(0,t.bF)(R,{label:"旁遮普语(Punjabi)",value:"pa"}),(0,t.bF)(R,{label:"波兰语(Polish)",value:"pl"}),(0,t.bF)(R,{label:"普什图语(Pashto)",value:"ps"}),(0,t.bF)(R,{label:"葡萄牙语(Portuguese)",value:"pt"}),(0,t.bF)(R,{label:"罗马尼亚语(Romanian)",value:"ro"}),(0,t.bF)(R,{label:"俄语(Russian)",value:"ru"}),(0,t.bF)(R,{label:"梵语(Sanskrit)",value:"sa"}),(0,t.bF)(R,{label:"信德语(Sindhi)",value:"sd"}),(0,t.bF)(R,{label:"僧伽罗语(Sinhala)",value:"si"}),(0,t.bF)(R,{label:"斯洛伐克语(Slovak)",value:"sk"}),(0,t.bF)(R,{label:"斯洛文尼亚语(Slovenian)",value:"sl"}),(0,t.bF)(R,{label:"修纳语(Shona)",value:"sn"}),(0,t.bF)(R,{label:"索马里语(Somali)",value:"so"}),(0,t.bF)(R,{label:"阿尔巴尼亚语(Albanian)",value:"sq"}),(0,t.bF)(R,{label:"塞尔维亚语(Serbian)",value:"sr"}),(0,t.bF)(R,{label:"巽他语(Sundanese)",value:"su"}),(0,t.bF)(R,{label:"瑞典语(Swedish)",value:"sv"}),(0,t.bF)(R,{label:"斯瓦希里语(Swahili)",value:"sw"}),(0,t.bF)(R,{label:"泰米尔语(Tamil)",value:"ta"}),(0,t.bF)(R,{label:"泰卢固语(Telugu)",value:"te"}),(0,t.bF)(R,{label:"塔吉克语(Tajik)",value:"tg"}),(0,t.bF)(R,{label:"泰语(Thai)",value:"th"}),(0,t.bF)(R,{label:"土库曼语(Turkmen)",value:"tk"}),(0,t.bF)(R,{label:"他加禄语(Tagalog)",value:"tl"}),(0,t.bF)(R,{label:"土耳其语(Turkish)",value:"tr"}),(0,t.bF)(R,{label:"鞑靼语(Tatar)",value:"tt"}),(0,t.bF)(R,{label:"乌克兰语(Ukrainian)",value:"uk"}),(0,t.bF)(R,{label:"乌尔都语(Urdu)",value:"ur"}),(0,t.bF)(R,{label:"乌兹别克语 (Uzbek)",value:"uz"}),(0,t.bF)(R,{label:"越南语(Vietnamese)",value:"vi"}),(0,t.bF)(R,{label:"依地语(Yiddish)",value:"yi"}),(0,t.bF)(R,{label:"约鲁巴语(Yoruba)",value:"yo"}),(0,t.bF)(R,{label:"粤语(Cantonese)",value:"yue"}),(0,t.bF)(R,{label:"中文(Chinese)",value:"zh"})])),_:1},8,["modelValue"])])),_:1}),(0,t.bF)(C,{label:"程序退出文本"},{default:(0,t.k6)((()=>[(0,t.bF)(V,{modelValue:(0,i.R1)(l).config.exitText,"onUpdate:modelValue":p[5]||(p[5]=e=>(0,i.R1)(l).config.exitText=e)},null,8,["modelValue"])])),_:1})])),_:1},8,["model"])])),_:1})])),_:1}),(0,t.bF)(A,{span:8},{default:(0,t.k6)((()=>[(0,t.bF)(W,{style:{height:"400px"}},{header:(0,t.k6)((()=>p[16]||(p[16]=[(0,t.Lk)("div",{class:"card-header"},[(0,t.Lk)("span",null,"用户信息配置")],-1)]))),default:(0,t.k6)((()=>[(0,t.bF)(w,{model:(0,i.R1)(l).config,"label-width":"auto"},{default:(0,t.k6)((()=>[(0,t.bF)(C,{label:"用户名"},{default:(0,t.k6)((()=>[(0,t.bF)(V,{modelValue:(0,i.R1)(l).config.userInfo.username,"onUpdate:modelValue":p[6]||(p[6]=e=>(0,i.R1)(l).config.userInfo.username=e)},null,8,["modelValue"])])),_:1}),(0,t.bF)(C,{label:"密码"},{default:(0,t.k6)((()=>[(0,t.bF)(V,{type:"password",modelValue:(0,i.R1)(l).config.userInfo.password,"onUpdate:modelValue":p[7]||(p[7]=e=>(0,i.R1)(l).config.userInfo.password=e),"show-password":""},null,8,["modelValue"])])),_:1})])),_:1},8,["model"])])),_:1})])),_:1}),(0,t.bF)(A,{span:8},{default:(0,t.k6)((()=>[(0,t.bF)(W,{style:{height:"400px"}},{header:(0,t.k6)((()=>p[17]||(p[17]=[(0,t.Lk)("div",{class:"card-header"},[(0,t.Lk)("span",null,"郊狼二维码")],-1)]))),default:(0,t.k6)((()=>[(0,i.R1)(l).local.imageSrc?((0,t.uX)(),(0,t.Wv)(S,{key:0,src:(0,i.R1)(l).local.imageSrc,style:{"min-width":"200px",width:"70%",height:"auto"},fit:"contain"},null,8,["src"])):(0,t.Q3)("",!0)])),_:1})])),_:1})])),_:1}),(0,t.bF)(W,{style:{"margin-top":"20px",height:"620px"}},{header:(0,t.k6)((()=>p[18]||(p[18]=[(0,t.Lk)("span",null,"自定义脚本配置",-1)]))),default:(0,t.k6)((()=>[(0,t.bF)(U,{gutter:5},{default:(0,t.k6)((()=>[(0,t.bF)(A,{span:6},{default:(0,t.k6)((()=>[p[21]||(p[21]=(0,t.Lk)("h5",{class:"mb-2"},"自定义脚本目录",-1)),(0,t.bF)(B,{"default-active":"1",class:"el-menu-vertical-demo",onOpen:e.handleOpen,onClose:e.handleClose},{default:(0,t.k6)((()=>[(0,t.bF)(T,{height:"420px"},{default:(0,t.k6)((()=>[((0,t.uX)(!0),(0,t.CE)(t.FK,null,(0,t.pI)((0,i.R1)(l).config.scripts,((e,a)=>((0,t.uX)(),(0,t.Wv)(I,{index:a,key:a,onClick:e=>(0,i.R1)(l).local.scriptClick=a},{default:(0,t.k6)((()=>[(0,t.Lk)("span",null,(0,o.v_)(e.action),1)])),_:2},1032,["index","onClick"])))),128))])),_:1})])),_:1},8,["onOpen","onClose"]),(0,t.bF)(_,{class:"ml-4"},{default:(0,t.k6)((()=>[(0,t.bF)(y,{type:"primary",onClick:m},{default:(0,t.k6)((()=>p[19]||(p[19]=[(0,t.eW)("添加脚本")]))),_:1}),(0,t.bF)(y,{type:"danger",onClick:v},{default:(0,t.k6)((()=>p[20]||(p[20]=[(0,t.eW)("删除选定脚本")]))),_:1})])),_:1})])),_:1}),(0,t.bF)(A,{span:9},{default:(0,t.k6)((()=>[(0,t.bF)(W,{style:{height:"500px"}},{header:(0,t.k6)((()=>p[22]||(p[22]=[(0,t.Lk)("span",null,"自定义脚本名称与关键词",-1)]))),default:(0,t.k6)((()=>[(0,t.bF)(w,{"label-width":"auto"},{default:(0,t.k6)((()=>[(0,t.bF)(C,{label:"自定义脚本名称"},{default:(0,t.k6)((()=>[(0,t.bF)(V,{modelValue:(0,i.R1)(l).config.scripts[(0,i.R1)(l).local.scriptClick].action,"onUpdate:modelValue":p[8]||(p[8]=e=>(0,i.R1)(l).config.scripts[(0,i.R1)(l).local.scriptClick].action=e),placeholder:"请输入名称"},null,8,["modelValue"])])),_:1}),(0,t.bF)(y,{type:"primary",onClick:r,style:{"margin-left":"70%","margin-bottom":"20px"}},{default:(0,t.k6)((()=>p[23]||(p[23]=[(0,t.eW)("添加关键词")]))),_:1}),(0,t.bF)(T,{height:"320px"},{default:(0,t.k6)((()=>[((0,t.uX)(!0),(0,t.CE)(t.FK,null,(0,t.pI)((0,i.R1)(l).config.scripts[(0,i.R1)(l).local.scriptClick].text,((e,a)=>((0,t.uX)(),(0,t.Wv)(C,{key:a,label:"关键词"+(a+1)},{default:(0,t.k6)((()=>[(0,t.Lk)("div",null,[(0,t.bF)(U,{gutter:20},{default:(0,t.k6)((()=>[(0,t.bF)(A,{span:18},{default:(0,t.k6)((()=>[(0,t.bF)(V,{modelValue:(0,i.R1)(l).config.scripts[(0,i.R1)(l).local.scriptClick].text[a],"onUpdate:modelValue":e=>(0,i.R1)(l).config.scripts[(0,i.R1)(l).local.scriptClick].text[a]=e,placeholder:"请输入文本"},null,8,["modelValue","onUpdate:modelValue"])])),_:2},1024),(0,t.bF)(A,{span:6},{default:(0,t.k6)((()=>[(0,t.bF)(y,{type:"danger",icon:(0,i.R1)(k.epd),circle:"",onClick:e=>c(a)},null,8,["icon","onClick"])])),_:2},1024)])),_:2},1024)])])),_:2},1032,["label"])))),128))])),_:1})])),_:1})])),_:1})])),_:1}),(0,t.bF)(A,{span:9},{default:(0,t.k6)((()=>[(0,t.bF)(W,{style:{height:"500px"}},{header:(0,t.k6)((()=>p[24]||(p[24]=[(0,t.Lk)("span",null,"自定义脚本执行动作",-1)]))),default:(0,t.k6)((()=>[(0,t.bF)(T,{height:"400px"},{default:(0,t.k6)((()=>[((0,t.uX)(!0),(0,t.CE)(t.FK,null,(0,t.pI)((0,i.R1)(l).config.scripts[(0,i.R1)(l).local.scriptClick].patterns,((e,a)=>((0,t.uX)(),(0,t.Wv)(j,{class:"margin-top",title:"波形"+(a+1),column:1,border:"",key:a},{extra:(0,t.k6)((()=>[(0,t.bF)(_,{class:"ml-4"},{default:(0,t.k6)((()=>[a==(0,i.R1)(l).config.scripts[(0,i.R1)(l).local.scriptClick].patterns.length-1?((0,t.uX)(),(0,t.Wv)(y,{key:0,type:"primary",icon:(0,i.R1)(k.FWt),onClick:s},null,8,["icon"])):(0,t.Q3)("",!0),(0,t.bF)(y,{type:"danger",icon:(0,i.R1)(k.epd),onClick:e=>g(a)},null,8,["icon","onClick"])])),_:2},1024)])),default:(0,t.k6)((()=>[(0,t.bF)(P,null,{label:(0,t.k6)((()=>p[25]||(p[25]=[(0,t.eW)(" 波形名称 ")]))),default:(0,t.k6)((()=>[(0,t.bF)(L,{modelValue:e.name,"onUpdate:modelValue":l=>e.name=l},{default:(0,t.k6)((()=>[(0,t.bF)(R,{label:"随机",value:"random"}),((0,t.uX)(!0),(0,t.CE)(t.FK,null,(0,t.pI)((0,i.R1)(l).local.patternName,((e,l)=>((0,t.uX)(),(0,t.Wv)(R,{key:l,label:e,value:e},null,8,["label","value"])))),128))])),_:2},1032,["modelValue","onUpdate:modelValue"])])),_:2},1024),(0,t.bF)(P,null,{label:(0,t.k6)((()=>p[26]||(p[26]=[(0,t.eW)(" 通道 ")]))),default:(0,t.k6)((()=>[(0,t.bF)(L,{modelValue:e.channel,"onUpdate:modelValue":l=>e.channel=l},{default:(0,t.k6)((()=>[(0,t.bF)(R,{label:"随机",value:"random"}),(0,t.bF)(R,{label:"A通道",value:"A"}),(0,t.bF)(R,{label:"B通道",value:"B"})])),_:2},1032,["modelValue","onUpdate:modelValue"])])),_:2},1024),(0,t.bF)(P,null,{label:(0,t.k6)((()=>p[27]||(p[27]=[(0,t.eW)(" 强度(%) ")]))),default:(0,t.k6)((()=>[(0,t.bF)(O,{modelValue:e.intensity,"onUpdate:modelValue":l=>e.intensity=l,"show-input":""},null,8,["modelValue","onUpdate:modelValue"])])),_:2},1024),(0,t.bF)(P,null,{label:(0,t.k6)((()=>p[28]||(p[28]=[(0,t.eW)(" 时长(s) ")]))),default:(0,t.k6)((()=>[(0,t.bF)(O,{modelValue:e.time,"onUpdate:modelValue":l=>e.time=l,min:1,max:5,step:.1,"show-input":""},null,8,["modelValue","onUpdate:modelValue"])])),_:2},1024)])),_:2},1032,["title"])))),128))])),_:1})])),_:1})])),_:1})])),_:1})])),_:1})])),_:1}),(0,t.bF)(F,{width:"10%"},{default:(0,t.k6)((()=>[(0,t.bF)(d)])),_:1})])),_:1})])),_:1})}}};const m=(0,r.A)(g,[["__scopeId","data-v-651f4516"]]);var v=m,h={name:"App",components:{configPage:v}};const y=(0,r.A)(h,[["render",u]]);var _=y,V=a(809);a(4188),a(1862);const C=(0,n.Ef)(_);C.use(V.A),C.mount("#app")}},l={};function a(n){var t=l[n];if(void 0!==t)return t.exports;var u=l[n]={exports:{}};return e[n].call(u.exports,u,u.exports,a),u.exports}a.m=e,function(){var e=[];a.O=function(l,n,t,u){if(!n){var i=1/0;for(c=0;c=u)&&Object.keys(a.O).every((function(e){return a.O[e](n[b])}))?n.splice(b--,1):(o=!1,u0&&e[c-1][2]>u;c--)e[c]=e[c-1];e[c]=[n,t,u]}}(),function(){a.n=function(e){var l=e&&e.__esModule?function(){return e["default"]}:function(){return e};return a.d(l,{a:l}),l}}(),function(){a.d=function(e,l){for(var n in l)a.o(l,n)&&!a.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:l[n]})}}(),function(){a.g=function(){if("object"===typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"===typeof window)return window}}()}(),function(){a.o=function(e,l){return Object.prototype.hasOwnProperty.call(e,l)}}(),function(){a.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}}(),function(){var e={524:0};a.O.j=function(l){return 0===e[l]};var l=function(l,n){var t,u,i=n[0],o=n[1],b=n[2],r=0;if(i.some((function(l){return 0!==e[l]}))){for(t in o)a.o(o,t)&&(a.m[t]=o[t]);if(b)var c=b(a)}for(l&&l(n);r\n \n \n \n \n \n \n ","\r\n","import { render } from \"./side-info.vue?vue&type=template&id=e33be9c6\"\nconst script = {}\n\nimport exportComponent from \"../../node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render]])\n\nexport default __exports__","\r\n\r\n\r\n\r\n\r\n\r\n","import script from \"./config-page.vue?vue&type=script&setup=true&lang=js\"\nexport * from \"./config-page.vue?vue&type=script&setup=true&lang=js\"\n\nimport \"./config-page.vue?vue&type=style&index=0&id=651f4516&scoped=true&lang=css\"\n\nimport exportComponent from \"../../node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['__scopeId',\"data-v-651f4516\"]])\n\nexport default __exports__","import { render } from \"./App.vue?vue&type=template&id=3237ff5a\"\nimport script from \"./App.vue?vue&type=script&lang=js\"\nexport * from \"./App.vue?vue&type=script&lang=js\"\n\nimport \"./App.vue?vue&type=style&index=0&id=3237ff5a&lang=css\"\n\nimport exportComponent from \"../node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render]])\n\nexport default __exports__","import { createApp } from 'vue'\nimport App from './App.vue'\nimport ElementPlus from 'element-plus'\nimport 'element-plus/dist/index.css'\nimport 'element-plus/theme-chalk/dark/css-vars.css'\nconst app = createApp(App)\napp.use(ElementPlus)\napp.mount('#app')\n","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n// expose the modules object (__webpack_modules__)\n__webpack_require__.m = __webpack_modules__;\n\n","var deferred = [];\n__webpack_require__.O = function(result, chunkIds, fn, priority) {\n\tif(chunkIds) {\n\t\tpriority = priority || 0;\n\t\tfor(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];\n\t\tdeferred[i] = [chunkIds, fn, priority];\n\t\treturn;\n\t}\n\tvar notFulfilled = Infinity;\n\tfor (var i = 0; i < deferred.length; i++) {\n\t\tvar chunkIds = deferred[i][0];\n\t\tvar fn = deferred[i][1];\n\t\tvar priority = deferred[i][2];\n\t\tvar fulfilled = true;\n\t\tfor (var j = 0; j < chunkIds.length; j++) {\n\t\t\tif ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every(function(key) { return __webpack_require__.O[key](chunkIds[j]); })) {\n\t\t\t\tchunkIds.splice(j--, 1);\n\t\t\t} else {\n\t\t\t\tfulfilled = false;\n\t\t\t\tif(priority < notFulfilled) notFulfilled = priority;\n\t\t\t}\n\t\t}\n\t\tif(fulfilled) {\n\t\t\tdeferred.splice(i--, 1)\n\t\t\tvar r = fn();\n\t\t\tif (r !== undefined) result = r;\n\t\t}\n\t}\n\treturn result;\n};","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = function(module) {\n\tvar getter = module && module.__esModule ?\n\t\tfunction() { return module['default']; } :\n\t\tfunction() { return module; };\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = function(exports, definition) {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }","// define __esModule on exports\n__webpack_require__.r = function(exports) {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","// no baseURI\n\n// object to store loaded and loading chunks\n// undefined = chunk not loaded, null = chunk preloaded/prefetched\n// [resolve, reject, Promise] = chunk loading, 0 = chunk loaded\nvar installedChunks = {\n\t524: 0\n};\n\n// no chunk on demand loading\n\n// no prefetching\n\n// no preloaded\n\n// no HMR\n\n// no HMR manifest\n\n__webpack_require__.O.j = function(chunkId) { return installedChunks[chunkId] === 0; };\n\n// install a JSONP callback for chunk loading\nvar webpackJsonpCallback = function(parentChunkLoadingFunction, data) {\n\tvar chunkIds = data[0];\n\tvar moreModules = data[1];\n\tvar runtime = data[2];\n\t// add \"moreModules\" to the modules object,\n\t// then flag all \"chunkIds\" as loaded and fire callback\n\tvar moduleId, chunkId, i = 0;\n\tif(chunkIds.some(function(id) { return installedChunks[id] !== 0; })) {\n\t\tfor(moduleId in moreModules) {\n\t\t\tif(__webpack_require__.o(moreModules, moduleId)) {\n\t\t\t\t__webpack_require__.m[moduleId] = moreModules[moduleId];\n\t\t\t}\n\t\t}\n\t\tif(runtime) var result = runtime(__webpack_require__);\n\t}\n\tif(parentChunkLoadingFunction) parentChunkLoadingFunction(data);\n\tfor(;i < chunkIds.length; i++) {\n\t\tchunkId = chunkIds[i];\n\t\tif(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {\n\t\t\tinstalledChunks[chunkId][0]();\n\t\t}\n\t\tinstalledChunks[chunkId] = 0;\n\t}\n\treturn __webpack_require__.O(result);\n}\n\nvar chunkLoadingGlobal = self[\"webpackChunkVoiceLinkDGLAB\"] = self[\"webpackChunkVoiceLinkDGLAB\"] || [];\nchunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));\nchunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));","// startup\n// Load entry module and return exports\n// This entry module depends on other loaded chunks and execution need to be delayed\nvar __webpack_exports__ = __webpack_require__.O(undefined, [504], function() { return __webpack_require__(6527); })\n__webpack_exports__ = __webpack_require__.O(__webpack_exports__);\n"],"names":["_createBlock","_component_configPage","_createElementBlock","_Fragment","_createElementVNode","style","_createVNode","_component_el_text","class","default","_withCtx","_cache","_createTextVNode","_","_component_el_link","type","href","target","script","__exports__","data","reactive","local","imageSrc","scriptClick","patternName","micName","config","getconfig","axios","get","then","response","ElMessage","message","saveconfig","post","headers","saveAndBoot","reboot","addCustomItem","scripts","text","push","removeCustomItem","index","splice","addActionItem","patterns","removeActionItem","addScriptItem","removeScriptItem","ElMessageBox","confirm","confirmButtonText","cancelButtonText","length","catch","fetchImage","base64Image","image","error","console","onMounted","name","components","configPage","render","app","createApp","App","use","ElementPlus","mount","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","exports","module","__webpack_modules__","call","m","deferred","O","result","chunkIds","fn","priority","notFulfilled","Infinity","i","fulfilled","j","Object","keys","every","key","r","n","getter","__esModule","d","a","definition","o","defineProperty","enumerable","g","globalThis","this","Function","e","window","obj","prop","prototype","hasOwnProperty","Symbol","toStringTag","value","installedChunks","chunkId","webpackJsonpCallback","parentChunkLoadingFunction","moreModules","runtime","some","id","chunkLoadingGlobal","self","forEach","bind","__webpack_exports__"],"sourceRoot":""} -------------------------------------------------------------------------------- /webUI/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | pnpm-debug.log* 14 | 15 | # Editor directories and files 16 | .idea 17 | .vscode 18 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | *.sw? 23 | -------------------------------------------------------------------------------- /webUI/README.md: -------------------------------------------------------------------------------- 1 | # vrclsweb 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | npm run lint 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /webUI/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /webUI/client.json: -------------------------------------------------------------------------------- 1 | { 2 | "userInfo": { 3 | "username": "testuser", 4 | "password": "abc123!" 5 | }, 6 | "baseurl": "https://whisper.boyqiu001.cn:7070", 7 | "api-ip": "127.0.0.1", 8 | "api-port": 8980, 9 | "sourceLanguage": "zh", 10 | "dglabServerIp": "", 11 | "dglabServerPort": 56742, 12 | "activateText": "", 13 | "exitText": "退出程序", 14 | "scripts": [ 15 | { 16 | "action": "1", 17 | "text": [ 18 | "测试", 19 | "可以" 20 | ], 21 | "patterns": [ 22 | { 23 | "name": "呼吸", 24 | "channel": "B", 25 | "intensity": 10, 26 | "time": 2 27 | }, 28 | { 29 | "name": "呼吸", 30 | "channel": "A", 31 | "intensity": 10, 32 | "time": 3 33 | } 34 | ] 35 | } 36 | ] 37 | } -------------------------------------------------------------------------------- /webUI/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "esnext", 5 | "baseUrl": "./", 6 | "moduleResolution": "node", 7 | "paths": { 8 | "@/*": [ 9 | "src/*" 10 | ] 11 | }, 12 | "lib": [ 13 | "esnext", 14 | "dom", 15 | "dom.iterable", 16 | "scripthost" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /webUI/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "VoiceLinkDGLAB", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "axios": "^1.7.9", 12 | "core-js": "^3.8.3", 13 | "element-plus": "^2.9.2", 14 | "vue": "^3.2.13" 15 | }, 16 | "devDependencies": { 17 | "@babel/core": "^7.12.16", 18 | "@babel/eslint-parser": "^7.12.16", 19 | "@vue/cli-plugin-babel": "~5.0.0", 20 | "@vue/cli-plugin-eslint": "~5.0.0", 21 | "@vue/cli-service": "~5.0.0", 22 | "eslint": "^7.32.0", 23 | "eslint-plugin-vue": "^8.0.3" 24 | }, 25 | "eslintConfig": { 26 | "root": true, 27 | "env": { 28 | "node": true 29 | }, 30 | "extends": [ 31 | "plugin:vue/vue3-essential", 32 | "eslint:recommended" 33 | ], 34 | "parserOptions": { 35 | "parser": "@babel/eslint-parser" 36 | }, 37 | "rules": {} 38 | }, 39 | "browserslist": [ 40 | "> 1%", 41 | "last 2 versions", 42 | "not dead", 43 | "not ie 11" 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /webUI/patterns.json: -------------------------------------------------------------------------------- 1 | { 2 | "呼吸": [ 3 | [ 4 | [ 5 | 10, 6 | 10, 7 | 10, 8 | 10 9 | ], 10 | [ 11 | 0, 12 | 0, 13 | 0, 14 | 0 15 | ] 16 | ], 17 | [ 18 | [ 19 | 10, 20 | 10, 21 | 10, 22 | 10 23 | ], 24 | [ 25 | 0, 26 | 5, 27 | 10, 28 | 20 29 | ] 30 | ], 31 | [ 32 | [ 33 | 10, 34 | 10, 35 | 10, 36 | 10 37 | ], 38 | [ 39 | 20, 40 | 25, 41 | 30, 42 | 40 43 | ] 44 | ], 45 | [ 46 | [ 47 | 10, 48 | 10, 49 | 10, 50 | 10 51 | ], 52 | [ 53 | 40, 54 | 45, 55 | 50, 56 | 60 57 | ] 58 | ], 59 | [ 60 | [ 61 | 10, 62 | 10, 63 | 10, 64 | 10 65 | ], 66 | [ 67 | 60, 68 | 65, 69 | 70, 70 | 80 71 | ] 72 | ], 73 | [ 74 | [ 75 | 10, 76 | 10, 77 | 10, 78 | 10 79 | ], 80 | [ 81 | 100, 82 | 100, 83 | 100, 84 | 100 85 | ] 86 | ], 87 | [ 88 | [ 89 | 10, 90 | 10, 91 | 10, 92 | 10 93 | ], 94 | [ 95 | 100, 96 | 100, 97 | 100, 98 | 100 99 | ] 100 | ], 101 | [ 102 | [ 103 | 10, 104 | 10, 105 | 10, 106 | 10 107 | ], 108 | [ 109 | 100, 110 | 100, 111 | 100, 112 | 100 113 | ] 114 | ], 115 | [ 116 | [ 117 | 0, 118 | 0, 119 | 0, 120 | 0 121 | ], 122 | [ 123 | 0, 124 | 0, 125 | 0, 126 | 0 127 | ] 128 | ], 129 | [ 130 | [ 131 | 0, 132 | 0, 133 | 0, 134 | 0 135 | ], 136 | [ 137 | 0, 138 | 0, 139 | 0, 140 | 0 141 | ] 142 | ], 143 | [ 144 | [ 145 | 0, 146 | 0, 147 | 0, 148 | 0 149 | ], 150 | [ 151 | 0, 152 | 0, 153 | 0, 154 | 0 155 | ] 156 | ] 157 | ], 158 | "潮汐": [ 159 | [ 160 | [ 161 | 10, 162 | 10, 163 | 10, 164 | 10 165 | ], 166 | [ 167 | 0, 168 | 0, 169 | 0, 170 | 0 171 | ] 172 | ], 173 | [ 174 | [ 175 | 10, 176 | 10, 177 | 10, 178 | 10 179 | ], 180 | [ 181 | 0, 182 | 4, 183 | 8, 184 | 17 185 | ] 186 | ], 187 | [ 188 | [ 189 | 10, 190 | 10, 191 | 10, 192 | 10 193 | ], 194 | [ 195 | 17, 196 | 21, 197 | 25, 198 | 33 199 | ] 200 | ], 201 | [ 202 | [ 203 | 10, 204 | 10, 205 | 10, 206 | 10 207 | ], 208 | [ 209 | 50, 210 | 50, 211 | 50, 212 | 50 213 | ] 214 | ], 215 | [ 216 | [ 217 | 10, 218 | 10, 219 | 10, 220 | 10 221 | ], 222 | [ 223 | 50, 224 | 54, 225 | 58, 226 | 67 227 | ] 228 | ], 229 | [ 230 | [ 231 | 10, 232 | 10, 233 | 10, 234 | 10 235 | ], 236 | [ 237 | 67, 238 | 71, 239 | 75, 240 | 83 241 | ] 242 | ], 243 | [ 244 | [ 245 | 10, 246 | 10, 247 | 10, 248 | 10 249 | ], 250 | [ 251 | 100, 252 | 100, 253 | 100, 254 | 100 255 | ] 256 | ], 257 | [ 258 | [ 259 | 10, 260 | 10, 261 | 10, 262 | 10 263 | ], 264 | [ 265 | 100, 266 | 98, 267 | 96, 268 | 92 269 | ] 270 | ], 271 | [ 272 | [ 273 | 10, 274 | 10, 275 | 10, 276 | 10 277 | ], 278 | [ 279 | 92, 280 | 90, 281 | 88, 282 | 84 283 | ] 284 | ], 285 | [ 286 | [ 287 | 10, 288 | 10, 289 | 10, 290 | 10 291 | ], 292 | [ 293 | 84, 294 | 82, 295 | 80, 296 | 76 297 | ] 298 | ], 299 | [ 300 | [ 301 | 10, 302 | 10, 303 | 10, 304 | 10 305 | ], 306 | [ 307 | 68, 308 | 68, 309 | 68, 310 | 68 311 | ] 312 | ] 313 | ], 314 | "连击": [ 315 | [ 316 | [ 317 | 10, 318 | 10, 319 | 10, 320 | 10 321 | ], 322 | [ 323 | 100, 324 | 100, 325 | 100, 326 | 100 327 | ] 328 | ], 329 | [ 330 | [ 331 | 10, 332 | 10, 333 | 10, 334 | 10 335 | ], 336 | [ 337 | 0, 338 | 0, 339 | 0, 340 | 0 341 | ] 342 | ], 343 | [ 344 | [ 345 | 10, 346 | 10, 347 | 10, 348 | 10 349 | ], 350 | [ 351 | 100, 352 | 100, 353 | 100, 354 | 100 355 | ] 356 | ], 357 | [ 358 | [ 359 | 10, 360 | 10, 361 | 10, 362 | 10 363 | ], 364 | [ 365 | 100, 366 | 92, 367 | 84, 368 | 67 369 | ] 370 | ], 371 | [ 372 | [ 373 | 10, 374 | 10, 375 | 10, 376 | 10 377 | ], 378 | [ 379 | 67, 380 | 58, 381 | 50, 382 | 33 383 | ] 384 | ], 385 | [ 386 | [ 387 | 10, 388 | 10, 389 | 10, 390 | 10 391 | ], 392 | [ 393 | 0, 394 | 0, 395 | 0, 396 | 0 397 | ] 398 | ], 399 | [ 400 | [ 401 | 10, 402 | 10, 403 | 10, 404 | 10 405 | ], 406 | [ 407 | 0, 408 | 0, 409 | 0, 410 | 1 411 | ] 412 | ], 413 | [ 414 | [ 415 | 10, 416 | 10, 417 | 10, 418 | 10 419 | ], 420 | [ 421 | 2, 422 | 2, 423 | 2, 424 | 2 425 | ] 426 | ] 427 | ], 428 | "快速按捏": [ 429 | [ 430 | [ 431 | 10, 432 | 10, 433 | 10, 434 | 10 435 | ], 436 | [ 437 | 0, 438 | 0, 439 | 0, 440 | 0 441 | ] 442 | ], 443 | [ 444 | [ 445 | 10, 446 | 10, 447 | 10, 448 | 10 449 | ], 450 | [ 451 | 100, 452 | 100, 453 | 100, 454 | 100 455 | ] 456 | ], 457 | [ 458 | [ 459 | 0, 460 | 0, 461 | 0, 462 | 0 463 | ], 464 | [ 465 | 0, 466 | 0, 467 | 0, 468 | 0 469 | ] 470 | ] 471 | ], 472 | "按捏渐强": [ 473 | [ 474 | [ 475 | 10, 476 | 10, 477 | 10, 478 | 10 479 | ], 480 | [ 481 | 0, 482 | 0, 483 | 0, 484 | 0 485 | ] 486 | ], 487 | [ 488 | [ 489 | 10, 490 | 10, 491 | 10, 492 | 10 493 | ], 494 | [ 495 | 29, 496 | 29, 497 | 29, 498 | 29 499 | ] 500 | ], 501 | [ 502 | [ 503 | 10, 504 | 10, 505 | 10, 506 | 10 507 | ], 508 | [ 509 | 0, 510 | 0, 511 | 0, 512 | 0 513 | ] 514 | ], 515 | [ 516 | [ 517 | 10, 518 | 10, 519 | 10, 520 | 10 521 | ], 522 | [ 523 | 52, 524 | 52, 525 | 52, 526 | 52 527 | ] 528 | ], 529 | [ 530 | [ 531 | 10, 532 | 10, 533 | 10, 534 | 10 535 | ], 536 | [ 537 | 2, 538 | 2, 539 | 2, 540 | 2 541 | ] 542 | ], 543 | [ 544 | [ 545 | 10, 546 | 10, 547 | 10, 548 | 10 549 | ], 550 | [ 551 | 73, 552 | 73, 553 | 73, 554 | 73 555 | ] 556 | ], 557 | [ 558 | [ 559 | 10, 560 | 10, 561 | 10, 562 | 10 563 | ], 564 | [ 565 | 0, 566 | 0, 567 | 0, 568 | 0 569 | ] 570 | ], 571 | [ 572 | [ 573 | 10, 574 | 10, 575 | 10, 576 | 10 577 | ], 578 | [ 579 | 87, 580 | 87, 581 | 87, 582 | 87 583 | ] 584 | ], 585 | [ 586 | [ 587 | 10, 588 | 10, 589 | 10, 590 | 10 591 | ], 592 | [ 593 | 0, 594 | 0, 595 | 0, 596 | 0 597 | ] 598 | ], 599 | [ 600 | [ 601 | 10, 602 | 10, 603 | 10, 604 | 10 605 | ], 606 | [ 607 | 100, 608 | 100, 609 | 100, 610 | 100 611 | ] 612 | ], 613 | [ 614 | [ 615 | 10, 616 | 10, 617 | 10, 618 | 10 619 | ], 620 | [ 621 | 0, 622 | 0, 623 | 0, 624 | 0 625 | ] 626 | ] 627 | ], 628 | "心跳节奏": [ 629 | [ 630 | [ 631 | 110, 632 | 110, 633 | 110, 634 | 110 635 | ], 636 | [ 637 | 100, 638 | 100, 639 | 100, 640 | 100 641 | ] 642 | ], 643 | [ 644 | [ 645 | 110, 646 | 110, 647 | 110, 648 | 110 649 | ], 650 | [ 651 | 100, 652 | 100, 653 | 100, 654 | 100 655 | ] 656 | ], 657 | [ 658 | [ 659 | 10, 660 | 10, 661 | 10, 662 | 10 663 | ], 664 | [ 665 | 0, 666 | 0, 667 | 0, 668 | 0 669 | ] 670 | ], 671 | [ 672 | [ 673 | 10, 674 | 10, 675 | 10, 676 | 10 677 | ], 678 | [ 679 | 0, 680 | 0, 681 | 0, 682 | 0 683 | ] 684 | ], 685 | [ 686 | [ 687 | 10, 688 | 10, 689 | 10, 690 | 10 691 | ], 692 | [ 693 | 0, 694 | 0, 695 | 0, 696 | 0 697 | ] 698 | ], 699 | [ 700 | [ 701 | 10, 702 | 10, 703 | 10, 704 | 10 705 | ], 706 | [ 707 | 0, 708 | 0, 709 | 0, 710 | 0 711 | ] 712 | ], 713 | [ 714 | [ 715 | 10, 716 | 10, 717 | 10, 718 | 10 719 | ], 720 | [ 721 | 0, 722 | 0, 723 | 0, 724 | 0 725 | ] 726 | ], 727 | [ 728 | [ 729 | 10, 730 | 10, 731 | 10, 732 | 10 733 | ], 734 | [ 735 | 75, 736 | 75, 737 | 75, 738 | 75 739 | ] 740 | ], 741 | [ 742 | [ 743 | 10, 744 | 10, 745 | 10, 746 | 10 747 | ], 748 | [ 749 | 75, 750 | 77, 751 | 79, 752 | 83 753 | ] 754 | ], 755 | [ 756 | [ 757 | 10, 758 | 10, 759 | 10, 760 | 10 761 | ], 762 | [ 763 | 83, 764 | 85, 765 | 88, 766 | 92 767 | ] 768 | ], 769 | [ 770 | [ 771 | 10, 772 | 10, 773 | 10, 774 | 10 775 | ], 776 | [ 777 | 100, 778 | 100, 779 | 100, 780 | 100 781 | ] 782 | ], 783 | [ 784 | [ 785 | 10, 786 | 10, 787 | 10, 788 | 10 789 | ], 790 | [ 791 | 0, 792 | 0, 793 | 0, 794 | 0 795 | ] 796 | ], 797 | [ 798 | [ 799 | 10, 800 | 10, 801 | 10, 802 | 10 803 | ], 804 | [ 805 | 0, 806 | 0, 807 | 0, 808 | 0 809 | ] 810 | ], 811 | [ 812 | [ 813 | 10, 814 | 10, 815 | 10, 816 | 10 817 | ], 818 | [ 819 | 0, 820 | 0, 821 | 0, 822 | 0 823 | ] 824 | ], 825 | [ 826 | [ 827 | 10, 828 | 10, 829 | 10, 830 | 10 831 | ], 832 | [ 833 | 0, 834 | 0, 835 | 0, 836 | 0 837 | ] 838 | ], 839 | [ 840 | [ 841 | 10, 842 | 10, 843 | 10, 844 | 10 845 | ], 846 | [ 847 | 0, 848 | 0, 849 | 0, 850 | 0 851 | ] 852 | ] 853 | ], 854 | "压缩": [ 855 | [ 856 | [ 857 | 25, 858 | 25, 859 | 24, 860 | 24 861 | ], 862 | [ 863 | 100, 864 | 100, 865 | 100, 866 | 100 867 | ] 868 | ], 869 | [ 870 | [ 871 | 24, 872 | 23, 873 | 23, 874 | 23 875 | ], 876 | [ 877 | 100, 878 | 100, 879 | 100, 880 | 100 881 | ] 882 | ], 883 | [ 884 | [ 885 | 22, 886 | 22, 887 | 22, 888 | 21 889 | ], 890 | [ 891 | 100, 892 | 100, 893 | 100, 894 | 100 895 | ] 896 | ], 897 | [ 898 | [ 899 | 21, 900 | 21, 901 | 20, 902 | 20 903 | ], 904 | [ 905 | 100, 906 | 100, 907 | 100, 908 | 100 909 | ] 910 | ], 911 | [ 912 | [ 913 | 20, 914 | 19, 915 | 19, 916 | 19 917 | ], 918 | [ 919 | 100, 920 | 100, 921 | 100, 922 | 100 923 | ] 924 | ], 925 | [ 926 | [ 927 | 18, 928 | 18, 929 | 18, 930 | 17 931 | ], 932 | [ 933 | 100, 934 | 100, 935 | 100, 936 | 100 937 | ] 938 | ], 939 | [ 940 | [ 941 | 17, 942 | 16, 943 | 16, 944 | 16 945 | ], 946 | [ 947 | 100, 948 | 100, 949 | 100, 950 | 100 951 | ] 952 | ], 953 | [ 954 | [ 955 | 15, 956 | 15, 957 | 15, 958 | 14 959 | ], 960 | [ 961 | 100, 962 | 100, 963 | 100, 964 | 100 965 | ] 966 | ], 967 | [ 968 | [ 969 | 14, 970 | 14, 971 | 13, 972 | 13 973 | ], 974 | [ 975 | 100, 976 | 100, 977 | 100, 978 | 100 979 | ] 980 | ], 981 | [ 982 | [ 983 | 13, 984 | 12, 985 | 12, 986 | 12 987 | ], 988 | [ 989 | 100, 990 | 100, 991 | 100, 992 | 100 993 | ] 994 | ], 995 | [ 996 | [ 997 | 11, 998 | 11, 999 | 11, 1000 | 10 1001 | ], 1002 | [ 1003 | 100, 1004 | 100, 1005 | 100, 1006 | 100 1007 | ] 1008 | ], 1009 | [ 1010 | [ 1011 | 10, 1012 | 10, 1013 | 10, 1014 | 10 1015 | ], 1016 | [ 1017 | 100, 1018 | 100, 1019 | 100, 1020 | 100 1021 | ] 1022 | ], 1023 | [ 1024 | [ 1025 | 10, 1026 | 10, 1027 | 10, 1028 | 10 1029 | ], 1030 | [ 1031 | 100, 1032 | 100, 1033 | 100, 1034 | 100 1035 | ] 1036 | ], 1037 | [ 1038 | [ 1039 | 10, 1040 | 10, 1041 | 10, 1042 | 10 1043 | ], 1044 | [ 1045 | 100, 1046 | 100, 1047 | 100, 1048 | 100 1049 | ] 1050 | ], 1051 | [ 1052 | [ 1053 | 10, 1054 | 10, 1055 | 10, 1056 | 10 1057 | ], 1058 | [ 1059 | 100, 1060 | 100, 1061 | 100, 1062 | 100 1063 | ] 1064 | ], 1065 | [ 1066 | [ 1067 | 10, 1068 | 10, 1069 | 10, 1070 | 10 1071 | ], 1072 | [ 1073 | 100, 1074 | 100, 1075 | 100, 1076 | 100 1077 | ] 1078 | ], 1079 | [ 1080 | [ 1081 | 10, 1082 | 10, 1083 | 10, 1084 | 10 1085 | ], 1086 | [ 1087 | 100, 1088 | 100, 1089 | 100, 1090 | 100 1091 | ] 1092 | ], 1093 | [ 1094 | [ 1095 | 10, 1096 | 10, 1097 | 10, 1098 | 10 1099 | ], 1100 | [ 1101 | 100, 1102 | 100, 1103 | 100, 1104 | 100 1105 | ] 1106 | ], 1107 | [ 1108 | [ 1109 | 10, 1110 | 10, 1111 | 10, 1112 | 10 1113 | ], 1114 | [ 1115 | 100, 1116 | 100, 1117 | 100, 1118 | 100 1119 | ] 1120 | ], 1121 | [ 1122 | [ 1123 | 10, 1124 | 10, 1125 | 10, 1126 | 10 1127 | ], 1128 | [ 1129 | 100, 1130 | 100, 1131 | 100, 1132 | 100 1133 | ] 1134 | ], 1135 | [ 1136 | [ 1137 | 10, 1138 | 10, 1139 | 10, 1140 | 10 1141 | ], 1142 | [ 1143 | 100, 1144 | 100, 1145 | 100, 1146 | 100 1147 | ] 1148 | ] 1149 | ], 1150 | "节奏步伐": [ 1151 | [ 1152 | [ 1153 | 10, 1154 | 10, 1155 | 10, 1156 | 10 1157 | ], 1158 | [ 1159 | 0, 1160 | 0, 1161 | 0, 1162 | 0 1163 | ] 1164 | ], 1165 | [ 1166 | [ 1167 | 10, 1168 | 10, 1169 | 10, 1170 | 10 1171 | ], 1172 | [ 1173 | 0, 1174 | 5, 1175 | 10, 1176 | 20 1177 | ] 1178 | ], 1179 | [ 1180 | [ 1181 | 10, 1182 | 10, 1183 | 10, 1184 | 10 1185 | ], 1186 | [ 1187 | 20, 1188 | 25, 1189 | 30, 1190 | 40 1191 | ] 1192 | ], 1193 | [ 1194 | [ 1195 | 10, 1196 | 10, 1197 | 10, 1198 | 10 1199 | ], 1200 | [ 1201 | 40, 1202 | 45, 1203 | 50, 1204 | 60 1205 | ] 1206 | ], 1207 | [ 1208 | [ 1209 | 10, 1210 | 10, 1211 | 10, 1212 | 10 1213 | ], 1214 | [ 1215 | 60, 1216 | 65, 1217 | 70, 1218 | 80 1219 | ] 1220 | ], 1221 | [ 1222 | [ 1223 | 10, 1224 | 10, 1225 | 10, 1226 | 10 1227 | ], 1228 | [ 1229 | 100, 1230 | 100, 1231 | 100, 1232 | 100 1233 | ] 1234 | ], 1235 | [ 1236 | [ 1237 | 10, 1238 | 10, 1239 | 10, 1240 | 10 1241 | ], 1242 | [ 1243 | 0, 1244 | 0, 1245 | 0, 1246 | 0 1247 | ] 1248 | ], 1249 | [ 1250 | [ 1251 | 10, 1252 | 10, 1253 | 10, 1254 | 10 1255 | ], 1256 | [ 1257 | 0, 1258 | 6, 1259 | 12, 1260 | 25 1261 | ] 1262 | ], 1263 | [ 1264 | [ 1265 | 10, 1266 | 10, 1267 | 10, 1268 | 10 1269 | ], 1270 | [ 1271 | 25, 1272 | 31, 1273 | 38, 1274 | 50 1275 | ] 1276 | ], 1277 | [ 1278 | [ 1279 | 10, 1280 | 10, 1281 | 10, 1282 | 10 1283 | ], 1284 | [ 1285 | 50, 1286 | 56, 1287 | 62, 1288 | 75 1289 | ] 1290 | ], 1291 | [ 1292 | [ 1293 | 10, 1294 | 10, 1295 | 10, 1296 | 10 1297 | ], 1298 | [ 1299 | 100, 1300 | 100, 1301 | 100, 1302 | 100 1303 | ] 1304 | ], 1305 | [ 1306 | [ 1307 | 10, 1308 | 10, 1309 | 10, 1310 | 10 1311 | ], 1312 | [ 1313 | 0, 1314 | 0, 1315 | 0, 1316 | 0 1317 | ] 1318 | ], 1319 | [ 1320 | [ 1321 | 10, 1322 | 10, 1323 | 10, 1324 | 10 1325 | ], 1326 | [ 1327 | 0, 1328 | 8, 1329 | 16, 1330 | 33 1331 | ] 1332 | ], 1333 | [ 1334 | [ 1335 | 10, 1336 | 10, 1337 | 10, 1338 | 10 1339 | ], 1340 | [ 1341 | 33, 1342 | 42, 1343 | 50, 1344 | 67 1345 | ] 1346 | ], 1347 | [ 1348 | [ 1349 | 10, 1350 | 10, 1351 | 10, 1352 | 10 1353 | ], 1354 | [ 1355 | 100, 1356 | 100, 1357 | 100, 1358 | 100 1359 | ] 1360 | ], 1361 | [ 1362 | [ 1363 | 10, 1364 | 10, 1365 | 10, 1366 | 10 1367 | ], 1368 | [ 1369 | 0, 1370 | 0, 1371 | 0, 1372 | 0 1373 | ] 1374 | ], 1375 | [ 1376 | [ 1377 | 10, 1378 | 10, 1379 | 10, 1380 | 10 1381 | ], 1382 | [ 1383 | 0, 1384 | 12, 1385 | 25, 1386 | 50 1387 | ] 1388 | ], 1389 | [ 1390 | [ 1391 | 10, 1392 | 10, 1393 | 10, 1394 | 10 1395 | ], 1396 | [ 1397 | 100, 1398 | 100, 1399 | 100, 1400 | 100 1401 | ] 1402 | ], 1403 | [ 1404 | [ 1405 | 10, 1406 | 10, 1407 | 10, 1408 | 10 1409 | ], 1410 | [ 1411 | 0, 1412 | 0, 1413 | 0, 1414 | 0 1415 | ] 1416 | ], 1417 | [ 1418 | [ 1419 | 10, 1420 | 10, 1421 | 10, 1422 | 10 1423 | ], 1424 | [ 1425 | 100, 1426 | 100, 1427 | 100, 1428 | 100 1429 | ] 1430 | ], 1431 | [ 1432 | [ 1433 | 10, 1434 | 10, 1435 | 10, 1436 | 10 1437 | ], 1438 | [ 1439 | 0, 1440 | 0, 1441 | 0, 1442 | 0 1443 | ] 1444 | ], 1445 | [ 1446 | [ 1447 | 10, 1448 | 10, 1449 | 10, 1450 | 10 1451 | ], 1452 | [ 1453 | 100, 1454 | 100, 1455 | 100, 1456 | 100 1457 | ] 1458 | ], 1459 | [ 1460 | [ 1461 | 10, 1462 | 10, 1463 | 10, 1464 | 10 1465 | ], 1466 | [ 1467 | 0, 1468 | 0, 1469 | 0, 1470 | 0 1471 | ] 1472 | ], 1473 | [ 1474 | [ 1475 | 10, 1476 | 10, 1477 | 10, 1478 | 10 1479 | ], 1480 | [ 1481 | 100, 1482 | 100, 1483 | 100, 1484 | 100 1485 | ] 1486 | ], 1487 | [ 1488 | [ 1489 | 10, 1490 | 10, 1491 | 10, 1492 | 10 1493 | ], 1494 | [ 1495 | 0, 1496 | 0, 1497 | 0, 1498 | 0 1499 | ] 1500 | ], 1501 | [ 1502 | [ 1503 | 10, 1504 | 10, 1505 | 10, 1506 | 10 1507 | ], 1508 | [ 1509 | 100, 1510 | 100, 1511 | 100, 1512 | 100 1513 | ] 1514 | ] 1515 | ], 1516 | "颗粒摩擦": [ 1517 | [ 1518 | [ 1519 | 10, 1520 | 10, 1521 | 10, 1522 | 10 1523 | ], 1524 | [ 1525 | 100, 1526 | 100, 1527 | 100, 1528 | 100 1529 | ] 1530 | ], 1531 | [ 1532 | [ 1533 | 10, 1534 | 10, 1535 | 10, 1536 | 10 1537 | ], 1538 | [ 1539 | 100, 1540 | 100, 1541 | 100, 1542 | 100 1543 | ] 1544 | ], 1545 | [ 1546 | [ 1547 | 10, 1548 | 10, 1549 | 10, 1550 | 10 1551 | ], 1552 | [ 1553 | 100, 1554 | 100, 1555 | 100, 1556 | 100 1557 | ] 1558 | ], 1559 | [ 1560 | [ 1561 | 10, 1562 | 10, 1563 | 10, 1564 | 10 1565 | ], 1566 | [ 1567 | 0, 1568 | 0, 1569 | 0, 1570 | 0 1571 | ] 1572 | ] 1573 | ], 1574 | "渐变弹跳": [ 1575 | [ 1576 | [ 1577 | 10, 1578 | 10, 1579 | 10, 1580 | 10 1581 | ], 1582 | [ 1583 | 1, 1584 | 1, 1585 | 1, 1586 | 1 1587 | ] 1588 | ], 1589 | [ 1590 | [ 1591 | 10, 1592 | 10, 1593 | 10, 1594 | 10 1595 | ], 1596 | [ 1597 | 1, 1598 | 9, 1599 | 18, 1600 | 34 1601 | ] 1602 | ], 1603 | [ 1604 | [ 1605 | 10, 1606 | 10, 1607 | 10, 1608 | 10 1609 | ], 1610 | [ 1611 | 34, 1612 | 42, 1613 | 50, 1614 | 67 1615 | ] 1616 | ], 1617 | [ 1618 | [ 1619 | 10, 1620 | 10, 1621 | 10, 1622 | 10 1623 | ], 1624 | [ 1625 | 100, 1626 | 100, 1627 | 100, 1628 | 100 1629 | ] 1630 | ], 1631 | [ 1632 | [ 1633 | 0, 1634 | 0, 1635 | 0, 1636 | 0 1637 | ], 1638 | [ 1639 | 0, 1640 | 0, 1641 | 0, 1642 | 0 1643 | ] 1644 | ], 1645 | [ 1646 | [ 1647 | 0, 1648 | 0, 1649 | 0, 1650 | 0 1651 | ], 1652 | [ 1653 | 0, 1654 | 0, 1655 | 0, 1656 | 0 1657 | ] 1658 | ] 1659 | ], 1660 | "波浪涟漪": [ 1661 | [ 1662 | [ 1663 | 10, 1664 | 10, 1665 | 10, 1666 | 10 1667 | ], 1668 | [ 1669 | 0, 1670 | 0, 1671 | 0, 1672 | 0 1673 | ] 1674 | ], 1675 | [ 1676 | [ 1677 | 10, 1678 | 10, 1679 | 10, 1680 | 10 1681 | ], 1682 | [ 1683 | 0, 1684 | 12, 1685 | 25, 1686 | 50 1687 | ] 1688 | ], 1689 | [ 1690 | [ 1691 | 10, 1692 | 10, 1693 | 10, 1694 | 10 1695 | ], 1696 | [ 1697 | 100, 1698 | 100, 1699 | 100, 1700 | 100 1701 | ] 1702 | ], 1703 | [ 1704 | [ 1705 | 10, 1706 | 10, 1707 | 10, 1708 | 10 1709 | ], 1710 | [ 1711 | 73, 1712 | 73, 1713 | 73, 1714 | 73 1715 | ] 1716 | ] 1717 | ], 1718 | "雨水冲刷": [ 1719 | [ 1720 | [ 1721 | 10, 1722 | 10, 1723 | 10, 1724 | 10 1725 | ], 1726 | [ 1727 | 34, 1728 | 34, 1729 | 34, 1730 | 34 1731 | ] 1732 | ], 1733 | [ 1734 | [ 1735 | 10, 1736 | 10, 1737 | 10, 1738 | 10 1739 | ], 1740 | [ 1741 | 34, 1742 | 42, 1743 | 50, 1744 | 67 1745 | ] 1746 | ], 1747 | [ 1748 | [ 1749 | 10, 1750 | 10, 1751 | 10, 1752 | 10 1753 | ], 1754 | [ 1755 | 100, 1756 | 100, 1757 | 100, 1758 | 100 1759 | ] 1760 | ], 1761 | [ 1762 | [ 1763 | 10, 1764 | 10, 1765 | 10, 1766 | 10 1767 | ], 1768 | [ 1769 | 100, 1770 | 100, 1771 | 100, 1772 | 100 1773 | ] 1774 | ], 1775 | [ 1776 | [ 1777 | 10, 1778 | 10, 1779 | 10, 1780 | 10 1781 | ], 1782 | [ 1783 | 100, 1784 | 100, 1785 | 100, 1786 | 100 1787 | ] 1788 | ], 1789 | [ 1790 | [ 1791 | 0, 1792 | 0, 1793 | 0, 1794 | 0 1795 | ], 1796 | [ 1797 | 0, 1798 | 0, 1799 | 0, 1800 | 0 1801 | ] 1802 | ], 1803 | [ 1804 | [ 1805 | 0, 1806 | 0, 1807 | 0, 1808 | 0 1809 | ], 1810 | [ 1811 | 0, 1812 | 0, 1813 | 0, 1814 | 0 1815 | ] 1816 | ] 1817 | ], 1818 | "变速敲击": [ 1819 | [ 1820 | [ 1821 | 10, 1822 | 10, 1823 | 10, 1824 | 10 1825 | ], 1826 | [ 1827 | 100, 1828 | 100, 1829 | 100, 1830 | 100 1831 | ] 1832 | ], 1833 | [ 1834 | [ 1835 | 10, 1836 | 10, 1837 | 10, 1838 | 10 1839 | ], 1840 | [ 1841 | 100, 1842 | 100, 1843 | 100, 1844 | 100 1845 | ] 1846 | ], 1847 | [ 1848 | [ 1849 | 10, 1850 | 10, 1851 | 10, 1852 | 10 1853 | ], 1854 | [ 1855 | 100, 1856 | 100, 1857 | 100, 1858 | 100 1859 | ] 1860 | ], 1861 | [ 1862 | [ 1863 | 10, 1864 | 10, 1865 | 10, 1866 | 10 1867 | ], 1868 | [ 1869 | 0, 1870 | 0, 1871 | 0, 1872 | 0 1873 | ] 1874 | ], 1875 | [ 1876 | [ 1877 | 10, 1878 | 10, 1879 | 10, 1880 | 10 1881 | ], 1882 | [ 1883 | 0, 1884 | 0, 1885 | 0, 1886 | 0 1887 | ] 1888 | ], 1889 | [ 1890 | [ 1891 | 10, 1892 | 10, 1893 | 10, 1894 | 10 1895 | ], 1896 | [ 1897 | 0, 1898 | 0, 1899 | 0, 1900 | 0 1901 | ] 1902 | ], 1903 | [ 1904 | [ 1905 | 10, 1906 | 10, 1907 | 10, 1908 | 10 1909 | ], 1910 | [ 1911 | 0, 1912 | 0, 1913 | 0, 1914 | 0 1915 | ] 1916 | ], 1917 | [ 1918 | [ 1919 | 110, 1920 | 110, 1921 | 110, 1922 | 110 1923 | ], 1924 | [ 1925 | 100, 1926 | 100, 1927 | 100, 1928 | 100 1929 | ] 1930 | ], 1931 | [ 1932 | [ 1933 | 110, 1934 | 110, 1935 | 110, 1936 | 110 1937 | ], 1938 | [ 1939 | 100, 1940 | 100, 1941 | 100, 1942 | 100 1943 | ] 1944 | ], 1945 | [ 1946 | [ 1947 | 110, 1948 | 110, 1949 | 110, 1950 | 110 1951 | ], 1952 | [ 1953 | 100, 1954 | 100, 1955 | 100, 1956 | 100 1957 | ] 1958 | ], 1959 | [ 1960 | [ 1961 | 110, 1962 | 110, 1963 | 110, 1964 | 110 1965 | ], 1966 | [ 1967 | 100, 1968 | 100, 1969 | 100, 1970 | 100 1971 | ] 1972 | ], 1973 | [ 1974 | [ 1975 | 0, 1976 | 0, 1977 | 0, 1978 | 0 1979 | ], 1980 | [ 1981 | 0, 1982 | 0, 1983 | 0, 1984 | 0 1985 | ] 1986 | ] 1987 | ], 1988 | "信号灯": [ 1989 | [ 1990 | [ 1991 | 197, 1992 | 197, 1993 | 197, 1994 | 197 1995 | ], 1996 | [ 1997 | 100, 1998 | 100, 1999 | 100, 2000 | 100 2001 | ] 2002 | ], 2003 | [ 2004 | [ 2005 | 197, 2006 | 197, 2007 | 197, 2008 | 197 2009 | ], 2010 | [ 2011 | 100, 2012 | 100, 2013 | 100, 2014 | 100 2015 | ] 2016 | ], 2017 | [ 2018 | [ 2019 | 197, 2020 | 197, 2021 | 197, 2022 | 197 2023 | ], 2024 | [ 2025 | 100, 2026 | 100, 2027 | 100, 2028 | 100 2029 | ] 2030 | ], 2031 | [ 2032 | [ 2033 | 197, 2034 | 197, 2035 | 197, 2036 | 197 2037 | ], 2038 | [ 2039 | 100, 2040 | 100, 2041 | 100, 2042 | 100 2043 | ] 2044 | ], 2045 | [ 2046 | [ 2047 | 10, 2048 | 10, 2049 | 10, 2050 | 10 2051 | ], 2052 | [ 2053 | 0, 2054 | 0, 2055 | 0, 2056 | 0 2057 | ] 2058 | ], 2059 | [ 2060 | [ 2061 | 10, 2062 | 10, 2063 | 10, 2064 | 10 2065 | ], 2066 | [ 2067 | 0, 2068 | 8, 2069 | 16, 2070 | 33 2071 | ] 2072 | ], 2073 | [ 2074 | [ 2075 | 10, 2076 | 10, 2077 | 10, 2078 | 10 2079 | ], 2080 | [ 2081 | 33, 2082 | 42, 2083 | 50, 2084 | 67 2085 | ] 2086 | ], 2087 | [ 2088 | [ 2089 | 10, 2090 | 10, 2091 | 10, 2092 | 10 2093 | ], 2094 | [ 2095 | 100, 2096 | 100, 2097 | 100, 2098 | 100 2099 | ] 2100 | ] 2101 | ], 2102 | "挑逗1": [ 2103 | [ 2104 | [ 2105 | 10, 2106 | 10, 2107 | 10, 2108 | 10 2109 | ], 2110 | [ 2111 | 0, 2112 | 0, 2113 | 0, 2114 | 0 2115 | ] 2116 | ], 2117 | [ 2118 | [ 2119 | 10, 2120 | 10, 2121 | 10, 2122 | 10 2123 | ], 2124 | [ 2125 | 0, 2126 | 6, 2127 | 12, 2128 | 25 2129 | ] 2130 | ], 2131 | [ 2132 | [ 2133 | 10, 2134 | 10, 2135 | 10, 2136 | 10 2137 | ], 2138 | [ 2139 | 25, 2140 | 31, 2141 | 38, 2142 | 50 2143 | ] 2144 | ], 2145 | [ 2146 | [ 2147 | 10, 2148 | 10, 2149 | 10, 2150 | 10 2151 | ], 2152 | [ 2153 | 50, 2154 | 56, 2155 | 62, 2156 | 75 2157 | ] 2158 | ], 2159 | [ 2160 | [ 2161 | 10, 2162 | 10, 2163 | 10, 2164 | 10 2165 | ], 2166 | [ 2167 | 100, 2168 | 100, 2169 | 100, 2170 | 100 2171 | ] 2172 | ], 2173 | [ 2174 | [ 2175 | 10, 2176 | 10, 2177 | 10, 2178 | 10 2179 | ], 2180 | [ 2181 | 100, 2182 | 100, 2183 | 100, 2184 | 100 2185 | ] 2186 | ], 2187 | [ 2188 | [ 2189 | 10, 2190 | 10, 2191 | 10, 2192 | 10 2193 | ], 2194 | [ 2195 | 100, 2196 | 100, 2197 | 100, 2198 | 100 2199 | ] 2200 | ], 2201 | [ 2202 | [ 2203 | 10, 2204 | 10, 2205 | 10, 2206 | 10 2207 | ], 2208 | [ 2209 | 0, 2210 | 0, 2211 | 0, 2212 | 0 2213 | ] 2214 | ], 2215 | [ 2216 | [ 2217 | 10, 2218 | 10, 2219 | 10, 2220 | 10 2221 | ], 2222 | [ 2223 | 0, 2224 | 0, 2225 | 0, 2226 | 0 2227 | ] 2228 | ], 2229 | [ 2230 | [ 2231 | 10, 2232 | 10, 2233 | 10, 2234 | 10 2235 | ], 2236 | [ 2237 | 0, 2238 | 0, 2239 | 0, 2240 | 0 2241 | ] 2242 | ], 2243 | [ 2244 | [ 2245 | 10, 2246 | 10, 2247 | 10, 2248 | 10 2249 | ], 2250 | [ 2251 | 0, 2252 | 0, 2253 | 0, 2254 | 0 2255 | ] 2256 | ], 2257 | [ 2258 | [ 2259 | 10, 2260 | 10, 2261 | 10, 2262 | 10 2263 | ], 2264 | [ 2265 | 100, 2266 | 100, 2267 | 100, 2268 | 100 2269 | ] 2270 | ] 2271 | ], 2272 | "挑逗2": [ 2273 | [ 2274 | [ 2275 | 10, 2276 | 10, 2277 | 10, 2278 | 10 2279 | ], 2280 | [ 2281 | 1, 2282 | 1, 2283 | 1, 2284 | 1 2285 | ] 2286 | ], 2287 | [ 2288 | [ 2289 | 10, 2290 | 10, 2291 | 10, 2292 | 10 2293 | ], 2294 | [ 2295 | 1, 2296 | 4, 2297 | 6, 2298 | 12 2299 | ] 2300 | ], 2301 | [ 2302 | [ 2303 | 10, 2304 | 10, 2305 | 10, 2306 | 10 2307 | ], 2308 | [ 2309 | 12, 2310 | 15, 2311 | 18, 2312 | 23 2313 | ] 2314 | ], 2315 | [ 2316 | [ 2317 | 10, 2318 | 10, 2319 | 10, 2320 | 10 2321 | ], 2322 | [ 2323 | 23, 2324 | 26, 2325 | 28, 2326 | 34 2327 | ] 2328 | ], 2329 | [ 2330 | [ 2331 | 10, 2332 | 10, 2333 | 10, 2334 | 10 2335 | ], 2336 | [ 2337 | 34, 2338 | 37, 2339 | 40, 2340 | 45 2341 | ] 2342 | ], 2343 | [ 2344 | [ 2345 | 10, 2346 | 10, 2347 | 10, 2348 | 10 2349 | ], 2350 | [ 2351 | 45, 2352 | 48, 2353 | 50, 2354 | 56 2355 | ] 2356 | ], 2357 | [ 2358 | [ 2359 | 10, 2360 | 10, 2361 | 10, 2362 | 10 2363 | ], 2364 | [ 2365 | 56, 2366 | 59, 2367 | 62, 2368 | 67 2369 | ] 2370 | ], 2371 | [ 2372 | [ 2373 | 10, 2374 | 10, 2375 | 10, 2376 | 10 2377 | ], 2378 | [ 2379 | 67, 2380 | 70, 2381 | 72, 2382 | 78 2383 | ] 2384 | ], 2385 | [ 2386 | [ 2387 | 10, 2388 | 10, 2389 | 10, 2390 | 10 2391 | ], 2392 | [ 2393 | 78, 2394 | 81, 2395 | 84, 2396 | 89 2397 | ] 2398 | ], 2399 | [ 2400 | [ 2401 | 10, 2402 | 10, 2403 | 10, 2404 | 10 2405 | ], 2406 | [ 2407 | 100, 2408 | 100, 2409 | 100, 2410 | 100 2411 | ] 2412 | ], 2413 | [ 2414 | [ 2415 | 10, 2416 | 10, 2417 | 10, 2418 | 10 2419 | ], 2420 | [ 2421 | 100, 2422 | 100, 2423 | 100, 2424 | 100 2425 | ] 2426 | ], 2427 | [ 2428 | [ 2429 | 10, 2430 | 10, 2431 | 10, 2432 | 10 2433 | ], 2434 | [ 2435 | 0, 2436 | 0, 2437 | 0, 2438 | 0 2439 | ] 2440 | ], 2441 | [ 2442 | [ 2443 | 0, 2444 | 0, 2445 | 0, 2446 | 0 2447 | ], 2448 | [ 2449 | 0, 2450 | 0, 2451 | 0, 2452 | 0 2453 | ] 2454 | ] 2455 | ] 2456 | } -------------------------------------------------------------------------------- /webUI/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VoiceLinkVR/VoiceLinkDGLAB/398ecbd8c28812650e77c08590957cd90ed4a932/webUI/public/favicon.ico -------------------------------------------------------------------------------- /webUI/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /webUI/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | 16 | 31 | -------------------------------------------------------------------------------- /webUI/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VoiceLinkVR/VoiceLinkDGLAB/398ecbd8c28812650e77c08590957cd90ed4a932/webUI/src/assets/logo.png -------------------------------------------------------------------------------- /webUI/src/components/config-page.vue: -------------------------------------------------------------------------------- 1 | 340 | 341 | 533 | 534 | 545 | 546 | -------------------------------------------------------------------------------- /webUI/src/components/side-info.vue: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /webUI/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | import ElementPlus from 'element-plus' 4 | import 'element-plus/dist/index.css' 5 | import 'element-plus/theme-chalk/dark/css-vars.css' 6 | const app = createApp(App) 7 | app.use(ElementPlus) 8 | app.mount('#app') 9 | -------------------------------------------------------------------------------- /webUI/vue.config.js: -------------------------------------------------------------------------------- 1 | const { defineConfig } = require('@vue/cli-service') 2 | module.exports = defineConfig({ 3 | transpileDependencies: true, 4 | outputDir: '../templates', 5 | devServer: { 6 | proxy: { 7 | '/api': { 8 | target: 'http://localhost:8980', // 你的后端服务地址 9 | changeOrigin: true, 10 | }, 11 | }} 12 | }) 13 | --------------------------------------------------------------------------------