Showing
2 changed files
with
164 additions
and
37 deletions
| @@ -8,17 +8,17 @@ def llm_response(message,nerfreal:BaseReal): | @@ -8,17 +8,17 @@ def llm_response(message,nerfreal:BaseReal): | ||
| 8 | from openai import OpenAI | 8 | from openai import OpenAI |
| 9 | client = OpenAI( | 9 | client = OpenAI( |
| 10 | # 如果您没有配置环境变量,请在此处用您的API Key进行替换 | 10 | # 如果您没有配置环境变量,请在此处用您的API Key进行替换 |
| 11 | - # api_key=os.getenv("DASHSCOPE_API_KEY"), | ||
| 12 | - api_key = "localkey", | ||
| 13 | - base_url="http://127.0.0.1:5000/v1" | 11 | + api_key=os.getenv("DASHSCOPE_API_KEY"), |
| 12 | + #api_key = "localkey", | ||
| 13 | + #base_url="http://127.0.0.1:5000/v1" | ||
| 14 | # 填写DashScope SDK的base_url | 14 | # 填写DashScope SDK的base_url |
| 15 | - # base_url="https://dashscope.aliyuncs.com/compatible-mode/v1", | 15 | + base_url="https://dashscope.aliyuncs.com/compatible-mode/v1", |
| 16 | ) | 16 | ) |
| 17 | end = time.perf_counter() | 17 | end = time.perf_counter() |
| 18 | logger.info(f"llm Time init: {end-start}s") | 18 | logger.info(f"llm Time init: {end-start}s") |
| 19 | completion = client.chat.completions.create( | 19 | completion = client.chat.completions.create( |
| 20 | - model="fay-streaming", | ||
| 21 | - # model="qwen-plus", | 20 | + # model="fay-streaming", |
| 21 | + model="qwen-plus", | ||
| 22 | messages=[{'role': 'system', 'content': '你是小艺,是由艺云展陈开发的AI语音聊天机器人,回答风格精简。'}, | 22 | messages=[{'role': 'system', 'content': '你是小艺,是由艺云展陈开发的AI语音聊天机器人,回答风格精简。'}, |
| 23 | {'role': 'user', 'content': message}], | 23 | {'role': 'user', 'content': message}], |
| 24 | stream=True, | 24 | stream=True, |
| @@ -13,7 +13,6 @@ | @@ -13,7 +13,6 @@ | ||
| 13 | font-family: Arial, sans-serif; | 13 | font-family: Arial, sans-serif; |
| 14 | display: flex; | 14 | display: flex; |
| 15 | height: 100vh; | 15 | height: 100vh; |
| 16 | - overflow: hidden; | ||
| 17 | } | 16 | } |
| 18 | 17 | ||
| 19 | /* 侧边栏样式 */ | 18 | /* 侧边栏样式 */ |
| @@ -49,32 +48,24 @@ | @@ -49,32 +48,24 @@ | ||
| 49 | #sidebar-toggle { | 48 | #sidebar-toggle { |
| 50 | position: fixed; | 49 | position: fixed; |
| 51 | top: 50%; | 50 | top: 50%; |
| 52 | - left: -24px; | ||
| 53 | transform: translateY(-50%); | 51 | transform: translateY(-50%); |
| 52 | + /* left is managed by JavaScript */ | ||
| 54 | width: 48px; | 53 | width: 48px; |
| 55 | height: 48px; | 54 | height: 48px; |
| 56 | - background-color: #4285f4; | 55 | + background-color: #4285f4; /* Original color */ |
| 57 | color: white; | 56 | color: white; |
| 58 | - border: none; | 57 | + border: none; /* Original border */ |
| 59 | border-radius: 50%; | 58 | border-radius: 50%; |
| 60 | - display: flex; | 59 | + display: flex !important; /* Ensure it's displayed as flex */ |
| 61 | align-items: center; | 60 | align-items: center; |
| 62 | justify-content: center; | 61 | justify-content: center; |
| 63 | cursor: pointer; | 62 | cursor: pointer; |
| 64 | - z-index: 100; | 63 | + z-index: 1002 !important; /* Higher than media's 1000, and ensure it applies */ |
| 65 | font-size: 20px; | 64 | font-size: 20px; |
| 66 | box-shadow: 0 3px 8px rgba(0,0,0,0.2); | 65 | box-shadow: 0 3px 8px rgba(0,0,0,0.2); |
| 67 | - transition: all 0.3s ease; | ||
| 68 | - } | ||
| 69 | - | ||
| 70 | - #sidebar-toggle { | ||
| 71 | - left: 0; | ||
| 72 | - } | ||
| 73 | - | ||
| 74 | - /* 收缩状态下的切换按钮位置调整 */ | ||
| 75 | - #sidebar.collapsed #sidebar-toggle { | ||
| 76 | - left: 0; | ||
| 77 | - background-color: #4285f4; | 66 | + transition: left 0.3s ease, background-color 0.3s ease, transform 0.3s ease; |
| 67 | + opacity: 1 !important; /* Ensure opacity */ | ||
| 68 | + visibility: visible !important; /* Ensure visibility */ | ||
| 78 | } | 69 | } |
| 79 | 70 | ||
| 80 | /* 主内容区域样式 */ | 71 | /* 主内容区域样式 */ |
| @@ -177,7 +168,6 @@ | @@ -177,7 +168,6 @@ | ||
| 177 | visibility: visible !important; | 168 | visibility: visible !important; |
| 178 | opacity: 1 !important; | 169 | opacity: 1 !important; |
| 179 | } | 170 | } |
| 180 | - | ||
| 181 | /* NEW: Fullscreen media when sidebar is collapsed */ | 171 | /* NEW: Fullscreen media when sidebar is collapsed */ |
| 182 | #sidebar.collapsed ~ #main-content #media { | 172 | #sidebar.collapsed ~ #main-content #media { |
| 183 | position: fixed; | 173 | position: fixed; |
| @@ -235,9 +225,11 @@ | @@ -235,9 +225,11 @@ | ||
| 235 | </head> | 225 | </head> |
| 236 | <body> | 226 | <body> |
| 237 | 227 | ||
| 228 | +<!-- 侧边栏切换按钮 (Moved to be a direct child of body) --> | ||
| 229 | +<button id="sidebar-toggle">≪</button> | ||
| 230 | + | ||
| 238 | <!-- 侧边栏 --> | 231 | <!-- 侧边栏 --> |
| 239 | <div id="sidebar"> | 232 | <div id="sidebar"> |
| 240 | - <button id="sidebar-toggle">≪</button> | ||
| 241 | <div> | 233 | <div> |
| 242 | <div class="section-title">连接控制</div> | 234 | <div class="section-title">连接控制</div> |
| 243 | <div class="option"> | 235 | <div class="option"> |
| @@ -265,6 +257,20 @@ | @@ -265,6 +257,20 @@ | ||
| 265 | <button type="submit" class="btn btn-default">发送</button> | 257 | <button type="submit" class="btn btn-default">发送</button> |
| 266 | </form> | 258 | </form> |
| 267 | </div> | 259 | </div> |
| 260 | + | ||
| 261 | + <div> | ||
| 262 | + <div class="section-title">服务器配置</div> | ||
| 263 | + <div class="form-group"> | ||
| 264 | + <label for="ws-host">WebSocket 主机</label> | ||
| 265 | + <input type="text" class="form-control" id="ws-host" placeholder="默认使用当前主机名"> | ||
| 266 | + </div> | ||
| 267 | + <div class="form-group"> | ||
| 268 | + <label for="ws-port">WebSocket 端口</label> | ||
| 269 | + <input type="text" class="form-control" id="ws-port" placeholder="默认: 10002"> | ||
| 270 | + </div> | ||
| 271 | + <button id="save-ws-config" class="btn btn-default">保存配置</button> | ||
| 272 | + <button id="reset-ws-config" class="btn btn-default">重置配置</button> | ||
| 273 | + </div> | ||
| 268 | </div> | 274 | </div> |
| 269 | 275 | ||
| 270 | <!-- 主内容区域 --> | 276 | <!-- 主内容区域 --> |
| @@ -283,23 +289,138 @@ | @@ -283,23 +289,138 @@ | ||
| 283 | <script type="text/javascript" charset="utf-8"> | 289 | <script type="text/javascript" charset="utf-8"> |
| 284 | 290 | ||
| 285 | $(document).ready(function() { | 291 | $(document).ready(function() { |
| 292 | + var expandedSidebarLeft = '300px'; // Corresponds to #sidebar CSS width | ||
| 293 | + var collapsedSidebarLeft = '10px'; // Test: offset from edge | ||
| 294 | + | ||
| 295 | + // Function to update toggle button based on sidebar state | ||
| 296 | + function updateToggleButtonState() { | ||
| 297 | + var sidebarIsCollapsed = $('#sidebar').hasClass('collapsed'); | ||
| 298 | + console.log('[Sidebar Toggle] Sidebar collapsed state:', sidebarIsCollapsed); | ||
| 299 | + var toggleButton = $('#sidebar-toggle'); | ||
| 300 | + if (sidebarIsCollapsed) { | ||
| 301 | + // Restore intended behavior: set left, icon, and original background color | ||
| 302 | + // Relies on base CSS for top: 50% and transform: translateY(-50%) | ||
| 303 | + toggleButton.html('≫').css({ | ||
| 304 | + 'left': collapsedSidebarLeft, // This is '10px' | ||
| 305 | + 'background-color': '#4285f4', // Original color | ||
| 306 | + 'top': '50%', // Ensure it matches base CSS | ||
| 307 | + 'transform': 'translateY(-50%)' // Ensure it matches base CSS | ||
| 308 | + }); | ||
| 309 | + console.log('[Sidebar Toggle] Action: Set to collapsed state. Left:', collapsedSidebarLeft, 'HTML:', toggleButton.html()); | ||
| 310 | + } else { | ||
| 311 | + // Restore intended behavior: set left, icon, and original background color | ||
| 312 | + toggleButton.html('≪').css({ | ||
| 313 | + 'left': expandedSidebarLeft, | ||
| 314 | + 'background-color': '#4285f4', // Original color | ||
| 315 | + 'top': '50%', // Ensure it matches base CSS | ||
| 316 | + 'transform': 'translateY(-50%)' // Ensure it matches base CSS | ||
| 317 | + }); | ||
| 318 | + console.log('[Sidebar Toggle] Action: Set to expanded state. Left:', expandedSidebarLeft, 'HTML:', toggleButton.html()); | ||
| 319 | + } | ||
| 320 | + // Log applied styles to be sure | ||
| 321 | + console.log('[Sidebar Toggle] Applied style attribute:', toggleButton.attr('style')); | ||
| 322 | + console.log('[Sidebar Toggle] Computed z-index:', toggleButton.css('z-index')); | ||
| 323 | + console.log('[Sidebar Toggle] Computed opacity:', toggleButton.css('opacity')); | ||
| 324 | + console.log('[Sidebar Toggle] Computed visibility:', toggleButton.css('visibility')); | ||
| 325 | + console.log('[Sidebar Toggle] Computed display:', toggleButton.css('display')); | ||
| 326 | + console.log('[Sidebar Toggle] Offset:', toggleButton.offset()); | ||
| 327 | + console.log('[Sidebar Toggle] Position:', toggleButton.position()); | ||
| 328 | + } | ||
| 329 | + | ||
| 330 | + // Initial state setup for the toggle button | ||
| 331 | + updateToggleButtonState(); | ||
| 332 | + | ||
| 333 | + // Load saved WebSocket configuration or set defaults | ||
| 334 | + function loadWsConfig() { | ||
| 335 | + var savedWsHost = localStorage.getItem('wsHost'); | ||
| 336 | + var savedWsPort = localStorage.getItem('wsPort'); | ||
| 337 | + | ||
| 338 | + if (savedWsHost) { | ||
| 339 | + $('#ws-host').val(savedWsHost); | ||
| 340 | + } else { | ||
| 341 | + $('#ws-host').val('127.0.0.1'); // Default host | ||
| 342 | + } | ||
| 343 | + | ||
| 344 | + if (savedWsPort) { | ||
| 345 | + $('#ws-port').val(savedWsPort); | ||
| 346 | + } else { | ||
| 347 | + $('#ws-port').val('10002'); // Default port | ||
| 348 | + } | ||
| 349 | + } | ||
| 350 | + loadWsConfig(); // Load config on document ready | ||
| 351 | + | ||
| 286 | // 侧边栏切换功能 | 352 | // 侧边栏切换功能 |
| 287 | $('#sidebar-toggle').click(function() { | 353 | $('#sidebar-toggle').click(function() { |
| 288 | $('#sidebar').toggleClass('collapsed'); | 354 | $('#sidebar').toggleClass('collapsed'); |
| 289 | - | ||
| 290 | - // 切换按钮图标 | ||
| 291 | - if ($('#sidebar').hasClass('collapsed')) { | ||
| 292 | - $(this).html('≫'); | ||
| 293 | - } else { | ||
| 294 | - $(this).html('≪'); | ||
| 295 | - } | 355 | + updateToggleButtonState(); |
| 296 | }); | 356 | }); |
| 297 | 357 | ||
| 298 | - // 展开侧边栏按钮功能 | ||
| 299 | - $('#expand-sidebar').click(function() { | ||
| 300 | - $('#sidebar').removeClass('collapsed'); | ||
| 301 | - $('#sidebar-toggle').html('≪'); | 358 | + // Note: The original '#expand-sidebar'.click handler was part of the replaced block. |
| 359 | + // If an element with id #expand-sidebar exists and needs to control the sidebar, | ||
| 360 | + // its click handler should be re-implemented similar to this: | ||
| 361 | + // $('#expand-sidebar').click(function() { | ||
| 362 | + // if ($('#sidebar').hasClass('collapsed')) { | ||
| 363 | + // $('#sidebar').removeClass('collapsed'); | ||
| 364 | + // updateToggleButtonState(); | ||
| 365 | + // } | ||
| 366 | + // }); | ||
| 367 | + | ||
| 368 | + // Server configuration save and reset | ||
| 369 | + $('#save-ws-config').click(function() { | ||
| 370 | + var wsHost = $('#ws-host').val().trim(); | ||
| 371 | + var wsPort = $('#ws-port').val().trim(); | ||
| 372 | + | ||
| 373 | + if (!wsHost) { | ||
| 374 | + alert('WebSocket 主机不能为空。'); | ||
| 375 | + $('#ws-host').focus(); | ||
| 376 | + return; | ||
| 377 | + } | ||
| 378 | + if (!wsPort) { | ||
| 379 | + alert('WebSocket 端口不能为空。'); | ||
| 380 | + $('#ws-port').focus(); | ||
| 381 | + return; | ||
| 382 | + } | ||
| 383 | + | ||
| 384 | + localStorage.setItem('wsHost', wsHost); | ||
| 385 | + localStorage.setItem('wsPort', wsPort); | ||
| 386 | + | ||
| 387 | + var originalText = $(this).text(); | ||
| 388 | + $(this).text('已保存!').prop('disabled', true); | ||
| 389 | + setTimeout(function() { | ||
| 390 | + $('#save-ws-config').text(originalText).prop('disabled', false); | ||
| 391 | + }, 1500); | ||
| 392 | + | ||
| 393 | + console.log('WebSocket configuration saved: Host - ' + wsHost + ', Port - ' + wsPort); | ||
| 394 | + // alert('配置已保存!更改将在下次连接时生效或您可以手动重新连接。'); | ||
| 395 | + }); | ||
| 396 | + | ||
| 397 | + $('#reset-ws-config').click(function() { | ||
| 398 | + $('#ws-host').val('127.0.0.1'); | ||
| 399 | + $('#ws-port').val('10002'); | ||
| 400 | + // No need to explicitly remove, connectWebSocket will use defaults if inputs are changed to defaults | ||
| 401 | + // localStorage.removeItem('wsHost'); | ||
| 402 | + // localStorage.removeItem('wsPort'); | ||
| 403 | + | ||
| 404 | + var originalText = $(this).text(); | ||
| 405 | + $(this).text('已重置!').prop('disabled', true); | ||
| 406 | + | ||
| 407 | + // Also update save button to reflect that new defaults need saving | ||
| 408 | + var saveButton = $('#save-ws-config'); | ||
| 409 | + var saveButtonOriginalText = saveButton.text(); | ||
| 410 | + if (saveButton.text() !== '已保存!') { // Only change if not in 'saved' state | ||
| 411 | + saveButton.text('保存默认值'); | ||
| 412 | + } | ||
| 413 | + | ||
| 414 | + setTimeout(function() { | ||
| 415 | + $('#reset-ws-config').text(originalText).prop('disabled', false); | ||
| 416 | + if (saveButton.text() === '保存默认值') { | ||
| 417 | + saveButton.text(saveButtonOriginalText); | ||
| 418 | + } | ||
| 419 | + }, 1500); | ||
| 420 | + console.log('WebSocket configuration reset to default values in fields.'); | ||
| 421 | + // alert('配置已重置为默认值,请点击“保存配置”以应用。'); | ||
| 302 | }); | 422 | }); |
| 423 | + | ||
| 303 | // Old WebSocket code commented out | 424 | // Old WebSocket code commented out |
| 304 | // var host = window.location.hostname | 425 | // var host = window.location.hostname |
| 305 | // var ws = new WebSocket("ws://"+host+":8000/humanecho"); | 426 | // var ws = new WebSocket("ws://"+host+":8000/humanecho"); |
| @@ -412,7 +533,13 @@ | @@ -412,7 +533,13 @@ | ||
| 412 | setUsername(); | 533 | setUsername(); |
| 413 | function connectWebSocket() { | 534 | function connectWebSocket() { |
| 414 | var host = window.location.hostname; | 535 | var host = window.location.hostname; |
| 415 | - ws = new WebSocket("ws://127.0.0.1:10002"); | 536 | + // 获取WebSocket服务器地址,优先使用配置值,否则使用当前主机名 |
| 537 | + var wsHost = localStorage.getItem('wsHost') || host; | ||
| 538 | + var wsPort = localStorage.getItem('wsPort') || '10002'; | ||
| 539 | + var wsProtocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://'; | ||
| 540 | + var wsUrl = wsProtocol + wsHost + ':' + wsPort; | ||
| 541 | + console.log('Connecting to WebSocket server:', wsUrl); | ||
| 542 | + ws = new WebSocket(wsUrl); | ||
| 416 | ws.onopen = function() { | 543 | ws.onopen = function() { |
| 417 | console.log('Connected to WebSocket on port 10002'); | 544 | console.log('Connected to WebSocket on port 10002'); |
| 418 | reconnectAttempts = 0; // 重置重连次数 | 545 | reconnectAttempts = 0; // 重置重连次数 |
-
Please register or login to post a comment