feat: UI component rendering in agent dialog mode (#1083)

Co-authored-by: csunny <cfqsunny@163.com>
This commit is contained in:
Hzh_97 2024-01-18 11:08:02 +08:00 committed by GitHub
parent 674104eb7c
commit 0936856c3a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
46 changed files with 1597 additions and 73 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
self.__BUILD_MANIFEST=function(s,c,a,t,e,n,k,d,f,h,b,i,u,j){return{__rewrites:{beforeFiles:[],afterFiles:[],fallback:[]},"/":["static/chunks/29107295-90b90cb30c825230.js",s,c,t,a,k,d,f,b,"static/chunks/861-78929b4f98dbbfd6.js","static/chunks/161-96143606b49cf4a1.js","static/chunks/pages/index-06183caf17230eba.js"],"/_error":["static/chunks/pages/_error-dee72aff9b2e2c12.js"],"/agent":[s,c,a,e,k,n,"static/chunks/pages/agent-2503b783a880d8dd.js"],"/chat":["static/chunks/pages/chat-a869c66578892120.js"],"/database":[s,c,t,a,e,n,f,h,"static/chunks/643-467e61c6d77597ec.js","static/chunks/pages/database-3f935c41115f9437.js"],"/knowledge":[i,s,c,a,e,k,n,f,u,h,b,"static/chunks/221-c10c5bf4eb885ce7.js","static/chunks/549-a7015f243d580f77.js","static/chunks/pages/knowledge-1848ba7d6a088e19.js"],"/knowledge/chunk":[s,t,e,d,n,"static/chunks/pages/knowledge/chunk-866a4383a7183b98.js"],"/models":[i,s,c,t,a,j,h,"static/chunks/pages/models-12ab4fc3d6a6b72c.js"],"/prompt":[s,c,t,a,j,d,u,"static/chunks/346-8340afd21e100a59.js","static/chunks/607-ecec81b815dc298b.js","static/chunks/pages/prompt-09aa8ca136c58eb8.js"],sortedPages:["/","/_app","/_error","/agent","/chat","/database","/knowledge","/knowledge/chunk","/models","/prompt"]}}("static/chunks/113-15fc0b8bd2b5b9a1.js","static/chunks/17-26dc9ac6c4adec30.js","static/chunks/479-784a3b3622f6eb73.js","static/chunks/9-31700d34ab596955.js","static/chunks/442-d388a67ef689277f.js","static/chunks/813-cce9482e33f2430c.js","static/chunks/553-a89ad624ca0f1ffa.js","static/chunks/810-120b98a5da95cba3.js","static/chunks/411-b5d3e7f64bee2335.js","static/chunks/928-5a69f9ff4dc4129f.js","static/chunks/234-42f62dc360b2d9e4.js","static/chunks/75fc9c18-a784766a129ec5fb.js","static/chunks/45-9ff739c09925ea35.js","static/chunks/947-5980a3ff49069ddd.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();

View File

@ -0,0 +1 @@
self.__SSG_MANIFEST=new Set([]);self.__SSG_MANIFEST_CB&&self.__SSG_MANIFEST_CB()

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -16,10 +16,10 @@ interface IChatContext {
model: string;
dbParam?: string;
modelList: Array<string>;
agentList: string[];
agent: string;
dialogueList?: DialogueListResponse;
setAgent?: (val: string) => void;
setMode: (mode: ThemeMode) => void;
setAgentList?: (val: string[]) => void;
setModel: (val: string) => void;
setIsContract: (val: boolean) => void;
setIsMenuExpand: (val: boolean) => void;
@ -47,8 +47,8 @@ const ChatContext = createContext<IChatContext>({
model: '',
dbParam: undefined,
dialogueList: [],
agentList: [],
setAgentList: () => {},
agent: '',
setAgent: () => {},
setModel: () => {},
setIsContract: () => {},
setIsMenuExpand: () => {},
@ -72,7 +72,7 @@ const ChatContextProvider = ({ children }: { children: React.ReactElement }) =>
const [model, setModel] = useState<string>('');
const [isMenuExpand, setIsMenuExpand] = useState<boolean>(scene !== 'chat_dashboard');
const [dbParam, setDbParam] = useState<string>(db_param);
const [agentList, setAgentList] = useState<string[]>([]);
const [agent, setAgent] = useState<string>('');
const [history, setHistory] = useState<ChatHistoryResponse>([]);
const [docId, setDocId] = useState<number>();
const [mode, setMode] = useState<ThemeMode>('light');
@ -91,6 +91,13 @@ const ChatContextProvider = ({ children }: { children: React.ReactElement }) =>
},
);
useEffect(() => {
if (dialogueList.length && scene === 'chat_agent') {
const agent = dialogueList.find((item) => item.conv_uid === chatId)?.select_param;
agent && setAgent(agent);
}
}, [dialogueList, scene, chatId]);
const { data: modelList = [] } = useRequest(async () => {
const [, res] = await apiInterceptors(getUsableModels());
return res ?? [];
@ -114,10 +121,10 @@ const ChatContextProvider = ({ children }: { children: React.ReactElement }) =>
model,
dbParam: dbParam || db_param,
dialogueList,
agentList,
agent,
setAgent,
mode,
setMode,
setAgentList,
setModel,
setIsContract,
setIsMenuExpand,

View File

@ -179,12 +179,15 @@ const en = {
Retry: 'Retry',
Load_more: 'load more',
new_chat: 'New Chat',
choice_agent_tip: 'Please choose an agent',
no_context_tip: 'Please enter your question',
Terminal: 'Terminal',
} as const;
type I18nKeys = keyof typeof en;
export type I18nKeys = keyof typeof en;
export interface Resources {
translation: Record<I18nKeys, string> & { [key: string]: string };
translation: Record<I18nKeys, string>;
}
const zh: Resources['translation'] = {
@ -364,6 +367,9 @@ const zh: Resources['translation'] = {
Retry: '重试',
Load_more: '加载更多',
new_chat: '创建会话',
choice_agent_tip: '请选择代理',
no_context_tip: '请输入你的问题',
Terminal: '终端',
} as const;
i18n.use(initReactI18next).init({

View File

@ -11,7 +11,13 @@ import {
PostEditorSQLRunParams,
PostSQLEditorSubmitParams,
} from '@/types/editor';
import { PostAgentHubUpdateParams, PostAgentQueryParams, PostAgentPluginResponse, PostAgentMyPluginResponse } from '@/types/agent';
import {
PostAgentHubUpdateParams,
PostAgentQueryParams,
PostAgentPluginResponse,
PostAgentMyPluginResponse,
GetDBGPTsListResponse,
} from '@/types/agent';
import {
AddKnowledgeParams,
ArgumentsParams,
@ -211,6 +217,9 @@ export const postAgentUpload = (user = '', data: FormData, config?: Omit<AxiosRe
...config,
});
};
export const getDbgptsList = () => {
return GET<undefined, GetDBGPTsListResponse>('/api/v1/dbgpts/list');
};
/** chat feedback **/
export const getChatFeedBackSelect = () => {

View File

@ -1,7 +1,7 @@
import { Empty, Row, Col, Select, Tooltip } from 'antd';
import { Advice, Advisor } from '@antv/ava';
import { Chart } from '@berryv/g2-react';
import i18n from '@/app/i18n';
import i18n, { I18nKeys } from '@/app/i18n';
import { customizeAdvisor, getVisAdvices } from './advisor/pipeline';
import { useContext, useEffect, useMemo, useState } from 'react';
import { defaultAdvicesFilter } from './advisor/utils';
@ -62,6 +62,8 @@ export const AutoChart = (props: AutoChartProps) => {
options={{
...spec,
theme: mode,
autoFit: true,
height: 300,
}}
/>
);
@ -83,7 +85,7 @@ export const AutoChart = (props: AutoChartProps) => {
size={'small'}
>
{advices?.map((item) => {
const name = i18n.t(item.type);
const name = i18n.t(item.type as I18nKeys);
return (
<Option key={item.type} value={item.type}>

View File

@ -0,0 +1,40 @@
import { ChatContext } from '@/app/chat-context';
import { IChatDialogueMessageSchema } from '@/types/chat';
import classNames from 'classnames';
import { memo, useContext } from 'react';
import ReactMarkdown from 'react-markdown';
import markdownComponents from './chat-content/config';
import rehypeRaw from 'rehype-raw';
interface Props {
content: IChatDialogueMessageSchema;
}
function formatMarkdownVal(val: string) {
return val.replace(/<table(\w*=[^>]+)>/gi, '<table $1>').replace(/<tr(\w*=[^>]+)>/gi, '<tr $1>');
}
function AgentContent({ content }: Props) {
const { scene } = useContext(ChatContext);
const isView = content.role === 'view';
return (
<div
className={classNames('relative w-full p-2 md:p-4 rounded-xl break-words', {
'bg-white dark:bg-[#232734]': isView,
'lg:w-full xl:w-full pl-0': ['chat_with_db_execute', 'chat_dashboard'].includes(scene),
})}
>
{isView ? (
<ReactMarkdown components={markdownComponents} rehypePlugins={[rehypeRaw]}>
{formatMarkdownVal(content.context)}
</ReactMarkdown>
) : (
<div className="">{content.context}</div>
)}
</div>
);
}
export default memo(AgentContent);

View File

@ -15,7 +15,7 @@ import { getInitMessage } from '@/utils';
const ChatContainer = () => {
const searchParams = useSearchParams();
const { scene, chatId, model, setModel, history, setHistory } = useContext(ChatContext);
const { scene, chatId, model, agent, setModel, history, setHistory } = useContext(ChatContext);
const chat = useChat({});
const initMessage = (searchParams && searchParams.get('initMessage')) ?? '';
@ -95,7 +95,7 @@ const ChatContainer = () => {
});
});
},
[history, chat, model],
[history, chat, chatId, model, agent, scene],
);
return (
@ -122,7 +122,7 @@ const ChatContainer = () => {
)}
{/** chat panel */}
<div
className={classNames('flex flex-1 flex-col', {
className={classNames('flex flex-1 flex-col overflow-hidden', {
'px-0 xl:pl-4 h-2/5 w-full xl:w-auto xl:h-full border-t xl:border-t-0 xl:border-l dark:border-gray-800': scene === 'chat_dashboard',
'h-full lg:px-8': scene !== 'chat_dashboard',
})}

View File

@ -0,0 +1,39 @@
import ReactMarkdown from 'react-markdown';
import markdownComponents from './config';
import { renderModelIcon } from '../header/model-selector';
import { SwapRightOutlined } from '@ant-design/icons';
interface Props {
data: {
sender: string;
receiver: string;
model: string | null;
markdown: string;
}[];
}
function AgentMessages({ data }: Props) {
if (!data || !data.length) return null;
return (
<>
{data.map((item, index) => (
<div key={index} className="rounded my-4 md:my-6">
<div className="flex items-center mb-3 text-sm">
{item.model ? renderModelIcon(item.model) : <div className="rounded-full w-6 h-6 bg-gray-100" />}
<div className="ml-2 opacity-70">
{item.sender}
<SwapRightOutlined className="mx-2 text-base" />
{item.receiver}
</div>
</div>
<div className="whitespace-normal text-sm">
<ReactMarkdown components={markdownComponents}>{item.markdown}</ReactMarkdown>
</div>
</div>
))}
</>
);
}
export default AgentMessages;

View File

@ -0,0 +1,46 @@
import { CaretRightOutlined, CheckOutlined, ClockCircleOutlined } from '@ant-design/icons';
import { Collapse } from 'antd';
import ReactMarkdown from 'react-markdown';
import markdownComponents from './config';
interface Props {
data: {
name: string;
num: number;
status: 'complete' | 'todo';
agent: string;
markdown: string;
}[];
}
function AgentPlans({ data }: Props) {
if (!data || !data.length) return null;
return (
<Collapse
bordered
className="my-3"
expandIcon={({ isActive }) => <CaretRightOutlined rotate={isActive ? 90 : 0} />}
items={data.map((item, index) => {
return {
key: index,
label: (
<div className="whitespace-normal">
<span>
{item.name} - {item.agent}
</span>
{item.status === 'complete' ? (
<CheckOutlined className="!text-green-500 ml-2" />
) : (
<ClockCircleOutlined className="!text-gray-500 ml-2" />
)}
</div>
),
children: <ReactMarkdown components={markdownComponents}>{item.markdown}</ReactMarkdown>,
};
})}
/>
);
}
export default AgentPlans;

View File

@ -0,0 +1,38 @@
import { Datum } from '@antv/ava';
import { Table, Tabs, TabsProps } from 'antd';
import React from 'react';
import { format } from 'sql-formatter';
import { AutoChart, BackEndChartType, getChartType } from '@/components/chart/autoChart';
import { CodePreview } from './code-preview';
function ChartView({ data, type, sql }: { data: Datum[]; type: BackEndChartType; sql: string }) {
const columns = data?.[0]
? Object.keys(data?.[0])?.map((item) => {
return {
title: item,
dataIndex: item,
key: item,
};
})
: [];
const ChartItem = {
key: 'chart',
label: 'Chart',
children: <AutoChart data={data} chartType={getChartType(type)} />,
};
const SqlItem = {
key: 'sql',
label: 'SQL',
children: <CodePreview language="sql" code={format(sql, { language: 'mysql' }) as string} />,
};
const DataItem = {
key: 'data',
label: 'Data',
children: <Table dataSource={data} columns={columns} />,
};
const TabItems: TabsProps['items'] = type === 'response_table' ? [DataItem, SqlItem] : [ChartItem, SqlItem, DataItem];
return <Tabs defaultActiveKey={type === 'response_table' ? 'data' : 'chart'} items={TabItems} size="small" />;
}
export default ChartView;

View File

@ -3,10 +3,18 @@ import { CopyOutlined } from '@ant-design/icons';
import { oneDark, coldarkDark } from 'react-syntax-highlighter/dist/esm/styles/prism';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import copy from 'copy-to-clipboard';
import { useContext } from 'react';
import { CSSProperties, useContext } from 'react';
import { ChatContext } from '@/app/chat-context';
export function CodePreview({ code, language }: { code: string; language: string }) {
interface Props {
code: string;
language: string;
customStyle?: CSSProperties;
light?: { [key: string]: CSSProperties };
dark?: { [key: string]: CSSProperties };
}
export function CodePreview({ code, light, dark, language, customStyle }: Props) {
const { mode } = useContext(ChatContext);
return (
@ -20,7 +28,7 @@ export function CodePreview({ code, language }: { code: string; language: string
message[success ? 'success' : 'error'](success ? 'Copy success' : 'Copy failed');
}}
/>
<SyntaxHighlighter language={language} style={mode === 'dark' ? coldarkDark : oneDark}>
<SyntaxHighlighter customStyle={customStyle} language={language} style={mode === 'dark' ? dark ?? coldarkDark : light ?? oneDark}>
{code}
</SyntaxHighlighter>
</div>

View File

@ -8,6 +8,13 @@ import { CodePreview } from './code-preview';
import { Datum } from '@antv/ava';
import rehypeRaw from 'rehype-raw';
import { IChunk } from '@/types/knowledge';
import AgentPlans from './agent-plans';
import AgentMessages from './agent-messages';
import VisConvertError from './vis-convert-error';
import VisChart from './vis-chart';
import VisDashboard from './vis-dashboard';
import VisPlugin from './vis-plugin';
import VisCode from './vis-code';
type MarkdownComponent = Parameters<typeof ReactMarkdown>['0']['components'];
@ -27,18 +34,82 @@ function matchCustomeTagValues(context: string) {
const basicComponents: MarkdownComponent = {
code({ inline, node, className, children, style, ...props }) {
const content = String(children);
/**
* @description
* In some cases, tags are nested within code syntax,
* so it is necessary to extract the tags present in the code block and render them separately.
*/
const { context, matchValues } = matchCustomeTagValues(Array.isArray(children) ? children.join('\n') : children);
const match = /language-(\w+)/.exec(className || '');
const { context, matchValues } = matchCustomeTagValues(content);
const lang = className?.replace('language-', '') || 'javascript';
if (lang === 'agent-plans') {
try {
const data = JSON.parse(content) as Parameters<typeof AgentPlans>[0]['data'];
return <AgentPlans data={data} />;
} catch (e) {
return <CodePreview language={lang} code={content} />;
}
}
if (lang === 'agent-messages') {
try {
const data = JSON.parse(content) as Parameters<typeof AgentMessages>[0]['data'];
return <AgentMessages data={data} />;
} catch (e) {
return <CodePreview language={lang} code={content} />;
}
}
if (lang === 'vis-convert-error') {
try {
const data = JSON.parse(content) as Parameters<typeof VisConvertError>[0]['data'];
return <VisConvertError data={data} />;
} catch (e) {
return <CodePreview language={lang} code={content} />;
}
}
if (lang === 'vis-dashboard') {
try {
const data = JSON.parse(content) as Parameters<typeof VisDashboard>[0]['data'];
return <VisDashboard data={data} />;
} catch (e) {
return <CodePreview language={lang} code={content} />;
}
}
if (lang === 'vis-chart') {
try {
const data = JSON.parse(content) as Parameters<typeof VisChart>[0]['data'];
return <VisChart data={data} />;
} catch (e) {
return <CodePreview language={lang} code={content} />;
}
}
if (lang === 'vis-plugin') {
try {
const data = JSON.parse(content) as Parameters<typeof VisPlugin>[0]['data'];
return <VisPlugin data={data} />;
} catch (e) {
return <CodePreview language={lang} code={content} />;
}
}
if (lang === 'vis-code') {
try {
const data = JSON.parse(content) as Parameters<typeof VisCode>[0]['data'];
return <VisCode data={data} />;
} catch (e) {
return <CodePreview language={lang} code={content} />;
}
}
return (
<>
{!inline ? (
<CodePreview code={context} language={match?.[1] ?? 'javascript'} />
<CodePreview code={context} language={lang} />
) : (
<code {...props} style={style} className="p-1 mx-1 rounded bg-theme-light dark:bg-theme-dark text-sm">
{children}
@ -61,7 +132,7 @@ const basicComponents: MarkdownComponent = {
},
table({ children }) {
return (
<table className="my-2 rounded-tl-md rounded-tr-md max-w-full bg-white dark:bg-gray-900 text-sm rounded-lg overflow-hidden">{children}</table>
<table className="my-2 rounded-tl-md rounded-tr-md max-w-full bg-white dark:bg-gray-800 text-sm rounded-lg overflow-hidden">{children}</table>
);
},
thead({ children }) {

View File

@ -0,0 +1,19 @@
import { BackEndChartType } from '@/components/chart';
import ChartView from './chart-view';
import { Datum } from '@antv/ava';
interface Props {
data: {
data: Datum[];
describe: string;
title: string;
type: BackEndChartType;
sql: string;
};
}
function VisChart({ data }: Props) {
return <ChartView data={data.data} type={data.type} sql={data.sql} />;
}
export default VisChart;

View File

@ -0,0 +1,69 @@
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import markdownComponents from './config';
import { CodePreview } from './code-preview';
import classNames from 'classnames';
import { useState } from 'react';
import { CheckOutlined, CloseOutlined } from '@ant-design/icons';
import { useTranslation } from 'react-i18next';
import { oneLight, oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism';
interface Props {
data: {
code: string[];
exit_success: true;
language: string;
log: string;
};
}
function VisCode({ data }: Props) {
const { t } = useTranslation();
const [show, setShow] = useState(0);
return (
<div className="bg-[#EAEAEB] rounded overflow-hidden border border-theme-primary dark:bg-theme-dark text-sm">
<div>
<div className="flex">
{data.code.map((item, index) => (
<div
key={index}
className={classNames('px-4 py-2 text-[#121417] dark:text-white cursor-pointer', {
'bg-white dark:bg-theme-dark-container': index === show,
})}
onClick={() => {
setShow(index);
}}
>
CODE {index + 1}: {item[0]}
</div>
))}
</div>
{data.code.length && (
<CodePreview
language={data.code[show][0]}
code={data.code[show][1]}
customStyle={{ maxHeight: 300, margin: 0 }}
light={oneLight}
dark={oneDark}
/>
)}
</div>
<div>
<div className="flex">
<div className="bg-white dark:bg-theme-dark-container px-4 py-2 text-[#121417] dark:text-white">
{t('Terminal')} {data.exit_success ? <CheckOutlined className="text-green-600" /> : <CloseOutlined className="text-red-600" />}
</div>
</div>
<div className="p-4 max-h-72 overflow-y-auto whitespace-normal bg-white dark:dark:bg-theme-dark">
<ReactMarkdown components={markdownComponents} remarkPlugins={[remarkGfm]}>
{data.log}
</ReactMarkdown>
</div>
</div>
</div>
);
}
export default VisCode;

View File

@ -0,0 +1,24 @@
import { format } from 'sql-formatter';
import { CodePreview } from './code-preview';
interface Props {
data: {
display_type: string;
sql: string;
thought: string;
};
}
function VisConvertError({ data }: Props) {
return (
<div className="rounded overflow-hidden">
<div className="p-3 text-white bg-red-500 whitespace-normal">{data.display_type}</div>
<div className="p-3 bg-red-50">
<div className="mb-2 whitespace-normal">{data.thought}</div>
<CodePreview code={format(data.sql)} language="sql" />
</div>
</div>
);
}
export default VisConvertError;

View File

@ -0,0 +1,58 @@
import { AutoChart, BackEndChartType, getChartType } from '@/components/chart';
import { Datum } from '@antv/ava';
import { useMemo } from 'react';
interface Props {
data: {
data: {
data: Datum[];
describe: string;
title: string;
type: BackEndChartType;
sql: string;
}[];
title: string | null;
display_strategy: string;
chart_count: number;
};
}
const chartLayout = [[2], [1, 2], [1, 3], [2, 1, 2], [2, 1, 3], [3, 1, 3], [3, 2, 3]];
function VisDashboard({ data }: Props) {
const charts = useMemo(() => {
if (data.chart_count > 1) {
const layout = chartLayout[data.chart_count - 2];
let prevIndex = 0;
return layout.map((item) => {
const items = data.data.slice(prevIndex, prevIndex + item);
prevIndex = item;
return items;
});
}
return [data.data];
}, [data.data, data.chart_count]);
return (
<div className="flex flex-col gap-3">
{charts.map((row, index) => (
<div key={`row-${index}`} className="flex gap-3">
{row.map((chart, subIndex) => (
<div
key={`chart-${subIndex}`}
className="flex flex-1 flex-col justify-between p-4 rounded border border-gray-200 dark:border-gray-500 whitespace-normal"
>
<div>
{chart.title && <div className="mb-2 text-lg">{chart.title}</div>}
{chart.describe && <div className="mb-4 text-sm text-gray-500">{chart.describe}</div>}
</div>
<AutoChart data={chart.data} chartType={getChartType(chart.type)} />
</div>
))}
</div>
))}
</div>
);
}
export default VisDashboard;

View File

@ -0,0 +1,64 @@
import { CheckOutlined, ClockCircleOutlined, CloseOutlined, LoadingOutlined } from '@ant-design/icons';
import classNames from 'classnames';
import { ReactNode } from 'react';
import ReactMarkdown from 'react-markdown';
import markdownComponents from './config';
import rehypeRaw from 'rehype-raw';
interface IVisPlugin {
name: string;
args: {
query: string;
};
status: 'todo' | 'runing' | 'failed' | 'complete' | (string & {});
logo: string | null;
result: string;
err_msg: string | null;
}
interface Props {
data: IVisPlugin;
}
const pluginViewStatusMapper: Record<IVisPlugin['status'], { bgClass: string; icon: ReactNode }> = {
todo: {
bgClass: 'bg-gray-500',
icon: <ClockCircleOutlined className="ml-2" />,
},
runing: {
bgClass: 'bg-blue-500',
icon: <LoadingOutlined className="ml-2" />,
},
failed: {
bgClass: 'bg-red-500',
icon: <CloseOutlined className="ml-2" />,
},
complete: {
bgClass: 'bg-green-500',
icon: <CheckOutlined className="ml-2" />,
},
};
function VisPlugin({ data }: Props) {
const { bgClass, icon } = pluginViewStatusMapper[data.status] ?? {};
return (
<div className="bg-theme-light dark:bg-theme-dark-container rounded overflow-hidden my-2 flex flex-col lg:max-w-[80%]">
<div className={classNames('flex px-4 md:px-6 py-2 items-center text-white text-sm', bgClass)}>
{data.name}
{icon}
</div>
{data.result ? (
<div className="px-4 md:px-6 py-4 text-sm whitespace-normal">
<ReactMarkdown components={markdownComponents} rehypePlugins={[rehypeRaw]}>
{data.result ?? ''}
</ReactMarkdown>
</div>
) : (
<div className="px-4 md:px-6 py-4 text-sm">{data.err_msg}</div>
)}
</div>
);
}
export default VisPlugin;

View File

@ -19,6 +19,7 @@ import { CopyOutlined, RedoOutlined } from '@ant-design/icons';
import { getInitMessage } from '@/utils';
import { apiInterceptors, getChatFeedBackSelect } from '@/client/api';
import useSummary from '@/hooks/use-summary';
import AgentContent from './agent-content';
type Props = {
messages: IChatDialogueMessageSchema[];
@ -26,7 +27,7 @@ type Props = {
};
const Completion = ({ messages, onSubmit }: Props) => {
const { dbParam, currentDialogue, scene, model, refreshDialogList, chatId, agentList, docId } = useContext(ChatContext);
const { dbParam, currentDialogue, scene, model, refreshDialogList, chatId, agent, docId } = useContext(ChatContext);
const { t } = useTranslation();
const searchParams = useSearchParams();
@ -47,19 +48,23 @@ const Completion = ({ messages, onSubmit }: Props) => {
const selectParam = useMemo(() => {
switch (scene) {
case 'chat_agent':
return agentList.join(',');
return agent;
case 'chat_excel':
return currentDialogue?.select_param;
default:
return spaceNameOriginal || dbParam;
}
}, [scene, agentList, currentDialogue, dbParam, spaceNameOriginal]);
}, [scene, agent, currentDialogue, dbParam, spaceNameOriginal]);
const handleChat = async (message: string) => {
if (isLoading || !message.trim()) return;
const handleChat = async (content: string) => {
if (isLoading || !content.trim()) return;
if (scene === 'chat_agent' && !agent) {
message.warning(t('choice_agent_tip'));
return;
}
try {
setIsLoading(true);
await onSubmit(message, {
await onSubmit(content, {
select_param: selectParam ?? '',
});
} finally {
@ -145,6 +150,9 @@ const Completion = ({ messages, onSubmit }: Props) => {
<div className="flex items-center flex-1 flex-col text-sm leading-6 text-slate-900 dark:text-slate-300 sm:text-base sm:leading-7">
{showMessages.length ? (
showMessages.map((content, index) => {
if (scene === 'chat_agent') {
return <AgentContent key={index} content={content} />;
}
return (
<ChatContent
key={index}

View File

@ -1,49 +1,28 @@
import { ChatContext } from '@/app/chat-context';
import { apiInterceptors, postAgentMy } from '@/client/api';
import { apiInterceptors, getDbgptsList } from '@/client/api';
import { useRequest } from 'ahooks';
import { Button, Select } from 'antd';
import { useRouter } from 'next/router';
import { Select } from 'antd';
import { useContext } from 'react';
import { useTranslation } from 'react-i18next';
function AgentSelector() {
const { push } = useRouter();
const { t } = useTranslation();
const { agentList, setAgentList } = useContext(ChatContext);
const { agent, setAgent } = useContext(ChatContext);
const { data = [] } = useRequest(async () => {
const [, res] = await apiInterceptors(postAgentMy());
if (res && res.length) {
setAgentList?.([res[0].name]);
}
const [, res] = await apiInterceptors(getDbgptsList());
return res ?? [];
});
if (!data.length) {
return (
<Button
type="primary"
onClick={() => {
push('/agent');
}}
>
{t('To_Plugin_Market')}
</Button>
);
}
return (
<Select
className="w-60"
value={agentList}
mode="multiple"
maxTagCount={1}
maxTagTextLength={12}
value={agent}
placeholder={t('Select_Plugins')}
options={data.map((item) => ({ label: item.name, value: item.name }))}
options={data.map((item) => ({ label: item.gpts_describe, value: item.gpts_name }))}
allowClear
onChange={(val) => {
setAgentList?.(val);
setAgent?.(val);
}}
/>
);

View File

@ -54,7 +54,8 @@ function smallMenuItemStyle(active?: boolean) {
}
function SideBar() {
const { chatId, scene, isMenuExpand, dialogueList, queryDialogueList, refreshDialogList, setIsMenuExpand, mode, setMode } = useContext(ChatContext);
const { chatId, scene, isMenuExpand, dialogueList, queryDialogueList, refreshDialogList, setIsMenuExpand, setAgent, mode, setMode } =
useContext(ChatContext);
const { pathname, replace } = useRouter();
const { t, i18n } = useTranslation();
@ -192,6 +193,12 @@ function SideBar() {
[refreshDialogList],
);
const handleClickChatItem = (item: IChatDialogueSchema) => {
if (item.chat_mode === 'chat_agent' && item.select_param) {
setAgent?.(item.select_param);
}
};
const copyLink = useCallback((item: IChatDialogueSchema) => {
const success = copy(`${location.origin}/chat?scene=${item.chat_mode}&id=${item.conv_uid}`);
message[success ? 'success' : 'error'](success ? 'Copy success' : 'Copy failed');
@ -223,7 +230,13 @@ function SideBar() {
return (
<Tooltip key={item.conv_uid} title={item.user_name || item.user_input} placement="right">
<Link href={`/chat?scene=${item.chat_mode}&id=${item.conv_uid}`} className={smallMenuItemStyle(active)}>
<Link
href={`/chat?scene=${item.chat_mode}&id=${item.conv_uid}`}
className={smallMenuItemStyle(active)}
onClick={() => {
handleClickChatItem(item);
}}
>
<MessageOutlined />
</Link>
</Tooltip>
@ -271,7 +284,14 @@ function SideBar() {
const active = item.conv_uid === chatId && item.chat_mode === scene;
return (
<Link key={item.conv_uid} href={`/chat?scene=${item.chat_mode}&id=${item.conv_uid}`} className={`group/item ${menuItemStyle(active)}`}>
<Link
key={item.conv_uid}
href={`/chat?scene=${item.chat_mode}&id=${item.conv_uid}`}
className={`group/item ${menuItemStyle(active)}`}
onClick={() => {
handleClickChatItem(item);
}}
>
<MessageOutlined className="text-base" />
<div className="flex-1 line-clamp-1 mx-2 text-sm">{item.user_name || item.user_input}</div>
<div

View File

@ -10,6 +10,7 @@ type Props = {
type ChatParams = {
chatId: string;
data?: Record<string, any>;
query?: Record<string, string>;
onMessage: (message: string) => void;
onClose?: () => void;
onDone?: () => void;
@ -22,7 +23,7 @@ const useChat = ({ queryAgentURL = '/api/v1/chat/completions' }: Props) => {
const chat = useCallback(
async ({ data, chatId, onMessage, onClose, onDone, onError }: ChatParams) => {
if (!data?.user_input && !data?.doc_id) {
message.warning(i18n.t('NoContextTip'));
message.warning(i18n.t('no_context_tip'));
return;
}
@ -58,7 +59,12 @@ const useChat = ({ queryAgentURL = '/api/v1/chat/completions' }: Props) => {
throw new Error(err);
},
onmessage: (event) => {
const message = event.data?.replaceAll('\\n', '\n');
let message = event.data;
try {
message = JSON.parse(message).vis;
} catch (e) {
message.replaceAll('\\n', '\n');
}
if (message === '[DONE]') {
onDone?.();
} else if (message?.startsWith('[ERROR]')) {

229
web/package-lock.json generated
View File

@ -35,6 +35,7 @@
"react-markdown": "^8.0.7",
"react-syntax-highlighter": "^15.5.0",
"rehype-raw": "6.1.1",
"remark-gfm": "^3.0.1",
"sql-formatter": "^12.2.4",
"tailwindcss": "3.3.2",
"tailwindcss-animated": "^1.0.1",
@ -3314,6 +3315,15 @@
}
]
},
"node_modules/ccount": {
"version": "2.0.1",
"resolved": "https://registry.npm.alibaba-inc.com/ccount/download/ccount-2.0.1.tgz",
"integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/center-align": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
@ -6144,6 +6154,11 @@
"node": ">=0.10.0"
}
},
"node_modules/longest-streak": {
"version": "3.1.0",
"resolved": "https://registry.npm.alibaba-inc.com/longest-streak/download/longest-streak-3.1.0.tgz",
"integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="
},
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@ -6168,6 +6183,11 @@
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/markdown-table": {
"version": "3.0.3",
"resolved": "https://registry.npm.alibaba-inc.com/markdown-table/download/markdown-table-3.0.3.tgz",
"integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw=="
},
"node_modules/mdast-util-definitions": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz",
@ -6182,6 +6202,25 @@
"url": "https://opencollective.com/unified"
}
},
"node_modules/mdast-util-find-and-replace": {
"version": "2.2.2",
"resolved": "https://registry.npm.alibaba-inc.com/mdast-util-find-and-replace/download/mdast-util-find-and-replace-2.2.2.tgz",
"integrity": "sha512-MTtdFRz/eMDHXzeK6W3dO7mXUlF82Gom4y0oOgvHhh/HXZAGvIQDUvQ0SuUx+j2tv44b8xTHOm8K/9OoRFnXKw==",
"dependencies": {
"@types/mdast": "^3.0.0",
"escape-string-regexp": "^5.0.0",
"unist-util-is": "^5.0.0",
"unist-util-visit-parents": "^5.0.0"
}
},
"node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": {
"version": "5.0.0",
"resolved": "https://registry.npm.alibaba-inc.com/escape-string-regexp/download/escape-string-regexp-5.0.0.tgz",
"integrity": "sha1-RoMSa1ALYXYvLb66zhgG6L4xscg=",
"engines": {
"node": ">=12"
}
},
"node_modules/mdast-util-from-markdown": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz",
@ -6205,6 +6244,79 @@
"url": "https://opencollective.com/unified"
}
},
"node_modules/mdast-util-gfm": {
"version": "2.0.2",
"resolved": "https://registry.npm.alibaba-inc.com/mdast-util-gfm/download/mdast-util-gfm-2.0.2.tgz",
"integrity": "sha512-qvZ608nBppZ4icQlhQQIAdc6S3Ffj9RGmzwUKUWuEICFnd1LVkN3EktF7ZHAgfcEdvZB5owU9tQgt99e2TlLjg==",
"dependencies": {
"mdast-util-from-markdown": "^1.0.0",
"mdast-util-gfm-autolink-literal": "^1.0.0",
"mdast-util-gfm-footnote": "^1.0.0",
"mdast-util-gfm-strikethrough": "^1.0.0",
"mdast-util-gfm-table": "^1.0.0",
"mdast-util-gfm-task-list-item": "^1.0.0",
"mdast-util-to-markdown": "^1.0.0"
}
},
"node_modules/mdast-util-gfm-autolink-literal": {
"version": "1.0.3",
"resolved": "https://registry.npm.alibaba-inc.com/mdast-util-gfm-autolink-literal/download/mdast-util-gfm-autolink-literal-1.0.3.tgz",
"integrity": "sha512-My8KJ57FYEy2W2LyNom4n3E7hKTuQk/0SES0u16tjA9Z3oFkF4RrC/hPAPgjlSpezsOvI8ObcXcElo92wn5IGA==",
"dependencies": {
"@types/mdast": "^3.0.0",
"ccount": "^2.0.0",
"mdast-util-find-and-replace": "^2.0.0",
"micromark-util-character": "^1.0.0"
}
},
"node_modules/mdast-util-gfm-footnote": {
"version": "1.0.2",
"resolved": "https://registry.npm.alibaba-inc.com/mdast-util-gfm-footnote/download/mdast-util-gfm-footnote-1.0.2.tgz",
"integrity": "sha512-56D19KOGbE00uKVj3sgIykpwKL179QsVFwx/DCW0u/0+URsryacI4MAdNJl0dh+u2PSsD9FtxPFbHCzJ78qJFQ==",
"dependencies": {
"@types/mdast": "^3.0.0",
"mdast-util-to-markdown": "^1.3.0",
"micromark-util-normalize-identifier": "^1.0.0"
}
},
"node_modules/mdast-util-gfm-strikethrough": {
"version": "1.0.3",
"resolved": "https://registry.npm.alibaba-inc.com/mdast-util-gfm-strikethrough/download/mdast-util-gfm-strikethrough-1.0.3.tgz",
"integrity": "sha512-DAPhYzTYrRcXdMjUtUjKvW9z/FNAMTdU0ORyMcbmkwYNbKocDpdk+PX1L1dQgOID/+vVs1uBQ7ElrBQfZ0cuiQ==",
"dependencies": {
"@types/mdast": "^3.0.0",
"mdast-util-to-markdown": "^1.3.0"
}
},
"node_modules/mdast-util-gfm-table": {
"version": "1.0.7",
"resolved": "https://registry.npm.alibaba-inc.com/mdast-util-gfm-table/download/mdast-util-gfm-table-1.0.7.tgz",
"integrity": "sha512-jjcpmNnQvrmN5Vx7y7lEc2iIOEytYv7rTvu+MeyAsSHTASGCCRA79Igg2uKssgOs1i1po8s3plW0sTu1wkkLGg==",
"dependencies": {
"@types/mdast": "^3.0.0",
"markdown-table": "^3.0.0",
"mdast-util-from-markdown": "^1.0.0",
"mdast-util-to-markdown": "^1.3.0"
}
},
"node_modules/mdast-util-gfm-task-list-item": {
"version": "1.0.2",
"resolved": "https://registry.npm.alibaba-inc.com/mdast-util-gfm-task-list-item/download/mdast-util-gfm-task-list-item-1.0.2.tgz",
"integrity": "sha512-PFTA1gzfp1B1UaiJVyhJZA1rm0+Tzn690frc/L8vNX1Jop4STZgOE6bxUhnzdVSB+vm2GU1tIsuQcA9bxTQpMQ==",
"dependencies": {
"@types/mdast": "^3.0.0",
"mdast-util-to-markdown": "^1.3.0"
}
},
"node_modules/mdast-util-phrasing": {
"version": "3.0.1",
"resolved": "https://registry.npm.alibaba-inc.com/mdast-util-phrasing/download/mdast-util-phrasing-3.0.1.tgz",
"integrity": "sha512-WmI1gTXUBJo4/ZmSk79Wcb2HcjPJBzM1nlI/OUWA8yk2X9ik3ffNbBGsU+09BFmXaL1IBb9fiuvq6/KMiNycSg==",
"dependencies": {
"@types/mdast": "^3.0.0",
"unist-util-is": "^5.0.0"
}
},
"node_modules/mdast-util-to-hast": {
"version": "12.3.0",
"resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-12.3.0.tgz",
@ -6224,6 +6336,21 @@
"url": "https://opencollective.com/unified"
}
},
"node_modules/mdast-util-to-markdown": {
"version": "1.5.0",
"resolved": "https://registry.npm.alibaba-inc.com/mdast-util-to-markdown/download/mdast-util-to-markdown-1.5.0.tgz",
"integrity": "sha512-bbv7TPv/WC49thZPg3jXuqzuvI45IL2EVAr/KxF0BSdHsU0ceFHOmwQn6evxAh1GaoK/6GQ1wp4R4oW2+LFL/A==",
"dependencies": {
"@types/mdast": "^3.0.0",
"@types/unist": "^2.0.0",
"longest-streak": "^3.0.0",
"mdast-util-phrasing": "^3.0.0",
"mdast-util-to-string": "^3.0.0",
"micromark-util-decode-string": "^1.0.0",
"unist-util-visit": "^4.0.0",
"zwitch": "^2.0.0"
}
},
"node_modules/mdast-util-to-string": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz",
@ -6311,6 +6438,92 @@
"uvu": "^0.5.0"
}
},
"node_modules/micromark-extension-gfm": {
"version": "2.0.3",
"resolved": "https://registry.npm.alibaba-inc.com/micromark-extension-gfm/download/micromark-extension-gfm-2.0.3.tgz",
"integrity": "sha512-vb9OoHqrhCmbRidQv/2+Bc6pkP0FrtlhurxZofvOEy5o8RtuuvTq+RQ1Vw5ZDNrVraQZu3HixESqbG+0iKk/MQ==",
"dependencies": {
"micromark-extension-gfm-autolink-literal": "^1.0.0",
"micromark-extension-gfm-footnote": "^1.0.0",
"micromark-extension-gfm-strikethrough": "^1.0.0",
"micromark-extension-gfm-table": "^1.0.0",
"micromark-extension-gfm-tagfilter": "^1.0.0",
"micromark-extension-gfm-task-list-item": "^1.0.0",
"micromark-util-combine-extensions": "^1.0.0",
"micromark-util-types": "^1.0.0"
}
},
"node_modules/micromark-extension-gfm-autolink-literal": {
"version": "1.0.5",
"resolved": "https://registry.npm.alibaba-inc.com/micromark-extension-gfm-autolink-literal/download/micromark-extension-gfm-autolink-literal-1.0.5.tgz",
"integrity": "sha512-z3wJSLrDf8kRDOh2qBtoTRD53vJ+CWIyo7uyZuxf/JAbNJjiHsOpG1y5wxk8drtv3ETAHutCu6N3thkOOgueWg==",
"dependencies": {
"micromark-util-character": "^1.0.0",
"micromark-util-sanitize-uri": "^1.0.0",
"micromark-util-symbol": "^1.0.0",
"micromark-util-types": "^1.0.0"
}
},
"node_modules/micromark-extension-gfm-footnote": {
"version": "1.1.2",
"resolved": "https://registry.npm.alibaba-inc.com/micromark-extension-gfm-footnote/download/micromark-extension-gfm-footnote-1.1.2.tgz",
"integrity": "sha512-Yxn7z7SxgyGWRNa4wzf8AhYYWNrwl5q1Z8ii+CSTTIqVkmGZF1CElX2JI8g5yGoM3GAman9/PVCUFUSJ0kB/8Q==",
"dependencies": {
"micromark-core-commonmark": "^1.0.0",
"micromark-factory-space": "^1.0.0",
"micromark-util-character": "^1.0.0",
"micromark-util-normalize-identifier": "^1.0.0",
"micromark-util-sanitize-uri": "^1.0.0",
"micromark-util-symbol": "^1.0.0",
"micromark-util-types": "^1.0.0",
"uvu": "^0.5.0"
}
},
"node_modules/micromark-extension-gfm-strikethrough": {
"version": "1.0.7",
"resolved": "https://registry.npm.alibaba-inc.com/micromark-extension-gfm-strikethrough/download/micromark-extension-gfm-strikethrough-1.0.7.tgz",
"integrity": "sha512-sX0FawVE1o3abGk3vRjOH50L5TTLr3b5XMqnP9YDRb34M0v5OoZhG+OHFz1OffZ9dlwgpTBKaT4XW/AsUVnSDw==",
"dependencies": {
"micromark-util-chunked": "^1.0.0",
"micromark-util-classify-character": "^1.0.0",
"micromark-util-resolve-all": "^1.0.0",
"micromark-util-symbol": "^1.0.0",
"micromark-util-types": "^1.0.0",
"uvu": "^0.5.0"
}
},
"node_modules/micromark-extension-gfm-table": {
"version": "1.0.7",
"resolved": "https://registry.npm.alibaba-inc.com/micromark-extension-gfm-table/download/micromark-extension-gfm-table-1.0.7.tgz",
"integrity": "sha512-3ZORTHtcSnMQEKtAOsBQ9/oHp9096pI/UvdPtN7ehKvrmZZ2+bbWhi0ln+I9drmwXMt5boocn6OlwQzNXeVeqw==",
"dependencies": {
"micromark-factory-space": "^1.0.0",
"micromark-util-character": "^1.0.0",
"micromark-util-symbol": "^1.0.0",
"micromark-util-types": "^1.0.0",
"uvu": "^0.5.0"
}
},
"node_modules/micromark-extension-gfm-tagfilter": {
"version": "1.0.2",
"resolved": "https://registry.npm.alibaba-inc.com/micromark-extension-gfm-tagfilter/download/micromark-extension-gfm-tagfilter-1.0.2.tgz",
"integrity": "sha512-5XWB9GbAUSHTn8VPU8/1DBXMuKYT5uOgEjJb8gN3mW0PNW5OPHpSdojoqf+iq1xo7vWzw/P8bAHY0n6ijpXF7g==",
"dependencies": {
"micromark-util-types": "^1.0.0"
}
},
"node_modules/micromark-extension-gfm-task-list-item": {
"version": "1.0.5",
"resolved": "https://registry.npm.alibaba-inc.com/micromark-extension-gfm-task-list-item/download/micromark-extension-gfm-task-list-item-1.0.5.tgz",
"integrity": "sha512-RMFXl2uQ0pNQy6Lun2YBYT9g9INXtWJULgbt01D/x8/6yJ2qpKyzdZD3pi6UIkzF++Da49xAelVKUeUMqd5eIQ==",
"dependencies": {
"micromark-factory-space": "^1.0.0",
"micromark-util-character": "^1.0.0",
"micromark-util-symbol": "^1.0.0",
"micromark-util-types": "^1.0.0",
"uvu": "^0.5.0"
}
},
"node_modules/micromark-factory-destination": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.1.0.tgz",
@ -8459,6 +8672,22 @@
"url": "https://opencollective.com/unified"
}
},
"node_modules/remark-gfm": {
"version": "3.0.1",
"resolved": "https://registry.npm.alibaba-inc.com/remark-gfm/download/remark-gfm-3.0.1.tgz",
"integrity": "sha1-CxgPCV4wNlRend2sDo3z+lz+5U8=",
"license": "MIT",
"dependencies": {
"@types/mdast": "^3.0.0",
"mdast-util-gfm": "^2.0.0",
"micromark-extension-gfm": "^2.0.0",
"unified": "^10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/remark-parse": {
"version": "10.0.2",
"resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.2.tgz",

View File

@ -38,6 +38,7 @@
"react-markdown": "^8.0.7",
"react-syntax-highlighter": "^15.5.0",
"rehype-raw": "6.1.1",
"remark-gfm": "^3.0.1",
"sql-formatter": "^12.2.4",
"tailwindcss": "3.3.2",
"tailwindcss-animated": "^1.0.1",
@ -62,4 +63,4 @@
"author": "",
"license": "ISC",
"repository": "https://github.com/eosphoros-ai/DB-GPT-Web.git"
}
}

View File

@ -59,3 +59,20 @@ export type IMyPlugin = {
};
export type PostAgentMyPluginResponse = IMyPlugin[];
export type GetDBGPTsListResponse = {
gpts_name: string;
gpts_describe: string;
resource_db: string;
resource_knowledge: string;
gpts_models: string;
language: string;
sys_code: string;
updated_at: string;
team_mode: string;
id: number;
resource_internet: string;
gpts_agents: string;
user_code: string;
created_at: string;
}[];

View File

@ -36,7 +36,15 @@ export type IChatDialogueSchema = {
conv_uid: string;
user_input: string;
user_name: string;
chat_mode: 'chat_with_db_execute' | 'chat_excel' | 'chat_with_db_qa' | 'chat_knowledge' | 'chat_dashboard' | 'chat_execution' | 'chat_agent';
chat_mode:
| 'chat_with_db_execute'
| 'chat_excel'
| 'chat_with_db_qa'
| 'chat_knowledge'
| 'chat_dashboard'
| 'chat_execution'
| 'chat_agent'
| (string & {});
select_param: string;
};