diff --git a/src/backend/bisheng/api/v1/mark_task.py b/src/backend/bisheng/api/v1/mark_task.py index 982977d77..040e9e157 100644 --- a/src/backend/bisheng/api/v1/mark_task.py +++ b/src/backend/bisheng/api/v1/mark_task.py @@ -146,7 +146,8 @@ async def mark(data: MarkData, task = MarkTaskDao.get_task_byid(task_id=data.task_id) msg_list = ChatMessageDao.get_msg_by_flows(task.app_id.split(",")) - m_list = [msg.chat_id for msg in msg_list] + #m_list = [msg.chat_id for msg in msg_list] + m_list = msg_list r_list = MarkRecordDao.get_list_by_taskid(data.task_id) app_record = [r.session_id for r in r_list ] @@ -191,8 +192,8 @@ async def pre_or_next(chat_id:str,action:str,task_id:int,login_user: UserPayload if record: queue = deque() for r in record: - if r.session_id == chat_id: - break + # if r.session_id == chat_id: + # break queue.append(r) if len(queue) == 0: @@ -235,6 +236,17 @@ async def pre_or_next(chat_id:str,action:str,task_id:int,login_user: UserPayload result["chat_id"] = cur.chat_id result["flow_id"] = cur.flow_id return resp_200(data=result) + else: + cur = k_list[linked.head().data] + flow = FlowDao.get_flow_by_idstr(cur.flow_id) + if flow: + result['flow_type'] = 'flow' + else: + result['flow_type'] = 'assistant' + result["chat_id"] = cur.chat_id + result["flow_id"] = cur.flow_id + return resp_200(data=result) + return resp_200() diff --git a/src/backend/bisheng/api/v1/skillcenter.py b/src/backend/bisheng/api/v1/skillcenter.py index 1a60376be..7a2c19b44 100644 --- a/src/backend/bisheng/api/v1/skillcenter.py +++ b/src/backend/bisheng/api/v1/skillcenter.py @@ -4,6 +4,7 @@ from sqlmodel import select from bisheng.api.services.user_service import get_login_user +from bisheng.api.errcode.flow import FlowTemplateNameError from bisheng.api.utils import remove_api_keys from bisheng.api.v1.schemas import UnifiedResponseModel, resp_200 from bisheng.database.base import session_getter @@ -31,7 +32,7 @@ def create_template(*, template: TemplateCreate): name_repeat = session.exec( select(Template).where(Template.name == db_template.name)).first() if name_repeat: - raise HTTPException(status_code=500, detail='Repeat name, please choose another name') + raise FlowTemplateNameError.http_exception() # 增加 order_num x,x+65535 with session_getter() as session: max_order = session.exec(select(Template).order_by( diff --git a/src/backend/bisheng/api/v1/workflow.py b/src/backend/bisheng/api/v1/workflow.py index 09c3d2e06..ca5975be9 100644 --- a/src/backend/bisheng/api/v1/workflow.py +++ b/src/backend/bisheng/api/v1/workflow.py @@ -3,13 +3,10 @@ from typing import Optional from uuid import UUID -from bisheng.api.v1.skillcenter import ORDER_GAP -from bisheng.database.models.template import Template, TemplateCreate, TemplateRead from sqlmodel import select from bisheng.api.errcode.base import UnAuthorizedError -from bisheng.api.errcode.flow import FlowOnlineEditError, FlowTemplateNameError +from bisheng.api.errcode.flow import FlowOnlineEditError from bisheng.api.services.workflow import WorkFlowService -from bisheng.api.utils import get_L2_param_from_flow from bisheng.database.base import session_getter from bisheng.database.models.flow import Flow, FlowCreate, FlowDao, FlowRead, FlowReadWithStyle, FlowType, FlowUpdate from bisheng.database.models.flow_version import FlowVersionDao @@ -270,34 +267,3 @@ def read_flows(*, except Exception as e: logger.exception(e) raise HTTPException(status_code=500, detail=str(e)) from e - - -@router.post('/template/create', - response_model=UnifiedResponseModel[TemplateRead], - status_code=201) -def create_template(*, template: TemplateCreate): - """Create a new workflow or assitant.""" - template.flow_type = FlowType.WORKFLOW.value - db_template = Template.model_validate(template) - # TODO: if assitant need more data - if not db_template.data: - with session_getter() as session: - db_flow = session.get(Flow, template.flow_id) - db_template.data = db_flow.data - # 校验name - with session_getter() as session: - name_repeat = session.exec( - select(Template).where(Template.name == db_template.name)).first() - if name_repeat: - raise FlowTemplateNameError.http_exception() - # 增加 order_num x,x+65535 - with session_getter() as session: - max_order = session.exec(select(Template).order_by( - Template.order_num.desc()).limit(1)).first() - # 如果没有数据,就从 65535 开始 - db_template.order_num = max_order.order_num + ORDER_GAP if max_order else ORDER_GAP - with session_getter() as session: - session.add(db_template) - session.commit() - session.refresh(db_template) - return resp_200(db_template) diff --git a/src/backend/bisheng/database/models/message.py b/src/backend/bisheng/database/models/message.py index a7b13a715..5fbc5420d 100644 --- a/src/backend/bisheng/database/models/message.py +++ b/src/backend/bisheng/database/models/message.py @@ -177,8 +177,7 @@ def get_messages_by_chat_id(cls, chat_id: str, category_list: list = None, limit @classmethod def get_last_msg_by_flow_id(cls, flow_id: List[str], chat_id: List[str]): with session_getter() as session: - statement = select(ChatMessage).where(ChatMessage.flow_id.in_(flow_id)).where( - not_(ChatMessage.chat_id.in_(chat_id))).group_by(ChatMessage.chat_id).order_by( + statement = select(ChatMessage).where(ChatMessage.flow_id.in_(flow_id)).where(not_(ChatMessage.chat_id.in_(chat_id))).group_by(ChatMessage.chat_id).order_by( ChatMessage.create_time) return session.exec(statement).all() @@ -192,7 +191,7 @@ def get_msg_by_chat_id(cls, chat_id: str): def get_msg_by_flow(cls, flow_id: str): with session_getter() as session: # sql = text("select chat_id,count(*) as chat_count from chatmessage where flow_id=:flow_id group by chat_id") - st = select(ChatMessage).where(ChatMessage.flow_id == flow_id).group_by(ChatMessage.chat_id) + st = select(ChatMessage.chat_id).where(ChatMessage.flow_id == flow_id).group_by(ChatMessage.chat_id) return session.exec(st).all() @classmethod @@ -200,7 +199,7 @@ def get_msg_by_flows(cls, flow_id: List[str]): ids = [UUID(i) for i in flow_id] with session_getter() as session: # sql = text("select chat_id,count(*) as chat_count from chatmessage where flow_id=:flow_id group by chat_id") - st = select(ChatMessage).where(ChatMessage.flow_id.in_(ids)).group_by(ChatMessage.chat_id) + st = select(ChatMessage.chat_id).where(ChatMessage.flow_id.in_(ids)).group_by(ChatMessage.chat_id) return session.exec(st).all() @classmethod diff --git a/src/backend/bisheng/interface/initialize/loading.py b/src/backend/bisheng/interface/initialize/loading.py index 2da68b110..a075b75bf 100644 --- a/src/backend/bisheng/interface/initialize/loading.py +++ b/src/backend/bisheng/interface/initialize/loading.py @@ -255,6 +255,7 @@ def instantiate_llm(node_type, class_object, params: Dict, user_llm_request: boo if is_openai_v1() and params.get('openai_proxy'): params['http_client'] = httpx.Client(proxies=params.get('openai_proxy')) params['http_async_client'] = httpx.AsyncClient(proxies=params.get('openai_proxy')) + del params['openai_proxy'] if node_type == '': anthropic_api_key = params.pop('anthropic_api_key', None) diff --git a/src/backend/bisheng/utils/minio_client.py b/src/backend/bisheng/utils/minio_client.py index cb6a90816..82994922d 100644 --- a/src/backend/bisheng/utils/minio_client.py +++ b/src/backend/bisheng/utils/minio_client.py @@ -138,12 +138,14 @@ def object_exists(self, bucket_name, object_name, **kwargs): raise e def get_object(self, bucket_name, object_name, **kwargs) -> bytes: + response = None try: response = self.minio_client.get_object(bucket_name, object_name, **kwargs) return response.read() finally: - response.close() - response.release_conn() + if response: + response.close() + response.release_conn() def copy_object( self, diff --git a/src/backend/bisheng/workflow/nodes/report/report.py b/src/backend/bisheng/workflow/nodes/report/report.py index d2dab3aae..a1c49117d 100644 --- a/src/backend/bisheng/workflow/nodes/report/report.py +++ b/src/backend/bisheng/workflow/nodes/report/report.py @@ -20,6 +20,8 @@ def __init__(self, *args, **kwargs): def _run(self, unique_id: str): # 下载报告模板文件 + if not self._minio_client.object_exists(self._minio_client.bucket, self._object_name): + raise Exception(f"{self.name}节点模板文件不存在,请先编辑对应的报告模板") file_content = self._minio_client.get_object(self._minio_client.bucket, self._object_name) doc_parse = DocxTemplateRender(file_content=io.BytesIO(file_content)) # 获取所有的节点变量 diff --git a/src/frontend/public/locales/en/bs.json b/src/frontend/public/locales/en/bs.json index 2b02847c4..4ff26e760 100644 --- a/src/frontend/public/locales/en/bs.json +++ b/src/frontend/public/locales/en/bs.json @@ -830,6 +830,7 @@ "10520": "Skill does not exist", "10521": "Skill is online, cannot edit", "10525": "Workflow is online and cannot be edited", + "10530": "Template name already exists", "10900": "Knowledge base name already exists", "10901": "Knowledge base must select an embedding model", "10910": "Current knowledge base version does not support segment modification. Please create a new knowledge base to modify segments.", diff --git a/src/frontend/public/locales/zh/bs.json b/src/frontend/public/locales/zh/bs.json index bb56fbe97..826975290 100644 --- a/src/frontend/public/locales/zh/bs.json +++ b/src/frontend/public/locales/zh/bs.json @@ -827,6 +827,7 @@ "10520": "技能不存在", "10521": "技能已上线,不可编辑", "10525": "工作流已上线,不可编辑", + "10530": "模板名称已存在", "10900": "知识库名称不可重复", "10901": "知识库必须选择一个embedding模型", "10910": "当前知识库版本不支持修改分段,请创建新知识库后进行分段修改", diff --git a/src/frontend/src/components/bs-comp/apiComponent/index.tsx b/src/frontend/src/components/bs-comp/apiComponent/index.tsx index f375496d2..4b8cc0de3 100644 --- a/src/frontend/src/components/bs-comp/apiComponent/index.tsx +++ b/src/frontend/src/components/bs-comp/apiComponent/index.tsx @@ -27,7 +27,7 @@ const ApiMainPage = ({ type = API_TYPE.ASSISTANT }) => { case 'no-login-link': return ; case 'login-link': - // return ; + return ; default: return ; } diff --git a/src/frontend/src/components/bs-icons/rbDrag/Drag.svg b/src/frontend/src/components/bs-icons/rbDrag/Drag.svg new file mode 100644 index 000000000..f443d7dcb --- /dev/null +++ b/src/frontend/src/components/bs-icons/rbDrag/Drag.svg @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/src/frontend/src/components/bs-icons/rbDrag/index.tsx b/src/frontend/src/components/bs-icons/rbDrag/index.tsx new file mode 100644 index 000000000..15c0131cb --- /dev/null +++ b/src/frontend/src/components/bs-icons/rbDrag/index.tsx @@ -0,0 +1,9 @@ +import React, { forwardRef } from "react"; +import Drag from "./Drag.svg?react"; + +export const RbDragIcon = forwardRef< + SVGSVGElement & { className: any }, + React.PropsWithChildren<{ className?: string }> +>(({ className, ...props }, ref) => { + return ; +}); \ No newline at end of file diff --git a/src/frontend/src/components/inputFileComponent/index.tsx b/src/frontend/src/components/inputFileComponent/index.tsx index 437068512..0ff50da21 100644 --- a/src/frontend/src/components/inputFileComponent/index.tsx +++ b/src/frontend/src/components/inputFileComponent/index.tsx @@ -5,6 +5,8 @@ import { TabsContext } from "../../contexts/tabsContext"; import { uploadFile } from "../../controllers/API"; import { uploadFileWithProgress } from "../../modals/UploadModal/upload"; import { FileComponentType } from "../../types/components"; +import { LoadIcon } from "../bs-icons/loading"; +import { Button } from "../bs-ui/button"; export default function InputFileComponent({ value, @@ -115,20 +117,17 @@ export default function InputFileComponent({ > {myValue !== "" ? myValue : placeholder} - + {!editNode && loading && ()} + ); diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index 84058a305..58c33bf95 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -85,7 +85,7 @@ export async function readTempsDatabase(type, id?: number): Promise } /** - * 创建模板. + * 创建模板.(工作流\助手\技能) * * @param data {flow_id name description} * @returns null. diff --git a/src/frontend/src/controllers/API/workflow.ts b/src/frontend/src/controllers/API/workflow.ts index af028ebe7..c54160e83 100644 --- a/src/frontend/src/controllers/API/workflow.ts +++ b/src/frontend/src/controllers/API/workflow.ts @@ -336,7 +336,7 @@ const workflowTemplate = [ { "key": "model_id", "label": "模型", - "type": "bisheng_model", + "type": "agent_model", "required": true, "value": "", "placeholder": "请选择模型" @@ -401,7 +401,7 @@ const workflowTemplate = [ "type": "knowledge_select_multi", "placeholder": "请选择知识库", "value": { - "tab": "knowledge", + "type": "knowledge", "value": [] } } diff --git a/src/frontend/src/pages/BuildPage/apps.tsx b/src/frontend/src/pages/BuildPage/apps.tsx index 272b9e53b..56892a0b9 100644 --- a/src/frontend/src/pages/BuildPage/apps.tsx +++ b/src/frontend/src/pages/BuildPage/apps.tsx @@ -4,6 +4,7 @@ import AppTempSheet from "@/components/bs-comp/sheets/AppTempSheet"; import { LoadingIcon } from "@/components/bs-icons/loading"; import { MoveOneIcon } from "@/components/bs-icons/moveOne"; import { bsConfirm } from "@/components/bs-ui/alertDialog/useConfirm"; +import { Badge } from "@/components/bs-ui/badge"; import { Button } from "@/components/bs-ui/button"; import { SearchInput } from "@/components/bs-ui/input"; import AutoPagination from "@/components/bs-ui/pagination/autoPagination"; @@ -12,7 +13,7 @@ import SelectSearch from "@/components/bs-ui/select/select"; import { useToast } from "@/components/bs-ui/toast/use-toast"; import { userContext } from "@/contexts/userContext"; import { readTempsDatabase } from "@/controllers/API"; -import { changeAssistantStatusApi } from "@/controllers/API/assistant"; +import { changeAssistantStatusApi, deleteAssistantApi } from "@/controllers/API/assistant"; import { deleteFlowFromDatabase, getAppsApi, saveFlowToDatabase, updataOnlineState } from "@/controllers/API/flow"; import { onlineWorkflow } from "@/controllers/API/workflow"; import { captureAndAlertRequestErrorHoc } from "@/controllers/request"; @@ -27,7 +28,6 @@ import { useQueryLabels } from "./assistant"; import CreateApp from "./CreateApp"; import CardSelectVersion from "./skills/CardSelectVersion"; import CreateTemp from "./skills/CreateTemp"; -import { Badge } from "@/components/bs-ui/badge"; export const SelectType = ({ all = false, defaultValue = 'all', onChange }) => { const [value, setValue] = useState(defaultValue) @@ -113,7 +113,8 @@ export default function apps() { desc: descMap[data.flow_type], okTxt: t('delete'), onOk(next) { - captureAndAlertRequestErrorHoc(deleteFlowFromDatabase(data.id).then(reload)); + const promise = data.flow_type == 5 ? deleteAssistantApi(data.id) : deleteFlowFromDatabase(data.id) + captureAndAlertRequestErrorHoc(promise.then(reload)); next() } }) diff --git a/src/frontend/src/pages/BuildPage/assistant/editAssistant/Setting.tsx b/src/frontend/src/pages/BuildPage/assistant/editAssistant/Setting.tsx index 030144d71..dec6ceb44 100644 --- a/src/frontend/src/pages/BuildPage/assistant/editAssistant/Setting.tsx +++ b/src/frontend/src/pages/BuildPage/assistant/editAssistant/Setting.tsx @@ -13,6 +13,7 @@ import { import { Button } from "@/components/bs-ui/button"; import { Input, InputList, Textarea } from "@/components/bs-ui/input"; import { + QuestionTooltip, Tooltip, TooltipContent, TooltipProvider, @@ -73,16 +74,7 @@ export default function Setting() {
dispatchAssistant("setting", { max_token: Number(e.target.value) }) diff --git a/src/frontend/src/pages/BuildPage/flow/FlowChat/ChatMessages.tsx b/src/frontend/src/pages/BuildPage/flow/FlowChat/ChatMessages.tsx index 8bd83b114..a95cf364c 100644 --- a/src/frontend/src/pages/BuildPage/flow/FlowChat/ChatMessages.tsx +++ b/src/frontend/src/pages/BuildPage/flow/FlowChat/ChatMessages.tsx @@ -119,10 +119,6 @@ export default function ChatMessages({ mark = false, logo, useName, guideWord, l return ; case 'node_run': return ; - // case 'file': - // return ; - // case 'runLog': - // return ; default: return
Unknown message type
; } diff --git a/src/frontend/src/pages/BuildPage/flow/FlowChat/messageStore.ts b/src/frontend/src/pages/BuildPage/flow/FlowChat/messageStore.ts index 531bdd8b1..9b26eeee4 100644 --- a/src/frontend/src/pages/BuildPage/flow/FlowChat/messageStore.ts +++ b/src/frontend/src/pages/BuildPage/flow/FlowChat/messageStore.ts @@ -54,7 +54,7 @@ const handleHistoryMsg = (data: any[]): ChatMessageType[] => { .replace(/\t/g, '\\t') // 转义制表符 .replace(/'/g, '"'); // 将单引号替换为双引号 - return data.filter(item => ['answer', 'question', 'processing', 'system', 'report', 'tool', 'knowledge', 'divider', 'flow'].includes(item.category)).map(item => { + return data.filter(item => ["question", "output_input_msg", "output_choose_msg", "stream_msg", "output_msg", "guide_question", "guide_word", "user_input", "node_run"].includes(item.category)).map(item => { let { message, files, is_bot, intermediate_steps, category, ...other } = item try { message = message && message[0] === '{' ? JSON.parse(message) : message || '' @@ -170,6 +170,7 @@ export const useMessageStore = create((set, get) => ({ }) }, async loadHistoryMsg(flowid, chatId, { lastMsg }) { + console.log('1234 :>> ', 1234); const res = await getChatHistory(flowid, chatId, 30, 0) const msgs = handleHistoryMsg(res) const hisMessages = msgs.reverse() diff --git a/src/frontend/src/pages/BuildPage/flow/FlowNode/Parameter.tsx b/src/frontend/src/pages/BuildPage/flow/FlowNode/Parameter.tsx index 86381f217..6e9230d12 100644 --- a/src/frontend/src/pages/BuildPage/flow/FlowNode/Parameter.tsx +++ b/src/frontend/src/pages/BuildPage/flow/FlowNode/Parameter.tsx @@ -67,6 +67,8 @@ export default function Parameter({ nodeId, item, onOutPutChange, onStatusChange return case 'bisheng_model': return + case 'agent_model': + return case 'slide': return case 'slide_switch': diff --git a/src/frontend/src/pages/BuildPage/flow/FlowNode/component/KnowledgeSelectItem.tsx b/src/frontend/src/pages/BuildPage/flow/FlowNode/component/KnowledgeSelectItem.tsx index 4cb4744d3..379033f7b 100644 --- a/src/frontend/src/pages/BuildPage/flow/FlowNode/component/KnowledgeSelectItem.tsx +++ b/src/frontend/src/pages/BuildPage/flow/FlowNode/component/KnowledgeSelectItem.tsx @@ -26,8 +26,8 @@ type KnowledgeTypeValues = `${KnowledgeType}`; export default function KnowledgeSelectItem({ data, onChange, onValidate }) { const { flow } = useFlowStore() - const currentTabRef = useRef(data.value.tab) - const [tabType, setTabType] = useState(data.value.tab) + const currentTabRef = useRef(data.value.type) + const [tabType, setTabType] = useState(data.value.type) const [value, setValue] = useState(() => data.value.value.map(el => { return { label: el.label, value: el.key } })) diff --git a/src/frontend/src/pages/BuildPage/flow/FlowNode/component/ModelItem.tsx b/src/frontend/src/pages/BuildPage/flow/FlowNode/component/ModelItem.tsx index 860ff989e..fbf901db9 100644 --- a/src/frontend/src/pages/BuildPage/flow/FlowNode/component/ModelItem.tsx +++ b/src/frontend/src/pages/BuildPage/flow/FlowNode/component/ModelItem.tsx @@ -1,13 +1,13 @@ import { Label } from "@/components/bs-ui/label"; import Cascader from "@/components/bs-ui/select/cascader"; -import { getModelListApi } from "@/controllers/API/finetune"; +import { getAssistantModelList, getModelListApi } from "@/controllers/API/finetune"; import { useEffect, useMemo, useState } from "react"; -export default function ModelItem({ data, onChange, onValidate }) { +export default function ModelItem({ agent = false, data, onChange, onValidate }) { const [options, setOptions] = useState([]) useEffect(() => { - getModelListApi().then(res => { + (agent ? getAssistantModelList() : getModelListApi()).then(res => { let llmOptions = [] let embeddings = [] res.forEach(server => { diff --git a/src/frontend/src/pages/BuildPage/flow/FlowNode/component/VarInput.tsx b/src/frontend/src/pages/BuildPage/flow/FlowNode/component/VarInput.tsx index 6b7010fcf..69a9fd6de 100644 --- a/src/frontend/src/pages/BuildPage/flow/FlowNode/component/VarInput.tsx +++ b/src/frontend/src/pages/BuildPage/flow/FlowNode/component/VarInput.tsx @@ -2,9 +2,10 @@ import { Button } from "@/components/bs-ui/button"; import { Label } from "@/components/bs-ui/label"; import { isVarInFlow } from "@/util/flowUtils"; import { UploadCloud, Variable } from "lucide-react"; -import { useEffect, useRef } from "react"; +import { useEffect, useRef, useState } from "react"; import useFlowStore from "../../flowStore"; import SelectVar from "./SelectVar"; +import { RbDragIcon } from "@/components/bs-icons/rbDrag"; // 解析富文本内容为保存格式 function parseToValue(input, flowNode) { @@ -36,56 +37,67 @@ function parseToValue(input, flowNode) { } -export default function VarInput({ nodeId, itemKey, placeholder = '', flowNode, value, error = false, children = null, onUpload = undefined, onChange, onVarEvent = undefined }) { +export default function VarInput({ + nodeId, + itemKey, + placeholder = '', + flowNode, + value, + error = false, + children = null, + onUpload = undefined, + onChange, + onVarEvent = undefined, +}) { const { textareaRef, handleFocus, handleBlur } = usePlaceholder(placeholder); const valueRef = useRef(value || ''); const selectVarRef = useRef(null); - const { flow } = useFlowStore() + const { flow } = useFlowStore(); // 校验变量是否可用 const validateVarAvailble = () => { const value = valueRef.current; - const [html, error] = parseToHTML(value || '', true) - textareaRef.current.innerHTML = html - return error - } - useEffect(() => { - onVarEvent && onVarEvent(validateVarAvailble) - return () => onVarEvent && onVarEvent(() => { }) - }, [flowNode]) + const [html, error] = parseToHTML(value || '', true); + textareaRef.current.innerHTML = html; + return error; + }; + useEffect(() => { + onVarEvent && onVarEvent(validateVarAvailble); + return () => onVarEvent && onVarEvent(() => { }); + }, [flowNode]); const handleInput = () => { - const value = parseToValue(textareaRef.current.innerHTML, flowNode) + const value = parseToValue(textareaRef.current.innerHTML, flowNode); // console.log('textarea value :>> ', value); valueRef.current = value; onChange(value); - } + }; function parseToHTML(input, validate = false) { - let error = '' + let error = ''; const html = input .replace(/{{#(.*?)#}}/g, (a, part) => { if (validate) { - error = isVarInFlow(nodeId, flow.nodes, part, flowNode.varZh?.[part]) + error = isVarInFlow(nodeId, flow.nodes, part, flowNode.varZh?.[part]); } const msgZh = flowNode.varZh?.[part] || part; - return `${msgZh}` + return `${msgZh}`; }) .replace(/\n/g, '
'); - return [html, error] + return [html, error]; } useEffect(() => { // console.log('value :>> ', value); textareaRef.current.innerHTML = parseToHTML(value || '')[0]; - handleBlur() - }, []) + handleBlur(); + }, []); // 在光标位置插入内容 function handleInsertVariable(item, _var) { - handleFocus() + handleFocus(); const selection = window.getSelection(); let range = selection.getRangeAt(0); @@ -100,17 +112,17 @@ export default function VarInput({ nodeId, itemKey, placeholder = '', flowNode, } // 文本框内容 - const key = `${item.id}.${_var.value}` - const label = `${item.name}/${_var.label}` + const key = `${item.id}.${_var.value}`; + const label = `${item.name}/${_var.label}`; if (flowNode.varZh) { - flowNode.varZh[key] = label + flowNode.varZh[key] = label; } else { flowNode.varZh = { - [key]: label - } + [key]: label, + }; } - const html = `${label}` + const html = `${label}`; const fragment = range.createContextualFragment(html); const lastChild = fragment.lastChild; // 提前保存引用 @@ -127,46 +139,99 @@ export default function VarInput({ nodeId, itemKey, placeholder = '', flowNode, console.warn('No valid child nodes to insert.'); } - handleInput() + handleInput(); } const handlePaste = (e) => { // fomat text - e.preventDefault(); // 阻止默认粘贴行为 - const text = e.clipboardData.getData('text'); // 从剪贴板中获取纯文本内容 + e.preventDefault(); // 阻止默认粘贴行为 + const text = e.clipboardData.getData('text'); // 从剪贴板中获取纯文本内容 document.execCommand('insertText', false, text); - } + }; + // resize + const { height, handleMouseDown } = useResize(textareaRef, 80, 40); - return
-
textareaRef.current.focus()}> - -
- - - - {onUpload && } + return ( +
+
textareaRef.current.focus()}> + +
+ + + + {onUpload && ( + + )} +
+
{ + // 唤起插入变量 + if (e.key === '{') { + selectVarRef.current.open(); + e.preventDefault(); + } + }} + className="nowheel bisheng-richtext px-3 py-2 whitespace-pre-line min-h-[80px] max-h-64 overflow-y-auto overflow-x-hidden border-none outline-none bg-search-input rounded-md dark:text-gray-50 placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50" + >
+ {children} +
-
{ - // 唤起插入变量 - if (e.key === '{') { - selectVarRef.current.open() - e.preventDefault(); - } - }} - className="nowheel bisheng-richtext px-3 py-2 whitespace-pre-line min-h-[80px] max-h-24 overflow-y-auto overflow-x-hidden border-none outline-none bg-search-input rounded-md dark:text-gray-50 placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50" - >
- {children} -
+ ); +} + +const useResize = (textareaRef, initialHeight = 80, minHeight = 40) => { + const [height, setHeight] = useState(initialHeight); // 初始高度 + + // 处理拖拽调整高度 + const handleDrag = (e) => { + e.preventDefault(); + const newHeight = e.clientY - textareaRef.current.getBoundingClientRect().top; + if (newHeight > minHeight) { + setHeight(newHeight); // 更新高度 + } + }; + + const handleMouseUp = () => { + document.removeEventListener('mousemove', handleDrag); // 停止拖拽 + document.removeEventListener('mouseup', handleMouseUp); + }; + + const handleMouseDown = (e) => { + document.addEventListener('mousemove', handleDrag); // 开始拖拽 + document.addEventListener('mouseup', handleMouseUp); + }; + + useEffect(() => { + // 在组件卸载时清理事件监听器 + return () => { + document.removeEventListener('mousemove', handleDrag); + document.removeEventListener('mouseup', handleMouseUp); + }; + }, []); + + return { + height, + textareaRef, + handleMouseDown + }; }; diff --git a/src/frontend/src/pages/BuildPage/flow/Sidebar.tsx b/src/frontend/src/pages/BuildPage/flow/Sidebar.tsx index f028954cd..d3c7a77be 100644 --- a/src/frontend/src/pages/BuildPage/flow/Sidebar.tsx +++ b/src/frontend/src/pages/BuildPage/flow/Sidebar.tsx @@ -127,7 +127,7 @@ export default function Sidebar({ dropdown = false, onInitStartNode = (node: any {/* tool */} - + {toolTemps.map((temp, index) => diff --git a/src/frontend/src/pages/BuildPage/skills/editSkill/Header.tsx b/src/frontend/src/pages/BuildPage/skills/editSkill/Header.tsx index a24b1504f..4f4b56f35 100644 --- a/src/frontend/src/pages/BuildPage/skills/editSkill/Header.tsx +++ b/src/frontend/src/pages/BuildPage/skills/editSkill/Header.tsx @@ -25,7 +25,7 @@ import { useTranslation } from "react-i18next"; import { useNavigate } from "react-router-dom"; import TipPng from "@/assets/tip.jpg"; -export default function Header({ flow }) { +export default function Header({ flow, onTabChange }) { const navgate = useNavigate() const { t } = useTranslation() const { message } = useToast() @@ -105,6 +105,7 @@ export default function Header({ flow }) { })) } + const [tabType, setTabType] = useState('edit') return
{ loading &&
@@ -131,6 +132,18 @@ export default function Header({ flow }) { {t('skills.simplify')}
+ {/* api */} +
+
{ setTabType('edit'); onTabChange('edit') }} + >{t('api.skillOrchestration')}
+
{ setTabType('api'); onTabChange('api') }} + >{t('api.externalPublishing')} +
+
{ version &&
- +
{/* 删除确认 */} diff --git a/src/frontend/src/pages/ChatAppPage/components/ChatPanne.tsx b/src/frontend/src/pages/ChatAppPage/components/ChatPanne.tsx index 0e60243c2..8cefca209 100644 --- a/src/frontend/src/pages/ChatAppPage/components/ChatPanne.tsx +++ b/src/frontend/src/pages/ChatAppPage/components/ChatPanne.tsx @@ -68,10 +68,13 @@ export default function ChatPanne({ customWsHost = '', appendHistory = false, da setAssistant(null) setFlow(null) const _flow = await getFlowApi(id, version) - version === 'v1' ? loadFlowHistoryMsg(_flow.id, chatId, { + version === 'v1' ? await loadFlowHistoryMsg(_flow.id, chatId, { lastMsg: '本轮会话已结束' }).then(res => + { + console.log('1234 :>> ', 1234); setAutoRun(!res.length) + } // setAutoRun() ) : clearMsgs() const { data, ...f } = _flow