Commit 907203ba authored by jaden's avatar jaden

fix: fix bug: cancel、input text、check

parent 1118e560
......@@ -34,7 +34,7 @@ type message = {
export default class OpenAI {
static async request(
messages: message[],
onFinish: (responseText: string) => any,
onFinish: (responseText: string, cancel?: boolean) => any,
onUpdate: (responseText: string, delta: string) => any,
onError: (e: Error) => any,
functions: any[],
......@@ -65,8 +65,12 @@ export default class OpenAI {
},
};
const requestTimeoutId = setTimeout(() => controller.abort(), 1000 * 120);
const chatPath = '/openai/v1/chat/completions';
if (closeFn) {
controller.signal.onabort = () => {
onFinish('', true);
};
closeFn.current = () => {
clearTimeout(requestTimeoutId);
controller.abort();
......@@ -75,13 +79,15 @@ export default class OpenAI {
if (stream) {
let responseText = '';
let finished = false;
const finish = () => {
const finish = (cancel?: boolean) => {
if (!finished) {
onFinish(responseText);
onFinish(responseText, cancel);
finished = true;
}
};
controller.signal.onabort = finish;
controller.signal.onabort = () => {
finish(true);
};
fetchEventSource(chatPath, {
...chatPayload,
async onopen(res) {
......@@ -152,7 +158,6 @@ export default class OpenAI {
const message =
resJson.choices?.at(0)?.message?.content ??
(JSON.stringify(get(resJson, 'choices[0].message.function_call')) || '');
console.log(message);
onFinish(message);
}
}
......
......@@ -9,6 +9,8 @@ import {
Spin,
Notification,
AutoComplete,
Alert,
Switch,
} from '@arco-design/web-react';
import { useTranslation } from 'react-i18next';
import MessageItem from './MessageItem';
......@@ -16,6 +18,7 @@ import MessageItem from './MessageItem';
import { debounce, filter, get, map } from 'lodash';
import React, {
ReactElement,
ReactNode,
useCallback,
useEffect,
useMemo,
......@@ -84,7 +87,9 @@ export function AIWrapper({
// 发送信息事件和成功的事件
const [currentAssistantMessage, setCurrentAssistantMessage] = useState('');
const [tinking, setTinking] = useState(false); //假的加载
const [thinking, setThinking] = useState(false); //假的加载
const [check, setCheck] = useState<string | boolean>(false); // 检查需求
const [checkOpen, setIsCheck] = useState(isCheck);
const handleButtonClickSuccess = useEffect(() => {
if (!currentAssistantMessage || loading) {
return;
......@@ -104,11 +109,9 @@ export function AIWrapper({
const closeRef = useRef<any>();
const close = () => {
closeRef.current && closeRef.current();
// setCurrentAssistantMessage('');
// requestAnimationFrame(() => {
// setLoading(false);
// });
if (closeRef.current) {
closeRef.current();
}
};
const toView = useCallback(
debounce(
......@@ -168,10 +171,10 @@ export function AIWrapper({
},
]);
// @ts-ignore
inputRef.value = '';
setRecordValue('');
setLoading(true);
toView();
let check = !isCheck;
let checked = checkOpen ? false : true;
const request = () => {
OpenAI.request(
noHistory
......@@ -181,20 +184,22 @@ export function AIWrapper({
})
: initMessageList,
currentAssistantMessageStr => {
setTinking(true);
(currentAssistantMessageStr, cancel) => {
setThinking(true);
setCheck(true);
const done = () => {
setCheck(false);
setLoading(false);
setTimeout(toView, 100);
setCurrentAssistantMessage(currentAssistantMessageStr);
callBack && callBack(currentAssistantMessageStr);
doneFx && doneFx(currentAssistantMessageStr);
};
check
checked || cancel
? done()
: getView
.checkChatResult([
...messageList,
...initMessageList,
{
role: 'user',
content: inputValue,
......@@ -213,11 +218,13 @@ export function AIWrapper({
'data.output',
{}
);
check = true;
setTinking(false);
checked = true;
setThinking(false);
setTimeout(toView, 100);
if (answerMeetsRequirements) {
done();
} else {
setCheck(why);
initMessageList.push(
{
role: 'assistant',
......@@ -230,7 +237,7 @@ export function AIWrapper({
},
{
role: 'user',
content: why,
content: `错误!!!!,你的回答不符合的需求,你的回答存在以下问题:\n${why}。\n请改正这些问题并重新输出。`,
}
);
request();
......@@ -262,6 +269,8 @@ export function AIWrapper({
input,
handleButtonClickSuccess,
scrollContainer,
setCheck,
checkOpen,
]
);
......@@ -269,7 +278,7 @@ export function AIWrapper({
const clear = () => {
const inputRef = get(input, 'current.dom');
if (inputRef) {
inputRef.value = '';
setRecordValue('');
setMessageList(messageList.slice(0, startView));
setCurrentAssistantMessage('');
}
......@@ -355,10 +364,10 @@ export function AIWrapper({
const [beforeRecordValue, setBeforeRecordValue] = useState('');
const [recordValue, setRecordValue] = useState('');
useEffect(() => {
if (!isRecording) {
const el = input.current?.dom;
console.log(recordValue);
if (el) el.value = recordValue || '';
}
}, [isRecording, recordValue]);
......@@ -435,6 +444,80 @@ export function AIWrapper({
/>
);
const detail = useMemo<ReactNode>(() => {
if (check) {
return (
<div className="my-[20px]">
<div
className={`flex gap-3 p-4 box-border shadow mx-[5px] rounded transition-colors mt-[20px] font-hm ${'bg-[var(--white-bg)] text-[#333]'}`}
>
<Form style={{ width: '100%' }} autoComplete="off">
<div className="py-[10px] pb-[30px] text-[20px] justify-between flex">
{t('Reviewing and checking if query aligns with requirements')}
<span>
<IconSwap />
</span>
</div>
{check !== true ? (
<Alert
content={t('Requirements and answers do not align')}
type={'warning'}
className="my-[20px]"
/>
) : null}
<pre
className="break-before-all"
style={{
whiteSpace: 'break-spaces',
}}
>
{check}
</pre>
</Form>
</div>
</div>
);
}
if (currentAssistantMessage) {
return (
<div className="my-[20px]">
<div
className={`flex gap-3 p-4 box-border shadow mx-[5px] rounded transition-colors mt-[20px] font-hm ${'bg-[var(--white-bg)] text-[#333]'}`}
>
<Form style={{ width: '100%' }} autoComplete="off">
<div className="py-[10px] pb-[30px] text-[20px] justify-between flex">
{t('A query has been generated for you')}
<span>
<IconSwap />
</span>
</div>
<pre
className="break-before-all"
style={{
whiteSpace: 'break-spaces',
}}
>
{currentAssistantMessage}
</pre>
</Form>
</div>
</div>
);
} else {
return (
<div className="my-[20px]">
<Skeleton
animation
text={{
rows: 5,
width: ['100%', '100%', '100%', '100%', 400],
}}
/>
</div>
);
}
}, [currentAssistantMessage, check]);
if (simpleMode) {
if (simpleMode === 'input') {
return inputNode;
......@@ -530,61 +613,41 @@ export function AIWrapper({
style={{ fontSize: '32px', color: 'rgb(var(--primary-6))' }}
/>
}
content={
!currentAssistantMessage ? (
<div className="my-[20px]">
<Skeleton
animation
text={{
rows: 5,
width: ['100%', '100%', '100%', '100%', 400],
}}
/>
</div>
) : (
<div className="my-[20px]">
<div
className={`flex gap-3 p-4 box-border shadow mx-[5px] rounded transition-colors mt-[20px] font-hm ${'bg-[var(--white-bg)] text-[#333]'}`}
>
<Form style={{ width: '100%' }} autoComplete="off">
<div className="py-[10px] pb-[30px] text-[20px] justify-between flex">
{t('A query has been generated for you')}
<span>
<IconSwap />
</span>
</div>
<pre
className="break-before-all"
style={{
whiteSpace: 'break-spaces',
}}
>
{currentAssistantMessage}
</pre>
</Form>
</div>
</div>
)
}
content={detail}
/>
)}
<div ref={scrollContainer} />
</div>
{loading ? (
<div className="animate-bounce">
<div className="h-12 my-4 flex items-center justify-center rounded-sm text-[30px] font-bold gradient-text">
{!tinking
? `${t('Analyzing requirements')}...`
: `${t('Creating query')}...`}
<>
<div className="animate-bounce">
<div className="h-12 my-4 flex items-center justify-center rounded-sm text-[30px] font-bold gradient-text">
{check
? check !== true
? `${t('Requirements and answers do not align, rethinking')}...`
: `${t('Reviewing requirements and answers')}...`
: `${t('Analyzing requirements')}...`}
</div>
</div>
<Button className="shadow" onClick={close} size="mini" shape="round">
取消
{t('Cancel')}
</Button>
</div>
</>
) : (
<Comment
className="items-stretch !mt-[5px] pt-[15px] mx-[-15px] px-[15px] shadow-t"
actions={[
<span className="flex items-center">
<span className="mr-[10px] text-[12px]">自动检查</span>
<Switch
type="line"
size="small"
checked={checkOpen}
onChange={value => {
setIsCheck(value);
}}
/>
</span>,
<Button
key="0"
onClick={clear}
......@@ -638,8 +701,12 @@ export function AIWrapper({
value={inputValue}
onChange={value => {
setRecordValue(value);
const el = input.current?.dom;
console.log(value, recordValue, el, el.value);
if (el) el.value = value || '';
}}
onPressEnter={e => {
console.log('w22');
if (
e.key === 'Enter' &&
!e?.nativeEvent.isComposing &&
......@@ -673,6 +740,7 @@ export function AIWrapper({
// popupVisible: true,
}}
onSelect={(value: string) => {
console.log('w22');
const el = input.current?.dom;
if (el) {
el.value = value;
......
......@@ -152,6 +152,9 @@ i18n.use(LanguageDetector)
'Execution succeeded': '执行成功',
'Analyzing requirements': '分析需求中',
'Creating query': '创建查询中',
'Query generation in progress': '正在生成查询',
'Reviewing and checking if query aligns with requirements':
'正在审核查询是否满足需求',
'Hello! I an CHAT QUERY ai, please describe your business!':
'您好!我是 CHAT QUERY AI,请描述您的业务!',
'Connection Name': '连接名称',
......@@ -166,6 +169,13 @@ i18n.use(LanguageDetector)
_QUERY_: '_查询_',
'Failed to generate query': '生成查询失败',
'Error in query': '错误查询',
Cancel: '取消',
'Cannot generate executable query from the requirement description, please continue to describe the requirement!':
'从需求描述中不能为您生成可执行的查询,请继续描述的需求!',
'Requirements and answers do not align': '需求和回答没有对齐',
'Requirements and answers do not align, rethinking':
'需求和回答没有对齐,重新思考中',
'Reviewing requirements and answers': '正在审查需求和回答',
},
modal: {
Import: '导入',
......@@ -211,6 +221,15 @@ i18n.use(LanguageDetector)
},
chatView: {
'component display': '组件显示',
'Function for processing data': '处理数据的函数',
'Add component': '添加组件',
'Code generation in progress, please wait...': '代码生成中,请稍后...',
'Data processing': '数据处理',
'Comment + Tab to generate function': '注释 + Tab 生成函数',
'Execute function name': '执行函数名称',
'No function description available': '暂无函数描述',
Run: '运行',
'Execution successful': '执行成功',
},
},
},
......
......@@ -53,6 +53,7 @@ import 'systemjs';
import dayjs from 'dayjs';
import { simple } from 'acorn-walk';
import jsx from 'acorn-jsx';
import i18n from '@/next-i18next.config';
const CollapseItem = Collapse.Item;
......@@ -65,11 +66,16 @@ function Error() {
return <code>{error}</code>;
}
const init = `/**
* @description 处理数据的函数
// const initText = i18n.getFixedT(i18n.language, 'chatView')('Function for processing data');
const init = (initText: string): string => {
return `/**
* @description ${initText}
* @param record<string,any> data
*/
`;
};
async function getUMDPath(packageName: string) {
const response = await fetch(`https://data.jsdelivr.com/v1/packages/npm/${packageName}`);
const packageJson = await response.json();
......@@ -140,6 +146,8 @@ async function loadUMDModuleBySystem(packageName: string) {
function ReactView({ props }: { props: Record<string, any> }) {
const { code } = useLiveContext();
const { t } = useTranslation('chatView');
return (
<div>
<div className="flex justify-end my-[5px]">
......@@ -161,7 +169,7 @@ function ReactView({ props }: { props: Record<string, any> }) {
}
}}
>
<IconPlus /> 添加组件
<IconPlus /> {t('Add component')}
</Button>
</div>
<LivePreview className="overflow-auto min-h-[350px]" />
......@@ -173,7 +181,7 @@ export function ChatView({
defaultNode,
props: propsRaw,
id,
functions = init,
functions = '',
}: {
defaultNode?: ReactElement;
props: Record<string, any>;
......@@ -271,6 +279,7 @@ export function ChatView({
const example = get(data, 'data.code');
const { t } = useTranslation('chatView');
functions = functions || init(t('Function for processing data'));
const Live = useMemo(() => {
let node;
......@@ -323,7 +332,7 @@ export function ChatView({
const position = editor.getPosition()!;
const lineNumber = position.lineNumber;
const column = position.column;
const insertText = ' 代码生成中,请稍后...';
const insertText = ` ` + t('Code generation in progress, please wait...');
const op = {
range: new monaco.Range(lineNumber, column, lineNumber, column),
text: insertText,
......@@ -406,9 +415,9 @@ export function ChatView({
<CollapseItem
header={
<div>
数据处理
{t('Data processing')}
<span className="text-[var(--pc)] mx-[10px] text-[12px]">
(注释 + Tab 生成函数)
({t('Comment + Tab to generate function')})
</span>
</div>
}
......@@ -416,7 +425,7 @@ export function ChatView({
extra={
<div className="flex">
<Select
placeholder="执行函数名称"
placeholder={t('Execute function name')}
size="mini"
allowClear
style={{
......@@ -465,7 +474,9 @@ export function ChatView({
{get(
item,
'comment',
'暂无函数描述'
t(
'No function description available'
)
)}
</span>
</Tooltip>
......@@ -497,7 +508,7 @@ export function ChatView({
size="mini"
shape="round"
>
运行
{t('Run')}
</Button>
</div>
}
......@@ -516,7 +527,11 @@ export function ChatView({
</div>
</>
) : (
<Alert style={{ marginBottom: 20 }} type="success" content="执行成功" />
<Alert
style={{ marginBottom: 20 }}
type="success"
content={t('Execution successful')}
/>
)}
<Spin loading={isMutating} block className="my-[20px]">
{example && !showTable ? (
......
......@@ -520,7 +520,9 @@ const MessageItemHOC = ({ setShowQueriesList, activeDb, currentModels, activeMod
<Alert
content={
<div className="text-[#7e7d7d]">
从需求描述中不能为您生成可执行的查询,请继续描述的需求!
{t(
'Cannot generate executable query from the requirement description, please continue to describe the requirement!'
)}
</div>
}
/>
......@@ -656,7 +658,10 @@ export default function Actions() {
try {
const data = await getAllGraphs();
if (data && data.length) {
data.sort((a, b) => b.createdAt - a.createdAt);
data.sort(
(a: { createdAt: number }, b: { createdAt: number }) =>
b.createdAt - a.createdAt
);
setGraphs(data);
}
} catch (e) {
......
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