Showing
5 changed files
with
194 additions
and
30 deletions
| @@ -20,13 +20,25 @@ def main(): | @@ -20,13 +20,25 @@ def main(): | ||
| 20 | """主函数""" | 20 | """主函数""" |
| 21 | st.set_page_config( | 21 | st.set_page_config( |
| 22 | page_title="Insight Agent", | 22 | page_title="Insight Agent", |
| 23 | - page_icon="", | 23 | + page_icon="🔍", |
| 24 | layout="wide" | 24 | layout="wide" |
| 25 | ) | 25 | ) |
| 26 | 26 | ||
| 27 | st.title("Insight Agent") | 27 | st.title("Insight Agent") |
| 28 | st.markdown("私有舆情数据库深度分析AI代理") | 28 | st.markdown("私有舆情数据库深度分析AI代理") |
| 29 | 29 | ||
| 30 | + # 检查URL参数 | ||
| 31 | + try: | ||
| 32 | + # 尝试使用新版本的query_params | ||
| 33 | + query_params = st.query_params | ||
| 34 | + auto_query = query_params.get('query', '') | ||
| 35 | + auto_search = query_params.get('auto_search', 'false').lower() == 'true' | ||
| 36 | + except AttributeError: | ||
| 37 | + # 兼容旧版本 | ||
| 38 | + query_params = st.experimental_get_query_params() | ||
| 39 | + auto_query = query_params.get('query', [''])[0] | ||
| 40 | + auto_search = query_params.get('auto_search', ['false'])[0].lower() == 'true' | ||
| 41 | + | ||
| 30 | # ----- 配置被硬编码 ----- | 42 | # ----- 配置被硬编码 ----- |
| 31 | # 强制使用 Kimi | 43 | # 强制使用 Kimi |
| 32 | llm_provider = "kimi" | 44 | llm_provider = "kimi" |
| @@ -40,8 +52,13 @@ def main(): | @@ -40,8 +52,13 @@ def main(): | ||
| 40 | 52 | ||
| 41 | with col1: | 53 | with col1: |
| 42 | st.header("研究查询") | 54 | st.header("研究查询") |
| 55 | + | ||
| 56 | + # 如果有自动查询,使用它作为默认值 | ||
| 57 | + default_query = auto_query if auto_query else "" | ||
| 58 | + | ||
| 43 | query = st.text_area( | 59 | query = st.text_area( |
| 44 | "请输入您要研究的问题", | 60 | "请输入您要研究的问题", |
| 61 | + value=default_query, | ||
| 45 | placeholder="例如:2025年人工智能发展趋势", | 62 | placeholder="例如:2025年人工智能发展趋势", |
| 46 | height=100 | 63 | height=100 |
| 47 | ) | 64 | ) |
| @@ -61,6 +78,12 @@ def main(): | @@ -61,6 +78,12 @@ def main(): | ||
| 61 | with col2_btn: | 78 | with col2_btn: |
| 62 | start_research = st.button("开始研究", type="primary", use_container_width=True) | 79 | start_research = st.button("开始研究", type="primary", use_container_width=True) |
| 63 | 80 | ||
| 81 | + # 自动搜索逻辑 | ||
| 82 | + if auto_search and auto_query and 'auto_search_executed' not in st.session_state: | ||
| 83 | + st.session_state.auto_search_executed = True | ||
| 84 | + start_research = True | ||
| 85 | + query = auto_query | ||
| 86 | + | ||
| 64 | # 验证配置 | 87 | # 验证配置 |
| 65 | if start_research: | 88 | if start_research: |
| 66 | if not query.strip(): | 89 | if not query.strip(): |
| @@ -20,13 +20,25 @@ def main(): | @@ -20,13 +20,25 @@ def main(): | ||
| 20 | """主函数""" | 20 | """主函数""" |
| 21 | st.set_page_config( | 21 | st.set_page_config( |
| 22 | page_title="Media Agent", | 22 | page_title="Media Agent", |
| 23 | - page_icon="", | 23 | + page_icon="🔍", |
| 24 | layout="wide" | 24 | layout="wide" |
| 25 | ) | 25 | ) |
| 26 | 26 | ||
| 27 | st.title("Media Agent") | 27 | st.title("Media Agent") |
| 28 | st.markdown("具备强大多模态能力的AI代理") | 28 | st.markdown("具备强大多模态能力的AI代理") |
| 29 | 29 | ||
| 30 | + # 检查URL参数 | ||
| 31 | + try: | ||
| 32 | + # 尝试使用新版本的query_params | ||
| 33 | + query_params = st.query_params | ||
| 34 | + auto_query = query_params.get('query', '') | ||
| 35 | + auto_search = query_params.get('auto_search', 'false').lower() == 'true' | ||
| 36 | + except AttributeError: | ||
| 37 | + # 兼容旧版本 | ||
| 38 | + query_params = st.experimental_get_query_params() | ||
| 39 | + auto_query = query_params.get('query', [''])[0] | ||
| 40 | + auto_search = query_params.get('auto_search', ['false'])[0].lower() == 'true' | ||
| 41 | + | ||
| 30 | # ----- 配置被硬编码 ----- | 42 | # ----- 配置被硬编码 ----- |
| 31 | # 强制使用 Gemini | 43 | # 强制使用 Gemini |
| 32 | llm_provider = "gemini" | 44 | llm_provider = "gemini" |
| @@ -40,8 +52,13 @@ def main(): | @@ -40,8 +52,13 @@ def main(): | ||
| 40 | 52 | ||
| 41 | with col1: | 53 | with col1: |
| 42 | st.header("研究查询") | 54 | st.header("研究查询") |
| 55 | + | ||
| 56 | + # 如果有自动查询,使用它作为默认值 | ||
| 57 | + default_query = auto_query if auto_query else "" | ||
| 58 | + | ||
| 43 | query = st.text_area( | 59 | query = st.text_area( |
| 44 | "请输入您要研究的问题", | 60 | "请输入您要研究的问题", |
| 61 | + value=default_query, | ||
| 45 | placeholder="例如:2025年人工智能发展趋势", | 62 | placeholder="例如:2025年人工智能发展趋势", |
| 46 | height=100 | 63 | height=100 |
| 47 | ) | 64 | ) |
| @@ -61,6 +78,12 @@ def main(): | @@ -61,6 +78,12 @@ def main(): | ||
| 61 | with col2_btn: | 78 | with col2_btn: |
| 62 | start_research = st.button("开始研究", type="primary", use_container_width=True) | 79 | start_research = st.button("开始研究", type="primary", use_container_width=True) |
| 63 | 80 | ||
| 81 | + # 自动搜索逻辑 | ||
| 82 | + if auto_search and auto_query and 'auto_search_executed' not in st.session_state: | ||
| 83 | + st.session_state.auto_search_executed = True | ||
| 84 | + start_research = True | ||
| 85 | + query = auto_query | ||
| 86 | + | ||
| 64 | # 验证配置 | 87 | # 验证配置 |
| 65 | if start_research: | 88 | if start_research: |
| 66 | if not query.strip(): | 89 | if not query.strip(): |
| @@ -27,6 +27,18 @@ def main(): | @@ -27,6 +27,18 @@ def main(): | ||
| 27 | st.title("Query Agent") | 27 | st.title("Query Agent") |
| 28 | st.markdown("具备强大网页搜索能力的AI代理") | 28 | st.markdown("具备强大网页搜索能力的AI代理") |
| 29 | 29 | ||
| 30 | + # 检查URL参数 | ||
| 31 | + try: | ||
| 32 | + # 尝试使用新版本的query_params | ||
| 33 | + query_params = st.query_params | ||
| 34 | + auto_query = query_params.get('query', '') | ||
| 35 | + auto_search = query_params.get('auto_search', 'false').lower() == 'true' | ||
| 36 | + except AttributeError: | ||
| 37 | + # 兼容旧版本 | ||
| 38 | + query_params = st.experimental_get_query_params() | ||
| 39 | + auto_query = query_params.get('query', [''])[0] | ||
| 40 | + auto_search = query_params.get('auto_search', ['false'])[0].lower() == 'true' | ||
| 41 | + | ||
| 30 | # ----- 配置被硬编码 ----- | 42 | # ----- 配置被硬编码 ----- |
| 31 | # 强制使用 DeepSeek | 43 | # 强制使用 DeepSeek |
| 32 | llm_provider = "deepseek" | 44 | llm_provider = "deepseek" |
| @@ -40,8 +52,13 @@ def main(): | @@ -40,8 +52,13 @@ def main(): | ||
| 40 | 52 | ||
| 41 | with col1: | 53 | with col1: |
| 42 | st.header("研究查询") | 54 | st.header("研究查询") |
| 55 | + | ||
| 56 | + # 如果有自动查询,使用它作为默认值 | ||
| 57 | + default_query = auto_query if auto_query else "" | ||
| 58 | + | ||
| 43 | query = st.text_area( | 59 | query = st.text_area( |
| 44 | "请输入您要研究的问题", | 60 | "请输入您要研究的问题", |
| 61 | + value=default_query, | ||
| 45 | placeholder="例如:2025年人工智能发展趋势", | 62 | placeholder="例如:2025年人工智能发展趋势", |
| 46 | height=100 | 63 | height=100 |
| 47 | ) | 64 | ) |
| @@ -61,6 +78,12 @@ def main(): | @@ -61,6 +78,12 @@ def main(): | ||
| 61 | with col2_btn: | 78 | with col2_btn: |
| 62 | start_research = st.button("开始研究", type="primary", use_container_width=True) | 79 | start_research = st.button("开始研究", type="primary", use_container_width=True) |
| 63 | 80 | ||
| 81 | + # 自动搜索逻辑 | ||
| 82 | + if auto_search and auto_query and 'auto_search_executed' not in st.session_state: | ||
| 83 | + st.session_state.auto_search_executed = True | ||
| 84 | + start_research = True | ||
| 85 | + query = auto_query | ||
| 86 | + | ||
| 64 | # 验证配置 | 87 | # 验证配置 |
| 65 | if start_research: | 88 | if start_research: |
| 66 | if not query.strip(): | 89 | if not query.strip(): |
| @@ -221,6 +221,7 @@ def start_app(app_name): | @@ -221,6 +221,7 @@ def start_app(app_name): | ||
| 221 | processes[app_name]['port'] | 221 | processes[app_name]['port'] |
| 222 | ) | 222 | ) |
| 223 | 223 | ||
| 224 | + | ||
| 224 | if success: | 225 | if success: |
| 225 | # 等待应用启动 | 226 | # 等待应用启动 |
| 226 | startup_success, startup_message = wait_for_app_startup(app_name, 15) | 227 | startup_success, startup_message = wait_for_app_startup(app_name, 15) |
| @@ -106,6 +106,7 @@ | @@ -106,6 +106,7 @@ | ||
| 106 | .embedded-content { | 106 | .embedded-content { |
| 107 | height: calc(100% - 60px); | 107 | height: calc(100% - 60px); |
| 108 | position: relative; | 108 | position: relative; |
| 109 | + overflow: hidden; | ||
| 109 | } | 110 | } |
| 110 | 111 | ||
| 111 | /* 控制台输出区域 */ | 112 | /* 控制台输出区域 */ |
| @@ -332,6 +333,11 @@ | @@ -332,6 +333,11 @@ | ||
| 332 | setInterval(updateTime, 1000); | 333 | setInterval(updateTime, 1000); |
| 333 | checkStatus(); | 334 | checkStatus(); |
| 334 | setInterval(checkStatus, 5000); | 335 | setInterval(checkStatus, 5000); |
| 336 | + | ||
| 337 | + // 延迟预加载iframe以确保应用启动完成 | ||
| 338 | + setTimeout(() => { | ||
| 339 | + preloadIframes(); | ||
| 340 | + }, 3000); | ||
| 335 | }); | 341 | }); |
| 336 | 342 | ||
| 337 | // Socket.IO连接 | 343 | // Socket.IO连接 |
| @@ -389,29 +395,49 @@ | @@ -389,29 +395,49 @@ | ||
| 389 | button.disabled = true; | 395 | button.disabled = true; |
| 390 | button.innerHTML = '<span class="loading"></span> 搜索中...'; | 396 | button.innerHTML = '<span class="loading"></span> 搜索中...'; |
| 391 | 397 | ||
| 392 | - fetch('/api/search', { | ||
| 393 | - method: 'POST', | ||
| 394 | - headers: { | ||
| 395 | - 'Content-Type': 'application/json', | ||
| 396 | - }, | ||
| 397 | - body: JSON.stringify({ query: query }) | ||
| 398 | - }) | ||
| 399 | - .then(response => response.json()) | ||
| 400 | - .then(data => { | ||
| 401 | - if (data.success) { | ||
| 402 | - showMessage('搜索请求已发送到所有运行中的应用', 'success'); | ||
| 403 | - } else { | ||
| 404 | - showMessage(data.message || '搜索失败', 'error'); | 398 | + // 确保所有iframe已初始化 |
| 399 | + if (!iframesInitialized) { | ||
| 400 | + preloadIframes(); | ||
| 405 | } | 401 | } |
| 406 | - }) | ||
| 407 | - .catch(error => { | ||
| 408 | - console.error('搜索错误:', error); | ||
| 409 | - showMessage('搜索请求失败', 'error'); | ||
| 410 | - }) | ||
| 411 | - .finally(() => { | 402 | + |
| 403 | + // 向所有运行中的应用发送搜索请求(通过新窗口方式避免刷新现有iframe) | ||
| 404 | + let totalRunning = 0; | ||
| 405 | + const ports = { insight: 8501, media: 8502, query: 8503 }; | ||
| 406 | + | ||
| 407 | + Object.keys(appStatus).forEach(app => { | ||
| 408 | + if (appStatus[app] === 'running') { | ||
| 409 | + totalRunning++; | ||
| 410 | + | ||
| 411 | + // 为每个应用创建一个临时的搜索iframe,避免干扰主iframe | ||
| 412 | + const searchIframe = document.createElement('iframe'); | ||
| 413 | + searchIframe.style.display = 'none'; | ||
| 414 | + searchIframe.style.position = 'absolute'; | ||
| 415 | + searchIframe.style.top = '-9999px'; | ||
| 416 | + | ||
| 417 | + const searchUrl = `http://localhost:${ports[app]}?query=${encodeURIComponent(query)}&auto_search=true`; | ||
| 418 | + console.log(`向 ${app} 发送搜索请求: ${searchUrl}`); | ||
| 419 | + | ||
| 420 | + searchIframe.src = searchUrl; | ||
| 421 | + document.body.appendChild(searchIframe); | ||
| 422 | + | ||
| 423 | + // 几秒后移除临时iframe | ||
| 424 | + setTimeout(() => { | ||
| 425 | + if (searchIframe.parentNode) { | ||
| 426 | + searchIframe.parentNode.removeChild(searchIframe); | ||
| 427 | + } | ||
| 428 | + }, 5000); | ||
| 429 | + } | ||
| 430 | + }); | ||
| 431 | + | ||
| 432 | + if (totalRunning === 0) { | ||
| 412 | button.disabled = false; | 433 | button.disabled = false; |
| 413 | button.innerHTML = '搜索'; | 434 | button.innerHTML = '搜索'; |
| 414 | - }); | 435 | + showMessage('没有运行中的应用,无法执行搜索', 'error'); |
| 436 | + } else { | ||
| 437 | + button.disabled = false; | ||
| 438 | + button.innerHTML = '搜索'; | ||
| 439 | + showMessage(`已向 ${totalRunning} 个应用发送搜索请求`, 'success'); | ||
| 440 | + } | ||
| 415 | } | 441 | } |
| 416 | 442 | ||
| 417 | // 切换应用 | 443 | // 切换应用 |
| @@ -472,6 +498,40 @@ | @@ -472,6 +498,40 @@ | ||
| 472 | consoleOutput.scrollTop = consoleOutput.scrollHeight; | 498 | consoleOutput.scrollTop = consoleOutput.scrollHeight; |
| 473 | } | 499 | } |
| 474 | 500 | ||
| 501 | + // 预加载的iframe存储 | ||
| 502 | + let preloadedIframes = {}; | ||
| 503 | + let iframesInitialized = false; | ||
| 504 | + | ||
| 505 | + // 预加载所有iframe(只执行一次) | ||
| 506 | + function preloadIframes() { | ||
| 507 | + if (iframesInitialized) return; | ||
| 508 | + | ||
| 509 | + const ports = { insight: 8501, media: 8502, query: 8503 }; | ||
| 510 | + const content = document.getElementById('embeddedContent'); | ||
| 511 | + | ||
| 512 | + for (const [app, port] of Object.entries(ports)) { | ||
| 513 | + const iframe = document.createElement('iframe'); | ||
| 514 | + iframe.src = `http://localhost:${port}`; | ||
| 515 | + iframe.style.width = '100%'; | ||
| 516 | + iframe.style.height = '100%'; | ||
| 517 | + iframe.style.border = 'none'; | ||
| 518 | + iframe.style.position = 'absolute'; | ||
| 519 | + iframe.style.top = '0'; | ||
| 520 | + iframe.style.left = '0'; | ||
| 521 | + iframe.style.display = 'none'; | ||
| 522 | + iframe.id = `iframe-${app}`; | ||
| 523 | + | ||
| 524 | + // 直接添加到content区域 | ||
| 525 | + content.appendChild(iframe); | ||
| 526 | + preloadedIframes[app] = iframe; | ||
| 527 | + | ||
| 528 | + console.log(`预加载 ${app} 应用完成`); | ||
| 529 | + } | ||
| 530 | + | ||
| 531 | + iframesInitialized = true; | ||
| 532 | + console.log('所有iframe预加载完成,准备进行无缝切换'); | ||
| 533 | + } | ||
| 534 | + | ||
| 475 | // 更新嵌入页面 | 535 | // 更新嵌入页面 |
| 476 | function updateEmbeddedPage(app) { | 536 | function updateEmbeddedPage(app) { |
| 477 | const header = document.getElementById('embeddedHeader'); | 537 | const header = document.getElementById('embeddedHeader'); |
| @@ -485,16 +545,47 @@ | @@ -485,16 +545,47 @@ | ||
| 485 | 545 | ||
| 486 | header.textContent = appNames[app] || app; | 546 | header.textContent = appNames[app] || app; |
| 487 | 547 | ||
| 488 | - // 如果应用正在运行,显示iframe | 548 | + // 如果应用正在运行,显示对应的iframe |
| 489 | if (appStatus[app] === 'running') { | 549 | if (appStatus[app] === 'running') { |
| 490 | - const ports = { insight: 8501, media: 8502, query: 8503 }; | ||
| 491 | - content.innerHTML = `<iframe src="http://localhost:${ports[app]}" style="width: 100%; height: 100%; border: none;"></iframe>`; | 550 | + // 确保iframe已初始化 |
| 551 | + if (!iframesInitialized) { | ||
| 552 | + preloadIframes(); | ||
| 553 | + } | ||
| 554 | + | ||
| 555 | + // 隐藏所有iframe | ||
| 556 | + Object.values(preloadedIframes).forEach(iframe => { | ||
| 557 | + iframe.style.display = 'none'; | ||
| 558 | + }); | ||
| 559 | + | ||
| 560 | + // 移除占位符 | ||
| 561 | + const placeholder = content.querySelector('.status-placeholder'); | ||
| 562 | + if (placeholder) { | ||
| 563 | + placeholder.remove(); | ||
| 564 | + } | ||
| 565 | + | ||
| 566 | + // 显示当前应用的iframe | ||
| 567 | + if (preloadedIframes[app]) { | ||
| 568 | + preloadedIframes[app].style.display = 'block'; | ||
| 569 | + console.log(`切换到 ${app} 应用 - 无刷新切换`); | ||
| 570 | + } | ||
| 492 | } else { | 571 | } else { |
| 493 | - content.innerHTML = ` | ||
| 494 | - <div style="display: flex; align-items: center; justify-content: center; height: 100%; color: #666; flex-direction: column;"> | 572 | + // 隐藏所有iframe |
| 573 | + Object.values(preloadedIframes).forEach(iframe => { | ||
| 574 | + iframe.style.display = 'none'; | ||
| 575 | + }); | ||
| 576 | + | ||
| 577 | + // 显示状态信息 | ||
| 578 | + let placeholder = content.querySelector('.status-placeholder'); | ||
| 579 | + if (!placeholder) { | ||
| 580 | + placeholder = document.createElement('div'); | ||
| 581 | + placeholder.className = 'status-placeholder'; | ||
| 582 | + placeholder.style.cssText = 'display: flex; align-items: center; justify-content: center; height: 100%; color: #666; flex-direction: column; position: absolute; top: 0; left: 0; width: 100%;'; | ||
| 583 | + content.appendChild(placeholder); | ||
| 584 | + } | ||
| 585 | + | ||
| 586 | + placeholder.innerHTML = ` | ||
| 495 | <div style="margin-bottom: 10px;">${appNames[app]} 未运行</div> | 587 | <div style="margin-bottom: 10px;">${appNames[app]} 未运行</div> |
| 496 | <div style="font-size: 12px;">状态: ${appStatus[app]}</div> | 588 | <div style="font-size: 12px;">状态: ${appStatus[app]}</div> |
| 497 | - </div> | ||
| 498 | `; | 589 | `; |
| 499 | } | 590 | } |
| 500 | } | 591 | } |
| @@ -514,10 +605,13 @@ | @@ -514,10 +605,13 @@ | ||
| 514 | // 更新应用状态 | 605 | // 更新应用状态 |
| 515 | function updateAppStatus(data) { | 606 | function updateAppStatus(data) { |
| 516 | for (const [app, info] of Object.entries(data)) { | 607 | for (const [app, info] of Object.entries(data)) { |
| 517 | - appStatus[app] = info.status; | 608 | + // 适配实际的API格式:{app: {status: string, port: int, output_lines: int}} |
| 609 | + const status = info.status === 'running' ? 'running' : 'stopped'; | ||
| 610 | + appStatus[app] = status; | ||
| 611 | + | ||
| 518 | const indicator = document.getElementById(`status-${app}`); | 612 | const indicator = document.getElementById(`status-${app}`); |
| 519 | if (indicator) { | 613 | if (indicator) { |
| 520 | - indicator.className = `status-indicator ${info.status}`; | 614 | + indicator.className = `status-indicator ${status}`; |
| 521 | } | 615 | } |
| 522 | } | 616 | } |
| 523 | 617 |
-
Please register or login to post a comment