Commit ebd75809 authored by jaden's avatar jaden

feat: functions feature

parent 3e321e59
......@@ -3,6 +3,7 @@ import { backendApi } from '.';
import { getModel } from '@/utils/gpt';
import { fetchEventSource, EventStreamContentType } from '@microsoft/fetch-event-source';
import { MutableRefObject, SetStateAction } from 'react';
import { functions, get } from 'lodash';
export interface View {
type: 'schema' | 'table';
......@@ -36,6 +37,7 @@ export default class OpenAI {
onFinish: (responseText: string) => any,
onUpdate: (responseText: string, delta: string) => any,
onError: (e: Error) => any,
functions: any[] = [],
closeFn?: MutableRefObject<any>,
stream: boolean = true
) {
......@@ -46,6 +48,7 @@ export default class OpenAI {
frequency_penalty: model.frequency_penalty,
presence_penalty: model.presence_penalty,
stream,
functions: functions,
};
const controller = new AbortController();
const chatPayload = {
......@@ -116,8 +119,13 @@ export default class OpenAI {
}
const text = msg.data;
try {
console.log(text);
const json = JSON.parse(text);
const delta = json.choices[0].delta.content;
if (json.choices[0].finish_reason === 'function_call') {
// 🌟 output the Tree structure data
console.log(json);
}
if (delta) {
responseText += delta;
onUpdate?.(responseText, delta);
......@@ -139,7 +147,9 @@ export default class OpenAI {
const res = await fetch(chatPath, chatPayload);
clearTimeout(requestTimeoutId);
const resJson = await res.json();
const message = resJson.choices?.at(0)?.message?.content ?? '';
const message =
resJson.choices?.at(0)?.message?.content ??
(JSON.stringify(get(resJson, 'choices[0].message.function_call')) || '');
console.log(message);
onFinish(message);
}
......
......@@ -50,6 +50,8 @@ type AIProps = {
inputProps?: Record<string, any>;
SendButton?: ({ inputRef }: { inputRef: any }) => JSX.Element;
noHistory?: boolean;
functions: any[];
stream?: boolean;
};
export function AIWrapper({
......@@ -68,6 +70,8 @@ export function AIWrapper({
inputProps = {},
SendButton,
noHistory,
functions,
stream,
}: AIProps) {
const input = useRef<any>();
const scrollContainer = useRef<any>();
......@@ -164,7 +168,9 @@ export function AIWrapper({
content: undefined,
});
},
closeRef
functions,
closeRef,
stream || !functions
);
},
[
......
export const QUERY_FUNCTION = [
{
name: 'saveExecuteSqlInfo',
description: '存储执行该需求所需要的关键信息',
parameters: {
type: 'object',
properties: {
sql: {
type: 'string',
description: 'The SQL statement to execute',
},
variablesArr: {
type: 'array',
description: 'The array containing variables and their descriptions',
items: {
type: 'object',
properties: {
variable: {
type: 'string',
description: 'The variable',
},
varDescription: {
type: 'string',
description: 'The description of the variable',
},
},
required: ['variable', 'varDescription'],
},
},
queryName: {
type: 'string',
description: 'The name of the query',
},
queryDescription: {
type: 'string',
description: 'The description of the query',
},
},
required: ['sql', 'variablesArr', 'queryName', 'queryDescription'],
},
},
];
......@@ -372,7 +372,7 @@ export function ChatView({
const [FunctionOption, setFunctionOption] = useState<ReturnType<typeof Parser.parse>[]>([]);
return (
<div>
{props.length ? (
{propsRaw.length ? (
<>
<div className="flex justify-between items-center mb-[20px]">
<AI
......
......@@ -44,6 +44,7 @@ import {
filter,
find,
first,
forEach,
get,
isEqual,
map,
......@@ -73,6 +74,8 @@ import { DataTable, QueriesList } from './queriesList';
import { GET_QUERY, GET_SCHEMA_INFO } from '@/data/prompt';
import Welcome from 'components/AITool/MessageItem';
import * as queryTipRaw from '@/data/prompt/query-tip';
import { QUERY_FUNCTION } from '@/data/prompt/functions';
import { FunctionsJson, functionsJson } from '@/utils/getXMLContent';
const queryTip = map(queryTipRaw, v => {
return {
name: v,
......@@ -281,6 +284,8 @@ const MessageItemHOC = ({ setShowQueriesList, activeDb, currentModels, activeMod
queryName: any;
queryDescription: any;
}>(() => {
const funcJson = new FunctionsJson(message);
const elNode = document.createElement('div');
elNode.innerHTML = message;
let sqlNodes = elNode.querySelectorAll('sql');
......@@ -290,27 +295,19 @@ const MessageItemHOC = ({ setShowQueriesList, activeDb, currentModels, activeMod
elNode.innerHTML = str;
sqlNodes = elNode.querySelectorAll('sql');
}
const varNodes = elNode.querySelectorAll('var');
const varDescriptionNodes = elNode.querySelectorAll('varDescription');
const queryName = elNode.querySelector('queryName');
const queryDescription = elNode.querySelector('queryDescription');
const params = {};
forEach(funcJson.get('variablesArr'), (item: any) => {
const key = get(item, 'variable');
if (key) {
set(params, key, get(item, 'varDescription'));
}
});
return {
sql: map(sqlNodes, node => node.textContent?.trim()),
types: map(sqlNodes, node => getQueryType(node.tagName)),
params: pickBy(
Object.fromEntries(
map(varNodes, (node, index) => [
node.textContent?.trim(),
varDescriptionNodes[index]?.textContent?.trim() || '',
])
),
(_, key) => {
return /^\$(.*)\$$/.test(key);
}
),
queryName: queryName?.textContent?.trim(),
queryDescription: queryDescription?.textContent?.trim(),
sql: [funcJson.get('sql').replace(/;\s+/g, ';\n')],
types: ['sql'],
params,
queryName: funcJson.get('queryName'),
queryDescription: funcJson.get('queryDescription'),
};
}, [message]);
const [preViewData, setPreViewData] = useState([]);
......@@ -805,6 +802,8 @@ INSERT INTO users (email, name) VALUES ($email$, $name$);
>
<Content>
<AI
functions={QUERY_FUNCTION}
stream={false}
noHistory
quickTip={queryTip}
welcome={
......
import { functions, get } from 'lodash';
export class XML {
private root: HTMLDivElement;
......@@ -12,3 +13,15 @@ export class XML {
return insertText;
}
}
export class FunctionsJson {
private root: HTMLDivElement;
constructor(code: string) {
this.root = JSON.parse(code);
}
get(code: string): string {
return JSON.parse(get(this.root, 'arguments', '{}'))[code];
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment