Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
chat-query
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Jobs
Commits
Open sidebar
jaden
chat-query
Commits
907203ba
Commit
907203ba
authored
Jul 18, 2023
by
jaden
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix: fix bug: cancel、input text、check
parent
1118e560
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
190 additions
and
78 deletions
+190
-78
client/api/openAI.ts
client/api/openAI.ts
+10
-5
components/AITool/index.tsx
components/AITool/index.tsx
+128
-60
next-i18next.config.js
next-i18next.config.js
+19
-0
pages/actions/View/chatView.tsx
pages/actions/View/chatView.tsx
+26
-11
pages/actions/index.tsx
pages/actions/index.tsx
+7
-2
No files found.
client/api/openAI.ts
View file @
907203ba
...
...
@@ -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
);
}
}
...
...
components/AITool/index.tsx
View file @
907203ba
...
...
@@ -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
check
ed
=
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
check
ed
||
cancel
?
done
()
:
getView
.
checkChatResult
([
...
m
essageList
,
...
initM
essageList
,
{
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
-
[
5
px
]
rounded
transition
-
colors
mt
-
[
20
px
]
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
-
[
5
px
]
rounded
transition
-
colors
mt
-
[
20
px
]
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
-
[
5
px
]
rounded
transition
-
colors
mt
-
[
20
px
]
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;
...
...
next-i18next.config.js
View file @
907203ba
...
...
@@ -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
'
:
'
执行成功
'
,
},
},
},
...
...
pages/actions/View/chatView.tsx
View file @
907203ba
...
...
@@ -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
?
(
...
...
pages/actions/index.tsx
View file @
907203ba
...
...
@@ -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
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment