From a62c8ed495b1cd2cb1e54cbb393252ee11898774 Mon Sep 17 00:00:00 2001 From: tanxing Date: Wed, 6 Aug 2025 14:08:13 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=89=8D=E7=AB=AF=E8=BE=93?= =?UTF-8?q?=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deepsearcher/backend/templates/index.html | 65 +++++++++++++++++++++++ deepsearcher/utils/log.py | 62 ++++++++++++++++++++- main.py | 21 ++++++-- 3 files changed, 144 insertions(+), 4 deletions(-) diff --git a/deepsearcher/backend/templates/index.html b/deepsearcher/backend/templates/index.html index a0ef791..465eaad 100644 --- a/deepsearcher/backend/templates/index.html +++ b/deepsearcher/backend/templates/index.html @@ -14,6 +14,7 @@ --success-color: #10b981; --error-color: #ef4444; --warning-color: #f59e0b; + --info-color: #3b82f6; } * { @@ -191,6 +192,29 @@ line-height: 1.6; } + /* 进度日志样式 */ + .progress-log { + background-color: #1e1e1e; + color: #d4d4d4; + border-radius: 6px; + padding: 16px; + font-family: 'Courier New', monospace; + font-size: 14px; + margin: 16px 0; + max-height: 300px; + overflow-y: auto; + display: none; + } + + .progress-log.visible { + display: block; + } + + .progress-log-entry { + margin: 4px 0; + line-height: 1.4; + } + footer { text-align: center; margin-top: 30px; @@ -266,6 +290,10 @@
+ + +
+

查询结果:

@@ -319,6 +347,37 @@ resultElement.classList.remove('visible'); } + // 工具函数:显示进度日志 + function showProgressLog(messages) { + const logElement = document.getElementById('progressLog'); + if (messages && messages.length > 0) { + logElement.innerHTML = messages.map(msg => + `
${escapeHtml(msg)}
` + ).join(''); + logElement.classList.add('visible'); + } else { + logElement.classList.remove('visible'); + } + } + + // 工具函数:隐藏进度日志 + function hideProgressLog() { + const logElement = document.getElementById('progressLog'); + logElement.classList.remove('visible'); + } + + // 工具函数:转义HTML特殊字符 + function escapeHtml(text) { + const map = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''' + }; + return text.replace(/[&<>"']/g, function(m) { return map[m]; }); + } + // 工具函数:设置按钮加载状态 function setButtonLoading(button, loading) { if (loading) { @@ -347,6 +406,7 @@ setButtonLoading(button, true); showStatus('loadStatus', '正在加载文件...', 'loading'); hideResult(); + hideProgressLog(); try { const response = await fetch('/load-files/', { @@ -392,6 +452,7 @@ setButtonLoading(button, true); showStatus('webLoadStatus', '正在加载网站内容...', 'loading'); hideResult(); + hideProgressLog(); try { const response = await fetch('/load-website/', { @@ -439,6 +500,7 @@ setButtonLoading(button, true); showStatus('queryStatus', '正在处理查询...', 'loading'); hideResult(); + hideProgressLog(); try { const response = await fetch(`/query/?original_query=${encodeURIComponent(queryText)}&max_iter=${maxIter}`, { @@ -455,6 +517,9 @@ document.getElementById('resultText').textContent = data.result; document.getElementById('tokenInfo').textContent = `消耗Token数: ${data.consume_token}`; showResult(); + + // 显示进度日志 + showProgressLog(data.progress_messages); } else { showStatus('queryStatus', `查询失败: ${data.detail}`, 'error'); } diff --git a/deepsearcher/utils/log.py b/deepsearcher/utils/log.py index f6771de..eedbe25 100644 --- a/deepsearcher/utils/log.py +++ b/deepsearcher/utils/log.py @@ -1,5 +1,6 @@ import logging - +import io +from typing import List from termcolor import colored @@ -50,6 +51,44 @@ class ColoredFormatter(logging.Formatter): # return super().format(record) +class StreamCaptureHandler(logging.Handler): + """ + A custom logging handler that captures log messages in a list. + + This handler stores log messages in memory so they can be retrieved later, + which is useful for sending log messages to a frontend. + """ + + def __init__(self): + super().__init__() + self.messages: List[str] = [] + + def emit(self, record): + """ + Emit a log record by storing it in the messages list. + + Args: + record: The log record to emit. + """ + log_entry = self.format(record) + self.messages.append(log_entry) + + def get_messages(self) -> List[str]: + """ + Get all captured log messages. + + Returns: + A list of captured log messages. + """ + return self.messages.copy() + + def clear_messages(self): + """ + Clear all captured log messages. + """ + self.messages.clear() + + # config log dev_logger = logging.getLogger("dev") dev_formatter = ColoredFormatter("%(asctime)s - %(levelname)s - %(message)s") @@ -60,8 +99,11 @@ dev_logger.setLevel(logging.INFO) progress_logger = logging.getLogger("progress") progress_handler = logging.StreamHandler() +progress_capture_handler = StreamCaptureHandler() progress_handler.setFormatter(ColoredFormatter("%(message)s")) +progress_capture_handler.setFormatter(logging.Formatter("%(message)s")) progress_logger.addHandler(progress_handler) +progress_logger.addHandler(progress_capture_handler) progress_logger.setLevel(logging.INFO) dev_mode = False @@ -158,3 +200,21 @@ def color_print(message, **kwargs): **kwargs: Additional keyword arguments to pass to the logger. """ progress_logger.info(message) + progress_handler.flush() + + +def get_progress_messages() -> List[str]: + """ + Get all captured progress messages. + + Returns: + A list of captured progress messages. + """ + return progress_capture_handler.get_messages() + + +def clear_progress_messages(): + """ + Clear all captured progress messages. + """ + progress_capture_handler.clear_messages() \ No newline at end of file diff --git a/main.py b/main.py index 9a29d40..78916c4 100644 --- a/main.py +++ b/main.py @@ -155,11 +155,12 @@ def load_files( HTTPException: If loading files fails. """ try: + # 修复batch_size为None时的问题 load_from_local_files( paths_or_directory=paths, collection_name=collection_name, collection_description=collection_description, - batch_size=batch_size, + batch_size=batch_size if batch_size is not None else 256, # 提供默认值 ) return {"message": "Files loaded successfully."} except Exception as e: @@ -205,11 +206,12 @@ def load_website( HTTPException: If loading website content fails. """ try: + # 修复batch_size为None时的问题 load_from_website( urls=urls, collection_name=collection_name, collection_description=collection_description, - batch_size=batch_size, + batch_size=batch_size if batch_size is not None else 256, # 提供默认值 ) return {"message": "Website loaded successfully."} except Exception as e: @@ -244,8 +246,21 @@ def perform_query( HTTPException: If the query fails. """ try: + # 清除之前的进度消息 + from deepsearcher.utils.log import clear_progress_messages + clear_progress_messages() + result_text, _, consume_token = query(original_query, max_iter) - return {"result": result_text, "consume_token": consume_token} + + # 获取进度消息 + from deepsearcher.utils.log import get_progress_messages + progress_messages = get_progress_messages() + + return { + "result": result_text, + "consume_token": consume_token, + "progress_messages": progress_messages + } except Exception as e: raise HTTPException(status_code=500, detail=str(e))