mirror of
https://github.com/csunny/DB-GPT.git
synced 2025-09-05 02:51:07 +00:00
feat(datasource): Support reasoning for ChatDashboard (#2401)
This commit is contained in:
@@ -13,6 +13,76 @@ import MuiLoading from '../common/loading';
|
||||
import Completion from './completion';
|
||||
import Header from './header';
|
||||
|
||||
// Function to extract JSON from vis-thinking code blocks
|
||||
const parseVisThinking = (content: any) => {
|
||||
// Check if content is a string
|
||||
if (typeof content !== 'string') {
|
||||
return content;
|
||||
}
|
||||
|
||||
// Check if this is a vis-thinking code block
|
||||
if (content.startsWith('```vis-thinking') || content.includes('```vis-thinking')) {
|
||||
// Find where the JSON part begins
|
||||
// We're looking for the first occurrence of '{"' after the vis-thinking header
|
||||
const jsonStartIndex = content.indexOf('{"');
|
||||
|
||||
if (jsonStartIndex !== -1) {
|
||||
// Extract everything from the JSON start to the end
|
||||
const jsonContent = content.substring(jsonStartIndex);
|
||||
|
||||
// Attempt to parse the JSON
|
||||
try {
|
||||
return JSON.parse(jsonContent);
|
||||
} catch {
|
||||
// If there's a parsing error, try to clean up the JSON string
|
||||
// This might happen if there are backticks at the end
|
||||
const cleanedContent = jsonContent.replace(/```$/g, '').trim();
|
||||
try {
|
||||
return JSON.parse(cleanedContent);
|
||||
} catch (e2) {
|
||||
console.error('Error parsing cleaned JSON:', e2);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If it's not a vis-thinking block, try to parse it directly as JSON
|
||||
try {
|
||||
return typeof content === 'string' ? JSON.parse(content) : content;
|
||||
} catch {
|
||||
// If it's not valid JSON, return the original content
|
||||
console.log('Not JSON format or vis-thinking format, returning original content');
|
||||
return content;
|
||||
}
|
||||
};
|
||||
|
||||
// Function to extract the thinking part from vis-thinking code blocks while preserving tags
|
||||
const formatToVisThinking = (content: any) => {
|
||||
// Only process strings
|
||||
if (typeof content !== 'string') {
|
||||
return content;
|
||||
}
|
||||
|
||||
// Check if this is a vis-thinking code block
|
||||
if (content.startsWith('```vis-thinking') || content.includes('```vis-thinking')) {
|
||||
// Find the start of the vis-thinking block
|
||||
const blockStartIndex = content.indexOf('```vis-thinking');
|
||||
const thinkingStartIndex = blockStartIndex + '```vis-thinking'.length;
|
||||
|
||||
// Find the end of the vis-thinking block
|
||||
const thinkingEndIndex = content.indexOf('```', thinkingStartIndex);
|
||||
|
||||
if (thinkingEndIndex !== -1) {
|
||||
// Extract the thinking content with the tags
|
||||
return content.substring(blockStartIndex, thinkingEndIndex + 3);
|
||||
}
|
||||
}
|
||||
|
||||
// If it's not a vis-thinking block or can't extract thinking part, return the original content
|
||||
return content;
|
||||
};
|
||||
|
||||
const ChatContainer = () => {
|
||||
const searchParams = useSearchParams();
|
||||
const { scene, chatId, model, agent, setModel, history, setHistory } = useContext(ChatContext);
|
||||
@@ -33,7 +103,17 @@ const ChatContainer = () => {
|
||||
const contextTemp = list[list.length - 1]?.context;
|
||||
if (contextTemp) {
|
||||
try {
|
||||
const contextObj = typeof contextTemp === 'string' ? JSON.parse(contextTemp) : contextTemp;
|
||||
// First, parse the context to handle vis-thinking code blocks
|
||||
const parsedContext = parseVisThinking(contextTemp);
|
||||
|
||||
// Then, handle the normal JSON processing
|
||||
const contextObj =
|
||||
typeof parsedContext === 'object'
|
||||
? parsedContext
|
||||
: typeof contextTemp === 'string'
|
||||
? JSON.parse(contextTemp)
|
||||
: contextTemp;
|
||||
|
||||
setChartsData(contextObj?.template_name === 'report' ? contextObj?.charts : undefined);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
@@ -127,7 +207,11 @@ const ChatContainer = () => {
|
||||
'h-full lg:px-8': scene !== 'chat_dashboard',
|
||||
})}
|
||||
>
|
||||
<Completion messages={history} onSubmit={handleChat} />
|
||||
<Completion
|
||||
messages={history}
|
||||
onSubmit={handleChat}
|
||||
onFormatContent={formatToVisThinking} // Pass the formatting function to Completion
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
@@ -25,9 +25,10 @@ import MonacoEditor from './monaco-editor';
|
||||
type Props = {
|
||||
messages: IChatDialogueMessageSchema[];
|
||||
onSubmit: (message: string, otherQueryBody?: Record<string, any>) => Promise<void>;
|
||||
onFormatContent?: (content: any) => any; // Callback for extracting thinking part
|
||||
};
|
||||
|
||||
const Completion = ({ messages, onSubmit }: Props) => {
|
||||
const Completion = ({ messages, onSubmit, onFormatContent }: Props) => {
|
||||
const { dbParam, currentDialogue, scene, model, refreshDialogList, chatId, agent, docId } = useContext(ChatContext);
|
||||
const { t } = useTranslation();
|
||||
const searchParams = useSearchParams();
|
||||
@@ -78,18 +79,23 @@ const Completion = ({ messages, onSubmit }: Props) => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleJson2Obj = (jsonStr: string) => {
|
||||
try {
|
||||
return JSON.parse(jsonStr);
|
||||
} catch {
|
||||
return jsonStr;
|
||||
// Process message content - if onFormatContent is provided and this is a dashboard chat,
|
||||
// we'll extract the thinking part from vis-thinking code blocks
|
||||
const processMessageContent = (content: any) => {
|
||||
if (isChartChat && onFormatContent && typeof content === 'string') {
|
||||
return onFormatContent(content);
|
||||
}
|
||||
return content;
|
||||
};
|
||||
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
|
||||
const onCopyContext = async (context: any) => {
|
||||
const pureStr = context?.replace(/\trelations:.*/g, '');
|
||||
// If we have a formatting function and this is a string, apply it before copying
|
||||
const contentToCopy =
|
||||
isChartChat && onFormatContent && typeof context === 'string' ? onFormatContent(context) : context;
|
||||
|
||||
const pureStr = contentToCopy?.replace(/\trelations:.*/g, '');
|
||||
const result = copy(pureStr);
|
||||
if (result) {
|
||||
if (pureStr) {
|
||||
@@ -124,14 +130,25 @@ const Completion = ({ messages, onSubmit }: Props) => {
|
||||
let tempMessage: IChatDialogueMessageSchema[] = messages;
|
||||
if (isChartChat) {
|
||||
tempMessage = cloneDeep(messages).map(item => {
|
||||
if (item?.role === 'view' && typeof item?.context === 'string') {
|
||||
item.context = handleJson2Obj(item?.context);
|
||||
if (item?.role === 'view') {
|
||||
if (typeof item?.context === 'string') {
|
||||
// Try to parse JSON first
|
||||
try {
|
||||
item.context = JSON.parse(item.context);
|
||||
} catch {
|
||||
// If JSON parsing fails and we have a formatting function,
|
||||
// it might be a vis-thinking block, so process it
|
||||
if (onFormatContent) {
|
||||
item.context = processMessageContent(item.context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return item;
|
||||
});
|
||||
}
|
||||
setShowMessages(tempMessage.filter(item => ['view', 'human'].includes(item.role)));
|
||||
}, [isChartChat, messages]);
|
||||
}, [isChartChat, messages, onFormatContent]);
|
||||
|
||||
useEffect(() => {
|
||||
apiInterceptors(getChatFeedBackSelect())
|
||||
|
Reference in New Issue
Block a user