mirror of
https://git.mirrors.martin98.com/https://github.com/infiniflow/ragflow.git
synced 2025-08-14 05:05:54 +08:00
add show debug (#7390)
### What problem does this PR solve? add show debug  ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
parent
d05e8a173d
commit
514c08a932
2
.gitignore
vendored
2
.gitignore
vendored
@ -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
|
||||
|
@ -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()
|
||||
return self.components[cpnnm]["obj"].get_input_elements()
|
||||
|
||||
def set_component_infor(self, cpn_id, infor):
|
||||
self.components[cpn_id]["obj"].set_infor(infor)
|
||||
|
@ -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")])
|
||||
|
@ -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)}")
|
||||
|
@ -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"^.*</think>", "", 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):
|
||||
|
@ -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())
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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',
|
||||
|
@ -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 (
|
||||
<Popover>
|
||||
<PopoverTrigger onClick={stopPropagation} asChild>
|
||||
@ -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' }}
|
||||
>
|
||||
<div className="mb-3 font-semibold text-[16px]">
|
||||
{name} {t('operationResults')}
|
||||
</div>
|
||||
<div className="flex w-full gap-4 flex-col">
|
||||
<div className="flex flex-col space-y-1.5">
|
||||
<span className="font-semibold text-[14px]">{t('input')}</span>
|
||||
<div
|
||||
style={
|
||||
theme === 'dark'
|
||||
? {
|
||||
backgroundColor: 'rgba(150, 150, 150, 0.2)',
|
||||
}
|
||||
: {}
|
||||
}
|
||||
className={`bg-gray-100 p-1 rounded`}
|
||||
>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>{t('componentId')}</TableHead>
|
||||
<TableHead className="w-[60px]">{t('content')}</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{inputs.map((x, idx) => (
|
||||
<TableRow key={idx}>
|
||||
<TableCell>{getLabel(x.component_id)}</TableCell>
|
||||
<TableCell className="truncate">{x.content}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col space-y-1.5">
|
||||
<span className="font-semibold text-[14px]">{t('output')}</span>
|
||||
<div
|
||||
style={
|
||||
theme === 'dark'
|
||||
? {
|
||||
backgroundColor: 'rgba(150, 150, 150, 0.2)',
|
||||
}
|
||||
: {}
|
||||
}
|
||||
className="bg-gray-100 p-1 rounded"
|
||||
>
|
||||
<JsonView
|
||||
src={replacedOutput}
|
||||
displaySize={30}
|
||||
className="w-full max-h-[300px] break-words overflow-auto"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Card
|
||||
bordered={false}
|
||||
style={{ marginBottom: 16, padding: 0 }}
|
||||
bodyStyle={{ padding: 0 }}
|
||||
>
|
||||
<Typography.Title
|
||||
level={5}
|
||||
style={{
|
||||
marginBottom: 16,
|
||||
fontWeight: 600,
|
||||
fontSize: 18,
|
||||
borderBottom: '1px solid #f0f0f0',
|
||||
paddingBottom: 8,
|
||||
}}
|
||||
>
|
||||
{name} {t('operationResults')}
|
||||
</Typography.Title>
|
||||
</Card>
|
||||
<Tabs
|
||||
defaultActiveKey="input"
|
||||
items={[
|
||||
{
|
||||
key: 'input',
|
||||
label: t('input'),
|
||||
children: (
|
||||
<Card
|
||||
size="small"
|
||||
className="bg-gray-50 dark:bg-gray-800"
|
||||
style={{ borderRadius: 8, border: '1px solid #e5e7eb' }}
|
||||
bodyStyle={{ padding: 16 }}
|
||||
>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>{t('componentId')}</TableHead>
|
||||
<TableHead className="w-[60px]">
|
||||
{t('content')}
|
||||
</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{pagedInputs.map((x, idx) => (
|
||||
<TableRow key={idx + (inputPage - 1) * pageSize}>
|
||||
<TableCell>{getLabel(x.component_id)}</TableCell>
|
||||
<TableCell className="truncate">
|
||||
{x.content}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
{/* Pagination */}
|
||||
{inputs.length > pageSize && (
|
||||
<Row justify="end" style={{ marginTop: 8 }}>
|
||||
<Space>
|
||||
<Button
|
||||
size="small"
|
||||
disabled={inputPage === 1}
|
||||
onClick={() => setInputPage(inputPage - 1)}
|
||||
>
|
||||
Prev
|
||||
</Button>
|
||||
<span className="mx-2 text-sm">
|
||||
{inputPage} / {Math.ceil(inputs.length / pageSize)}
|
||||
</span>
|
||||
<Button
|
||||
size="small"
|
||||
disabled={
|
||||
inputPage === Math.ceil(inputs.length / pageSize)
|
||||
}
|
||||
onClick={() => setInputPage(inputPage + 1)}
|
||||
>
|
||||
Next
|
||||
</Button>
|
||||
</Space>
|
||||
</Row>
|
||||
)}
|
||||
</Card>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'output',
|
||||
label: t('output'),
|
||||
children: (
|
||||
<Card
|
||||
size="small"
|
||||
className="bg-gray-50 dark:bg-gray-800"
|
||||
style={{ borderRadius: 8, border: '1px solid #e5e7eb' }}
|
||||
bodyStyle={{ padding: 16 }}
|
||||
>
|
||||
<JsonView
|
||||
src={replacedOutput}
|
||||
displaySize={30}
|
||||
className="w-full max-h-[300px] break-words overflow-auto"
|
||||
/>
|
||||
</Card>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'infor',
|
||||
label: t('infor'),
|
||||
children: (
|
||||
<Card
|
||||
size="small"
|
||||
className="bg-gray-50 dark:bg-gray-800"
|
||||
style={{ borderRadius: 8, border: '1px solid #e5e7eb' }}
|
||||
bodyStyle={{ padding: 16 }}
|
||||
>
|
||||
<Row gutter={16}>
|
||||
<Col span={12}>
|
||||
{conf && (
|
||||
<Card
|
||||
size="small"
|
||||
bordered={false}
|
||||
style={{
|
||||
marginBottom: 16,
|
||||
background: 'transparent',
|
||||
}}
|
||||
bodyStyle={{ padding: 0 }}
|
||||
>
|
||||
<Typography.Text
|
||||
strong
|
||||
style={{
|
||||
color: '#888',
|
||||
marginBottom: 8,
|
||||
display: 'block',
|
||||
}}
|
||||
>
|
||||
Configuration:
|
||||
</Typography.Text>
|
||||
<JsonView
|
||||
src={conf}
|
||||
displaySize={30}
|
||||
className="w-full max-h-[120px] break-words overflow-auto"
|
||||
/>
|
||||
</Card>
|
||||
)}
|
||||
{prompt && (
|
||||
<Card
|
||||
size="small"
|
||||
bordered={false}
|
||||
style={{ background: 'transparent' }}
|
||||
bodyStyle={{ padding: 0 }}
|
||||
>
|
||||
<Row
|
||||
align="middle"
|
||||
justify="space-between"
|
||||
style={{ marginBottom: 8 }}
|
||||
>
|
||||
<Col>
|
||||
<Typography.Text strong style={{ color: '#888' }}>
|
||||
Prompt:
|
||||
</Typography.Text>
|
||||
</Col>
|
||||
<Col>
|
||||
<Button
|
||||
size="small"
|
||||
onClick={() => {
|
||||
const inlineString = prompt
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim();
|
||||
navigator.clipboard.writeText(inlineString);
|
||||
message.success(
|
||||
'Prompt copied as single line!',
|
||||
);
|
||||
}}
|
||||
>
|
||||
Copy as single line
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
<Input.TextArea
|
||||
value={prompt}
|
||||
readOnly
|
||||
autoSize={{ minRows: 2, maxRows: 6 }}
|
||||
className="bg-white dark:bg-gray-900 border-gray-200 dark:border-gray-700"
|
||||
/>
|
||||
</Card>
|
||||
)}
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
{messages && (
|
||||
<Card
|
||||
size="small"
|
||||
bordered={false}
|
||||
style={{
|
||||
marginBottom: 16,
|
||||
background: 'transparent',
|
||||
}}
|
||||
bodyStyle={{ padding: 0 }}
|
||||
>
|
||||
<Typography.Text
|
||||
strong
|
||||
style={{
|
||||
color: '#888',
|
||||
marginBottom: 8,
|
||||
display: 'block',
|
||||
}}
|
||||
>
|
||||
Messages:
|
||||
</Typography.Text>
|
||||
<div className="max-h-[300px] overflow-auto">
|
||||
<JsonView
|
||||
src={messages}
|
||||
displaySize={30}
|
||||
className="w-full break-words"
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user