diff --git a/.gitignore b/.gitignore index 9042026819..b9c688dcc1 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,5 @@ nltk_data/ # Exclude hash-like temporary files like 9b5ad71b2ce5302211f9c61530b329a4922fc6a4 *[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]* .lh/ +.venv +docker/data diff --git a/agent/canvas.py b/agent/canvas.py index 3b22128b30..302b98c5f6 100644 --- a/agent/canvas.py +++ b/agent/canvas.py @@ -17,7 +17,6 @@ import logging import json from copy import deepcopy from functools import partial - import pandas as pd from agent.component import component_class @@ -362,4 +361,7 @@ class Canvas: return self.components["begin"]["obj"]._param.query def get_component_input_elements(self, cpnnm): - return self.components[cpnnm]["obj"].get_input_elements() \ No newline at end of file + return self.components[cpnnm]["obj"].get_input_elements() + + def set_component_infor(self, cpn_id, infor): + self.components[cpn_id]["obj"].set_infor(infor) diff --git a/agent/component/base.py b/agent/component/base.py index f03c5d1070..15b3c345e1 100644 --- a/agent/component/base.py +++ b/agent/component/base.py @@ -34,6 +34,7 @@ _IS_RAW_CONF = "_is_raw_conf" class ComponentParamBase(ABC): def __init__(self): self.output_var_name = "output" + self.infor_var_name = "infor" self.message_history_window_size = 22 self.query = [] self.inputs = [] @@ -462,6 +463,9 @@ class ComponentBase(ABC): def set_output(self, v): setattr(self._param, self._param.output_var_name, v) + def set_infor(self, v): + setattr(self._param, self._param.infor_var_name, v) + def _fetch_outputs_from(self, sources: list[dict[str, Any]]) -> list[pd.DataFrame]: outs = [] for q in sources: @@ -488,7 +492,6 @@ class ComponentBase(ABC): elif q.get("value"): outs.append(pd.DataFrame([{"content": q["value"]}])) return outs - def get_input(self): if self._param.debug_inputs: return pd.DataFrame([{"content": v["value"]} for v in self._param.debug_inputs if v.get("value")]) diff --git a/agent/component/categorize.py b/agent/component/categorize.py index 4d8715f097..9171f809aa 100644 --- a/agent/component/categorize.py +++ b/agent/component/categorize.py @@ -85,6 +85,8 @@ class Categorize(Generate, ABC): input = self.get_input() input = " - ".join(input["content"]) if "content" in input else "" chat_mdl = LLMBundle(self._canvas.get_tenant_id(), LLMType.CHAT, self._param.llm_id) + self._canvas.set_component_infor(self._id, {"prompt":self._param.get_prompt(input),"messages": [{"role": "user", "content": "\nCategory: "}],"conf": self._param.gen_conf()}) + ans = chat_mdl.chat(self._param.get_prompt(input), [{"role": "user", "content": "\nCategory: "}], self._param.gen_conf()) logging.debug(f"input: {input}, answer: {str(ans)}") diff --git a/agent/component/generate.py b/agent/component/generate.py index 7972f77d7d..ed0eeeeeee 100644 --- a/agent/component/generate.py +++ b/agent/component/generate.py @@ -201,7 +201,7 @@ class Generate(ComponentBase): msg.append({"role": "user", "content": "Output: "}) ans = chat_mdl.chat(msg[0]["content"], msg[1:], self._param.gen_conf()) ans = re.sub(r"^.*", "", ans, flags=re.DOTALL) - + self._canvas.set_component_infor(self._id, {"prompt":msg[0]["content"],"messages": msg[1:],"conf": self._param.gen_conf()}) if self._param.cite and "chunks" in retrieval_res.columns: res = self.set_cite(retrieval_res, ans) return pd.DataFrame([res]) @@ -234,7 +234,7 @@ class Generate(ComponentBase): if self._param.cite and "chunks" in retrieval_res.columns: res = self.set_cite(retrieval_res, answer) yield res - + self._canvas.set_component_infor(self._id, {"prompt":msg[0]["content"],"messages": msg[1:],"conf": self._param.gen_conf()}) self.set_output(Generate.be_output(res)) def debug(self, **kwargs): diff --git a/agent/component/keyword.py b/agent/component/keyword.py index 4a0b54f28c..a34a1ad462 100644 --- a/agent/component/keyword.py +++ b/agent/component/keyword.py @@ -58,6 +58,8 @@ class KeywordExtract(Generate, ABC): chat_mdl = LLMBundle(self._canvas.get_tenant_id(), LLMType.CHAT, self._param.llm_id) + self._canvas.set_component_infor(self._id, {"prompt":self._param.get_prompt(),"messages": [{"role": "user", "content": query}],"conf": self._param.gen_conf()}) + ans = chat_mdl.chat(self._param.get_prompt(), [{"role": "user", "content": query}], self._param.gen_conf()) diff --git a/api/apps/canvas_app.py b/api/apps/canvas_app.py index 6a9787f6cc..efb1e1cd35 100644 --- a/api/apps/canvas_app.py +++ b/api/apps/canvas_app.py @@ -26,7 +26,6 @@ from api.utils.api_utils import get_json_result, server_error_response, validate from agent.canvas import Canvas from peewee import MySQLDatabase, PostgresqlDatabase from api.db.db_models import APIToken -import logging import time @manager.route('/templates', methods=['GET']) # noqa: F821 @@ -89,7 +88,6 @@ def save(): @login_required def get(canvas_id): e, c = UserCanvasService.get_by_tenant_id(canvas_id) - logging.info(f"get canvas_id: {canvas_id} c: {c}") if not e: return get_data_error_result(message="canvas not found.") return get_json_result(data=c) diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index 82c3a367c0..b98574c603 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -1258,6 +1258,7 @@ This delimiter is used to split the input text into several text pieces echo of promptTip: 'Use the system prompt to describe the task for the LLM, specify how it should respond, and outline other miscellaneous requirements. The system prompt is often used in conjunction with keys (variables), which serve as various data inputs for the LLM. Use a forward slash `/` or the (x) button to show the keys to use.', promptMessage: 'Prompt is required', + infor: 'Information run', knowledgeBasesTip: 'Select the knowledge bases to associate with this chat assistant, or choose variables containing knowledge base IDs below.', knowledgeBaseVars: 'Knowledge base variables', diff --git a/web/src/pages/flow/canvas/node/popover.tsx b/web/src/pages/flow/canvas/node/popover.tsx index 342ce40eba..871aa80643 100644 --- a/web/src/pages/flow/canvas/node/popover.tsx +++ b/web/src/pages/flow/canvas/node/popover.tsx @@ -1,11 +1,15 @@ import { useFetchFlow } from '@/hooks/flow-hooks'; import get from 'lodash/get'; -import React, { MouseEventHandler, useCallback, useMemo } from 'react'; +import React, { + MouseEventHandler, + useCallback, + useMemo, + useState, +} from 'react'; import JsonView from 'react18-json-view'; import 'react18-json-view/src/style.css'; import { useReplaceIdWithText } from '../../hooks'; -import { useTheme } from '@/components/theme-provider'; import { Popover, PopoverContent, @@ -20,6 +24,17 @@ import { TableRow, } from '@/components/ui/table'; import { useTranslate } from '@/hooks/common-hooks'; +import { + Button, + Card, + Col, + Input, + Row, + Space, + Tabs, + Typography, + message, +} from 'antd'; import { useGetComponentLabelByValue } from '../../hooks/use-get-begin-query'; interface IProps extends React.PropsWithChildren { @@ -31,7 +46,8 @@ export function NextNodePopover({ children, nodeId, name }: IProps) { const { t } = useTranslate('flow'); const { data } = useFetchFlow(); - const { theme } = useTheme(); + console.log(data); + const component = useMemo(() => { return get(data, ['dsl', 'components', nodeId], {}); }, [nodeId, data]); @@ -42,6 +58,11 @@ export function NextNodePopover({ children, nodeId, name }: IProps) { [], ); const output = get(component, ['obj', 'output'], {}); + const { conf, messages, prompt } = get( + component, + ['obj', 'params', 'infor'], + {}, + ); const { replacedOutput } = useReplaceIdWithText(output); const stopPropagation: MouseEventHandler = useCallback((e) => { e.stopPropagation(); @@ -49,6 +70,13 @@ export function NextNodePopover({ children, nodeId, name }: IProps) { const getLabel = useGetComponentLabelByValue(nodeId); + const [inputPage, setInputPage] = useState(1); + const pageSize = 3; + const pagedInputs = inputs.slice( + (inputPage - 1) * pageSize, + inputPage * pageSize, + ); + return ( @@ -59,62 +87,226 @@ export function NextNodePopover({ children, nodeId, name }: IProps) { side={'right'} sideOffset={20} onClick={stopPropagation} - className="w-[400px]" + className="w-[800px] p-4" + style={{ maxHeight: 600, overflow: 'auto' }} > -
- {name} {t('operationResults')} -
-
-
- {t('input')} -
- - - - {t('componentId')} - {t('content')} - - - - {inputs.map((x, idx) => ( - - {getLabel(x.component_id)} - {x.content} - - ))} - -
-
-
-
- {t('output')} -
- -
-
-
+ + + {name} {t('operationResults')} + + + + + + + {t('componentId')} + + {t('content')} + + + + + {pagedInputs.map((x, idx) => ( + + {getLabel(x.component_id)} + + {x.content} + + + ))} + +
+ {/* Pagination */} + {inputs.length > pageSize && ( + + + + + {inputPage} / {Math.ceil(inputs.length / pageSize)} + + + + + )} + + ), + }, + { + key: 'output', + label: t('output'), + children: ( + + + + ), + }, + { + key: 'infor', + label: t('infor'), + children: ( + + + + {conf && ( + + + Configuration: + + + + )} + {prompt && ( + + + + + Prompt: + + + + + + + + + )} + + + {messages && ( + + + Messages: + +
+ +
+
+ )} + +
+
+ ), + }, + ]} + />
);