From 2c8559dd18c4a989057c5f88e5e848f9fc7a3c31 Mon Sep 17 00:00:00 2001 From: Wenruli Date: Thu, 11 Sep 2025 17:11:30 +0800 Subject: [PATCH 01/11] =?UTF-8?q?fix:ollama=E4=BF=AE=E5=A4=8D=E6=B7=B1?= =?UTF-8?q?=E5=BA=A6=E6=80=9D=E8=80=83=E6=B2=A1=E6=9C=89=E5=8E=86=E5=8F=B2?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bisheng/interface/llms/custom_ollama.py | 296 ------------------ 1 file changed, 296 deletions(-) diff --git a/src/backend/bisheng/interface/llms/custom_ollama.py b/src/backend/bisheng/interface/llms/custom_ollama.py index 580ff67ee..49e94bd5d 100644 --- a/src/backend/bisheng/interface/llms/custom_ollama.py +++ b/src/backend/bisheng/interface/llms/custom_ollama.py @@ -117,67 +117,6 @@ class CustomChatOllamaWithReasoning(ChatOllama): ) yield chunk - def _generate( - self, - messages: List[BaseMessage], - stop: Optional[List[str]] = None, - run_manager: Optional[CallbackManagerForLLMRun] = None, - **kwargs - ) -> Any: - """Handle non-streaming calls, extract think content to reasoning_content field.""" - result = super()._generate(messages, stop=stop, run_manager=run_manager, **kwargs) - self._process_generations(result.generations, is_async=False) - return result - - async def _agenerate( - self, - messages: List[BaseMessage], - stop: Optional[List[str]] = None, - run_manager: Optional[AsyncCallbackManagerForLLMRun] = None, - **kwargs - ) -> ChatResult: - """Handle async non-streaming calls, extract think content to reasoning_content field.""" - result = await super()._agenerate(messages, stop=stop, run_manager=run_manager, **kwargs) - self._process_generations(result.generations, is_async=True) - return result - - def _stream( - self, - messages: List[BaseMessage], - stop: Optional[List[str]] = None, - run_manager: Optional[CallbackManagerForLLMRun] = None, - **kwargs - ) -> Iterator[ChatGenerationChunk]: - """Process streaming output, modifying chunks to add reasoning_content field.""" - logger.debug("CustomChatOllamaWithReasoning._stream called") - self._reset_think_state() - - try: - for chunk in super()._stream(messages, stop=stop, run_manager=run_manager, **kwargs): - yield from self._process_stream_chunk(chunk) - except Exception as e: - logger.error(f"Error in CustomChatOllamaWithReasoning stream processing: {e}") - raise - - async def _astream( - self, - messages: List[BaseMessage], - stop: Optional[List[str]] = None, - run_manager: Optional[AsyncCallbackManagerForLLMRun] = None, - **kwargs - ) -> AsyncIterator[ChatGenerationChunk]: - """Process async streaming output, modifying chunks to add reasoning_content field.""" - logger.debug("CustomChatOllamaWithReasoning._astream called") - self._reset_think_state() - - try: - async for chunk in super()._astream(messages, stop=stop, run_manager=run_manager, **kwargs): - for processed_chunk in self._process_stream_chunk(chunk): - yield processed_chunk - except Exception as e: - logger.error(f"Error in CustomChatOllamaWithReasoning async stream processing: {e}") - raise - # Helper methods for better code organization def _reset_think_state(self) -> None: @@ -243,238 +182,3 @@ class CustomChatOllamaWithReasoning(ChatOllama): ), generation_info=generation_info, ) - - def _process_generations(self, generations: List, is_async: bool = False) -> None: - """Process generations to extract think content.""" - if not generations: - return - - async_prefix = "Async " if is_async else "" - - for generation in generations: - try: - self._process_generation_message(generation, async_prefix) - self._process_generation_text(generation, async_prefix) - except Exception as e: - logger.error(f"{async_prefix}Error processing generation: {e}") - - def _process_generation_message(self, generation, async_prefix: str) -> None: - """Process generation message content.""" - if not (hasattr(generation, 'message') and - hasattr(generation.message, 'content')): - return - - original_content = generation.message.content - reasoning_content, cleaned_content = self._extract_think_content(original_content) - - generation.message.content = cleaned_content - - if not hasattr(generation.message, 'additional_kwargs'): - generation.message.additional_kwargs = {} - generation.message.additional_kwargs['reasoning_content'] = reasoning_content or None - - logger.debug( - f"{async_prefix}Original content length: {len(original_content)}, " - f"reasoning length: {len(reasoning_content)}, " - f"processed length: {len(cleaned_content)}" - ) - - def _process_generation_text(self, generation, async_prefix: str) -> None: - """Process generation text content.""" - if not hasattr(generation, 'text'): - return - - original_text = generation.text - reasoning_content, cleaned_text = self._extract_think_content(original_text) - generation.text = cleaned_text - - logger.debug( - f"{async_prefix}Original text length: {len(original_text)}, " - f"processed length: {len(cleaned_text)}" - ) - - def _extract_think_content(self, content: str) -> Tuple[str, str]: - """ - Extract think tag content and return (reasoning_content, cleaned_content). - - Args: - content: Original content with potential think tags - - Returns: - Tuple of (reasoning_content, cleaned_content) - """ - if not content: - return "", "" - - # Extract content inside think tags - think_matches = self.THINK_PATTERN.findall(content) - reasoning_content = '\n'.join(think_matches).strip() if think_matches else '' - - # Remove entire ... blocks - cleaned_content = self.THINK_REMOVAL_PATTERN.sub('', content).strip() - - return reasoning_content, cleaned_content - - def _process_stream_chunk(self, chunk: ChatGenerationChunk) -> Iterator[ChatGenerationChunk]: - """Process a single stream chunk and yield modified chunks.""" - if not (hasattr(chunk, 'message') and hasattr(chunk.message, 'content')): - # Add reasoning_content field for chunks without content - self._ensure_reasoning_content_field(chunk) - yield chunk - return - - content = chunk.message.content or "" - - if not content: - self._ensure_reasoning_content_field(chunk) - yield chunk - return - - logger.debug(f"Processing chunk content: '{content}', in_think state: {self.in_think}") - - # Process content with think tags - modified_chunks = self._process_chunk_with_think_tags(chunk, content) - - # Yield all modified chunks - yield from modified_chunks - - def _ensure_reasoning_content_field(self, chunk: ChatGenerationChunk) -> None: - """Ensure chunk has reasoning_content field set to None.""" - if not hasattr(chunk, 'message') or not chunk.message: - return - - if not hasattr(chunk.message, 'additional_kwargs'): - chunk.message.additional_kwargs = {} - chunk.message.additional_kwargs['reasoning_content'] = None - - def _process_chunk_with_think_tags( - self, - original_chunk: ChatGenerationChunk, - content: str - ) -> List[ChatGenerationChunk]: - """ - Process chunk containing think tags and return list of modified chunks. - - Args: - original_chunk: Original chunk from parent stream - content: Text content of the chunk - - Returns: - List of modified chunks with proper content/reasoning_content fields - """ - chunks = [] - current_pos = 0 - - while current_pos < len(content): - if not self.in_think: - current_pos = self._process_outside_think_tags( - chunks, original_chunk, content, current_pos - ) - else: - current_pos = self._process_inside_think_tags( - chunks, original_chunk, content, current_pos - ) - - if current_pos < 0: # Break condition - break - - return chunks - - def _process_outside_think_tags( - self, - chunks: List[ChatGenerationChunk], - original_chunk: ChatGenerationChunk, - content: str, - current_pos: int - ) -> int: - """Process content when outside think tags.""" - think_start = content.find(self.THINK_START_TAG, current_pos) - - if think_start != -1: - # Found tag, output content before it - before_think = content[current_pos:think_start] - if before_think: - chunk = self._create_content_chunk(original_chunk, before_think) - chunks.append(chunk) - - # Enter think state, skip tag and optional newline - new_pos = think_start + len(self.THINK_START_TAG) - if new_pos < len(content) and content[new_pos] == '\n': - new_pos += 1 - - self.in_think = True - return new_pos - else: - # No tag found, output remaining content - remaining = content[current_pos:] - if remaining: - chunk = self._create_content_chunk(original_chunk, remaining) - chunks.append(chunk) - return -1 # Break condition - - def _process_inside_think_tags( - self, - chunks: List[ChatGenerationChunk], - original_chunk: ChatGenerationChunk, - content: str, - current_pos: int - ) -> int: - """Process content when inside think tags.""" - think_end = content.find(self.THINK_END_TAG, current_pos) - - if think_end != -1: - # Found tag, output reasoning content - reasoning = content[current_pos:think_end] - if reasoning: - chunk = self._create_reasoning_chunk(original_chunk, reasoning) - chunks.append(chunk) - - # Exit think state, skip tag and optional newline - new_pos = think_end + len(self.THINK_END_TAG) - if new_pos < len(content) and content[new_pos] == '\n': - new_pos += 1 - - self.in_think = False - return new_pos - else: - # No tag found, output remaining reasoning content - remaining_reasoning = content[current_pos:] - if remaining_reasoning: - chunk = self._create_reasoning_chunk(original_chunk, remaining_reasoning) - chunks.append(chunk) - return -1 # Break condition - - def _create_content_chunk( - self, - original_chunk: ChatGenerationChunk, - content: str - ) -> ChatGenerationChunk: - """Create a chunk for regular content.""" - return ChatGenerationChunk( - message=AIMessageChunk( - content=content, - additional_kwargs={'reasoning_content': None} - ), - generation_info=original_chunk.generation_info - ) - - def _create_reasoning_chunk( - self, - original_chunk: ChatGenerationChunk, - reasoning_content: str - ) -> ChatGenerationChunk: - """Create a chunk for reasoning content.""" - return ChatGenerationChunk( - message=AIMessageChunk( - content="", - additional_kwargs={'reasoning_content': reasoning_content} - ), - generation_info=original_chunk.generation_info - ) - - # Deprecated method kept for backward compatibility - def _remove_think_tags(self, content: str) -> str: - """Remove think tags, keeping only content outside tags. (Deprecated)""" - logger.warning("_remove_think_tags is deprecated, use _extract_think_content instead") - _, cleaned_content = self._extract_think_content(content) - return cleaned_content From d6c4ac49b08f5d38ae197b6e7fece66bb5ec6581 Mon Sep 17 00:00:00 2001 From: lmr <350416710@qq.com> Date: Thu, 11 Sep 2025 17:56:04 +0800 Subject: [PATCH 02/11] =?UTF-8?q?fix:=20bug=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/KnowledgePage/AdjustFilesUpload.tsx | 3 ++- .../KnowledgePage/components/FileUploadStep2.tsx | 2 +- .../KnowledgePage/components/FileUploadStep4.tsx | 13 +++++++++---- .../pages/KnowledgePage/components/Paragraphs.tsx | 14 ++++++++++---- .../KnowledgePage/components/PreviewFile.tsx | 3 ++- .../KnowledgePage/components/PreviewResult.tsx | 15 +++++++++++++-- 6 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/frontend/platform/src/pages/KnowledgePage/AdjustFilesUpload.tsx b/src/frontend/platform/src/pages/KnowledgePage/AdjustFilesUpload.tsx index d7bed3f32..645dc566c 100644 --- a/src/frontend/platform/src/pages/KnowledgePage/AdjustFilesUpload.tsx +++ b/src/frontend/platform/src/pages/KnowledgePage/AdjustFilesUpload.tsx @@ -112,17 +112,18 @@ export default function AdjustFilesUpload() { const fileName = initFileData.name || initFileData.file_name || ''; const fileSuffix = fileName.split('.').pop()?.toLowerCase() || 'txt'; const fileType = ['xlsx', 'xls', 'csv'].includes(fileSuffix) ? 'table' : 'file'; + const [resultFiles, setResultFiles] = useState([ { id: initFileData.id, fileName: initFileData.name || initFileData.file_name, // 兼容字段名 file_path: initFileData.filePath || initFileData.object_name, // 兼容文件路径 suffix: initFileData.suffix || initFileData.file_name?.split(".").pop() || "", // 解析后缀 + previewUrl:initFileData.previewUrl, fileType: fileType, split_rule: getParsedSplitRule(initFileData.split_rule) // 传入转换后的配置对象 } ]); - console.log(initFileData,78); const [segmentRules, setSegmentRules] = useState(null); const [isSubmitting, setIsSubmitting] = useState(false); diff --git a/src/frontend/platform/src/pages/KnowledgePage/components/FileUploadStep2.tsx b/src/frontend/platform/src/pages/KnowledgePage/components/FileUploadStep2.tsx index 7b5f9bb67..a608ef748 100644 --- a/src/frontend/platform/src/pages/KnowledgePage/components/FileUploadStep2.tsx +++ b/src/frontend/platform/src/pages/KnowledgePage/components/FileUploadStep2.tsx @@ -56,7 +56,6 @@ const FileUploadStep2 = forwardRef(({ step, resultFiles, isSubmitting, onNext, o }); const displayMode: DisplayModeType | null = useMemo(() => { if (!resultFiles || resultFiles.length === 0) return null; -console.log(resultFiles,55555); const hasTableFiles = resultFiles.some(file => file.fileType === 'table'); const hasDocumentFiles = resultFiles.some(file => file.fileType === 'file'); @@ -338,6 +337,7 @@ const useFileProcessingRules = (initialStrategies, resultFiles, kid, splitRule) id: file.id, filePath: file.file_path, fileName: file.fileName, + previewUrl:file.previewUrl, suffix: file.suffix, fileType: file.fileType, excelRule: file.fileType === 'table' ? { diff --git a/src/frontend/platform/src/pages/KnowledgePage/components/FileUploadStep4.tsx b/src/frontend/platform/src/pages/KnowledgePage/components/FileUploadStep4.tsx index 57c26509a..174aa8e6d 100644 --- a/src/frontend/platform/src/pages/KnowledgePage/components/FileUploadStep4.tsx +++ b/src/frontend/platform/src/pages/KnowledgePage/components/FileUploadStep4.tsx @@ -44,7 +44,7 @@ console.log(data,kId,44); // 轮询函数 const pollFilesStatus = async () => { - console.log(kid,fileIdsRef.current,22); + console.log(kid,kId,fileIdsRef.current,22); try { const res = await readFileByLibDatabase({ @@ -110,11 +110,16 @@ useEffect(() => { } }, [files]); console.log('fukes :>> ', data, files); - - const [details] = useKnowledgeDetails([kid]) + let finalId = kid; + if ( kId) { + finalId = kId.replace(/\D/g, ''); + } + const [details] = useKnowledgeDetails([finalId]) const handleCreateFlow = async (params) => { const model = await getLlmDefaultModel() - const flow = await getKnowledgeDefaultFlowTemplate(kid, details[0].name, model.model_id) + console.log(details,9999); + + const flow = await getKnowledgeDefaultFlowTemplate(finalId, details[0].name, model.model_id) const res = await captureAndAlertRequestErrorHoc(createWorkflowApi( "文档知识库问答-" + generateUUID(5), "检索文档知识库,根据检索结果进行回答。", diff --git a/src/frontend/platform/src/pages/KnowledgePage/components/Paragraphs.tsx b/src/frontend/platform/src/pages/KnowledgePage/components/Paragraphs.tsx index ae490d9c1..6c995147d 100644 --- a/src/frontend/platform/src/pages/KnowledgePage/components/Paragraphs.tsx +++ b/src/frontend/platform/src/pages/KnowledgePage/components/Paragraphs.tsx @@ -55,7 +55,7 @@ export default function Paragraphs({ fileId, onBack }) { const searchInputRef = useRef(null); const isChangingRef = useRef(false); const [isInitReady, setIsInitReady] = useState(false); - + const [previewUrl,setPreviewUrl] = useState() // 1. 修复:URL乱码(添加decodeURIComponent)+ 确保数据顺序 const fetchFileUrl = useCallback(async (fileId) => { console.log('获取文件URL:', fileId); @@ -66,15 +66,20 @@ export default function Paragraphs({ fileId, onBack }) { const res = await getFilePathApi(fileId); const pares = await getFileBboxApi(fileId) setPartitions(pares) - console.log('getFilePathApi 响应:', res,pares); + console.log('getFilePathApi 响应:', res.original_url,pares); // 修复:提取URL并解码(解决中文/特殊字符乱码) let url; - if (res.data) { - url = res.data.url || res.data.filePath || res.data; + if (res) { + url = res.original_url || res.data.filePath || res.url; + if(res.preview_url){ + setPreviewUrl(res.preview_url) + } } else { url = res.url || res.filePath || res; } + console.log(url,2222); + const trimmedUrl = (url || '').trim(); if (!trimmedUrl) { @@ -363,6 +368,7 @@ export default function Paragraphs({ fileId, onBack }) { skipToStep: 2, fileId: selectedFileId, fileData: { + previewUrl:previewUrl, id: currentFile?.id, name: currentFile?.name, split_rule: currentFile?.split_rule || currentFile?.fullData?.split_rule, diff --git a/src/frontend/platform/src/pages/KnowledgePage/components/PreviewFile.tsx b/src/frontend/platform/src/pages/KnowledgePage/components/PreviewFile.tsx index 848c20437..b9ab9b4a3 100644 --- a/src/frontend/platform/src/pages/KnowledgePage/components/PreviewFile.tsx +++ b/src/frontend/platform/src/pages/KnowledgePage/components/PreviewFile.tsx @@ -45,8 +45,9 @@ export default function PreviewFile({ const targetFile = matchedRawFile || file; const fileParseType = targetFile.parse_type; - const fileName = targetFile.name || file.fileName; + const fileName = targetFile.name || file.fileName||file.name; const suffix = useMemo(() => { +console.log(fileName,3322); return fileName?.split('.').pop()?.toLowerCase() || ''; }, [fileName]); diff --git a/src/frontend/platform/src/pages/KnowledgePage/components/PreviewResult.tsx b/src/frontend/platform/src/pages/KnowledgePage/components/PreviewResult.tsx index 15755c5e9..af641bce7 100644 --- a/src/frontend/platform/src/pages/KnowledgePage/components/PreviewResult.tsx +++ b/src/frontend/platform/src/pages/KnowledgePage/components/PreviewResult.tsx @@ -29,6 +29,8 @@ export type Partition = { [key in string]: { text: string, type: string, part_id: string } } export default function PreviewResult({showPreview ,previewCount, rules, step, applyEachCell, cellGeneralConfig,kId,handlePreviewResult }: IProps) { + console.log(showPreview,rules,567); + const { id } = useParams() const [chunks, setChunks] = useState([]) // 当前文件分块 @@ -71,13 +73,22 @@ export default function PreviewResult({showPreview ,previewCount, rules, step, a const { fileList, pageHeaderFooter, chunkOverlap, chunkSize, enableFormula, forceOcr, knowledgeId , retainImages, separator, separatorRule } = rules const currentFile = fileList.find(file => file.id === selectId) + + let preview_url + if(showPreview){ + preview_url = currentFile.previewUrl ||currentFile?.filePath + }else { + preview_url=currentFile?.filePath + } + console.log(preview_url ,currentFile,6789); + captureAndAlertRequestErrorHoc(previewFileSplitApi({ // 缓存(修改规则后需要清空缓存, 切换文件使用缓存) // previewCount变更时为重新预览分段操作,不使用缓存 cache: prevPreviewCountMapRef.current[currentFile.id] === previewCount, knowledge_id: id||kId, file_list: [{ - file_path: currentFile?.filePath, + file_path:preview_url, excel_rule: applyEachCell ? currentFile.excelRule : { ...cellGeneralConfig } @@ -151,7 +162,7 @@ export default function PreviewResult({showPreview ,previewCount, rules, step, a setChunks={setChunks} partitions={partitions} />} -
+
{/* 下拉框 - 右上角 */} {(step === 3 ||(step===2 &&showPreview))&&(
From 1f12335d1eb7976d704f7f6cf7e6c6a169f50508 Mon Sep 17 00:00:00 2001 From: GuoQing Zhang Date: Thu, 11 Sep 2025 17:56:39 +0800 Subject: [PATCH 03/11] =?UTF-8?q?feat:=20minio=E7=9A=84share=E5=9C=B0?= =?UTF-8?q?=E5=9D=80=E6=94=AF=E6=8C=81=E9=85=8D=E7=BD=AE=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E6=98=AFhttps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/bisheng/chat/client.py | 13 ++----------- src/backend/bisheng/settings.py | 2 ++ src/backend/bisheng/utils/minio_client.py | 6 +++--- .../gpts/tools/code_interpreter/base_executor.py | 6 +++--- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/src/backend/bisheng/chat/client.py b/src/backend/bisheng/chat/client.py index 4eee8ef2c..a20c4ba5a 100644 --- a/src/backend/bisheng/chat/client.py +++ b/src/backend/bisheng/chat/client.py @@ -2,8 +2,6 @@ import json from queue import Queue from typing import Dict, Callable, List -from bisheng.utils import generate_uuid -from bisheng_langchain.gpts.message_types import LiberalToolMessage from fastapi import WebSocket, status, Request from langchain_core.messages import AIMessage, HumanMessage, BaseMessage, ToolMessage from loguru import logger @@ -20,7 +18,9 @@ from bisheng.database.models.flow import FlowType from bisheng.database.models.message import ChatMessageDao, ChatMessage as ChatMessageModel from bisheng.database.models.session import MessageSession, MessageSessionDao from bisheng.settings import settings +from bisheng.utils import generate_uuid from bisheng.utils.threadpool import thread_pool +from bisheng_langchain.gpts.message_types import LiberalToolMessage class ChatClient: @@ -301,16 +301,7 @@ class ChatClient: _ = await self.add_message('bot', one.json(), 'tool_result') else: logger.warning("unexpected message type") - # for one in result: - # if isinstance(one, AIMessage): - # answer += one.content - # todo: 后续优化代码解释器的实现方案,保证输出的文件可以公开访问 ugly solve - # 获取minio的share地址,把share域名去掉, 为毕昇的部署方案特殊处理下 - for one in self.gpts_agent.tools: - if one.name == "bisheng_code_interpreter": - minio_share = settings.get_minio_conf().sharepoint - answer = answer.replace(f"http://{minio_share}", "") answer_end_type = 'end' # 如果是流式的llm则用end_cover结束, 覆盖之前流式的输出 if getattr(self.gpts_agent.llm, 'streaming', False): diff --git a/src/backend/bisheng/settings.py b/src/backend/bisheng/settings.py index 003f43bee..51784a264 100644 --- a/src/backend/bisheng/settings.py +++ b/src/backend/bisheng/settings.py @@ -78,6 +78,8 @@ class MinioConf(BaseModel): cert_check: Optional[bool] = Field(default=False, description="是否校验证书") endpoint: Optional[str] = Field(default="127.0.0.1:9000", description="minio 地址") sharepoint: Optional[str] = Field(default="127.0.0.1:9000", description="minio 公开访问地址") + share_schema: Optional[bool] = Field(default=False, description="minio 公开访问地址是否使用https") + share_cert_check: Optional[bool] = Field(default=False, description="minio 公开访问地址是否校验证书") access_key: Optional[str] = Field(default="minioadmin", description="minio 用户名") secret_key: Optional[str] = Field(default="minioadmin", description="minio 密码") public_bucket: Optional[str] = Field(default="bisheng", diff --git a/src/backend/bisheng/utils/minio_client.py b/src/backend/bisheng/utils/minio_client.py index 5438a1765..064c0fe52 100644 --- a/src/backend/bisheng/utils/minio_client.py +++ b/src/backend/bisheng/utils/minio_client.py @@ -32,8 +32,8 @@ class MinioClient: endpoint=_MinioConf.sharepoint, access_key=_MinioConf.access_key, secret_key=_MinioConf.secret_key, - secure=_MinioConf.schema, - cert_check=_MinioConf.cert_check) + secure=_MinioConf.share_schema, + cert_check=_MinioConf.share_cert_check) self._init_bucket_conf() @@ -165,7 +165,7 @@ class MinioClient: 获取minio share host """ minio_share = _MinioConf.sharepoint - if _MinioConf.schema: + if _MinioConf.share_schema: return f'https://{minio_share}' return f'http://{minio_share}' diff --git a/src/backend/bisheng_langchain/gpts/tools/code_interpreter/base_executor.py b/src/backend/bisheng_langchain/gpts/tools/code_interpreter/base_executor.py index fd407a802..bb0325c8b 100644 --- a/src/backend/bisheng_langchain/gpts/tools/code_interpreter/base_executor.py +++ b/src/backend/bisheng_langchain/gpts/tools/code_interpreter/base_executor.py @@ -32,8 +32,8 @@ class BaseExecutor(ABC): endpoint=self.minio.get('sharepoint'), access_key=self.minio.get('access_key'), secret_key=self.minio.get('secret_key'), - secure=self.minio.get('schema'), - cert_check=self.minio.get('cert_check'), + secure=self.minio.get('share_schema', False), + cert_check=self.minio.get('share_cert_check', False), ) bucket = self.minio.get('tmp_bucket', 'tmp-dir') logger.debug( @@ -54,4 +54,4 @@ class BaseExecutor(ABC): ) def close(self) -> None: - pass \ No newline at end of file + pass From c145dc57811a9533425a0ffe8b672be98b6da19b Mon Sep 17 00:00:00 2001 From: dolphin Date: Thu, 11 Sep 2025 19:05:52 +0800 Subject: [PATCH 04/11] =?UTF-8?q?fix:=20=E5=AE=A1=E8=AE=A1=E4=BC=9A?= =?UTF-8?q?=E8=AF=9D=E5=A4=B4=E5=83=8F=E5=B1=95=E7=A4=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bs-comp/chatComponent/MessageBs.tsx | 3 ++- .../bs-comp/chatComponent/messageStore.ts | 14 +++++++++- .../platform/src/controllers/API/flow.ts | 7 +++++ .../src/pages/BuildPage/CreateApp.tsx | 2 +- .../editAssistant/EditAssistantDialog.tsx | 2 +- .../BuildPage/flow/FlowChat/messageStore.ts | 13 +++++++++- .../src/pages/BuildPage/skills/l2Edit.tsx | 2 +- .../ChatAppPage/components/ChatPanne.tsx | 4 +-- .../src/pages/DataSetPage/CreateDataSet.tsx | 2 +- .../pages/LogPage/useAppLog/appChatDetail.tsx | 26 ++++++++++++++++--- 10 files changed, 63 insertions(+), 12 deletions(-) diff --git a/src/frontend/platform/src/components/bs-comp/chatComponent/MessageBs.tsx b/src/frontend/platform/src/components/bs-comp/chatComponent/MessageBs.tsx index e6e60be06..5d4682cf5 100644 --- a/src/frontend/platform/src/components/bs-comp/chatComponent/MessageBs.tsx +++ b/src/frontend/platform/src/components/bs-comp/chatComponent/MessageBs.tsx @@ -54,7 +54,7 @@ export const ReasoningLog = ({ loading, msg = '' }) => {
} -export default function MessageBs({ debug, mark = false, logo, data, onUnlike = () => { }, onSource, onMarkClick,chat }: { logo: string, data: ChatMessageType, onUnlike?: any, onSource?: any }) { +export default function MessageBs({ debug, mark = false, logo, data, onUnlike = () => { }, onSource, onMarkClick, chat }: { logo: string, data: ChatMessageType, onUnlike?: any, onSource?: any }) { const avatarColor = colorList[ (data.sender?.split('').reduce((num, s) => num + s.charCodeAt(), 0) || 0) % colorList.length ] @@ -84,6 +84,7 @@ export default function MessageBs({ debug, mark = false, logo, data, onUnlike =
+ {logo} {data.message.toString() ?
{} diff --git a/src/frontend/platform/src/components/bs-comp/chatComponent/messageStore.ts b/src/frontend/platform/src/components/bs-comp/chatComponent/messageStore.ts index 8c834ea3c..c47875235 100644 --- a/src/frontend/platform/src/components/bs-comp/chatComponent/messageStore.ts +++ b/src/frontend/platform/src/components/bs-comp/chatComponent/messageStore.ts @@ -62,9 +62,21 @@ const handleHistoryMsg = (data: any[]): ChatMessageType[] => { // 未考虑的情况暂不处理 console.error('消息 to JSON error :>> ', e); } + + // hack + let chatKey = undefined + if (typeof message !== 'string') { + // 优先 input + if ('input' in message) { + chatKey = 'input' + } else { + Object.keys(message)[0] + } + } + return { ...other, - chatKey: typeof message === 'string' ? undefined : Object.keys(message)[0], + chatKey, end: true, files: files ? JSON.parse(files) : [], isSend: !is_bot, diff --git a/src/frontend/platform/src/controllers/API/flow.ts b/src/frontend/platform/src/controllers/API/flow.ts index 7f64b158b..df21d5456 100644 --- a/src/frontend/platform/src/controllers/API/flow.ts +++ b/src/frontend/platform/src/controllers/API/flow.ts @@ -118,6 +118,13 @@ export async function getFlowApi(flowId: string, version: string = 'v1'): Promis return await axios.get(`/api/${version}/flows/${flowId}`) } +/** + * 删除的技能 工作流详情 + */ +export async function getDeleteFlowApi(chatId: string): Promise { + return await axios.get(`/api/v1/chat/info?chat_id=${chatId}`) +} + /** * Saves a new flow to the database. * diff --git a/src/frontend/platform/src/pages/BuildPage/CreateApp.tsx b/src/frontend/platform/src/pages/BuildPage/CreateApp.tsx index fc51e6a2e..e9f21ff68 100644 --- a/src/frontend/platform/src/pages/BuildPage/CreateApp.tsx +++ b/src/frontend/platform/src/pages/BuildPage/CreateApp.tsx @@ -246,7 +246,7 @@ ${t('build.exampleTwo', { ns: 'bs' })} {appType === AppType.ASSISTANT ? t('assistantAvatar') : t('workflowAvatar')} - +
diff --git a/src/frontend/platform/src/pages/BuildPage/assistant/editAssistant/EditAssistantDialog.tsx b/src/frontend/platform/src/pages/BuildPage/assistant/editAssistant/EditAssistantDialog.tsx index 2eee5f48a..b2ca16211 100644 --- a/src/frontend/platform/src/pages/BuildPage/assistant/editAssistant/EditAssistantDialog.tsx +++ b/src/frontend/platform/src/pages/BuildPage/assistant/editAssistant/EditAssistantDialog.tsx @@ -96,7 +96,7 @@ export default function EditAssistantDialog({ logo, name, desc, onSave, loca }) className="mt-2" onChange={uploadAvator} > - + {errors.name &&

{errors.name}

} diff --git a/src/frontend/platform/src/pages/BuildPage/flow/FlowChat/messageStore.ts b/src/frontend/platform/src/pages/BuildPage/flow/FlowChat/messageStore.ts index 53f476eef..217011817 100644 --- a/src/frontend/platform/src/pages/BuildPage/flow/FlowChat/messageStore.ts +++ b/src/frontend/platform/src/pages/BuildPage/flow/FlowChat/messageStore.ts @@ -68,10 +68,21 @@ const handleHistoryMsg = (data: any[]): ChatMessageType[] => { // 未考虑的情况暂不处理 console.error('消息 to JSON error :>> ', e); } + // hack + let chatKey = undefined + if (typeof message !== 'string') { + // 优先 input + if ('input' in message) { + chatKey = 'input' + } else { + Object.keys(message)[0] + } + } + return { ...other, category, - chatKey: typeof message === 'string' ? undefined : Object.keys(message)[0], + chatKey, end: true, files: files ? JSON.parse(files) : [], isSend: !is_bot, diff --git a/src/frontend/platform/src/pages/BuildPage/skills/l2Edit.tsx b/src/frontend/platform/src/pages/BuildPage/skills/l2Edit.tsx index a818a293b..2989f12d8 100644 --- a/src/frontend/platform/src/pages/BuildPage/skills/l2Edit.tsx +++ b/src/frontend/platform/src/pages/BuildPage/skills/l2Edit.tsx @@ -175,7 +175,7 @@ export default function l2Edit() {
- +
diff --git a/src/frontend/platform/src/pages/ChatAppPage/components/ChatPanne.tsx b/src/frontend/platform/src/pages/ChatAppPage/components/ChatPanne.tsx index 5ad5d336e..802849c5c 100644 --- a/src/frontend/platform/src/pages/ChatAppPage/components/ChatPanne.tsx +++ b/src/frontend/platform/src/pages/ChatAppPage/components/ChatPanne.tsx @@ -281,8 +281,8 @@ export default function ChatPanne({ customWsHost = '', chatList, chat, appendHis { workflow &&
- - {chat.flow_name} + + {workflow.name}
diff --git a/src/frontend/platform/src/pages/DataSetPage/CreateDataSet.tsx b/src/frontend/platform/src/pages/DataSetPage/CreateDataSet.tsx index 6b3fdbc75..30cd13fbf 100644 --- a/src/frontend/platform/src/pages/DataSetPage/CreateDataSet.tsx +++ b/src/frontend/platform/src/pages/DataSetPage/CreateDataSet.tsx @@ -169,7 +169,7 @@ const CreateDataSet = forwardRef(({ onChange }, ref) => {
{loading &&
@@ -66,8 +70,8 @@ export default function AppChatDetail() {
{type === AppNumType.FLOW - ? loadMoreFlowHistoryMsg(fid, true)} onMarkClick={null}> - : loadMoreFlowHistoryMsg(fid, true)} onMarkClick={null}> + : loadMoreHistoryMsg(fid, true)} > } @@ -75,3 +79,19 @@ export default function AppChatDetail() {
}; + + +const useAppAvatar = (cid, flowType) => { + const [logo, setLogo] = useState('') + const [title, setTitle] = useState('') + const loadAppDetail = async () => { + const lostflow = await getDeleteFlowApi(cid) + setLogo(lostflow.flow_logo) + setTitle(lostflow.flow_name) + } + useEffect(() => { + loadAppDetail() + }, []) + + return +} \ No newline at end of file From e7146db49f4eadc60c2297a560a376e8d70052fb Mon Sep 17 00:00:00 2001 From: GuoQing Zhang Date: Thu, 11 Sep 2025 20:01:56 +0800 Subject: [PATCH 05/11] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E5=8F=B0=E5=A4=84=E7=90=86prompt=E6=97=B6=E7=9A=84?= =?UTF-8?q?=E6=8A=A5=E9=94=99=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/bisheng/api/v1/workstation.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/backend/bisheng/api/v1/workstation.py b/src/backend/bisheng/api/v1/workstation.py index c0f960c95..6fd82e067 100644 --- a/src/backend/bisheng/api/v1/workstation.py +++ b/src/backend/bisheng/api/v1/workstation.py @@ -401,10 +401,13 @@ async def chat_completions( extra['prompt'] = prompt message.extra = json.dumps(extra, ensure_ascii=False) ChatMessageDao.insert_one(message) + except MessageException as e: + error = True + final_res = str(e) except Exception as e: logger.exception(f'Error in processing the prompt') error = True - final_res = 'Error in processing the prompt' + final_res = f'Error in processing the prompt: {str(e)[-100:]}' if not error: messages = WorkStationService.get_chat_history(conversationId, 8)[:-1] From b8d3a96ffe63a0a32c12f7bc0967aa5f041e59ee Mon Sep 17 00:00:00 2001 From: GuoQing Zhang Date: Thu, 11 Sep 2025 20:38:41 +0800 Subject: [PATCH 06/11] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=85=B6?= =?UTF-8?q?=E4=BB=96=E6=8E=A5=E5=8F=A3=E6=A0=BC=E5=BC=8F=E4=BD=BF=E7=94=A8?= =?UTF-8?q?openai=E4=BD=86=E6=98=AFchunk=5Fsize=E4=B8=8D=E6=94=AF=E6=8C=81?= =?UTF-8?q?1000=E5=AF=BC=E8=87=B4=E7=9A=84=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/bisheng/interface/embeddings/custom.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/backend/bisheng/interface/embeddings/custom.py b/src/backend/bisheng/interface/embeddings/custom.py index 00d224204..a335f54bd 100644 --- a/src/backend/bisheng/interface/embeddings/custom.py +++ b/src/backend/bisheng/interface/embeddings/custom.py @@ -134,6 +134,12 @@ class BishengEmbedding(BaseModel, Embeddings): params.update({ 'model': model_info.model_name, }) + + # 非openai官方但是符合openai接口标准的embedding模型,强制chunk_size=1,防止batch_size太大导致服务报错 + if (self.llm_node_type.get(server_info.type) == "OpenAIEmbeddings" and + server_info.type != LLMServerType.OPENAI.value): + params['chunk_size'] = params.pop('chunk_size', 1) + if server_info.type == LLMServerType.QWEN.value: params = { 'dashscope_api_key': params.get('openai_api_key'), @@ -150,9 +156,6 @@ class BishengEmbedding(BaseModel, Embeddings): LLMServerType.VLLM.value ]: params['openai_api_key'] = params.pop('openai_api_key', None) or 'EMPTY' - params['chunk_size'] = params.pop('chunk_size', 1) - elif server_info.type == LLMServerType.OPENAI.value: - params['chunk_size'] = params.pop('chunk_size', 1) elif server_info.type == LLMServerType.OLLAMA.value: params['query_instruction'] = 'passage: ' return params From cd6b3ed9237187d14846288e0d37a222b497af2e Mon Sep 17 00:00:00 2001 From: GuoQing Zhang Date: Thu, 11 Sep 2025 20:39:44 +0800 Subject: [PATCH 07/11] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=85=B6?= =?UTF-8?q?=E4=BB=96=E6=8E=A5=E5=8F=A3=E6=A0=BC=E5=BC=8F=E4=BD=BF=E7=94=A8?= =?UTF-8?q?openai=E4=BD=86=E6=98=AFchunk=5Fsize=E4=B8=8D=E6=94=AF=E6=8C=81?= =?UTF-8?q?1000=E5=AF=BC=E8=87=B4=E7=9A=84=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/bisheng/interface/embeddings/custom.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/backend/bisheng/interface/embeddings/custom.py b/src/backend/bisheng/interface/embeddings/custom.py index a335f54bd..a6ebd362f 100644 --- a/src/backend/bisheng/interface/embeddings/custom.py +++ b/src/backend/bisheng/interface/embeddings/custom.py @@ -136,8 +136,7 @@ class BishengEmbedding(BaseModel, Embeddings): }) # 非openai官方但是符合openai接口标准的embedding模型,强制chunk_size=1,防止batch_size太大导致服务报错 - if (self.llm_node_type.get(server_info.type) == "OpenAIEmbeddings" and - server_info.type != LLMServerType.OPENAI.value): + if self.llm_node_type.get(server_info.type) == "OpenAIEmbeddings": params['chunk_size'] = params.pop('chunk_size', 1) if server_info.type == LLMServerType.QWEN.value: From 7db653d3e9157e36af1a1a16b3d7b15e05642ed7 Mon Sep 17 00:00:00 2001 From: dolphin Date: Thu, 11 Sep 2025 21:27:43 +0800 Subject: [PATCH 08/11] =?UTF-8?q?fix:=20=E4=BC=9A=E8=AF=9D=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E9=97=AE=E9=A2=98=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/Chat/Input/ChatFormTools.tsx | 6 ++-- .../Input/Files/Table/KnowledgeColumns.tsx | 2 +- .../Chat/Messages/Content/MessageContent.tsx | 2 +- .../src/components/Messages/Content/Error.tsx | 2 +- .../client/src/pages/appChat/ChatMessages.tsx | 2 +- .../src/pages/appChat/components/ChatFile.tsx | 5 ++- .../pages/appChat/components/MessageBs.tsx | 6 ++-- .../appChat/components/MessageBsChoose.tsx | 3 +- .../pages/appChat/components/MessageUser.tsx | 2 +- .../src/pages/appChat/useChatHelpers.ts | 35 ++++++++++++++++--- .../client/src/pages/appChat/useMessages.ts | 3 ++ .../client/src/pages/appChat/useWebsocket.ts | 2 ++ .../src/pages/apps/components/AgentCard.tsx | 2 +- 13 files changed, 52 insertions(+), 20 deletions(-) diff --git a/src/frontend/client/src/components/Chat/Input/ChatFormTools.tsx b/src/frontend/client/src/components/Chat/Input/ChatFormTools.tsx index 1355626f9..c7bdba8cb 100644 --- a/src/frontend/client/src/components/Chat/Input/ChatFormTools.tsx +++ b/src/frontend/client/src/components/Chat/Input/ChatFormTools.tsx @@ -88,7 +88,6 @@ export const ChatToolDown = ({ linsi, tools, setTools, config, searchType, setSe const LinsiTools = ({ tools, setTools }) => { const { data: bsConfig } = useGetBsConfig() - const [building] = useModelBuilding() useEffect(() => { const defaultTools = [{ @@ -101,7 +100,7 @@ const LinsiTools = ({ tools, setTools }) => { id: 'knowledge', name: '个人知识库', icon: , - checked: !building + checked: true },] if (bsConfig) { const tools = bsConfig.linsightConfig?.tools || [] @@ -115,7 +114,7 @@ const LinsiTools = ({ tools, setTools }) => { setTools((tools) => [...defaultTools, ...newTools]) } - }, [bsConfig, building]) + }, [bsConfig]) const active = useMemo(() => tools.some(tool => tool.checked), [tools]) @@ -136,7 +135,6 @@ const LinsiTools = ({ tools, setTools }) => {
setTools(tools.map(t => t.id === tool.id ? { ...t, checked: val } : t)) } diff --git a/src/frontend/client/src/components/Chat/Input/Files/Table/KnowledgeColumns.tsx b/src/frontend/client/src/components/Chat/Input/Files/Table/KnowledgeColumns.tsx index 04060c2d2..bfe90bdb3 100644 --- a/src/frontend/client/src/components/Chat/Input/Files/Table/KnowledgeColumns.tsx +++ b/src/frontend/client/src/components/Chat/Input/Files/Table/KnowledgeColumns.tsx @@ -49,7 +49,7 @@ export const getKnowledgeColumns = ( return '状态'; }, cell: ({ row }) => { - return ['', '处理中', '成功', '失败'][row.original.status] + return ['', '处理中', '成功', '失败', '模型向量切换中'][row.original.status] }, }, { diff --git a/src/frontend/client/src/components/Chat/Messages/Content/MessageContent.tsx b/src/frontend/client/src/components/Chat/Messages/Content/MessageContent.tsx index 7f473adab..6e4519713 100644 --- a/src/frontend/client/src/components/Chat/Messages/Content/MessageContent.tsx +++ b/src/frontend/client/src/components/Chat/Messages/Content/MessageContent.tsx @@ -60,7 +60,7 @@ export const ErrorMessage = ({ role="alert" aria-live="assertive" className={cn( - 'rounded-xl border border-red-500/20 bg-red-500/5 px-3 py-2 text-sm text-gray-600 dark:text-gray-200', + 'rounded-xl mt-2 border border-red-500/20 bg-red-500/5 px-3 py-2 text-sm text-gray-600 dark:text-gray-200', className, )} > diff --git a/src/frontend/client/src/components/Messages/Content/Error.tsx b/src/frontend/client/src/components/Messages/Content/Error.tsx index c1bea746e..96772c19c 100644 --- a/src/frontend/client/src/components/Messages/Content/Error.tsx +++ b/src/frontend/client/src/components/Messages/Content/Error.tsx @@ -103,7 +103,7 @@ const Error = ({ text }: { text: string }) => { const localize = useLocalize(); const jsonString = extractJson(text); const errorMessage = text.length > 512 && !jsonString ? text.slice(0, 512) + '...' : text; - const defaultResponse = `Something went wrong. Here's the specific error message we encountered: ${errorMessage}`; + const defaultResponse = `${errorMessage}`; if (!isJson(jsonString)) { return defaultResponse; diff --git a/src/frontend/client/src/pages/appChat/ChatMessages.tsx b/src/frontend/client/src/pages/appChat/ChatMessages.tsx index 155fef053..ece7748ce 100644 --- a/src/frontend/client/src/pages/appChat/ChatMessages.tsx +++ b/src/frontend/client/src/pages/appChat/ChatMessages.tsx @@ -30,7 +30,7 @@ export default function ChatMessages({ useName, title, logo }) { const remark = chatState?.flow?.guide_word - return
+ return
{/* 助手开场白 */} {remark && { - filePath && downloadFile(filePath, fileName) + if (filePath) { + const path = filePath.replace(/https?:\/\/[^\/]+/, __APP_ENV__.BASE_URL) + downloadFile(path, fileName) + } } return
{ }, onS
{!(data.reasoning_log && !message && !data.files.length) && <> -
+
{data.sender ?

{data.sender}

:

} -

+
{formatStrTime(data.create_time, 'MM 月 dd 日 HH:mm')}
@@ -92,7 +92,7 @@ export default function MessageBs({ logo, title, data, onUnlike = () => { }, onS } {/* 附加信息 */} { - data.end &&
+ data.end &&
!!data.message.hisValue || false, [data.message.hisValue]) const handleSend = () => { const val = textRef.current.value if (!val.trim()) return - setInputSended(true) emitAreaTextEvent({ action: EVENT_TYPE.MESSAGE_INPUT, data: { nodeId: data.message.node_id, diff --git a/src/frontend/client/src/pages/appChat/components/MessageUser.tsx b/src/frontend/client/src/pages/appChat/components/MessageUser.tsx index 65ed94597..8a0eb7fb0 100644 --- a/src/frontend/client/src/pages/appChat/components/MessageUser.tsx +++ b/src/frontend/client/src/pages/appChat/components/MessageUser.tsx @@ -29,7 +29,7 @@ export default function MessageUser({ useName, data, showButton }) { return
-
+
{formatStrTime(data.create_time, 'MM 月 dd 日 HH:mm')}
diff --git a/src/frontend/client/src/pages/appChat/useChatHelpers.ts b/src/frontend/client/src/pages/appChat/useChatHelpers.ts index 65907fb50..92e1a2541 100644 --- a/src/frontend/client/src/pages/appChat/useChatHelpers.ts +++ b/src/frontend/client/src/pages/appChat/useChatHelpers.ts @@ -8,9 +8,9 @@ import { Chat } from "~/@types/chat" import { baseMsgItem } from "~/api/apps" import { formatDate, generateUUID } from "~/utils" import { FLOW_TYPES } from "." +import { SkillMethod } from "./appUtils/skillMethod" import { bishengConfState, chatIdState, chatsState, currentChatState, currentRunningState, runningState } from "./store/atoms" import { emitAreaTextEvent, EVENT_TYPE } from "./useAreaText" -import { SkillMethod } from "./appUtils/skillMethod" export default function useChatHelpers() { const chatState = useRecoilValue(currentChatState) @@ -171,7 +171,7 @@ export default function useChatHelpers() { // 兼容后端问题 const _files = Array.isArray(files) ? files : [] - const messageId = message_id || (category === "guide_word" ? generateUUID(4) : "") + const messageId = message_id || (category === "guide_word" ? 'u-' + generateUUID(6) : "") const filteredMessages = deduplicateMessages(messages, message_id) return [ @@ -184,7 +184,7 @@ export default function useChatHelpers() { files: _files.map(el => ({ // 兼容 file_name: el.file_name || el.name, - file_url: el.file_url || el.url + file_url: el.file_url || el.url || el.path })), is_bot, message: msg, @@ -321,13 +321,40 @@ export default function useChatHelpers() { { ...baseMsgItem, category: "question", - id: generateUUID(8), + id: 'u-' + generateUUID(8), message: msg, create_time: formatDate(new Date(), "yyyy-MM-ddTHH:mm:ss"), }, ]), ) + + // 滚动到底部 + const dom = document.getElementById('messageScrollPanne') + setTimeout(() => { + if (dom) { + dom.scrollTop = dom.scrollHeight + } + }, 0); }, + closeOutputMsg: (input) => { + setChats((prev) => + updateChatMessages(prev, chatId, (messages) => { + const updatedMessages = messages.map(msg => { + if (["output_with_input_msg", "output_with_choose_msg"].includes(msg.category)) { + return { + ...msg, + message: { + ...msg.message, + hisValue: input + } + } + } + return msg + }) + return updatedMessages + }), + ) + } } return { diff --git a/src/frontend/client/src/pages/appChat/useMessages.ts b/src/frontend/client/src/pages/appChat/useMessages.ts index d9a195b9f..f09abfc8c 100644 --- a/src/frontend/client/src/pages/appChat/useMessages.ts +++ b/src/frontend/client/src/pages/appChat/useMessages.ts @@ -47,6 +47,9 @@ const useLoadMessage = (chatId: string, chatState: any, messageScrollRef: React. const loadMore = async (chatId: string) => { // 运行中or没有更多 || 最后一条消息id不存在,忽略 if (running || historyEnd || !messages?.[0]?.id || !flow) return + const messageId = messages[0].id + // u-开头的消息表示新建会话,新建会话无需加载历史消息 + if (typeof messageId === 'string' && messageId.startsWith('u-')) return const msgs = await getChatHistoryApi(flow.id, chatId, flow.flow_type, messages[0].id || 0) setChats((prev) => { diff --git a/src/frontend/client/src/pages/appChat/useWebsocket.ts b/src/frontend/client/src/pages/appChat/useWebsocket.ts index d658a0d2f..1b3e48161 100644 --- a/src/frontend/client/src/pages/appChat/useWebsocket.ts +++ b/src/frontend/client/src/pages/appChat/useWebsocket.ts @@ -325,6 +325,8 @@ export const useWebSocket = (helpers) => { } }, }) + // 闭合所有输出节点 + helpers.message.closeOutputMsg(submitData.data.data.output_result) break; case ActionType.STOP: sendWsMsg({ action: 'stop' }) diff --git a/src/frontend/client/src/pages/apps/components/AgentCard.tsx b/src/frontend/client/src/pages/apps/components/AgentCard.tsx index e1d2d0f9e..61a3eacf8 100644 --- a/src/frontend/client/src/pages/apps/components/AgentCard.tsx +++ b/src/frontend/client/src/pages/apps/components/AgentCard.tsx @@ -63,7 +63,7 @@ export function AgentCard({ {/* 2. 描述区域:占满剩余空间,最多显示 2 行(适配 150px 高度) */}

{/* 文字缩小为 xs,最多 2 行 */} - {agent.description || "无描述信息"} {/* 空描述兜底,避免高度塌陷 */} + {agent.description} {/* 空描述兜底,避免高度塌陷 */}

From 14d7d11ec5504aa2fb9b93de271b28d888af497e Mon Sep 17 00:00:00 2001 From: dolphin Date: Thu, 11 Sep 2025 22:22:32 +0800 Subject: [PATCH 09/11] =?UTF-8?q?fix:=20=E5=BA=94=E7=94=A8=E5=9B=BE?= =?UTF-8?q?=E6=A0=87=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/bs-comp/cardComponent/avatar.tsx | 2 +- .../platform/src/controllers/API/assistant.ts | 2 +- src/frontend/platform/src/controllers/API/flow.ts | 4 ++-- .../platform/src/controllers/API/workflow.ts | 4 ++-- .../platform/src/pages/BuildPage/CreateApp.tsx | 12 ++++++++---- .../assistant/editAssistant/EditAssistantDialog.tsx | 10 +++++++--- .../BuildPage/assistant/editAssistant/Header.tsx | 2 +- .../platform/src/pages/BuildPage/skills/l2Edit.tsx | 10 +++++++--- 8 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/frontend/platform/src/components/bs-comp/cardComponent/avatar.tsx b/src/frontend/platform/src/components/bs-comp/cardComponent/avatar.tsx index cc36426ef..cd701b065 100644 --- a/src/frontend/platform/src/components/bs-comp/cardComponent/avatar.tsx +++ b/src/frontend/platform/src/components/bs-comp/cardComponent/avatar.tsx @@ -14,7 +14,7 @@ const gradients = [ export default function AppAvator({ id = 1, flowType = '', url = '', className = '' }) { const color = useMemo(() => { - const str = id + '' + const str = (id + '').substring(0, 4) let hex = ''; for (let i = 0; i < str.length; i++) { hex += str.charCodeAt(i).toString(16); diff --git a/src/frontend/platform/src/controllers/API/assistant.ts b/src/frontend/platform/src/controllers/API/assistant.ts index c989b9e99..a7ff46f21 100644 --- a/src/frontend/platform/src/controllers/API/assistant.ts +++ b/src/frontend/platform/src/controllers/API/assistant.ts @@ -52,7 +52,7 @@ export const saveAssistanttApi = async ( ): Promise => { if (data.logo) { // logo保存相对路径 - data.logo = data.logo.replace('/bisheng', '') + data.logo = data.logo.replace(/^\/\w+/, '') } return await axios.put(`/api/v1/assistant`, data) }; diff --git a/src/frontend/platform/src/controllers/API/flow.ts b/src/frontend/platform/src/controllers/API/flow.ts index df21d5456..7aadd666a 100644 --- a/src/frontend/platform/src/controllers/API/flow.ts +++ b/src/frontend/platform/src/controllers/API/flow.ts @@ -201,7 +201,7 @@ export const createCustomFlowApi = async (params: { }, userName: string) => { if (params.logo) { // logo保存相对路径 - params.logo = params.logo.replace('/bisheng', '') + params.logo = params.logo.replace(/^\/\w+/, '') } const response: FlowType = await axios.post("/api/v1/flows/", { ...params, @@ -228,7 +228,7 @@ export async function updateFlowApi( ): Promise { if (updatedFlow.logo) { // logo保存相对路径 - updatedFlow.logo = updatedFlow.logo.replace('/bisheng', '') + updatedFlow.logo = updatedFlow.logo.replace(/^\/\w+/, '') } return await axios.patch(`/api/v1/flows/${updatedFlow.id}`, { logo: updatedFlow.logo || '', diff --git a/src/frontend/platform/src/controllers/API/workflow.ts b/src/frontend/platform/src/controllers/API/workflow.ts index 047d0d855..b4942f043 100644 --- a/src/frontend/platform/src/controllers/API/workflow.ts +++ b/src/frontend/platform/src/controllers/API/workflow.ts @@ -41,7 +41,7 @@ export const createWorkflowApi = async (name, desc, url, flow): Promise => export const saveWorkflow = async (versionId: number, data: WorkFlow): Promise => { if (data.logo) { // logo保存相对路径 - data.logo = data.logo.replace('/bisheng', '') + data.logo = data.logo.replace(/^\/\w+/, '') } return await axios.put(`/api/v1/workflow/versions/${versionId}`, data); } @@ -111,7 +111,7 @@ export async function getWorkFlowVersions(flow_id): Promise<{ data: any[], total */ export const onlineWorkflow = async (flow, status = ''): Promise => { const { name, description, logo } = flow - const data = { name, description, logo: logo && logo.replace('/bisheng', '') } + const data = { name, description, logo: logo && logo.replace(/^\/\w+/, '') } if (status) { data['status'] = status } diff --git a/src/frontend/platform/src/pages/BuildPage/CreateApp.tsx b/src/frontend/platform/src/pages/BuildPage/CreateApp.tsx index e9f21ff68..a4203f8ff 100644 --- a/src/frontend/platform/src/pages/BuildPage/CreateApp.tsx +++ b/src/frontend/platform/src/pages/BuildPage/CreateApp.tsx @@ -16,7 +16,7 @@ import { copyReportTemplate, createWorkflowApi } from "@/controllers/API/workflo import { captureAndAlertRequestErrorHoc } from "@/controllers/request"; import { uploadFileWithProgress } from "@/modals/UploadModal/upload"; import { AppType, AppTypeToNum } from "@/types/app"; -import { forwardRef, useContext, useImperativeHandle, useRef, useState } from "react"; +import { forwardRef, useContext, useImperativeHandle, useMemo, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { useNavigate } from "react-router-dom"; @@ -230,10 +230,14 @@ ${t('build.exampleTwo', { ns: 'bs' })} // 上传头像逻辑 const uploadAvator = (file: File) => { uploadFileWithProgress(file, (progress) => { }, 'icon').then(res => { - setFormData(prev => ({ ...prev, url: '/bisheng/' + res.relative_path })); + setFormData(prev => ({ ...prev, url: res.file_path })); }); }; + const previewAvatar = useMemo(() => + formData.url ? __APP_ENV__.BASE_URL + formData.url : '', + [formData.url]) + return ( @@ -245,8 +249,8 @@ ${t('build.exampleTwo', { ns: 'bs' })} - - + +
diff --git a/src/frontend/platform/src/pages/BuildPage/assistant/editAssistant/EditAssistantDialog.tsx b/src/frontend/platform/src/pages/BuildPage/assistant/editAssistant/EditAssistantDialog.tsx index b2ca16211..1cef5fff8 100644 --- a/src/frontend/platform/src/pages/BuildPage/assistant/editAssistant/EditAssistantDialog.tsx +++ b/src/frontend/platform/src/pages/BuildPage/assistant/editAssistant/EditAssistantDialog.tsx @@ -5,7 +5,7 @@ import { Input, Textarea } from "@/components/bs-ui/input"; import Avator from "@/components/bs-ui/input/avator"; import { useToast } from "@/components/bs-ui/toast/use-toast"; import { uploadFileWithProgress } from "@/modals/UploadModal/upload"; -import { useEffect, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; export default function EditAssistantDialog({ logo, name, desc, onSave, loca }) { @@ -84,6 +84,10 @@ export default function EditAssistantDialog({ logo, name, desc, onSave, loca }) }) } + const previewAvatar = useMemo(() => + formData.logo ? __APP_ENV__.BASE_URL + formData.logo : '', + [formData.logo]) + return {t('build.editAssistant')} @@ -92,11 +96,11 @@ export default function EditAssistantDialog({ logo, name, desc, onSave, loca })
- + {errors.name &&

{errors.name}

} diff --git a/src/frontend/platform/src/pages/BuildPage/assistant/editAssistant/Header.tsx b/src/frontend/platform/src/pages/BuildPage/assistant/editAssistant/Header.tsx index eb5d21d8d..077d645d0 100644 --- a/src/frontend/platform/src/pages/BuildPage/assistant/editAssistant/Header.tsx +++ b/src/frontend/platform/src/pages/BuildPage/assistant/editAssistant/Header.tsx @@ -37,7 +37,7 @@ export default function Header({ loca, onSave, onLine, onTabChange }) { return
- + {assistantState.name} {/* edit dialog */} diff --git a/src/frontend/platform/src/pages/BuildPage/skills/l2Edit.tsx b/src/frontend/platform/src/pages/BuildPage/skills/l2Edit.tsx index 2989f12d8..d231720b8 100644 --- a/src/frontend/platform/src/pages/BuildPage/skills/l2Edit.tsx +++ b/src/frontend/platform/src/pages/BuildPage/skills/l2Edit.tsx @@ -144,10 +144,14 @@ export default function l2Edit() { const [logo, setLogo] = useState('') const uploadAvator = (file) => { uploadFileWithProgress(file, (progress) => { }, 'icon').then(res => { - setLogo('/bisheng/' + res.relative_path); + setLogo(res.file_path); }) } + const previewAvatar = useMemo(() => + logo ? __APP_ENV__.BASE_URL + logo : '', + [logo]) + return
@@ -174,8 +178,8 @@ export default function l2Edit() {
- - + +
From c08035bc6029b5cfd4c0f7ccd5f655b10bebf769 Mon Sep 17 00:00:00 2001 From: lmr <350416710@qq.com> Date: Thu, 11 Sep 2025 22:40:11 +0800 Subject: [PATCH 10/11] =?UTF-8?q?fix:=20bug=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../platform/public/locales/zh/bs.json | 2 +- .../pages/EvaluationPage/EvaluationCreate.tsx | 27 +- .../pages/KnowledgePage/AdjustFilesUpload.tsx | 8 +- .../src/pages/KnowledgePage/KnowledgeFile.tsx | 276 +++++++++--------- .../components/FileUploadStep4.tsx | 156 ++++++---- .../platform/src/pages/KnowledgePage/qas.tsx | 29 +- 6 files changed, 278 insertions(+), 220 deletions(-) diff --git a/src/frontend/platform/public/locales/zh/bs.json b/src/frontend/platform/public/locales/zh/bs.json index 6ec04b67c..7c441a021 100644 --- a/src/frontend/platform/public/locales/zh/bs.json +++ b/src/frontend/platform/public/locales/zh/bs.json @@ -362,7 +362,7 @@ "enterUniqueId": "请选择具体应用", "enterVersion": "请选择版本", "workFlow":"请选择工作流", - "enterFile": "请选择测试集数据", + "enterFile": "请上传测试集数据", "fileSizeLimit": "文件大小限制在10M以内", "enterPrompt": "评测指令不能为空", "evaluationCollection": "评测集合", diff --git a/src/frontend/platform/src/pages/EvaluationPage/EvaluationCreate.tsx b/src/frontend/platform/src/pages/EvaluationPage/EvaluationCreate.tsx index fea8b4af4..db0535aa5 100644 --- a/src/frontend/platform/src/pages/EvaluationPage/EvaluationCreate.tsx +++ b/src/frontend/platform/src/pages/EvaluationPage/EvaluationCreate.tsx @@ -114,21 +114,22 @@ export default function EvaluatingCreate() { const navigate = useNavigate(); const handleCreateEvaluation = async () => { - const errorlist = []; - if (!selectedType) errorlist.push(t("evaluation.enterExecType")); - // if (!selectedKeyId) errorlist.push(t("evaluation.workFlow")); + const errorlist = []; + if (!selectedType) errorlist.push(t("evaluation.enterExecType")); + + if (selectedType && !selectedKeyId) { + if (selectedType === "workflow") errorlist.push(t("请选择工作流")); + if (selectedType === "flow") errorlist.push(t("请选择技能")); + if (selectedType === "assistant") errorlist.push(t("请选择助手")); + } - // 修复版本验证 - 取消注释并添加正确的验证 - if ((selectedType === "workflow" || selectedType === "flow" || !selectedKeyId) && !selectedVersion) { - errorlist.push(t("evaluation.workFlow")); - } + if (selectedKeyId && (selectedType === "workflow" || selectedType === "flow") && !selectedVersion) { + errorlist.push(t("请选择版本")); + } + if (!fileRef.current && selectedKeyId&&selectedVersion) errorlist.push(t("evaluation.enterFile")); + if (!prompt) errorlist.push(t("evaluation.enterPrompt")); - // 修复文件验证 - 所有类型都需要测试集数据 - // if (!fileRef.current) errorlist.push(t("evaluation.enterFile")); - - if (!prompt) errorlist.push(t("evaluation.enterPrompt")); - - if (errorlist.length) return handleError(errorlist); + if (errorlist.length) return handleError(errorlist); setLoading(true); try { await captureAndAlertRequestErrorHoc( diff --git a/src/frontend/platform/src/pages/KnowledgePage/AdjustFilesUpload.tsx b/src/frontend/platform/src/pages/KnowledgePage/AdjustFilesUpload.tsx index 645dc566c..6b63ba93f 100644 --- a/src/frontend/platform/src/pages/KnowledgePage/AdjustFilesUpload.tsx +++ b/src/frontend/platform/src/pages/KnowledgePage/AdjustFilesUpload.tsx @@ -5,7 +5,7 @@ import { useToast } from "@/components/bs-ui/toast/use-toast"; import { rebUploadFile, retryKnowledgeFileApi, subUploadLibFile } from "@/controllers/API"; import { captureAndAlertRequestErrorHoc } from "@/controllers/request"; import { ChevronLeft } from "lucide-react"; -import { useRef, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { useLocation, useNavigate, useParams } from "react-router-dom"; import FileUploadStep2 from "./components/FileUploadStep2"; @@ -29,6 +29,12 @@ export default function AdjustFilesUpload() { // 从路由状态获取调整模式的初始数据(必须传文件数据) const initFileData = location.state?.fileData; + useEffect(() => { + // 如果没有初始化数据,说明是直接访问,跳转到/filelib + if (!initFileData) { + navigate('/filelib', { replace: true }); + } + }, [initFileData, navigate]); if (!initFileData) { navigate(-1); // 无数据时回退 return null; diff --git a/src/frontend/platform/src/pages/KnowledgePage/KnowledgeFile.tsx b/src/frontend/platform/src/pages/KnowledgePage/KnowledgeFile.tsx index 1952ef25e..fbad75444 100644 --- a/src/frontend/platform/src/pages/KnowledgePage/KnowledgeFile.tsx +++ b/src/frontend/platform/src/pages/KnowledgePage/KnowledgeFile.tsx @@ -23,7 +23,7 @@ import { Dialog, DialogClose, DialogContent, DialogFooter, DialogHeader, DialogT import { Select, SelectContent, SelectItem, SelectTrigger } from "@/components/bs-ui/select"; import { useToast } from "@/components/bs-ui/toast/use-toast"; import { getKnowledgeModelConfig, getLLmServerDetail, getModelListApi } from "@/controllers/API/finetune"; -import { CircleAlert, Copy, Ellipsis, LoaderCircle, Settings, Trash2 } from "lucide-react"; +import { BookCopy, CircleAlert, Copy, Ellipsis, LoaderCircle, Settings, Trash2 } from "lucide-react"; import AutoPagination from "../../components/bs-ui/pagination/autoPagination"; import { useTable } from "../../util/hook"; import { ModelSelect } from "../ModelPage/manage/tabs/WorkbenchModel"; @@ -112,7 +112,7 @@ function CreateModal({ datalist, open, onOpenChange, onLoadEnd, mode = 'create', fetchModelData(); }, [open, mode, currentLib]); - + useEffect(() => { // 当弹窗关闭时,清空所有内部状态 if (!open) { @@ -122,112 +122,112 @@ function CreateModal({ datalist, open, onOpenChange, onLoadEnd, mode = 'create', setError({ name: false, desc: false }); } }, [open]); - + const { toast } = useToast() const [error, setError] = useState({ name: false, desc: false }) - const handleCreate = async (e, isImport = false) => { - const name = nameRef.current.value || ''; // 名称(默认空字符串,避免null) - let desc = descRef.current.value || ''; // 描述(默认空字符串) + const handleCreate = async (e, isImport = false) => { + const name = nameRef.current.value || ''; // 名称(默认空字符串,避免null) + let desc = descRef.current.value || ''; // 描述(默认空字符串) - // 1. 定义默认描述的"固定文本部分"(不含名称) - const defaultDescPrefix = "当回答与"; - const defaultDescSuffix = "相关的问题时,参考此知识库"; - // 固定文本总长度 = 前缀长度 + 后缀长度 - const fixedTextLength = defaultDescPrefix.length + defaultDescSuffix.length; - // 名称可占用的最大长度 = 200 - 固定文本长度(确保名称+固定文本≤200) - const maxNameLengthForDefaultDesc = 200 - fixedTextLength; + // 1. 定义默认描述的"固定文本部分"(不含名称) + const defaultDescPrefix = "当回答与"; + const defaultDescSuffix = "相关的问题时,参考此知识库"; + // 固定文本总长度 = 前缀长度 + 后缀长度 + const fixedTextLength = defaultDescPrefix.length + defaultDescSuffix.length; + // 名称可占用的最大长度 = 200 - 固定文本长度(确保名称+固定文本≤200) + const maxNameLengthForDefaultDesc = 200 - fixedTextLength; - // 2. 未输入描述时,生成默认描述(严格控制总长度≤200) - if (!desc) { - // 情况1:名称长度 ≤ 可占用最大长度 → 直接拼接生成默认描述 - if (name.length <= maxNameLengthForDefaultDesc) { - desc = `${defaultDescPrefix}${name}${defaultDescSuffix}`; - } - // 情况2:名称长度 > 可占用最大长度 → 截断名称后再拼接 - else { - // 截断名称(保留前 maxNameLengthForDefaultDesc 个字,避免总长度超200) - const truncatedName = name.slice(0, maxNameLengthForDefaultDesc); - // 生成截断截断后的默认描述 - desc = `${defaultDescPrefix}${truncatedName}${defaultDescSuffix}`; - // 提示用户:名称过长已被截断(提升体验,避免用户困惑) - toast({ - variant: "info", - description: `知识库名称过长,已自动截断为${maxNameLengthForDefaultDesc}字,确保默认描述不超过200字限制` - }); + // 2. 未输入描述时,生成默认描述(严格控制总长度≤200) + if (!desc) { + // 情况1:名称长度 ≤ 可占用最大长度 → 直接拼接生成默认描述 + if (name.length <= maxNameLengthForDefaultDesc) { + desc = `${defaultDescPrefix}${name}${defaultDescSuffix}`; + } + // 情况2:名称长度 > 可占用最大长度 → 截断名称后再拼接 + else { + // 截断名称(保留前 maxNameLengthForDefaultDesc 个字,避免总长度超200) + const truncatedName = name.slice(0, maxNameLengthForDefaultDesc); + // 生成截断截断后的默认描述 + desc = `${defaultDescPrefix}${truncatedName}${defaultDescSuffix}`; + // 提示用户:名称过长已被截断(提升体验,避免用户困惑) + toast({ + variant: "info", + description: `知识库名称过长,已自动截断为${maxNameLengthForDefaultDesc}字,确保默认描述不超过200字限制` + }); + } } - } - // 3. 原有校验逻辑(仅针对用户手动输入的描述,默认描述已确保≤200) - if (!name) { - handleError(t('lib.enterLibraryName')); - return; - } - if (name.length > 30) { - handleError('知识库名称不能超过30字'); - return; - } - if (!modal) { - handleError(t('lib.selectModel')); - return; - } - - // 修复:名称重复校验逻辑 - // 编辑模式且名称未变更时,不进行重复校验 - const isEditMode = mode === 'edit' && currentLib; - const nameUnchanged = isEditMode && name === currentLib.name; - - if (!nameUnchanged && datalist.find(data => data.name === name && (!currentLib || data.id !== currentLib.id))) { - handleError(t('lib.nameExists')); - return; - } - - // 仅校验用户手动输入的描述(默认描述已控制长度,可跳过) - if (descRef.current.value && desc.length > 200) { - handleError(t('lib.descriptionLimit')); - return; - } - - setIsSubmitting(true) - if (mode === 'create') { - await captureAndAlertRequestErrorHoc(createFileLib({ - name, - description: desc, - model: modal[1].value, - type: 0 - }).then(res => { - window.libname = [name, desc] - navigate(isImport - ? `/filelib/upload/${res.id}` - : `/filelib/${res.id}` - ); - onOpenChange(false); // 修复:用onOpenChange关闭弹窗 - })).finally(() => { - setIsSubmitting(false) - }) - } else { - const data = { - "model_id": modal[1].value, - "model_type": "embedding", - "knowledge_id": currentLib.id, - "knowledge_name": name, - "description": desc + // 3. 原有校验逻辑(仅针对用户手动输入的描述,默认描述已确保≤200) + if (!name) { + handleError(t('lib.enterLibraryName')); + return; } - await captureAndAlertRequestErrorHoc(updateKnowledge(data).then(res => { - toast({ - variant: "success", - description: '更新成功' + if (name.length > 200) { + handleError('知识库名称不能超过200字'); + return; + } + if (!modal) { + handleError(t('lib.selectModel')); + return; + } + + // 修复:名称重复校验逻辑 + // 编辑模式且名称未变更时,不进行重复校验 + const isEditMode = mode === 'edit' && currentLib; + const nameUnchanged = isEditMode && name === currentLib.name; + + if (!nameUnchanged && datalist.find(data => data.name === name && (!currentLib || data.id !== currentLib.id))) { + handleError(t('lib.nameExists')); + return; + } + + // 仅校验用户手动输入的描述(默认描述已控制长度,可跳过) + if (descRef.current.value && desc.length > 200) { + handleError(t('lib.descriptionLimit')); + return; + } + + setIsSubmitting(true) + if (mode === 'create') { + await captureAndAlertRequestErrorHoc(createFileLib({ + name, + description: desc, + model: modal[1].value, + type: 0 + }).then(res => { + window.libname = [name, desc] + navigate(isImport + ? `/filelib/upload/${res.id}` + : `/filelib/${res.id}` + ); + onOpenChange(false); // 修复:用onOpenChange关闭弹窗 + })).finally(() => { + setIsSubmitting(false) }) - onOpenChange(false); // 修复:用onOpenChange关闭弹窗(替代原setOpen) - onLoadEnd() - }).catch(error => { - toast({ variant: "error", description: '更新失败,请重试' }); - onOpenChange(false); // 错误时也关闭弹窗,避免状态卡住 - })).finally(() => { - setIsSubmitting(false) - }) + } else { + const data = { + "model_id": modal[1].value, + "model_type": "embedding", + "knowledge_id": currentLib.id, + "knowledge_name": name, + "description": desc + } + await captureAndAlertRequestErrorHoc(updateKnowledge(data).then(res => { + toast({ + variant: "success", + description: '更新成功' + }) + onOpenChange(false); // 修复:用onOpenChange关闭弹窗(替代原setOpen) + onLoadEnd() + }).catch(error => { + toast({ variant: "error", description: '更新失败,请重试' }); + onOpenChange(false); // 错误时也关闭弹窗,避免状态卡住 + })).finally(() => { + setIsSubmitting(false) + }) + } } -} const handleError = (message) => { toast({ @@ -411,21 +411,21 @@ export default function KnowledgeFile() { }) } -const handleOpenSettings = (lib) => { - console.log("=== handleOpenSettings 开始执行 ==="); - console.log("当前点击的lib ID:", lib.id); - // 1. 深拷贝:彻底断开与原 lib 的引用关联(解决嵌套属性引用不变问题) - const newCurrentLib = JSON.parse(JSON.stringify(lib)); - // 2. 注入唯一标识:即使数据完全相同,也让 currentSettingLib 引用绝对唯一 - newCurrentLib.__updateKey = Date.now(); // 每次点击生成不同的时间戳 - - setCurrentSettingLib(newCurrentLib); // 此时传递的是完全新的对象引用 - setSettingsOpen(true); - setModalKey(prev => prev + 1); // 保留 modalKey 确保弹窗重新挂载 - console.log("handleOpenSettings called with lib:", newCurrentLib); // 验证打印 -}; + const handleOpenSettings = (lib) => { + console.log("=== handleOpenSettings 开始执行 ==="); + console.log("当前点击的lib ID:", lib.id); + // 1. 深拷贝:彻底断开与原 lib 的引用关联(解决嵌套属性引用不变问题) + const newCurrentLib = JSON.parse(JSON.stringify(lib)); + // 2. 注入唯一标识:即使数据完全相同,也让 currentSettingLib 引用绝对唯一 + newCurrentLib.__updateKey = Date.now(); // 每次点击生成不同的时间戳 - const handleSettingsClose = (isOpen) => { + setCurrentSettingLib(newCurrentLib); // 此时传递的是完全新的对象引用 + setSettingsOpen(true); + setModalKey(prev => prev + 1); // 保留 modalKey 确保弹窗重新挂载 + console.log("handleOpenSettings called with lib:", newCurrentLib); // 验证打印 + }; + + const handleSettingsClose = (isOpen) => { console.log("handleSettingsClose called with isOpen:", isOpen); setSettingsOpen(isOpen); if (!isOpen) { @@ -439,7 +439,7 @@ const handleOpenSettings = (lib) => { const handleCachePage = () => { window.LibPage = { page, type: 'file' } } - + useEffect(() => { const _page = window.LibPage if (_page) { @@ -511,7 +511,7 @@ const handleOpenSettings = (lib) => { key={el.id} className=" h-[70px]" > - { window.libname = [el.name, el.description]; @@ -520,27 +520,27 @@ const handleOpenSettings = (lib) => { }} >
-
- +
+
{el.name}
- {el.description || ''} + {el.description || ''}
- { window.libname = [el.name, el.description]; @@ -551,7 +551,7 @@ const handleOpenSettings = (lib) => { {el.update_time.replace('T', ' ')} - { window.libname = [el.name, el.description]; @@ -565,15 +565,15 @@ const handleOpenSettings = (lib) => {