Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
赵月辉
/
fastgpt-migrated
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
b2e2f60e
authored
Jul 11, 2023
by
archer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
chatbox ui
parent
eb768d9c
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
45 changed files
with
344 additions
and
1116 deletions
+344
-1116
client/src/api/app.ts
+6
-7
client/src/api/chat.ts
+7
-7
client/src/api/fetch.ts
+5
-5
client/src/api/request.ts
+4
-4
client/src/api/response/chat.d.ts
+8
-7
client/src/components/ChatBox/index.tsx
+22
-14
client/src/components/Layout/index.tsx
+2
-1
client/src/components/Layout/navbar.tsx
+3
-3
client/src/components/Layout/navbarPhone.tsx
+3
-3
client/src/components/SideBar/index.tsx
+1
-1
client/src/components/Tag/index.tsx
+1
-1
client/src/pages/api/app/del.ts
+7
-7
client/src/pages/api/app/detail.tsx
+3
-3
client/src/pages/api/app/myApps.ts
+6
-31
client/src/pages/api/app/share/collection.ts
+6
-6
client/src/pages/api/chat/chatTest.ts
+6
-5
client/src/pages/api/chat/delChatRecordByContentId.ts
+5
-7
client/src/pages/api/chat/history/getHistory.ts
+7
-6
client/src/pages/api/chat/history/updateChatHistory.ts
+3
-3
client/src/pages/api/chat/init.ts
+32
-22
client/src/pages/api/chat/saveChat.ts
+23
-19
client/src/pages/api/openapi/chat/chat.ts
+0
-189
client/src/pages/api/openapi/v1/chat/completions.ts
+0
-0
client/src/pages/api/openapi/v1/chat/completions2.ts
+0
-0
client/src/pages/api/openapi/v1/chat/getHistory.ts
+6
-6
client/src/pages/app/detail/components/edit/components/ChatTest.tsx
+1
-3
client/src/pages/appStore/components/list.tsx
+1
-1
client/src/pages/appStore/index.tsx
+3
-6
client/src/pages/chat/components/ChatHistorySlider.tsx
+32
-25
client/src/pages/chat/components/History.tsx
+0
-304
client/src/pages/chat/components/ModelList.tsx
+0
-49
client/src/pages/chat/components/PhoneSliderBar.tsx
+0
-212
client/src/pages/chat/components/SliderApps.tsx
+77
-0
client/src/pages/chat/index.tsx
+0
-0
client/src/pages/chat/share.tsx
+7
-10
client/src/pages/login/index.tsx
+3
-5
client/src/service/api/request.ts
+7
-3
client/src/service/models/chat.ts
+5
-15
client/src/service/models/collection.ts
+1
-1
client/src/service/models/installApp.ts
+0
-18
client/src/service/utils/auth.ts
+0
-59
client/src/store/chat.ts
+37
-34
client/src/store/user.ts
+1
-2
client/src/types/chat.d.ts
+0
-4
client/src/types/mongoSchema.d.ts
+3
-8
No files found.
client/src/api/app.ts
View file @
b2e2f60e
import
{
GET
,
POST
,
DELETE
,
PUT
}
from
'./request'
;
import
{
GET
,
POST
,
DELETE
,
PUT
}
from
'./request'
;
import
type
{
AppSchema
}
from
'@/types/mongoSchema'
;
import
type
{
AppSchema
}
from
'@/types/mongoSchema'
;
import
type
{
App
Module
ItemType
,
AppUpdateParams
}
from
'@/types/app'
;
import
type
{
App
List
ItemType
,
AppUpdateParams
}
from
'@/types/app'
;
import
{
RequestPaging
}
from
'../types/index'
;
import
{
RequestPaging
}
from
'../types/index'
;
import
type
{
AppListResponse
}
from
'./response/app'
;
import
type
{
Props
as
CreateAppProps
}
from
'@/pages/api/app/create'
;
import
type
{
Props
as
CreateAppProps
}
from
'@/pages/api/app/create'
;
/**
/**
* 获取模型列表
* 获取模型列表
*/
*/
export
const
getMyModels
=
()
=>
GET
<
AppList
Response
>
(
'/app/list
'
);
export
const
getMyModels
=
()
=>
GET
<
AppList
ItemType
[]
>
(
'/app/myApps
'
);
/**
/**
* 创建一个模型
* 创建一个模型
...
@@ -18,12 +17,12 @@ export const postCreateApp = (data: CreateAppProps) => POST<string>('/app/create
...
@@ -18,12 +17,12 @@ export const postCreateApp = (data: CreateAppProps) => POST<string>('/app/create
/**
/**
* 根据 ID 删除模型
* 根据 ID 删除模型
*/
*/
export
const
delModelById
=
(
id
:
string
)
=>
DELETE
(
`/app/del?
model
Id=
${
id
}
`
);
export
const
delModelById
=
(
id
:
string
)
=>
DELETE
(
`/app/del?
app
Id=
${
id
}
`
);
/**
/**
* 根据 ID 获取模型
* 根据 ID 获取模型
*/
*/
export
const
getModelById
=
(
id
:
string
)
=>
GET
<
AppSchema
>
(
`/app/detail?
model
Id=
${
id
}
`
);
export
const
getModelById
=
(
id
:
string
)
=>
GET
<
AppSchema
>
(
`/app/detail?
app
Id=
${
id
}
`
);
/**
/**
* 根据 ID 更新模型
* 根据 ID 更新模型
...
@@ -41,5 +40,5 @@ export const getShareModelList = (data: { searchText?: string } & RequestPaging)
...
@@ -41,5 +40,5 @@ export const getShareModelList = (data: { searchText?: string } & RequestPaging)
/**
/**
* 收藏/取消收藏模型
* 收藏/取消收藏模型
*/
*/
export
const
triggerModelCollection
=
(
model
Id
:
string
)
=>
export
const
triggerModelCollection
=
(
app
Id
:
string
)
=>
POST
<
number
>
(
`/app/share/collection?
modelId=
${
model
Id
}
`
);
POST
<
number
>
(
`/app/share/collection?
appId=
${
app
Id
}
`
);
client/src/api/chat.ts
View file @
b2e2f60e
import
{
GET
,
POST
,
DELETE
,
PUT
}
from
'./request'
;
import
{
GET
,
POST
,
DELETE
,
PUT
}
from
'./request'
;
import
type
{
HistoryItemType
}
from
'@/types/chat'
;
import
type
{
Chat
HistoryItemType
}
from
'@/types/chat'
;
import
type
{
InitChatResponse
,
InitShareChatResponse
}
from
'./response/chat'
;
import
type
{
InitChatResponse
,
InitShareChatResponse
}
from
'./response/chat'
;
import
{
RequestPaging
}
from
'../types/index'
;
import
{
RequestPaging
}
from
'../types/index'
;
import
type
{
ShareChatSchema
}
from
'@/types/mongoSchema'
;
import
type
{
ShareChatSchema
}
from
'@/types/mongoSchema'
;
...
@@ -11,14 +11,14 @@ import type { Props as UpdateHistoryProps } from '@/pages/api/chat/history/updat
...
@@ -11,14 +11,14 @@ import type { Props as UpdateHistoryProps } from '@/pages/api/chat/history/updat
/**
/**
* 获取初始化聊天内容
* 获取初始化聊天内容
*/
*/
export
const
getInitChatSiteInfo
=
(
modelId
:
''
|
string
,
chatId
:
''
|
string
)
=>
export
const
getInitChatSiteInfo
=
(
data
:
{
appId
:
string
;
historyId
?:
string
}
)
=>
GET
<
InitChatResponse
>
(
`/chat/init
?modelId=
${
modelId
}
&chatId=
${
chatId
}
`
);
GET
<
InitChatResponse
>
(
`/chat/init
`
,
data
);
/**
/**
* 获取历史记录
* 获取历史记录
*/
*/
export
const
getChatHistory
=
(
data
:
RequestPaging
)
=>
export
const
getChatHistory
=
(
data
:
RequestPaging
&
{
appId
?:
string
}
)
=>
POST
<
HistoryItemType
[]
>
(
'/chat/history/getHistory'
,
data
);
POST
<
Chat
HistoryItemType
[]
>
(
'/chat/history/getHistory'
,
data
);
/**
/**
* 删除一条历史记录
* 删除一条历史记录
...
@@ -44,8 +44,8 @@ export const updateHistoryQuote = (params: {
...
@@ -44,8 +44,8 @@ export const updateHistoryQuote = (params: {
/**
/**
* 删除一句对话
* 删除一句对话
*/
*/
export
const
delChatRecordByIndex
=
(
chatId
:
string
,
contentId
:
string
)
=>
export
const
delChatRecordByIndex
=
(
data
:
{
historyId
:
string
;
contentId
:
string
}
)
=>
DELETE
(
`/chat/delChatRecordByContentId
?chatId=
${
chatId
}
&contentId=
${
contentId
}
`
);
DELETE
(
`/chat/delChatRecordByContentId
`
,
data
);
/**
/**
* 修改历史记录: 标题/置顶
* 修改历史记录: 标题/置顶
...
...
client/src/api/fetch.ts
View file @
b2e2f60e
...
@@ -9,12 +9,12 @@ interface StreamFetchProps {
...
@@ -9,12 +9,12 @@ interface StreamFetchProps {
abortSignal
:
AbortController
;
abortSignal
:
AbortController
;
}
}
export
const
streamFetch
=
({
export
const
streamFetch
=
({
url
=
'/api/openapi/v1/chat/completions
2
'
,
url
=
'/api/openapi/v1/chat/completions'
,
data
,
data
,
onMessage
,
onMessage
,
abortSignal
abortSignal
}:
StreamFetchProps
)
=>
}:
StreamFetchProps
)
=>
new
Promise
<
{
responseText
:
string
;
errMsg
:
string
;
new
Chat
Id
:
string
|
null
}
>
(
new
Promise
<
{
responseText
:
string
;
errMsg
:
string
;
new
History
Id
:
string
|
null
}
>
(
async
(
resolve
,
reject
)
=>
{
async
(
resolve
,
reject
)
=>
{
try
{
try
{
const
response
=
await
window
.
fetch
(
url
,
{
const
response
=
await
window
.
fetch
(
url
,
{
...
@@ -43,7 +43,7 @@ export const streamFetch = ({
...
@@ -43,7 +43,7 @@ export const streamFetch = ({
// response data
// response data
let
responseText
=
''
;
let
responseText
=
''
;
let
errMsg
=
''
;
let
errMsg
=
''
;
const
new
ChatId
=
response
.
headers
.
get
(
'newChat
Id'
);
const
new
HistoryId
=
response
.
headers
.
get
(
'newHistory
Id'
);
const
read
=
async
()
=>
{
const
read
=
async
()
=>
{
try
{
try
{
...
@@ -53,7 +53,7 @@ export const streamFetch = ({
...
@@ -53,7 +53,7 @@ export const streamFetch = ({
return
resolve
({
return
resolve
({
responseText
,
responseText
,
errMsg
,
errMsg
,
new
Chat
Id
new
History
Id
});
});
}
else
{
}
else
{
return
reject
(
'响应过程出现异常~'
);
return
reject
(
'响应过程出现异常~'
);
...
@@ -85,7 +85,7 @@ export const streamFetch = ({
...
@@ -85,7 +85,7 @@ export const streamFetch = ({
return
resolve
({
return
resolve
({
responseText
,
responseText
,
errMsg
,
errMsg
,
new
Chat
Id
new
History
Id
});
});
}
}
reject
(
getErrText
(
err
,
'请求异常'
));
reject
(
getErrText
(
err
,
'请求异常'
));
...
...
client/src/api/request.ts
View file @
b2e2f60e
...
@@ -92,8 +92,8 @@ function request(url: string, data: any, config: ConfigType, method: Method): an
...
@@ -92,8 +92,8 @@ function request(url: string, data: any, config: ConfigType, method: Method): an
baseURL
:
'/api'
,
baseURL
:
'/api'
,
url
,
url
,
method
,
method
,
data
:
method
===
'GET'
?
null
:
data
,
data
:
[
'POST'
,
'PUT'
].
includes
(
method
)
?
data
:
null
,
params
:
method
===
'GET'
?
data
:
null
,
// get请求不携带data,params放在url上
params
:
!
[
'POST'
,
'PUT'
].
includes
(
method
)
?
data
:
null
,
...
config
// 用户自定义配置,可以覆盖前面的配置
...
config
// 用户自定义配置,可以覆盖前面的配置
})
})
.
then
((
res
)
=>
checkRes
(
res
.
data
))
.
then
((
res
)
=>
checkRes
(
res
.
data
))
...
@@ -119,6 +119,6 @@ export function PUT<T>(url: string, data = {}, config: ConfigType = {}): Promise
...
@@ -119,6 +119,6 @@ export function PUT<T>(url: string, data = {}, config: ConfigType = {}): Promise
return
request
(
url
,
data
,
config
,
'PUT'
);
return
request
(
url
,
data
,
config
,
'PUT'
);
}
}
export
function
DELETE
<
T
>
(
url
:
string
,
config
:
ConfigType
=
{}):
Promise
<
T
>
{
export
function
DELETE
<
T
>
(
url
:
string
,
data
=
{},
config
:
ConfigType
=
{}):
Promise
<
T
>
{
return
request
(
url
,
{}
,
config
,
'DELETE'
);
return
request
(
url
,
data
,
config
,
'DELETE'
);
}
}
client/src/api/response/chat.d.ts
View file @
b2e2f60e
import
type
{
ChatPopulate
,
AppSchema
}
from
'@/types/mongoSchema'
;
import
type
{
AppSchema
}
from
'@/types/mongoSchema'
;
import
type
{
ChatItemType
}
from
'@/types/chat'
;
import
type
{
ChatItemType
}
from
'@/types/chat'
;
import
{
VariableItemType
}
from
'@/types/app'
;
import
{
VariableItemType
}
from
'@/types/app'
;
export
interface
InitChatResponse
{
export
interface
InitChatResponse
{
chat
Id
:
string
;
history
Id
:
string
;
model
Id
:
string
;
app
Id
:
string
;
systemPrompt
?:
string
;
app
:
{
limitPrompt
?:
string
;
variableModules
?:
VariableItemType
[]
;
model
:
{
welcomeText
?:
string
;
name
:
string
;
name
:
string
;
avatar
:
string
;
avatar
:
string
;
intro
:
string
;
intro
:
string
;
canUse
:
boolean
;
canUse
:
boolean
;
};
};
chatModel
:
AppSchema
[
'chat'
][
'chatModel'
];
// 对话模型名
title
:
string
;
variables
:
Record
<
string
,
any
>
;
history
:
ChatItemType
[];
history
:
ChatItemType
[];
}
}
...
...
client/src/components/ChatBox/index.tsx
View file @
b2e2f60e
...
@@ -38,8 +38,10 @@ export type StartChatFnProps = {
...
@@ -38,8 +38,10 @@ export type StartChatFnProps = {
};
};
export
type
ComponentRef
=
{
export
type
ComponentRef
=
{
getChatHistory
:
()
=>
ChatSiteItemType
[];
resetVariables
:
(
data
?:
Record
<
string
,
any
>
)
=>
void
;
resetVariables
:
(
data
?:
Record
<
string
,
any
>
)
=>
void
;
resetHistory
:
(
history
:
ChatSiteItemType
[])
=>
void
;
resetHistory
:
(
history
:
ChatSiteItemType
[])
=>
void
;
scrollToBottom
:
(
behavior
?:
'smooth'
|
'auto'
)
=>
void
;
};
};
const
VariableLabel
=
({
const
VariableLabel
=
({
...
@@ -73,7 +75,7 @@ const ChatBox = (
...
@@ -73,7 +75,7 @@ const ChatBox = (
welcomeText
?:
string
;
welcomeText
?:
string
;
onUpdateVariable
?:
(
e
:
Record
<
string
,
any
>
)
=>
void
;
onUpdateVariable
?:
(
e
:
Record
<
string
,
any
>
)
=>
void
;
onStartChat
:
(
e
:
StartChatFnProps
)
=>
Promise
<
{
responseText
:
string
}
>
;
onStartChat
:
(
e
:
StartChatFnProps
)
=>
Promise
<
{
responseText
:
string
}
>
;
onDelMessage
?:
(
e
:
{
i
d
?:
string
;
index
:
number
})
=>
void
;
onDelMessage
?:
(
e
:
{
contentI
d
?:
string
;
index
:
number
})
=>
void
;
},
},
ref
:
ForwardedRef
<
ComponentRef
>
ref
:
ForwardedRef
<
ComponentRef
>
)
=>
{
)
=>
{
...
@@ -279,6 +281,7 @@ const ChatBox = (
...
@@ -279,6 +281,7 @@ const ChatBox = (
);
);
useImperativeHandle
(
ref
,
()
=>
({
useImperativeHandle
(
ref
,
()
=>
({
getChatHistory
:
()
=>
chatHistory
,
resetVariables
(
e
)
{
resetVariables
(
e
)
{
const
defaultVal
:
Record
<
string
,
any
>
=
{};
const
defaultVal
:
Record
<
string
,
any
>
=
{};
variableModules
?.
forEach
((
item
)
=>
{
variableModules
?.
forEach
((
item
)
=>
{
...
@@ -290,7 +293,8 @@ const ChatBox = (
...
@@ -290,7 +293,8 @@ const ChatBox = (
},
},
resetHistory
(
e
)
{
resetHistory
(
e
)
{
setChatHistory
(
e
);
setChatHistory
(
e
);
}
},
scrollToBottom
}));
}));
const
controlIconStyle
=
{
const
controlIconStyle
=
{
...
@@ -305,25 +309,27 @@ const ChatBox = (
...
@@ -305,25 +309,27 @@ const ChatBox = (
};
};
const
controlContainerStyle
=
{
const
controlContainerStyle
=
{
className
:
'control'
,
className
:
'control'
,
display
:
[
'flex'
,
'none'
],
display
:
isChatting
?
'none'
:
[
'flex'
,
'none'
],
color
:
'myGray.400'
,
color
:
'myGray.400'
,
pl
:
1
,
pl
:
1
,
mt
:
2
,
mt
:
2
,
position
:
'absolute'
as
any
,
position
:
'absolute'
as
any
,
zIndex
:
1
zIndex
:
1
,
w
:
'100%'
};
};
return
(
return
(
<
Flex
flexDirection=
{
'column'
}
h=
{
'100%'
}
>
<
Flex
flexDirection=
{
'column'
}
h=
{
'100%'
}
>
<
Box
ref=
{
ChatBoxRef
}
flex=
{
'1 0 0'
}
overflow=
{
'overlay'
}
px=
{
[
2
,
5
]
}
>
<
Box
ref=
{
ChatBoxRef
}
flex=
{
'1 0 0'
}
overflow=
{
'overlay'
}
px=
{
[
2
,
5
,
8
]
}
py=
{
5
}
>
<
Box
maxW=
{
[
'100%'
,
'1000px'
,
'1200px'
]
}
mx=
{
'auto'
}
>
{
/* variable input */
}
{
/* variable input */
}
{
(
variableModules
||
welcomeText
)
&&
(
{
(
variableModules
||
welcomeText
)
&&
(
<
Flex
alignItems=
{
'flex-start'
}
py=
{
2
}
>
<
Flex
alignItems=
{
'flex-start'
}
py=
{
2
}
>
{
/* avatar */
}
{
/* avatar */
}
<
Avatar
<
Avatar
src=
{
appAvatar
}
src=
{
appAvatar
}
w=
{
isLargeWidth
?
'34px'
:
'24px'
}
w=
{
[
'24px'
,
'34px'
]
}
h=
{
isLargeWidth
?
'34px'
:
'24px'
}
h=
{
[
'24px'
,
'34px'
]
}
order=
{
1
}
order=
{
1
}
mr=
{
[
'6px'
,
2
]
}
mr=
{
[
'6px'
,
2
]
}
/>
/>
...
@@ -342,6 +348,7 @@ const ChatBox = (
...
@@ -342,6 +348,7 @@ const ChatBox = (
<
VariableLabel
required=
{
item
.
required
}
>
{
item
.
label
}
</
VariableLabel
>
<
VariableLabel
required=
{
item
.
required
}
>
{
item
.
label
}
</
VariableLabel
>
{
item
.
type
===
VariableInputEnum
.
input
&&
(
{
item
.
type
===
VariableInputEnum
.
input
&&
(
<
Input
<
Input
isDisabled=
{
variableIsFinish
}
{
...
register
(
item
.
key
,
{
{
...
register
(
item
.
key
,
{
required
:
item
.
required
required
:
item
.
required
})}
})}
...
@@ -350,6 +357,7 @@ const ChatBox = (
...
@@ -350,6 +357,7 @@ const ChatBox = (
{
item
.
type
===
VariableInputEnum
.
select
&&
(
{
item
.
type
===
VariableInputEnum
.
select
&&
(
<
MySelect
<
MySelect
width=
{
'100%'
}
width=
{
'100%'
}
isDisabled=
{
variableIsFinish
}
list=
{
(
item
.
enums
||
[]).
map
((
item
)
=>
({
list=
{
(
item
.
enums
||
[]).
map
((
item
)
=>
({
label
:
item
.
value
,
label
:
item
.
value
,
value
:
item
.
value
value
:
item
.
value
...
@@ -391,7 +399,7 @@ const ChatBox = (
...
@@ -391,7 +399,7 @@ const ChatBox = (
<
Flex
<
Flex
key=
{
item
.
_id
}
key=
{
item
.
_id
}
alignItems=
{
'flex-start'
}
alignItems=
{
'flex-start'
}
py=
{
2
}
py=
{
4
}
_hover=
{
{
_hover=
{
{
'& .control'
:
{
'& .control'
:
{
display
:
'flex'
display
:
'flex'
...
@@ -402,8 +410,8 @@ const ChatBox = (
...
@@ -402,8 +410,8 @@ const ChatBox = (
{
/* avatar */
}
{
/* avatar */
}
<
Avatar
<
Avatar
src=
{
item
.
obj
===
'Human'
?
userInfo
?.
avatar
||
HUMAN_ICON
:
appAvatar
}
src=
{
item
.
obj
===
'Human'
?
userInfo
?.
avatar
||
HUMAN_ICON
:
appAvatar
}
w=
{
isLargeWidth
?
'34px'
:
'24px'
}
w=
{
[
'24px'
,
'34px'
]
}
h=
{
isLargeWidth
?
'34px'
:
'24px'
}
h=
{
[
'24px'
,
'34px'
]
}
{
...
(
item
.
obj
===
'
AI
'
{
...
(
item
.
obj
===
'
AI
'
?
{
?
{
order
:
1,
order
:
1,
...
@@ -417,7 +425,7 @@ const ChatBox = (
...
@@ -417,7 +425,7 @@ const ChatBox = (
{
/* message */
}
{
/* message */
}
<
Box
order=
{
2
}
pt=
{
2
}
maxW=
{
`calc(100% - ${isLargeWidth ? '75px' : '58px'})`
}
>
<
Box
order=
{
2
}
pt=
{
2
}
maxW=
{
`calc(100% - ${isLargeWidth ? '75px' : '58px'})`
}
>
{
item
.
obj
===
'AI'
?
(
{
item
.
obj
===
'AI'
?
(
<
Box
w=
{
'100%
'
}
>
<
Box
w=
{
'100%'
}
position=
{
'relative
'
}
>
<
Card
bg=
{
'white'
}
px=
{
4
}
py=
{
3
}
borderRadius=
{
'0 8px 8px 8px'
}
>
<
Card
bg=
{
'white'
}
px=
{
4
}
py=
{
3
}
borderRadius=
{
'0 8px 8px 8px'
}
>
<
Markdown
<
Markdown
source=
{
item
.
value
}
source=
{
item
.
value
}
...
@@ -444,7 +452,7 @@ const ChatBox = (
...
@@ -444,7 +452,7 @@ const ChatBox = (
state
.
filter
((
chat
)
=>
chat
.
_id
!==
item
.
_id
)
state
.
filter
((
chat
)
=>
chat
.
_id
!==
item
.
_id
)
);
);
onDelMessage
({
onDelMessage
({
i
d
:
item
.
_id
,
contentI
d
:
item
.
_id
,
index
index
});
});
}
}
}
}
...
@@ -496,7 +504,7 @@ const ChatBox = (
...
@@ -496,7 +504,7 @@ const ChatBox = (
state
.
filter
((
chat
)
=>
chat
.
_id
!==
item
.
_id
)
state
.
filter
((
chat
)
=>
chat
.
_id
!==
item
.
_id
)
);
);
onDelMessage
({
onDelMessage
({
i
d
:
item
.
_id
,
contentI
d
:
item
.
_id
,
index
index
});
});
}
}
}
}
...
@@ -511,6 +519,7 @@ const ChatBox = (
...
@@ -511,6 +519,7 @@ const ChatBox = (
))
}
))
}
</
Box
>
</
Box
>
</
Box
>
</
Box
>
</
Box
>
{
variableIsFinish
?
(
{
variableIsFinish
?
(
<
Box
m=
{
[
'0 auto'
,
'20px auto'
]
}
w=
{
'100%'
}
maxW=
{
[
'auto'
,
'min(750px, 100%)'
]
}
px=
{
[
0
,
5
]
}
>
<
Box
m=
{
[
'0 auto'
,
'20px auto'
]
}
w=
{
'100%'
}
maxW=
{
[
'auto'
,
'min(750px, 100%)'
]
}
px=
{
[
0
,
5
]
}
>
<
Box
<
Box
...
@@ -531,7 +540,6 @@ const ChatBox = (
...
@@ -531,7 +540,6 @@ const ChatBox = (
_focusVisible=
{
{
_focusVisible=
{
{
border
:
'none'
border
:
'none'
}
}
}
}
isDisabled=
{
isChatting
}
placeholder=
"提问"
placeholder=
"提问"
resize=
{
'none'
}
resize=
{
'none'
}
rows=
{
1
}
rows=
{
1
}
...
...
client/src/components/Layout/index.tsx
View file @
b2e2f60e
...
@@ -15,7 +15,8 @@ const pcUnShowLayoutRoute: Record<string, boolean> = {
...
@@ -15,7 +15,8 @@ const pcUnShowLayoutRoute: Record<string, boolean> = {
'/'
:
true
,
'/'
:
true
,
'/login'
:
true
,
'/login'
:
true
,
'/chat/share'
:
true
,
'/chat/share'
:
true
,
'/app/edit'
:
true
'/app/edit'
:
true
,
'/chat'
:
true
};
};
const
phoneUnShowLayoutRoute
:
Record
<
string
,
boolean
>
=
{
const
phoneUnShowLayoutRoute
:
Record
<
string
,
boolean
>
=
{
'/'
:
true
,
'/'
:
true
,
...
...
client/src/components/Layout/navbar.tsx
View file @
b2e2f60e
...
@@ -17,14 +17,14 @@ export enum NavbarTypeEnum {
...
@@ -17,14 +17,14 @@ export enum NavbarTypeEnum {
const
Navbar
=
({
unread
}:
{
unread
:
number
})
=>
{
const
Navbar
=
({
unread
}:
{
unread
:
number
})
=>
{
const
router
=
useRouter
();
const
router
=
useRouter
();
const
{
userInfo
,
lastModelId
}
=
useUserStore
();
const
{
userInfo
,
lastModelId
}
=
useUserStore
();
const
{
lastChat
Model
Id
,
lastChatId
}
=
useChatStore
();
const
{
lastChat
App
Id
,
lastChatId
}
=
useChatStore
();
const
navbarList
=
useMemo
(
const
navbarList
=
useMemo
(
()
=>
[
()
=>
[
{
{
label
:
'聊天'
,
label
:
'聊天'
,
icon
:
'chatLight'
,
icon
:
'chatLight'
,
activeIcon
:
'chatFill'
,
activeIcon
:
'chatFill'
,
link
:
`/chat?appId=
${
lastChat
Model
Id
}
&chatId=
${
lastChatId
}
`
,
link
:
`/chat?appId=
${
lastChat
App
Id
}
&chatId=
${
lastChatId
}
`
,
activeLink
:
[
'/chat'
]
activeLink
:
[
'/chat'
]
},
},
{
{
...
@@ -56,7 +56,7 @@ const Navbar = ({ unread }: { unread: number }) => {
...
@@ -56,7 +56,7 @@ const Navbar = ({ unread }: { unread: number }) => {
activeLink
:
[
'/number'
]
activeLink
:
[
'/number'
]
}
}
],
],
[
lastChatId
,
lastChat
Model
Id
]
[
lastChatId
,
lastChat
App
Id
]
);
);
const
itemStyles
:
any
=
{
const
itemStyles
:
any
=
{
...
...
client/src/components/Layout/navbarPhone.tsx
View file @
b2e2f60e
...
@@ -7,13 +7,13 @@ import Badge from '../Badge';
...
@@ -7,13 +7,13 @@ import Badge from '../Badge';
const
NavbarPhone
=
({
unread
}:
{
unread
:
number
})
=>
{
const
NavbarPhone
=
({
unread
}:
{
unread
:
number
})
=>
{
const
router
=
useRouter
();
const
router
=
useRouter
();
const
{
lastChat
Model
Id
,
lastChatId
}
=
useChatStore
();
const
{
lastChat
App
Id
,
lastChatId
}
=
useChatStore
();
const
navbarList
=
useMemo
(
const
navbarList
=
useMemo
(
()
=>
[
()
=>
[
{
{
label
:
'聊天'
,
label
:
'聊天'
,
icon
:
'tabbarChat'
,
icon
:
'tabbarChat'
,
link
:
`/chat?appId=
${
lastChat
Model
Id
}
&chatId=
${
lastChatId
}
`
,
link
:
`/chat?appId=
${
lastChat
App
Id
}
&chatId=
${
lastChatId
}
`
,
activeLink
:
[
'/chat'
],
activeLink
:
[
'/chat'
],
unread
:
0
unread
:
0
},
},
...
@@ -39,7 +39,7 @@ const NavbarPhone = ({ unread }: { unread: number }) => {
...
@@ -39,7 +39,7 @@ const NavbarPhone = ({ unread }: { unread: number }) => {
unread
unread
}
}
],
],
[
lastChatId
,
lastChat
Model
Id
,
unread
]
[
lastChatId
,
lastChat
App
Id
,
unread
]
);
);
return
(
return
(
...
...
client/src/components/SideBar/index.tsx
View file @
b2e2f60e
...
@@ -7,7 +7,7 @@ interface Props extends BoxProps {}
...
@@ -7,7 +7,7 @@ interface Props extends BoxProps {}
const
SideBar
=
(
e
?:
Props
)
=>
{
const
SideBar
=
(
e
?:
Props
)
=>
{
const
{
const
{
w
=
[
'100%'
,
'0 0 250px'
,
'0 0 2
80px'
,
'0 0 310px'
,
'0 0 34
0px'
],
w
=
[
'100%'
,
'0 0 250px'
,
'0 0 2
70px'
,
'0 0 290px'
,
'0 0 31
0px'
],
children
,
children
,
...
props
...
props
}
=
e
||
{};
}
=
e
||
{};
...
...
client/src/components/Tag/index.tsx
View file @
b2e2f60e
...
@@ -10,7 +10,7 @@ const Tag = ({ children, colorSchema = 'blue', ...props }: Props) => {
...
@@ -10,7 +10,7 @@ const Tag = ({ children, colorSchema = 'blue', ...props }: Props) => {
const
theme
=
useMemo
(()
=>
{
const
theme
=
useMemo
(()
=>
{
const
map
=
{
const
map
=
{
blue
:
{
blue
:
{
borderColor
:
'myBlue.
7
00'
,
borderColor
:
'myBlue.
6
00'
,
bg
:
'#F2FBFF'
,
bg
:
'#F2FBFF'
,
color
:
'myBlue.700'
color
:
'myBlue.700'
},
},
...
...
client/src/pages/api/app/del.ts
View file @
b2e2f60e
...
@@ -7,9 +7,9 @@ import { authApp } from '@/service/utils/auth';
...
@@ -7,9 +7,9 @@ import { authApp } from '@/service/utils/auth';
/* 获取我的模型 */
/* 获取我的模型 */
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
<
any
>
)
{
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
<
any
>
)
{
try
{
try
{
const
{
modelId
}
=
req
.
query
as
{
model
Id
:
string
};
const
{
appId
}
=
req
.
query
as
{
app
Id
:
string
};
if
(
!
model
Id
)
{
if
(
!
app
Id
)
{
throw
new
Error
(
'参数错误'
);
throw
new
Error
(
'参数错误'
);
}
}
...
@@ -20,28 +20,28 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
...
@@ -20,28 +20,28 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
// 验证是否是该用户的 model
// 验证是否是该用户的 model
await
authApp
({
await
authApp
({
appId
:
modelId
,
appId
,
userId
userId
});
});
// 删除对应的聊天
// 删除对应的聊天
await
Chat
.
deleteMany
({
await
Chat
.
deleteMany
({
model
Id
app
Id
});
});
// 删除收藏列表
// 删除收藏列表
await
Collection
.
deleteMany
({
await
Collection
.
deleteMany
({
modelId
modelId
:
appId
});
});
// 删除分享链接
// 删除分享链接
await
ShareChat
.
deleteMany
({
await
ShareChat
.
deleteMany
({
model
Id
app
Id
});
});
// 删除模型
// 删除模型
await
App
.
deleteOne
({
await
App
.
deleteOne
({
_id
:
model
Id
,
_id
:
app
Id
,
userId
userId
});
});
...
...
client/src/pages/api/app/detail.tsx
View file @
b2e2f60e
...
@@ -7,9 +7,9 @@ import { authApp } from '@/service/utils/auth';
...
@@ -7,9 +7,9 @@ import { authApp } from '@/service/utils/auth';
/* 获取我的模型 */
/* 获取我的模型 */
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
<
any
>
)
{
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
<
any
>
)
{
try
{
try
{
const
{
modelId
}
=
req
.
query
as
{
model
Id
:
string
};
const
{
appId
}
=
req
.
query
as
{
app
Id
:
string
};
if
(
!
model
Id
)
{
if
(
!
app
Id
)
{
throw
new
Error
(
'参数错误'
);
throw
new
Error
(
'参数错误'
);
}
}
...
@@ -19,7 +19,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
...
@@ -19,7 +19,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
await
connectToDatabase
();
await
connectToDatabase
();
const
{
app
}
=
await
authApp
({
const
{
app
}
=
await
authApp
({
appId
:
modelId
,
appId
,
userId
,
userId
,
authOwner
:
false
authOwner
:
false
});
});
...
...
client/src/pages/api/app/
list
.ts
→
client/src/pages/api/app/
myApps
.ts
View file @
b2e2f60e
import
type
{
NextApiRequest
,
NextApiResponse
}
from
'next'
;
import
type
{
NextApiRequest
,
NextApiResponse
}
from
'next'
;
import
{
jsonRes
}
from
'@/service/response'
;
import
{
jsonRes
}
from
'@/service/response'
;
import
{
connectToDatabase
,
Collection
,
App
}
from
'@/service/mongo'
;
import
{
connectToDatabase
,
App
}
from
'@/service/mongo'
;
import
{
authUser
}
from
'@/service/utils/auth'
;
import
{
authUser
}
from
'@/service/utils/auth'
;
import
type
{
AppListResponse
}
from
'@/api/response
/app'
;
import
{
AppListItemType
}
from
'@/types
/app'
;
/* 获取模型列表 */
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
<
any
>
)
{
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
<
any
>
)
{
try
{
try
{
// 凭证校验
// 凭证校验
...
@@ -13,41 +12,17 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
...
@@ -13,41 +12,17 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
await
connectToDatabase
();
await
connectToDatabase
();
// 根据 userId 获取模型信息
// 根据 userId 获取模型信息
const
[
myApps
,
myCollections
]
=
await
Promise
.
all
([
const
myApps
=
await
App
.
find
(
App
.
find
(
{
{
userId
userId
},
},
'_id avatar name intro'
'_id avatar name intro'
).
sort
({
).
sort
({
updateTime
:
-
1
updateTime
:
-
1
}),
});
Collection
.
find
({
userId
})
.
populate
({
path
:
'modelId'
,
select
:
'_id avatar name intro'
,
match
:
{
'share.isShare'
:
true
}
})
.
then
((
res
)
=>
res
.
filter
((
item
)
=>
item
.
modelId
))
]);
jsonRes
<
AppListResponse
>
(
res
,
{
jsonRes
<
AppListItemType
[]
>
(
res
,
{
data
:
{
data
:
myApps
myApps
:
myApps
.
map
((
item
)
=>
({
_id
:
item
.
_id
,
name
:
item
.
name
,
avatar
:
item
.
avatar
,
intro
:
item
.
intro
})),
myCollectionApps
:
myCollections
.
map
((
item
:
any
)
=>
({
_id
:
item
.
modelId
?.
_id
,
name
:
item
.
modelId
?.
name
,
avatar
:
item
.
modelId
?.
avatar
,
intro
:
item
.
modelId
?.
intro
}))
.
filter
((
item
)
=>
!
myApps
.
find
((
model
)
=>
String
(
model
.
_id
)
===
String
(
item
.
_id
)))
// 去重
}
});
});
}
catch
(
err
)
{
}
catch
(
err
)
{
jsonRes
(
res
,
{
jsonRes
(
res
,
{
...
...
client/src/pages/api/app/share/collection.ts
View file @
b2e2f60e
...
@@ -6,9 +6,9 @@ import { authUser } from '@/service/utils/auth';
...
@@ -6,9 +6,9 @@ import { authUser } from '@/service/utils/auth';
/* 模型收藏切换 */
/* 模型收藏切换 */
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
<
any
>
)
{
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
<
any
>
)
{
try
{
try
{
const
{
modelId
}
=
req
.
query
as
{
model
Id
:
string
};
const
{
appId
}
=
req
.
query
as
{
app
Id
:
string
};
if
(
!
model
Id
)
{
if
(
!
app
Id
)
{
throw
new
Error
(
'缺少参数'
);
throw
new
Error
(
'缺少参数'
);
}
}
// 凭证校验
// 凭证校验
...
@@ -18,7 +18,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
...
@@ -18,7 +18,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
const
collectionRecord
=
await
Collection
.
findOne
({
const
collectionRecord
=
await
Collection
.
findOne
({
userId
,
userId
,
modelId
modelId
:
appId
});
});
if
(
collectionRecord
)
{
if
(
collectionRecord
)
{
...
@@ -26,12 +26,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
...
@@ -26,12 +26,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
}
else
{
}
else
{
await
Collection
.
create
({
await
Collection
.
create
({
userId
,
userId
,
modelId
modelId
:
appId
});
});
}
}
await
App
.
findByIdAndUpdate
(
model
Id
,
{
await
App
.
findByIdAndUpdate
(
app
Id
,
{
'share.collection'
:
await
Collection
.
countDocuments
({
modelId
})
'share.collection'
:
await
Collection
.
countDocuments
({
modelId
:
appId
})
});
});
jsonRes
(
res
);
jsonRes
(
res
);
...
...
client/src/pages/api/chat/chatTest.ts
View file @
b2e2f60e
...
@@ -6,14 +6,15 @@ import { sseResponseEventEnum } from '@/constants/chat';
...
@@ -6,14 +6,15 @@ import { sseResponseEventEnum } from '@/constants/chat';
import
{
sseResponse
}
from
'@/service/utils/tools'
;
import
{
sseResponse
}
from
'@/service/utils/tools'
;
import
{
type
ChatCompletionRequestMessage
}
from
'openai'
;
import
{
type
ChatCompletionRequestMessage
}
from
'openai'
;
import
{
AppModuleItemType
}
from
'@/types/app'
;
import
{
AppModuleItemType
}
from
'@/types/app'
;
import
{
dispatchModules
}
from
'../openapi/v1/chat/completions2'
;
import
{
dispatchModules
}
from
'../openapi/v1/chat/completions'
;
import
{
gptMessage2ChatType
}
from
'@/utils/adapt'
;
export
type
MessageItemType
=
ChatCompletionRequestMessage
&
{
_id
?:
string
};
export
type
MessageItemType
=
ChatCompletionRequestMessage
&
{
_id
?:
string
};
export
type
Props
=
{
export
type
Props
=
{
history
:
MessageItemType
[];
history
:
MessageItemType
[];
prompt
:
string
;
prompt
:
string
;
modules
:
AppModuleItemType
[];
modules
:
AppModuleItemType
[];
variable
:
Record
<
string
,
any
>
;
variable
s
:
Record
<
string
,
any
>
;
};
};
export
type
ChatResponseType
=
{
export
type
ChatResponseType
=
{
newChatId
:
string
;
newChatId
:
string
;
...
@@ -29,7 +30,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
...
@@ -29,7 +30,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
res
.
end
();
res
.
end
();
});
});
let
{
modules
=
[],
history
=
[],
prompt
,
variable
=
{}
}
=
req
.
body
as
Props
;
let
{
modules
=
[],
history
=
[],
prompt
,
variable
s
=
{}
}
=
req
.
body
as
Props
;
try
{
try
{
if
(
!
history
||
!
modules
||
!
prompt
)
{
if
(
!
history
||
!
modules
||
!
prompt
)
{
...
@@ -48,9 +49,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
...
@@ -48,9 +49,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const
{
responseData
}
=
await
dispatchModules
({
const
{
responseData
}
=
await
dispatchModules
({
res
,
res
,
modules
:
modules
,
modules
:
modules
,
variable
,
variable
s
,
params
:
{
params
:
{
history
,
history
:
gptMessage2ChatType
(
history
)
,
userChatInput
:
prompt
userChatInput
:
prompt
},
},
stream
:
true
stream
:
true
...
...
client/src/pages/api/chat/delChatRecordByContentId.ts
View file @
b2e2f60e
...
@@ -5,12 +5,10 @@ import { authUser } from '@/service/utils/auth';
...
@@ -5,12 +5,10 @@ import { authUser } from '@/service/utils/auth';
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
)
{
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
)
{
try
{
try
{
const
{
chatId
,
contentId
}
=
req
.
query
as
{
const
{
historyId
,
contentId
}
=
req
.
query
as
{
historyId
:
string
;
contentId
:
string
};
chatId
:
string
;
console
.
log
(
historyId
,
contentId
);
contentId
:
string
;
};
if
(
!
chat
Id
||
!
contentId
)
{
if
(
!
history
Id
||
!
contentId
)
{
throw
new
Error
(
'缺少参数'
);
throw
new
Error
(
'缺少参数'
);
}
}
...
@@ -19,7 +17,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
...
@@ -19,7 +17,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
// 凭证校验
// 凭证校验
const
{
userId
}
=
await
authUser
({
req
,
authToken
:
true
});
const
{
userId
}
=
await
authUser
({
req
,
authToken
:
true
});
const
chatRecord
=
await
Chat
.
findById
(
chat
Id
);
const
chatRecord
=
await
Chat
.
findById
(
history
Id
);
if
(
!
chatRecord
)
{
if
(
!
chatRecord
)
{
throw
new
Error
(
'找不到对话'
);
throw
new
Error
(
'找不到对话'
);
...
@@ -28,7 +26,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
...
@@ -28,7 +26,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
// 删除一条数据库记录
// 删除一条数据库记录
await
Chat
.
updateOne
(
await
Chat
.
updateOne
(
{
{
_id
:
chat
Id
,
_id
:
history
Id
,
userId
userId
},
},
{
$pull
:
{
content
:
{
_id
:
contentId
}
}
}
{
$pull
:
{
content
:
{
_id
:
contentId
}
}
}
...
...
client/src/pages/api/chat/history/getHistory.ts
View file @
b2e2f60e
...
@@ -2,31 +2,32 @@ import type { NextApiRequest, NextApiResponse } from 'next';
...
@@ -2,31 +2,32 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import
{
jsonRes
}
from
'@/service/response'
;
import
{
jsonRes
}
from
'@/service/response'
;
import
{
connectToDatabase
,
Chat
}
from
'@/service/mongo'
;
import
{
connectToDatabase
,
Chat
}
from
'@/service/mongo'
;
import
{
authUser
}
from
'@/service/utils/auth'
;
import
{
authUser
}
from
'@/service/utils/auth'
;
import
type
{
HistoryItemType
}
from
'@/types/chat'
;
import
type
{
Chat
HistoryItemType
}
from
'@/types/chat'
;
/* 获取历史记录 */
/* 获取历史记录 */
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
)
{
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
)
{
try
{
try
{
const
{
appId
}
=
req
.
body
as
{
appId
?:
string
};
const
{
userId
}
=
await
authUser
({
req
,
authToken
:
true
});
const
{
userId
}
=
await
authUser
({
req
,
authToken
:
true
});
await
connectToDatabase
();
await
connectToDatabase
();
const
data
=
await
Chat
.
find
(
const
data
=
await
Chat
.
find
(
{
{
userId
userId
,
...(
appId
&&
{
appId
})
},
},
'_id title top customTitle
modelId updateTime latestChat
'
'_id title top customTitle
appId updateTime
'
)
)
.
sort
({
top
:
-
1
,
updateTime
:
-
1
})
.
sort
({
top
:
-
1
,
updateTime
:
-
1
})
.
limit
(
20
);
.
limit
(
20
);
jsonRes
<
HistoryItemType
[]
>
(
res
,
{
jsonRes
<
Chat
HistoryItemType
[]
>
(
res
,
{
data
:
data
.
map
((
item
)
=>
({
data
:
data
.
map
((
item
)
=>
({
_id
:
item
.
_id
,
_id
:
item
.
_id
,
updateTime
:
item
.
updateTime
,
updateTime
:
item
.
updateTime
,
modelId
:
item
.
model
Id
,
appId
:
item
.
app
Id
,
title
:
item
.
customTitle
||
item
.
title
,
title
:
item
.
customTitle
||
item
.
title
,
latestChat
:
item
.
latestChat
,
top
:
item
.
top
top
:
item
.
top
}))
}))
});
});
...
...
client/src/pages/api/chat/history/updateChatHistory.ts
View file @
b2e2f60e
...
@@ -4,7 +4,7 @@ import { connectToDatabase, Chat } from '@/service/mongo';
...
@@ -4,7 +4,7 @@ import { connectToDatabase, Chat } from '@/service/mongo';
import
{
authUser
}
from
'@/service/utils/auth'
;
import
{
authUser
}
from
'@/service/utils/auth'
;
export
type
Props
=
{
export
type
Props
=
{
chatId
:
''
|
string
;
historyId
:
string
;
customTitle
?:
string
;
customTitle
?:
string
;
top
?:
boolean
;
top
?:
boolean
;
};
};
...
@@ -12,7 +12,7 @@ export type Props = {
...
@@ -12,7 +12,7 @@ export type Props = {
/* 更新聊天标题 */
/* 更新聊天标题 */
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
)
{
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
)
{
try
{
try
{
const
{
chat
Id
,
customTitle
,
top
}
=
req
.
body
as
Props
;
const
{
history
Id
,
customTitle
,
top
}
=
req
.
body
as
Props
;
const
{
userId
}
=
await
authUser
({
req
,
authToken
:
true
});
const
{
userId
}
=
await
authUser
({
req
,
authToken
:
true
});
...
@@ -20,7 +20,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
...
@@ -20,7 +20,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
await
Chat
.
findOneAndUpdate
(
await
Chat
.
findOneAndUpdate
(
{
{
_id
:
chat
Id
,
_id
:
history
Id
,
userId
userId
},
},
{
{
...
...
client/src/pages/api/chat/init.ts
View file @
b2e2f60e
...
@@ -6,23 +6,25 @@ import { authUser } from '@/service/utils/auth';
...
@@ -6,23 +6,25 @@ import { authUser } from '@/service/utils/auth';
import
{
ChatItemType
}
from
'@/types/chat'
;
import
{
ChatItemType
}
from
'@/types/chat'
;
import
{
authApp
}
from
'@/service/utils/auth'
;
import
{
authApp
}
from
'@/service/utils/auth'
;
import
mongoose
from
'mongoose'
;
import
mongoose
from
'mongoose'
;
import
type
{
AppSchema
}
from
'@/types/mongoSchema'
;
import
type
{
AppSchema
,
ChatSchema
}
from
'@/types/mongoSchema'
;
import
{
FlowModuleTypeEnum
}
from
'@/constants/flow'
;
import
{
SystemInputEnum
}
from
'@/constants/app'
;
/* 初始化我的聊天框,需要身份验证 */
/* 初始化我的聊天框,需要身份验证 */
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
)
{
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
)
{
try
{
try
{
const
{
userId
}
=
await
authUser
({
req
,
authToken
:
true
});
const
{
userId
}
=
await
authUser
({
req
,
authToken
:
true
});
let
{
modelId
,
chat
Id
}
=
req
.
query
as
{
let
{
appId
,
history
Id
}
=
req
.
query
as
{
model
Id
:
''
|
string
;
app
Id
:
''
|
string
;
chat
Id
:
''
|
string
;
history
Id
:
''
|
string
;
};
};
await
connectToDatabase
();
await
connectToDatabase
();
// 没有
model
Id 时,直接获取用户的第一个id
// 没有
app
Id 时,直接获取用户的第一个id
const
app
=
await
(
async
()
=>
{
const
app
=
await
(
async
()
=>
{
if
(
!
model
Id
)
{
if
(
!
app
Id
)
{
const
myModel
=
await
App
.
findOne
({
userId
});
const
myModel
=
await
App
.
findOne
({
userId
});
if
(
!
myModel
)
{
if
(
!
myModel
)
{
const
{
_id
}
=
await
App
.
create
({
const
{
_id
}
=
await
App
.
create
({
...
@@ -36,7 +38,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
...
@@ -36,7 +38,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
}
else
{
}
else
{
// 校验使用权限
// 校验使用权限
const
authRes
=
await
authApp
({
const
authRes
=
await
authApp
({
appId
:
modelId
,
appId
,
userId
,
userId
,
authUser
:
false
,
authUser
:
false
,
authOwner
:
false
authOwner
:
false
...
@@ -45,25 +47,25 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
...
@@ -45,25 +47,25 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
}
}
})();
})();
modelId
=
model
Id
||
app
.
_id
;
appId
=
app
Id
||
app
.
_id
;
// 历史记录
// 历史记录
let
history
:
ChatItemType
[]
=
[];
const
{
chat
,
history
=
[]
}:
{
chat
?:
ChatSchema
;
history
?:
ChatItemType
[]
}
=
await
(
async
()
=>
{
if
(
chat
Id
)
{
if
(
history
Id
)
{
// auth chatId
// auth chatId
const
chat
=
await
Chat
.
countDocuments
({
const
chat
=
await
Chat
.
findOne
({
_id
:
chat
Id
,
_id
:
history
Id
,
userId
userId
});
});
if
(
chat
===
0
)
{
if
(
!
chat
)
{
throw
new
Error
(
'聊天框不存在'
);
throw
new
Error
(
'聊天框不存在'
);
}
}
// 获取 chat.content 数据
// 获取 chat.content 数据
history
=
await
Chat
.
aggregate
([
const
history
=
await
Chat
.
aggregate
([
{
{
$match
:
{
$match
:
{
_id
:
new
mongoose
.
Types
.
ObjectId
(
chat
Id
),
_id
:
new
mongoose
.
Types
.
ObjectId
(
history
Id
),
userId
:
new
mongoose
.
Types
.
ObjectId
(
userId
)
userId
:
new
mongoose
.
Types
.
ObjectId
(
userId
)
}
}
},
},
...
@@ -85,23 +87,31 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
...
@@ -85,23 +87,31 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
}
}
}
}
]);
]);
return
{
history
,
chat
};
}
}
return
{};
})();
const
isOwner
=
String
(
app
.
userId
)
===
userId
;
const
isOwner
=
String
(
app
.
userId
)
===
userId
;
jsonRes
<
InitChatResponse
>
(
res
,
{
jsonRes
<
InitChatResponse
>
(
res
,
{
data
:
{
data
:
{
chatId
:
chatId
||
''
,
historyId
,
modelId
:
modelId
,
appId
,
model
:
{
app
:
{
variableModules
:
app
.
modules
.
find
((
item
)
=>
item
.
flowType
===
FlowModuleTypeEnum
.
userGuide
)
?.
inputs
?.
find
((
item
)
=>
item
.
key
===
SystemInputEnum
.
variables
)?.
value
,
welcomeText
:
app
.
modules
.
find
((
item
)
=>
item
.
flowType
===
FlowModuleTypeEnum
.
userGuide
)
?.
inputs
?.
find
((
item
)
=>
item
.
key
===
SystemInputEnum
.
welcomeText
)?.
value
,
name
:
app
.
name
,
name
:
app
.
name
,
avatar
:
app
.
avatar
,
avatar
:
app
.
avatar
,
intro
:
app
.
intro
,
intro
:
app
.
intro
,
canUse
:
app
.
share
.
isShare
||
isOwner
canUse
:
app
.
share
.
isShare
||
isOwner
},
},
chatModel
:
app
.
chat
.
chatModel
,
title
:
chat
?.
title
||
'新对话'
,
systemPrompt
:
isOwner
?
app
.
chat
.
systemPrompt
:
''
,
variables
:
chat
?.
variables
||
{},
limitPrompt
:
isOwner
?
app
.
chat
.
limitPrompt
:
''
,
history
history
}
}
});
});
...
...
client/src/pages/api/chat/saveChat.ts
View file @
b2e2f60e
...
@@ -7,15 +7,16 @@ import { authUser } from '@/service/utils/auth';
...
@@ -7,15 +7,16 @@ import { authUser } from '@/service/utils/auth';
import
{
Types
}
from
'mongoose'
;
import
{
Types
}
from
'mongoose'
;
type
Props
=
{
type
Props
=
{
chatId
?:
string
;
historyId
?:
string
;
modelId
:
string
;
appId
:
string
;
variables
?:
Record
<
string
,
any
>
;
prompts
:
[
ChatItemType
,
ChatItemType
];
prompts
:
[
ChatItemType
,
ChatItemType
];
};
};
/* 聊天内容存存储 */
/* 聊天内容存存储 */
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
)
{
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
)
{
try
{
try
{
const
{
chatId
,
model
Id
,
prompts
}
=
req
.
body
as
Props
;
const
{
historyId
,
app
Id
,
prompts
}
=
req
.
body
as
Props
;
if
(
!
prompts
)
{
if
(
!
prompts
)
{
throw
new
Error
(
'缺少参数'
);
throw
new
Error
(
'缺少参数'
);
...
@@ -24,8 +25,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
...
@@ -24,8 +25,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const
{
userId
}
=
await
authUser
({
req
,
authToken
:
true
});
const
{
userId
}
=
await
authUser
({
req
,
authToken
:
true
});
const
response
=
await
saveChat
({
const
response
=
await
saveChat
({
chat
Id
,
history
Id
,
model
Id
,
app
Id
,
prompts
,
prompts
,
userId
userId
});
});
...
@@ -42,14 +43,15 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
...
@@ -42,14 +43,15 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
}
}
export
async
function
saveChat
({
export
async
function
saveChat
({
new
Chat
Id
,
new
History
Id
,
chat
Id
,
history
Id
,
model
Id
,
app
Id
,
prompts
,
prompts
,
variables
,
userId
userId
}:
Props
&
{
new
ChatId
?:
Types
.
ObjectId
;
userId
:
string
}):
Promise
<
{
newChat
Id
:
string
}
>
{
}:
Props
&
{
new
HistoryId
?:
Types
.
ObjectId
;
userId
:
string
}):
Promise
<
{
newHistory
Id
:
string
}
>
{
await
connectToDatabase
();
await
connectToDatabase
();
const
{
app
}
=
await
authApp
({
appId
:
modelId
,
userId
,
authOwner
:
false
});
const
{
app
}
=
await
authApp
({
appId
,
userId
,
authOwner
:
false
});
const
content
=
prompts
.
map
((
item
)
=>
({
const
content
=
prompts
.
map
((
item
)
=>
({
_id
:
item
.
_id
,
_id
:
item
.
_id
,
...
@@ -60,43 +62,45 @@ export async function saveChat({
...
@@ -60,43 +62,45 @@ export async function saveChat({
}));
}));
if
(
String
(
app
.
userId
)
===
userId
)
{
if
(
String
(
app
.
userId
)
===
userId
)
{
await
App
.
findByIdAndUpdate
(
model
Id
,
{
await
App
.
findByIdAndUpdate
(
app
Id
,
{
updateTime
:
new
Date
()
updateTime
:
new
Date
()
});
});
}
}
const
[
response
]
=
await
Promise
.
all
([
const
[
response
]
=
await
Promise
.
all
([
...(
chat
Id
...(
history
Id
?
[
?
[
Chat
.
findByIdAndUpdate
(
chat
Id
,
{
Chat
.
findByIdAndUpdate
(
history
Id
,
{
$push
:
{
$push
:
{
content
:
{
content
:
{
$each
:
content
$each
:
content
}
}
},
},
variables
,
title
:
content
[
0
].
value
.
slice
(
0
,
20
),
title
:
content
[
0
].
value
.
slice
(
0
,
20
),
latestChat
:
content
[
1
].
value
,
latestChat
:
content
[
1
].
value
,
updateTime
:
new
Date
()
updateTime
:
new
Date
()
}).
then
(()
=>
({
}).
then
(()
=>
({
new
Chat
Id
:
''
new
History
Id
:
''
}))
}))
]
]
:
[
:
[
Chat
.
create
({
Chat
.
create
({
_id
:
new
Chat
Id
,
_id
:
new
History
Id
,
userId
,
userId
,
modelId
,
appId
,
variables
,
content
,
content
,
title
:
content
[
0
].
value
.
slice
(
0
,
20
),
title
:
content
[
0
].
value
.
slice
(
0
,
20
),
latestChat
:
content
[
1
].
value
latestChat
:
content
[
1
].
value
}).
then
((
res
)
=>
({
}).
then
((
res
)
=>
({
new
Chat
Id
:
String
(
res
.
_id
)
new
History
Id
:
String
(
res
.
_id
)
}))
}))
]),
]),
// update app
// update app
...(
String
(
app
.
userId
)
===
userId
...(
String
(
app
.
userId
)
===
userId
?
[
?
[
App
.
findByIdAndUpdate
(
model
Id
,
{
App
.
findByIdAndUpdate
(
app
Id
,
{
updateTime
:
new
Date
()
updateTime
:
new
Date
()
})
})
]
]
...
@@ -105,6 +109,6 @@ export async function saveChat({
...
@@ -105,6 +109,6 @@ export async function saveChat({
return
{
return
{
// @ts-ignore
// @ts-ignore
new
ChatId
:
response
?.
newChat
Id
||
''
new
HistoryId
:
response
?.
newHistory
Id
||
''
};
};
}
}
client/src/pages/api/openapi/chat/chat.ts
deleted
100644 → 0
View file @
eb768d9c
import
type
{
NextApiRequest
,
NextApiResponse
}
from
'next'
;
import
{
connectToDatabase
}
from
'@/service/mongo'
;
import
{
authUser
,
authApp
,
getApiKey
}
from
'@/service/utils/auth'
;
import
{
modelServiceToolMap
,
resStreamResponse
}
from
'@/service/utils/chat'
;
import
{
ChatItemType
}
from
'@/types/chat'
;
import
{
jsonRes
}
from
'@/service/response'
;
import
{
ChatModelMap
}
from
'@/constants/model'
;
import
{
pushChatBill
}
from
'@/service/events/pushBill'
;
import
{
ChatRoleEnum
}
from
'@/constants/chat'
;
import
{
withNextCors
}
from
'@/service/utils/tools'
;
import
{
BillTypeEnum
}
from
'@/constants/user'
;
import
{
appKbSearch
}
from
'../kb/appKbSearch'
;
/* 发送提示词 */
export
default
withNextCors
(
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
)
{
res
.
on
(
'close'
,
()
=>
{
res
.
end
();
});
res
.
on
(
'error'
,
()
=>
{
console
.
log
(
'error: '
,
'request error'
);
res
.
end
();
});
try
{
const
{
chatId
,
prompts
,
modelId
,
isStream
=
true
}
=
req
.
body
as
{
chatId
?:
string
;
prompts
:
ChatItemType
[];
modelId
:
string
;
isStream
:
boolean
;
};
if
(
!
prompts
||
!
modelId
)
{
throw
new
Error
(
'缺少参数'
);
}
if
(
!
Array
.
isArray
(
prompts
))
{
throw
new
Error
(
'prompts is not array'
);
}
if
(
prompts
.
length
>
30
||
prompts
.
length
===
0
)
{
throw
new
Error
(
'Prompts arr length range 1-30'
);
}
await
connectToDatabase
();
let
startTime
=
Date
.
now
();
/* 凭证校验 */
const
{
userId
}
=
await
authUser
({
req
});
const
{
app
}
=
await
authApp
({
userId
,
appId
:
modelId
});
/* get api key */
const
{
systemAuthKey
:
apiKey
}
=
await
getApiKey
({
model
:
app
.
chat
.
chatModel
,
userId
,
mustPay
:
true
});
const
modelConstantsData
=
ChatModelMap
[
app
.
chat
.
chatModel
];
const
prompt
=
prompts
[
prompts
.
length
-
1
];
const
{
userSystemPrompt
=
[],
userLimitPrompt
=
[],
quotePrompt
=
[]
}
=
await
(
async
()
=>
{
// 使用了知识库搜索
if
(
app
.
chat
.
relatedKbs
?.
length
>
0
)
{
const
{
quotePrompt
,
userSystemPrompt
,
userLimitPrompt
}
=
await
appKbSearch
({
model
:
app
,
userId
,
fixedQuote
:
[],
prompt
:
prompt
,
similarity
:
app
.
chat
.
searchSimilarity
,
limit
:
app
.
chat
.
searchLimit
});
return
{
userSystemPrompt
,
userLimitPrompt
,
quotePrompt
:
[
quotePrompt
]
};
}
return
{
userSystemPrompt
:
app
.
chat
.
systemPrompt
?
[
{
obj
:
ChatRoleEnum
.
System
,
value
:
app
.
chat
.
systemPrompt
}
]
:
[],
userLimitPrompt
:
app
.
chat
.
limitPrompt
?
[
{
obj
:
ChatRoleEnum
.
Human
,
value
:
app
.
chat
.
limitPrompt
}
]
:
[]
};
})();
// search result is empty
if
(
app
.
chat
.
relatedKbs
?.
length
>
0
&&
!
quotePrompt
[
0
]?.
value
&&
app
.
chat
.
searchEmptyText
)
{
const
response
=
app
.
chat
.
searchEmptyText
;
return
res
.
end
(
response
);
}
// 读取对话内容
const
completePrompts
=
[
...
quotePrompt
,
...
userSystemPrompt
,
...
prompts
.
slice
(
0
,
-
1
),
...
userLimitPrompt
,
prompt
];
// 计算温度
const
temperature
=
(
modelConstantsData
.
maxTemperature
*
(
app
.
chat
.
temperature
/
10
)).
toFixed
(
2
);
// 发出请求
const
{
streamResponse
,
responseMessages
,
responseText
,
totalTokens
}
=
await
modelServiceToolMap
.
chatCompletion
({
model
:
app
.
chat
.
chatModel
,
apiKey
,
temperature
:
+
temperature
,
messages
:
completePrompts
,
stream
:
isStream
,
res
});
console
.
log
(
'api response time:'
,
`
${(
Date
.
now
()
-
startTime
)
/
1000
}
s`
);
if
(
res
.
closed
)
return
res
.
end
();
const
{
textLen
=
0
,
tokens
=
totalTokens
}
=
await
(
async
()
=>
{
if
(
isStream
)
{
try
{
const
{
finishMessages
,
totalTokens
}
=
await
resStreamResponse
({
model
:
app
.
chat
.
chatModel
,
res
,
chatResponse
:
streamResponse
,
prompts
:
responseMessages
});
res
.
end
();
return
{
textLen
:
finishMessages
.
map
((
item
)
=>
item
.
value
).
join
(
''
).
length
,
tokens
:
totalTokens
};
}
catch
(
error
)
{
res
.
end
();
console
.
log
(
'error,结束'
,
error
);
}
}
else
{
jsonRes
(
res
,
{
data
:
responseText
});
return
{
textLen
:
responseMessages
.
map
((
item
)
=>
item
.
value
).
join
(
''
).
length
};
}
return
{};
})();
pushChatBill
({
isPay
:
true
,
chatModel
:
app
.
chat
.
chatModel
,
userId
,
textLen
,
tokens
,
type
:
BillTypeEnum
.
openapiChat
});
}
catch
(
err
:
any
)
{
res
.
status
(
500
);
jsonRes
(
res
,
{
code
:
500
,
error
:
err
});
}
});
client/src/pages/api/openapi/v1/chat/completions.ts
View file @
b2e2f60e
This diff is collapsed.
Click to expand it.
client/src/pages/api/openapi/v1/chat/completions2.ts
deleted
100644 → 0
View file @
eb768d9c
This diff is collapsed.
Click to expand it.
client/src/pages/api/openapi/v1/chat/getHistory.ts
View file @
b2e2f60e
...
@@ -7,7 +7,7 @@ import { Types } from 'mongoose';
...
@@ -7,7 +7,7 @@ import { Types } from 'mongoose';
import
type
{
ChatItemType
}
from
'@/types/chat'
;
import
type
{
ChatItemType
}
from
'@/types/chat'
;
export
type
Props
=
{
export
type
Props
=
{
chat
Id
?:
string
;
history
Id
?:
string
;
limit
?:
number
;
limit
?:
number
;
};
};
export
type
Response
=
{
history
:
ChatItemType
[]
};
export
type
Response
=
{
history
:
ChatItemType
[]
};
...
@@ -16,11 +16,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
...
@@ -16,11 +16,11 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
try
{
try
{
await
connectToDatabase
();
await
connectToDatabase
();
const
{
userId
}
=
await
authUser
({
req
});
const
{
userId
}
=
await
authUser
({
req
});
const
{
chat
Id
,
limit
}
=
req
.
body
as
Props
;
const
{
history
Id
,
limit
}
=
req
.
body
as
Props
;
jsonRes
<
Response
>
(
res
,
{
jsonRes
<
Response
>
(
res
,
{
data
:
await
getChatHistory
({
data
:
await
getChatHistory
({
chat
Id
,
history
Id
,
userId
,
userId
,
limit
limit
})
})
...
@@ -34,16 +34,16 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
...
@@ -34,16 +34,16 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
}
}
export
async
function
getChatHistory
({
export
async
function
getChatHistory
({
chat
Id
,
history
Id
,
userId
,
userId
,
limit
=
50
limit
=
50
}:
Props
&
{
userId
:
string
}):
Promise
<
Response
>
{
}:
Props
&
{
userId
:
string
}):
Promise
<
Response
>
{
if
(
!
chat
Id
)
{
if
(
!
history
Id
)
{
return
{
history
:
[]
};
return
{
history
:
[]
};
}
}
const
history
=
await
Chat
.
aggregate
([
const
history
=
await
Chat
.
aggregate
([
{
$match
:
{
_id
:
new
Types
.
ObjectId
(
chat
Id
),
userId
:
new
Types
.
ObjectId
(
userId
)
}
},
{
$match
:
{
_id
:
new
Types
.
ObjectId
(
history
Id
),
userId
:
new
Types
.
ObjectId
(
userId
)
}
},
{
{
$project
:
{
$project
:
{
content
:
{
content
:
{
...
...
client/src/pages/app/detail/components/edit/components/ChatTest.tsx
View file @
b2e2f60e
...
@@ -58,7 +58,6 @@ const ChatTest = (
...
@@ -58,7 +58,6 @@ const ChatTest = (
?.
find
((
item
)
=>
item
.
flowType
===
FlowModuleTypeEnum
.
historyNode
)
?.
find
((
item
)
=>
item
.
flowType
===
FlowModuleTypeEnum
.
historyNode
)
?.
inputs
?.
find
((
item
)
=>
item
.
key
===
'maxContext'
)?.
value
||
0
;
?.
inputs
?.
find
((
item
)
=>
item
.
key
===
'maxContext'
)?.
value
||
0
;
const
history
=
messages
.
slice
(
-
historyMaxLen
-
2
,
-
2
);
const
history
=
messages
.
slice
(
-
historyMaxLen
-
2
,
-
2
);
console
.
log
(
history
,
'history===='
);
// 流请求,获取数据
// 流请求,获取数据
const
{
responseText
}
=
await
streamFetch
({
const
{
responseText
}
=
await
streamFetch
({
...
@@ -87,8 +86,6 @@ const ChatTest = (
...
@@ -87,8 +86,6 @@ const ChatTest = (
useImperativeHandle
(
ref
,
()
=>
({
useImperativeHandle
(
ref
,
()
=>
({
resetChatTest
()
{
resetChatTest
()
{
console
.
log
(
ChatBoxRef
.
current
,
'==='
);
ChatBoxRef
.
current
?.
resetHistory
([]);
ChatBoxRef
.
current
?.
resetHistory
([]);
ChatBoxRef
.
current
?.
resetVariables
();
ChatBoxRef
.
current
?.
resetVariables
();
}
}
...
@@ -147,6 +144,7 @@ const ChatTest = (
...
@@ -147,6 +144,7 @@ const ChatTest = (
variableModules=
{
variableModules
}
variableModules=
{
variableModules
}
welcomeText=
{
welcomeText
}
welcomeText=
{
welcomeText
}
onStartChat=
{
startChat
}
onStartChat=
{
startChat
}
onDelMessage=
{
()
=>
{}
}
/>
/>
</
Box
>
</
Box
>
</
Flex
>
</
Flex
>
...
...
client/src/pages/appStore/components/list.tsx
View file @
b2e2f60e
...
@@ -12,7 +12,7 @@ const ShareModelList = ({
...
@@ -12,7 +12,7 @@ const ShareModelList = ({
onclickCollection
onclickCollection
}:
{
}:
{
models
:
ShareAppItem
[];
models
:
ShareAppItem
[];
onclickCollection
:
(
model
Id
:
string
)
=>
void
;
onclickCollection
:
(
app
Id
:
string
)
=>
void
;
})
=>
{
})
=>
{
const
router
=
useRouter
();
const
router
=
useRouter
();
...
...
client/src/pages/appStore/index.tsx
View file @
b2e2f60e
...
@@ -12,8 +12,6 @@ const modelList = () => {
...
@@ -12,8 +12,6 @@ const modelList = () => {
const
{
Loading
}
=
useLoading
();
const
{
Loading
}
=
useLoading
();
const
lastSearch
=
useRef
(
''
);
const
lastSearch
=
useRef
(
''
);
const
[
searchText
,
setSearchText
]
=
useState
(
''
);
const
[
searchText
,
setSearchText
]
=
useState
(
''
);
const
{
refreshModel
}
=
useUserStore
();
/* 加载模型 */
/* 加载模型 */
const
{
const
{
data
:
models
,
data
:
models
,
...
@@ -30,16 +28,15 @@ const modelList = () => {
...
@@ -30,16 +28,15 @@ const modelList = () => {
});
});
const
onclickCollection
=
useCallback
(
const
onclickCollection
=
useCallback
(
async
(
model
Id
:
string
)
=>
{
async
(
app
Id
:
string
)
=>
{
try
{
try
{
await
triggerModelCollection
(
model
Id
);
await
triggerModelCollection
(
app
Id
);
getData
(
pageNum
);
getData
(
pageNum
);
refreshModel
.
removeModelDetail
(
modelId
);
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
log
(
error
);
console
.
log
(
error
);
}
}
},
},
[
getData
,
pageNum
,
refreshModel
]
[
getData
,
pageNum
]
);
);
return
(
return
(
...
...
client/src/pages/chat/components/ChatHistorySlider.tsx
View file @
b2e2f60e
import
React
from
'react'
;
import
React
,
{
useMemo
}
from
'react'
;
import
{
AddIcon
}
from
'@chakra-ui/icons'
;
import
{
import
{
Box
,
Box
,
Button
,
Button
,
...
@@ -10,13 +9,16 @@ import {
...
@@ -10,13 +9,16 @@ import {
MenuList
,
MenuList
,
MenuItem
MenuItem
}
from
'@chakra-ui/react'
;
}
from
'@chakra-ui/react'
;
import
{
useRouter
}
from
'next/router'
;
import
MyIcon
from
'@/components/Icon'
;
import
MyIcon
from
'@/components/Icon'
;
import
type
{
ShareChatHistoryItemType
,
ExportChatType
}
from
'@/types/chat'
;
import
{
useChatStore
}
from
'@/store/chat'
;
import
{
useGlobalStore
}
from
'@/store/global'
;
import
{
useGlobalStore
}
from
'@/store/global'
;
import
Avatar
from
'@/components/Avatar'
;
import
Avatar
from
'@/components/Avatar'
;
type
HistoryItemType
=
{
id
:
string
;
title
:
string
;
top
?:
boolean
;
};
const
ChatHistorySlider
=
({
const
ChatHistorySlider
=
({
appName
,
appName
,
appAvatar
,
appAvatar
,
...
@@ -24,23 +26,26 @@ const ChatHistorySlider = ({
...
@@ -24,23 +26,26 @@ const ChatHistorySlider = ({
activeHistoryId
,
activeHistoryId
,
onChangeChat
,
onChangeChat
,
onDelHistory
,
onDelHistory
,
onSetHistoryTop
,
onCloseSlider
onCloseSlider
}:
{
}:
{
appName
:
string
;
appName
:
string
;
appAvatar
:
string
;
appAvatar
:
string
;
history
:
{
history
:
HistoryItemType
[];
id
:
string
;
title
:
string
;
}[];
activeHistoryId
:
string
;
activeHistoryId
:
string
;
onChangeChat
:
(
historyId
?:
string
)
=>
void
;
onChangeChat
:
(
historyId
?:
string
)
=>
void
;
onDelHistory
:
(
historyId
:
string
)
=>
void
;
onDelHistory
:
(
historyId
:
string
)
=>
void
;
onSetHistoryTop
?:
(
e
:
{
historyId
:
string
;
top
:
boolean
})
=>
void
;
onCloseSlider
:
()
=>
void
;
onCloseSlider
:
()
=>
void
;
})
=>
{
})
=>
{
const
router
=
useRouter
();
const
theme
=
useTheme
();
const
theme
=
useTheme
();
const
{
isPc
}
=
useGlobalStore
();
const
{
isPc
}
=
useGlobalStore
();
const
concatHistory
=
useMemo
<
HistoryItemType
[]
>
(
()
=>
(
!
activeHistoryId
?
[{
id
:
activeHistoryId
,
title
:
'新对话'
}].
concat
(
history
)
:
history
),
[
activeHistoryId
,
history
]
);
return
(
return
(
<
Flex
<
Flex
position=
{
'relative'
}
position=
{
'relative'
}
...
@@ -48,11 +53,11 @@ const ChatHistorySlider = ({
...
@@ -48,11 +53,11 @@ const ChatHistorySlider = ({
w=
{
'100%'
}
w=
{
'100%'
}
h=
{
'100%'
}
h=
{
'100%'
}
bg=
{
'white'
}
bg=
{
'white'
}
px=
{
[
2
,
5
]
}
borderRight=
{
[
''
,
theme
.
borders
.
base
]
}
borderRight=
{
[
''
,
theme
.
borders
.
base
]
}
whiteSpace=
{
'nowrap'
}
>
>
{
isPc
&&
(
{
isPc
&&
(
<
Flex
pt=
{
5
}
pb=
{
2
}
alignItems=
{
'center'
}
whiteSpace=
{
'nowrap
'
}
>
<
Flex
pt=
{
5
}
pb=
{
2
}
px=
{
[
2
,
5
]
}
alignItems=
{
'center
'
}
>
<
Avatar
src=
{
appAvatar
}
/>
<
Avatar
src=
{
appAvatar
}
/>
<
Box
ml=
{
2
}
fontWeight=
{
'bold'
}
className=
{
'textEllipsis'
}
>
<
Box
ml=
{
2
}
fontWeight=
{
'bold'
}
className=
{
'textEllipsis'
}
>
{
appName
}
{
appName
}
...
@@ -60,7 +65,7 @@ const ChatHistorySlider = ({
...
@@ -60,7 +65,7 @@ const ChatHistorySlider = ({
</
Flex
>
</
Flex
>
)
}
)
}
{
/* 新对话 */
}
{
/* 新对话 */
}
<
Box
w=
{
'100%'
}
h=
{
'36px'
}
my=
{
5
}
>
<
Box
w=
{
'100%'
}
px=
{
[
2
,
5
]
}
h=
{
'36px'
}
my=
{
5
}
>
<
Button
<
Button
variant=
{
'base'
}
variant=
{
'base'
}
w=
{
'100%'
}
w=
{
'100%'
}
...
@@ -76,8 +81,8 @@ const ChatHistorySlider = ({
...
@@ -76,8 +81,8 @@ const ChatHistorySlider = ({
</
Box
>
</
Box
>
{
/* chat history */
}
{
/* chat history */
}
<
Box
flex=
{
'1 0 0'
}
h=
{
0
}
overflow=
{
'overlay'
}
>
<
Box
flex=
{
'1 0 0'
}
h=
{
0
}
px=
{
[
2
,
5
]
}
overflow=
{
'overlay'
}
>
{
h
istory
.
map
((
item
)
=>
(
{
concatH
istory
.
map
((
item
)
=>
(
<
Flex
<
Flex
position=
{
'relative'
}
position=
{
'relative'
}
key=
{
item
.
id
}
key=
{
item
.
id
}
...
@@ -94,6 +99,7 @@ const ChatHistorySlider = ({
...
@@ -94,6 +99,7 @@ const ChatHistorySlider = ({
display
:
'block'
display
:
'block'
}
}
}
}
}
}
bg=
{
item
.
top
?
'#E6F6F6 !important'
:
''
}
{
...
(
item
.
id
===
activeHistoryId
{
...
(
item
.
id
===
activeHistoryId
?
{
?
{
backgroundColor
:
'
myBlue
.
100
!
important
',
backgroundColor
:
'
myBlue
.
100
!
important
',
...
@@ -109,6 +115,7 @@ const ChatHistorySlider = ({
...
@@ -109,6 +115,7 @@ const ChatHistorySlider = ({
<
Box
flex=
{
'1 0 0'
}
ml=
{
3
}
className=
"textEllipsis"
>
<
Box
flex=
{
'1 0 0'
}
ml=
{
3
}
className=
"textEllipsis"
>
{
item
.
title
}
{
item
.
title
}
</
Box
>
</
Box
>
{
!!
item
.
id
&&
(
<
Box
className=
"more"
display=
{
[
'block'
,
'none'
]
}
>
<
Box
className=
"more"
display=
{
[
'block'
,
'none'
]
}
>
<
Menu
autoSelect=
{
false
}
isLazy
offset=
{
[
0
,
5
]
}
>
<
Menu
autoSelect=
{
false
}
isLazy
offset=
{
[
0
,
5
]
}
>
<
MenuButton
<
MenuButton
...
@@ -122,10 +129,17 @@ const ChatHistorySlider = ({
...
@@ -122,10 +129,17 @@ const ChatHistorySlider = ({
<
MyIcon
name=
{
'more'
}
w=
{
'14px'
}
p=
{
1
}
/>
<
MyIcon
name=
{
'more'
}
w=
{
'14px'
}
p=
{
1
}
/>
</
MenuButton
>
</
MenuButton
>
<
MenuList
color=
{
'myGray.700'
}
minW=
{
`90px !important`
}
>
<
MenuList
color=
{
'myGray.700'
}
minW=
{
`90px !important`
}
>
<
MenuItem
>
{
onSetHistoryTop
&&
(
<
MenuItem
onClick=
{
(
e
)
=>
{
e
.
stopPropagation
();
onSetHistoryTop
({
historyId
:
item
.
id
,
top
:
!
item
.
top
});
}
}
>
<
MyIcon
mr=
{
2
}
name=
{
'setTop'
}
w=
{
'16px'
}
></
MyIcon
>
<
MyIcon
mr=
{
2
}
name=
{
'setTop'
}
w=
{
'16px'
}
></
MyIcon
>
置顶
{
item
.
top
?
'取消置顶'
:
'置顶'
}
</
MenuItem
>
</
MenuItem
>
)
}
<
MenuItem
<
MenuItem
_hover=
{
{
color
:
'red.500'
}
}
_hover=
{
{
color
:
'red.500'
}
}
onClick=
{
(
e
)
=>
{
onClick=
{
(
e
)
=>
{
...
@@ -142,16 +156,9 @@ const ChatHistorySlider = ({
...
@@ -142,16 +156,9 @@ const ChatHistorySlider = ({
</
MenuList
>
</
MenuList
>
</
Menu
>
</
Menu
>
</
Box
>
</
Box
>
)
}
</
Flex
>
</
Flex
>
))
}
))
}
{
history
.
length
===
0
&&
(
<
Flex
h=
{
'100%'
}
flexDirection=
{
'column'
}
alignItems=
{
'center'
}
pt=
{
'30vh'
}
>
<
MyIcon
name=
"empty"
w=
{
'48px'
}
h=
{
'48px'
}
color=
{
'transparent'
}
/>
<
Box
mt=
{
2
}
color=
{
'myGray.500'
}
>
还没有聊天记录
</
Box
>
</
Flex
>
)
}
</
Box
>
</
Box
>
</
Flex
>
</
Flex
>
);
);
...
...
client/src/pages/chat/components/History.tsx
deleted
100644 → 0
View file @
eb768d9c
import
React
,
{
useCallback
,
useRef
,
useState
,
useMemo
}
from
'react'
;
import
type
{
MouseEvent
}
from
'react'
;
import
{
AddIcon
}
from
'@chakra-ui/icons'
;
import
{
Box
,
Button
,
Flex
,
useTheme
,
Menu
,
MenuList
,
MenuItem
,
useOutsideClick
}
from
'@chakra-ui/react'
;
import
{
ChatIcon
}
from
'@chakra-ui/icons'
;
import
{
useQuery
}
from
'@tanstack/react-query'
;
import
{
useRouter
}
from
'next/router'
;
import
{
useLoading
}
from
'@/hooks/useLoading'
;
import
{
useUserStore
}
from
'@/store/user'
;
import
MyIcon
from
'@/components/Icon'
;
import
type
{
HistoryItemType
,
ExportChatType
}
from
'@/types/chat'
;
import
{
useChatStore
}
from
'@/store/chat'
;
import
ModelList
from
'./ModelList'
;
import
{
useGlobalStore
}
from
'@/store/global'
;
import
styles
from
'../index.module.scss'
;
import
{
useEditInfo
}
from
'@/hooks/useEditInfo'
;
import
{
putChatHistory
}
from
'@/api/chat'
;
import
{
useToast
}
from
'@/hooks/useToast'
;
import
{
formatTimeToChatTime
,
getErrText
}
from
'@/utils/tools'
;
const
PcSliderBar
=
({
onclickDelHistory
,
onclickExportChat
}:
{
onclickDelHistory
:
(
historyId
:
string
)
=>
Promise
<
void
>
;
onclickExportChat
:
(
type
:
ExportChatType
)
=>
void
;
})
=>
{
const
router
=
useRouter
();
const
{
toast
}
=
useToast
();
const
{
modelId
=
''
,
chatId
=
''
}
=
router
.
query
as
{
modelId
:
string
;
chatId
:
string
;
};
const
ContextMenuRef
=
useRef
(
null
);
const
onclickContext
=
useRef
(
false
);
const
theme
=
useTheme
();
const
{
isPc
}
=
useGlobalStore
();
const
{
Loading
,
setIsLoading
}
=
useLoading
();
const
[
contextMenuData
,
setContextMenuData
]
=
useState
<
{
left
:
number
;
top
:
number
;
history
:
HistoryItemType
;
}
>
();
const
{
history
,
loadHistory
}
=
useChatStore
();
const
{
myApps
,
myCollectionApps
,
loadMyModels
}
=
useUserStore
();
const
models
=
useMemo
(()
=>
[...
myApps
,
...
myCollectionApps
],
[
myCollectionApps
,
myApps
]);
// custom title edit
const
{
onOpenModal
,
EditModal
:
EditTitleModal
}
=
useEditInfo
({
title
:
'自定义历史记录标题'
,
placeholder
:
'如果设置为空,会自动跟随聊天记录。'
});
// close contextMenu
useOutsideClick
({
ref
:
ContextMenuRef
,
handler
:
()
=>
{
setTimeout
(()
=>
{
if
(
contextMenuData
&&
!
onclickContext
.
current
)
{
setContextMenuData
(
undefined
);
}
},
10
);
setTimeout
(()
=>
{
onclickContext
.
current
=
false
;
},
10
);
}
});
const
onclickContextMenu
=
useCallback
(
(
e
:
MouseEvent
<
HTMLDivElement
>
,
history
:
HistoryItemType
)
=>
{
e
.
preventDefault
();
// 阻止默认右键菜单
if
(
!
isPc
)
return
;
onclickContext
.
current
=
true
;
setContextMenuData
({
left
:
e
.
clientX
,
top
:
e
.
clientY
,
history
});
},
[
isPc
]
);
useQuery
([
'loadModels'
],
loadMyModels
);
const
{
isLoading
:
isLoadingHistory
}
=
useQuery
([
'loadingHistory'
],
()
=>
loadHistory
({
pageNum
:
1
})
);
return
(
<
Flex
position=
{
'relative'
}
flexDirection=
{
'column'
}
w=
{
'100%'
}
h=
{
'100%'
}
bg=
{
'white'
}
borderRight=
{
[
''
,
theme
.
borders
.
base
]
}
>
{
/* 新对话 */
}
{
isPc
&&
(
<
Box
className=
{
styles
.
newChat
}
zIndex=
{
1001
}
w=
{
'90%'
}
h=
{
'40px'
}
my=
{
5
}
mx=
{
'auto'
}
position=
{
'relative'
}
>
<
Button
variant=
{
'base'
}
w=
{
'100%'
}
h=
{
'100%'
}
leftIcon=
{
<
AddIcon
/>
}
onClick=
{
()
=>
router
.
replace
(
`/chat?appId=${modelId}`
)
}
>
新对话
</
Button
>
{
models
.
length
>
1
&&
(
<
Box
className=
{
styles
.
modelListContainer
}
position=
{
'absolute'
}
w=
{
'115%'
}
left=
{
0
}
top=
{
'40px'
}
transition=
{
'0.15s ease-out'
}
bg=
{
'white'
}
>
<
Box
className=
{
styles
.
modelList
}
mt=
{
'6px'
}
h=
{
'calc(100% - 6px)'
}
overflow=
{
'overlay'
}
>
<
ModelList
models=
{
models
}
modelId=
{
modelId
}
/>
</
Box
>
</
Box
>
)
}
</
Box
>
)
}
{
/* chat history */
}
<
Box
flex=
{
'1 0 0'
}
h=
{
0
}
pl=
{
2
}
overflowY=
{
'scroll'
}
userSelect=
{
'none'
}
>
{
history
.
map
((
item
)
=>
(
<
Flex
key=
{
item
.
_id
}
position=
{
'relative'
}
alignItems=
{
'center'
}
p=
{
3
}
borderRadius=
{
'md'
}
mb=
{
[
2
,
0
]
}
cursor=
{
'pointer'
}
transition=
{
'background-color .2s ease-in'
}
_hover=
{
{
backgroundImage
:
[
''
,
theme
.
lgColor
.
hoverBlueGradient
]
}
}
{
...
(
item
.
_id
===
chatId
?
{
backgroundImage
:
`
$
{
theme
.
lgColor
.
activeBlueGradient
}
!
important
`
}
:
{
bg
:
item
.
top
?
'
myGray
.
200'
:
''
})}
onClick=
{
()
=>
{
if
(
item
.
_id
===
chatId
)
return
;
if
(
isPc
)
{
router
.
replace
(
`/chat?appId=${item.modelId}&chatId=${item._id}`
);
}
else
{
router
.
push
(
`/chat?appId=${item.modelId}&chatId=${item._id}`
);
}
}
}
onContextMenu=
{
(
e
)
=>
onclickContextMenu
(
e
,
item
)
}
>
<
ChatIcon
fontSize=
{
'16px'
}
color=
{
'myGray.500'
}
/>
<
Box
flex=
{
'1 0 0'
}
w=
{
0
}
ml=
{
3
}
>
<
Flex
alignItems=
{
'center'
}
>
<
Box
flex=
{
'1 0 0'
}
w=
{
0
}
className=
"textEllipsis"
color=
{
'myGray.1000'
}
>
{
item
.
title
}
</
Box
>
<
Box
color=
{
'myGray.400'
}
fontSize=
{
'sm'
}
>
{
formatTimeToChatTime
(
item
.
updateTime
)
}
</
Box
>
</
Flex
>
<
Box
className=
"textEllipsis"
mt=
{
1
}
fontSize=
{
'sm'
}
color=
{
'myGray.500'
}
>
{
item
.
latestChat
||
'……'
}
</
Box
>
</
Box
>
{
/* phone quick delete */
}
{
!
isPc
&&
(
<
MyIcon
px=
{
3
}
name=
{
'delete'
}
w=
{
'16px'
}
onClickCapture=
{
async
(
e
)
=>
{
e
.
stopPropagation
();
setIsLoading
(
true
);
try
{
await
onclickDelHistory
(
item
.
_id
);
}
catch
(
error
)
{
console
.
log
(
error
);
}
setIsLoading
(
false
);
}
}
/>
)
}
</
Flex
>
))
}
{
!
isLoadingHistory
&&
history
.
length
===
0
&&
(
<
Flex
h=
{
'100%'
}
flexDirection=
{
'column'
}
alignItems=
{
'center'
}
pt=
{
'30vh'
}
>
<
MyIcon
name=
"empty"
w=
{
'48px'
}
h=
{
'48px'
}
color=
{
'transparent'
}
/>
<
Box
mt=
{
2
}
color=
{
'myGray.500'
}
>
还没有聊天记录
</
Box
>
</
Flex
>
)
}
</
Box
>
{
/* context menu */
}
{
contextMenuData
&&
(
<
Box
zIndex=
{
10
}
position=
{
'fixed'
}
top=
{
contextMenuData
.
top
}
left=
{
contextMenuData
.
left
}
>
<
Box
ref=
{
ContextMenuRef
}
></
Box
>
<
Menu
isOpen
>
<
MenuList
>
<
MenuItem
onClick=
{
async
()
=>
{
try
{
await
putChatHistory
({
chatId
:
contextMenuData
.
history
.
_id
,
top
:
!
contextMenuData
.
history
.
top
});
loadHistory
({
pageNum
:
1
,
init
:
true
});
}
catch
(
error
)
{}
}
}
>
{
contextMenuData
.
history
.
top
?
'取消置顶'
:
'置顶'
}
</
MenuItem
>
<
MenuItem
onClick=
{
async
()
=>
{
setIsLoading
(
true
);
try
{
await
onclickDelHistory
(
contextMenuData
.
history
.
_id
);
if
(
contextMenuData
.
history
.
_id
===
chatId
)
{
router
.
replace
(
`/chat?appId=${modelId}`
);
}
}
catch
(
error
)
{
console
.
log
(
error
);
}
setIsLoading
(
false
);
}
}
>
删除记录
</
MenuItem
>
<
MenuItem
onClick=
{
()
=>
onOpenModal
({
defaultVal
:
contextMenuData
.
history
.
title
,
onSuccess
:
async
(
val
:
string
)
=>
{
await
putChatHistory
({
chatId
:
contextMenuData
.
history
.
_id
,
customTitle
:
val
,
top
:
contextMenuData
.
history
.
top
});
toast
({
title
:
'自定义标题成功'
,
status
:
'success'
});
loadHistory
({
pageNum
:
1
,
init
:
true
});
},
onError
(
err
)
{
toast
({
title
:
getErrText
(
err
),
status
:
'error'
});
}
})
}
>
自定义标题
</
MenuItem
>
<
MenuItem
onClick=
{
()
=>
onclickExportChat
(
'html'
)
}
>
导出HTML格式
</
MenuItem
>
<
MenuItem
onClick=
{
()
=>
onclickExportChat
(
'pdf'
)
}
>
导出PDF格式
</
MenuItem
>
<
MenuItem
onClick=
{
()
=>
onclickExportChat
(
'md'
)
}
>
导出Markdown格式
</
MenuItem
>
</
MenuList
>
</
Menu
>
</
Box
>
)
}
<
EditTitleModal
/>
<
Loading
loading=
{
isLoadingHistory
}
fixed=
{
false
}
/>
</
Flex
>
);
};
export
default
PcSliderBar
;
client/src/pages/chat/components/ModelList.tsx
deleted
100644 → 0
View file @
eb768d9c
import
React
from
'react'
;
import
{
Box
,
Flex
}
from
'@chakra-ui/react'
;
import
{
useRouter
}
from
'next/router'
;
import
{
AppListItemType
}
from
'@/types/app'
;
import
Avatar
from
'@/components/Avatar'
;
const
ModelList
=
({
models
,
modelId
}:
{
models
:
AppListItemType
[];
modelId
:
string
})
=>
{
const
router
=
useRouter
();
return
(
<>
{
models
.
map
((
item
)
=>
(
<
Box
key=
{
item
.
_id
}
>
<
Flex
key=
{
item
.
_id
}
position=
{
'relative'
}
alignItems=
{
[
'flex-start'
,
'center'
]
}
p=
{
3
}
cursor=
{
'pointer'
}
transition=
{
'background-color .2s ease-in'
}
borderLeft=
{
[
''
,
'5px solid transparent'
]
}
zIndex=
{
0
}
_hover=
{
{
backgroundColor
:
[
''
,
'#dee0e3'
]
}
}
{
...
(
modelId
===
item
.
_id
?
{
backgroundColor
:
'#
eff0f1
',
borderLeftColor
:
'
myBlue
.
600'
}
:
{})}
onClick=
{
()
=>
{
router
.
replace
(
`/chat?appId=${item._id}`
);
}
}
>
<
Avatar
src=
{
item
.
avatar
}
w=
{
'34px'
}
h=
{
'34px'
}
/>
<
Box
flex=
{
'1 0 0'
}
w=
{
0
}
ml=
{
3
}
>
<
Box
className=
"textEllipsis"
color=
{
'myGray.1000'
}
>
{
item
.
name
}
</
Box
>
</
Box
>
</
Flex
>
</
Box
>
))
}
</>
);
};
export
default
ModelList
;
client/src/pages/chat/components/PhoneSliderBar.tsx
deleted
100644 → 0
View file @
eb768d9c
import
React
,
{
useMemo
,
useState
}
from
'react'
;
import
{
AddIcon
,
ChatIcon
}
from
'@chakra-ui/icons'
;
import
{
Box
,
Button
,
Flex
,
Divider
,
useDisclosure
,
useColorMode
,
useColorModeValue
}
from
'@chakra-ui/react'
;
import
{
useUserStore
}
from
'@/store/user'
;
import
{
useQuery
}
from
'@tanstack/react-query'
;
import
{
useRouter
}
from
'next/router'
;
import
MyIcon
from
'@/components/Icon'
;
import
WxConcat
from
'@/components/WxConcat'
;
import
{
delChatHistoryById
}
from
'@/api/chat'
;
import
{
useChatStore
}
from
'@/store/chat'
;
import
Avatar
from
'@/components/Avatar'
;
import
Tabs
from
'@/components/Tabs'
;
enum
TabEnum
{
app
=
'app'
,
history
=
'history'
}
const
PhoneSliderBar
=
({
chatId
,
modelId
,
onClose
}:
{
chatId
:
string
;
modelId
:
string
;
onClose
:
()
=>
void
;
})
=>
{
const
router
=
useRouter
();
const
[
currentTab
,
setCurrentTab
]
=
useState
(
TabEnum
.
app
);
const
{
myApps
,
myCollectionApps
,
loadMyModels
}
=
useUserStore
();
const
{
isOpen
:
isOpenWx
,
onOpen
:
onOpenWx
,
onClose
:
onCloseWx
}
=
useDisclosure
();
const
models
=
useMemo
(()
=>
[...
myApps
,
...
myCollectionApps
],
[
myCollectionApps
,
myApps
]);
useQuery
([
'loadModels'
],
loadMyModels
);
const
{
history
,
loadHistory
}
=
useChatStore
();
useQuery
([
'loadingHistory'
],
()
=>
loadHistory
({
pageNum
:
1
}));
const
RenderButton
=
({
onClick
,
children
}:
{
onClick
:
()
=>
void
;
children
:
JSX
.
Element
|
string
;
})
=>
(
<
Box
px=
{
3
}
mb=
{
2
}
>
<
Flex
alignItems=
{
'center'
}
p=
{
2
}
cursor=
{
'pointer'
}
borderRadius=
{
'md'
}
_hover=
{
{
backgroundColor
:
'rgba(255,255,255,0.2)'
}
}
onClick=
{
onClick
}
>
{
children
}
</
Flex
>
</
Box
>
);
return
(
<
Flex
flexDirection=
{
'column'
}
w=
{
'100%'
}
h=
{
'100%'
}
py=
{
3
}
backgroundColor=
{
useColorModeValue
(
'blackAlpha.800'
,
'blackAlpha.500'
)
}
color=
{
'white'
}
>
<
Flex
mb=
{
2
}
alignItems=
{
'center'
}
justifyContent=
{
'space-between'
}
px=
{
2
}
>
<
Tabs
w=
{
'140px'
}
list=
{
[
{
label
:
'应用'
,
id
:
TabEnum
.
app
},
{
label
:
'历史记录'
,
id
:
TabEnum
.
history
}
]
}
size=
{
'sm'
}
activeId=
{
currentTab
}
onChange=
{
(
e
:
any
)
=>
setCurrentTab
(
e
)
}
/>
{
/* 新对话 */
}
{
currentTab
===
TabEnum
.
app
&&
(
<
Button
size=
{
'sm'
}
variant=
{
'base'
}
color=
{
'white'
}
leftIcon=
{
<
AddIcon
/>
}
onClick=
{
()
=>
{
router
.
replace
(
`/chat?appId=${modelId}`
);
onClose
();
}
}
>
新对话
</
Button
>
)
}
</
Flex
>
{
/* 我的模型 & 历史记录 折叠框*/
}
<
Box
flex=
{
'1 0 0'
}
px=
{
3
}
h=
{
0
}
overflowY=
{
'auto'
}
>
{
currentTab
===
TabEnum
.
app
&&
(
<>
{
models
.
map
((
item
)
=>
(
<
Flex
key=
{
item
.
_id
}
alignItems=
{
'center'
}
p=
{
3
}
borderRadius=
{
'md'
}
mb=
{
2
}
cursor=
{
'pointer'
}
_hover=
{
{
backgroundColor
:
'rgba(255,255,255,0.1)'
}
}
fontSize=
{
'xs'
}
border=
{
'1px solid transparent'
}
{
...
(
item
.
_id
===
modelId
?
{
borderColor
:
'
rgba
(255,255,255,0
.
5)',
backgroundColor
:
'
rgba
(255,255,255,0
.
1)'
}
:
{})}
onClick=
{
async
()
=>
{
if
(
item
.
_id
===
modelId
)
return
;
router
.
replace
(
`/chat?appId=${item._id}`
);
onClose
();
}
}
>
<
Avatar
src=
{
item
.
avatar
}
mr=
{
2
}
w=
{
'18px'
}
h=
{
'18px'
}
/>
<
Box
className=
{
'textEllipsis'
}
flex=
{
'1 0 0'
}
w=
{
0
}
>
{
item
.
name
}
</
Box
>
</
Flex
>
))
}
</>
)
}
{
currentTab
===
TabEnum
.
history
&&
(
<>
{
history
.
map
((
item
)
=>
(
<
Flex
key=
{
item
.
_id
}
alignItems=
{
'center'
}
p=
{
3
}
borderRadius=
{
'md'
}
mb=
{
2
}
fontSize=
{
'xs'
}
border=
{
'1px solid transparent'
}
{
...
(
item
.
_id
===
chatId
?
{
borderColor
:
'
rgba
(255,255,255,0
.
5)',
backgroundColor
:
'
rgba
(255,255,255,0
.
1)'
}
:
{})}
onClick=
{
()
=>
{
if
(
item
.
_id
===
chatId
)
return
;
router
.
replace
(
`/chat?appId=${item.modelId}&chatId=${item._id}`
);
onClose
();
}
}
>
<
ChatIcon
mr=
{
2
}
/>
<
Box
flex=
{
'1 0 0'
}
w=
{
0
}
className=
"textEllipsis"
>
{
item
.
title
}
</
Box
>
<
Box
>
<
MyIcon
name=
{
'delete'
}
w=
{
'14px'
}
onClick=
{
async
(
e
)
=>
{
e
.
stopPropagation
();
console
.
log
(
111
);
await
delChatHistoryById
(
item
.
_id
);
loadHistory
({
pageNum
:
1
,
init
:
true
});
if
(
item
.
_id
===
chatId
)
{
router
.
replace
(
`/chat?appId=${modelId}`
);
}
}
}
/>
</
Box
>
</
Flex
>
))
}
</>
)
}
</
Box
>
<
Divider
my=
{
3
}
colorScheme=
{
useColorModeValue
(
'gray'
,
'white'
)
}
/>
<
RenderButton
onClick=
{
()
=>
router
.
push
(
'/model'
)
}
>
<>
<
MyIcon
name=
"out"
fill=
{
'white'
}
w=
{
'18px'
}
h=
{
'18px'
}
mr=
{
4
}
/>
退出聊天
</>
</
RenderButton
>
<
RenderButton
onClick=
{
onOpenWx
}
>
<>
<
MyIcon
name=
"wx"
fill=
{
'white'
}
w=
{
'18px'
}
h=
{
'18px'
}
mr=
{
4
}
/>
交流群
</>
</
RenderButton
>
{
/* wx 联系 */
}
{
isOpenWx
&&
<
WxConcat
onClose=
{
onCloseWx
}
/>
}
</
Flex
>
);
};
export
default
PhoneSliderBar
;
client/src/pages/chat/components/SliderApps.tsx
0 → 100644
View file @
b2e2f60e
import
React
from
'react'
;
import
{
Flex
,
Box
,
IconButton
}
from
'@chakra-ui/react'
;
import
{
useRouter
}
from
'next/router'
;
import
{
useUserStore
}
from
'@/store/user'
;
import
{
useQuery
}
from
'@tanstack/react-query'
;
import
MyIcon
from
'@/components/Icon'
;
import
Avatar
from
'@/components/Avatar'
;
const
SliderApps
=
({
appId
}:
{
appId
:
string
})
=>
{
const
router
=
useRouter
();
const
{
myApps
,
loadMyModels
}
=
useUserStore
();
useQuery
([
'loadModels'
],
loadMyModels
);
return
(
<>
<
Flex
alignItems=
{
'center'
}
cursor=
{
'pointer'
}
py=
{
2
}
px=
{
3
}
borderRadius=
{
'md'
}
_hover=
{
{
bg
:
'myGray.200'
}
}
onClick=
{
()
=>
router
.
replace
(
'/app/list'
)
}
>
<
IconButton
mr=
{
3
}
icon=
{
<
MyIcon
name=
{
'backFill'
}
w=
{
'18px'
}
color=
{
'myBlue.600'
}
/>
}
bg=
{
'white'
}
boxShadow=
{
'1px 1px 9px rgba(0,0,0,0.15)'
}
h=
{
'28px'
}
size=
{
'sm'
}
borderRadius=
{
'50%'
}
aria
-
label=
{
''
}
/>
退出聊天
</
Flex
>
<
Box
mt=
{
5
}
>
{
myApps
.
map
((
item
)
=>
(
<
Flex
key=
{
item
.
_id
}
py=
{
2
}
px=
{
3
}
mb=
{
3
}
cursor=
{
'pointer'
}
borderRadius=
{
'lg'
}
alignItems=
{
'center'
}
{
...
(
item
.
_id
===
appId
?
{
bg
:
'
white
',
boxShadow
:
'
md
'
}
:
{
_hover
:
{
bg
:
'
myGray
.
200'
},
onClick
:
()
=
>
{
router
.
replace
({
query
:
{
appId
:
item
.
_id
}
});
}
})}
>
<
Avatar
src=
{
item
.
avatar
}
w=
{
'24px'
}
/>
<
Box
ml=
{
2
}
className=
{
'textEllipsis'
}
>
{
item
.
name
}
</
Box
>
</
Flex
>
))
}
</
Box
>
</>
);
};
export
default
SliderApps
;
client/src/pages/chat/index.tsx
View file @
b2e2f60e
This diff is collapsed.
Click to expand it.
client/src/pages/chat/share.tsx
View file @
b2e2f60e
...
@@ -18,13 +18,13 @@ import { streamFetch } from '@/api/fetch';
...
@@ -18,13 +18,13 @@ import { streamFetch } from '@/api/fetch';
import
{
useShareChatStore
,
defaultHistory
}
from
'@/store/shareChat'
;
import
{
useShareChatStore
,
defaultHistory
}
from
'@/store/shareChat'
;
import
SideBar
from
'@/components/SideBar'
;
import
SideBar
from
'@/components/SideBar'
;
import
{
gptMessage2ChatType
}
from
'@/utils/adapt'
;
import
{
gptMessage2ChatType
}
from
'@/utils/adapt'
;
import
ChatHistorySlider
from
'./components/ChatHistorySlider'
;
import
{
getErrText
}
from
'@/utils/tools'
;
import
{
getErrText
}
from
'@/utils/tools'
;
import
ChatBox
,
{
type
ComponentRef
,
type
StartChatFnProps
}
from
'@/components/ChatBox'
;
import
ChatBox
,
{
type
ComponentRef
,
type
StartChatFnProps
}
from
'@/components/ChatBox'
;
import
MyIcon
from
'@/components/Icon'
;
import
MyIcon
from
'@/components/Icon'
;
import
Tag
from
'@/components/Tag'
;
import
Tag
from
'@/components/Tag'
;
import
PageContainer
from
'@/components/PageContainer'
;
import
PageContainer
from
'@/components/PageContainer'
;
import
ChatHistorySlider
from
'./components/ChatHistorySlider'
;
const
ShareChat
=
()
=>
{
const
ShareChat
=
()
=>
{
const
theme
=
useTheme
();
const
theme
=
useTheme
();
...
@@ -134,6 +134,10 @@ const ShareChat = () => {
...
@@ -134,6 +134,10 @@ const ShareChat = () => {
}
}
}
}
if
(
history
.
chats
.
length
>
0
)
{
ChatBoxRef
.
current
?.
scrollToBottom
(
'auto'
);
}
return
history
;
return
history
;
},
},
[
[
...
@@ -152,7 +156,7 @@ const ShareChat = () => {
...
@@ -152,7 +156,7 @@ const ShareChat = () => {
return
(
return
(
<
PageContainer
>
<
PageContainer
>
<
Flex
h=
{
'100%'
}
flexDirection=
{
[
'column'
,
'row'
]
}
backgroundColor=
{
'#fdfdfd'
}
>
<
Flex
h=
{
'100%'
}
flexDirection=
{
[
'column'
,
'row'
]
}
>
{
/* slider */
}
{
/* slider */
}
{
isPc
?
(
{
isPc
?
(
<
SideBar
>
<
SideBar
>
...
@@ -243,14 +247,7 @@ const ShareChat = () => {
...
@@ -243,14 +247,7 @@ const ShareChat = () => {
)
}
)
}
</
Flex
>
</
Flex
>
{
/* chat box */
}
{
/* chat box */
}
<
Box
<
Box
flex=
{
1
}
>
pt=
{
[
0
,
5
]
}
flex=
{
1
}
maxW=
{
[
'100%'
,
'1000px'
,
'1200px'
]
}
px=
{
[
0
,
5
]
}
w=
{
'100%'
}
mx=
{
'auto'
}
>
<
ChatBox
<
ChatBox
ref=
{
ChatBoxRef
}
ref=
{
ChatBoxRef
}
appAvatar=
{
shareChatData
.
app
.
avatar
}
appAvatar=
{
shareChatData
.
app
.
avatar
}
...
...
client/src/pages/login/index.tsx
View file @
b2e2f60e
...
@@ -18,17 +18,16 @@ const Login = () => {
...
@@ -18,17 +18,16 @@ const Login = () => {
const
{
isPc
}
=
useGlobalStore
();
const
{
isPc
}
=
useGlobalStore
();
const
[
pageType
,
setPageType
]
=
useState
<
`
${
PageTypeEnum
}
`
>
(
PageTypeEnum
.
login
);
const
[
pageType
,
setPageType
]
=
useState
<
`
${
PageTypeEnum
}
`
>
(
PageTypeEnum
.
login
);
const
{
setUserInfo
,
setLastModelId
,
loadKbList
,
setLastKbId
}
=
useUserStore
();
const
{
setUserInfo
,
setLastModelId
,
loadKbList
,
setLastKbId
}
=
useUserStore
();
const
{
setLastChatId
,
setLastChat
ModelId
,
loadHistory
}
=
useChatStore
();
const
{
setLastChatId
,
setLastChat
AppId
}
=
useChatStore
();
const
loginSuccess
=
useCallback
(
const
loginSuccess
=
useCallback
(
(
res
:
ResLogin
)
=>
{
(
res
:
ResLogin
)
=>
{
// init store
// init store
setLastChatId
(
''
);
setLastChatId
(
''
);
setLastModelId
(
''
);
setLastModelId
(
''
);
setLastChat
Model
Id
(
''
);
setLastChat
App
Id
(
''
);
setLastKbId
(
''
);
setLastKbId
(
''
);
loadKbList
(
true
);
loadKbList
(
true
);
loadHistory
({
pageNum
:
1
,
init
:
true
});
setUserInfo
(
res
.
user
);
setUserInfo
(
res
.
user
);
setTimeout
(()
=>
{
setTimeout
(()
=>
{
...
@@ -37,11 +36,10 @@ const Login = () => {
...
@@ -37,11 +36,10 @@ const Login = () => {
},
},
[
[
lastRoute
,
lastRoute
,
loadHistory
,
loadKbList
,
loadKbList
,
router
,
router
,
setLastChatId
,
setLastChatId
,
setLastChat
Model
Id
,
setLastChat
App
Id
,
setLastKbId
,
setLastKbId
,
setLastModelId
,
setLastModelId
,
setUserInfo
setUserInfo
...
...
client/src/service/api/request.ts
View file @
b2e2f60e
...
@@ -3,6 +3,7 @@ import { getErrText } from '@/utils/tools';
...
@@ -3,6 +3,7 @@ import { getErrText } from '@/utils/tools';
import
{
parseStreamChunk
}
from
'@/utils/adapt'
;
import
{
parseStreamChunk
}
from
'@/utils/adapt'
;
import
{
NextApiResponse
}
from
'next'
;
import
{
NextApiResponse
}
from
'next'
;
import
{
sseResponse
}
from
'../utils/tools'
;
import
{
sseResponse
}
from
'../utils/tools'
;
import
{
SpecificInputEnum
}
from
'@/constants/app'
;
interface
Props
{
interface
Props
{
res
:
NextApiResponse
;
// 用于流转发
res
:
NextApiResponse
;
// 用于流转发
...
@@ -13,7 +14,7 @@ export const moduleFetch = ({ url, data, res }: Props) =>
...
@@ -13,7 +14,7 @@ export const moduleFetch = ({ url, data, res }: Props) =>
new
Promise
<
Record
<
string
,
any
>>
(
async
(
resolve
,
reject
)
=>
{
new
Promise
<
Record
<
string
,
any
>>
(
async
(
resolve
,
reject
)
=>
{
try
{
try
{
const
abortSignal
=
new
AbortController
();
const
abortSignal
=
new
AbortController
();
const
baseUrl
=
`http://localhost:
3000
/api`
;
const
baseUrl
=
`http://localhost:
${
process
.
env
.
PORT
||
3000
}
/api`
;
const
requestUrl
=
url
.
startsWith
(
'/'
)
?
`
${
baseUrl
}${
url
}
`
:
url
;
const
requestUrl
=
url
.
startsWith
(
'/'
)
?
`
${
baseUrl
}${
url
}
`
:
url
;
const
response
=
await
fetch
(
requestUrl
,
{
const
response
=
await
fetch
(
requestUrl
,
{
method
:
'POST'
,
method
:
'POST'
,
...
@@ -41,7 +42,9 @@ export const moduleFetch = ({ url, data, res }: Props) =>
...
@@ -41,7 +42,9 @@ export const moduleFetch = ({ url, data, res }: Props) =>
const
reader
=
response
.
body
?.
getReader
();
const
reader
=
response
.
body
?.
getReader
();
let
chatResponse
:
Record
<
string
,
any
>
=
{};
let
chatResponse
:
Record
<
string
,
any
>
=
{
[
SpecificInputEnum
.
answerText
]:
''
};
const
read
=
async
()
=>
{
const
read
=
async
()
=>
{
try
{
try
{
...
@@ -80,7 +83,8 @@ export const moduleFetch = ({ url, data, res }: Props) =>
...
@@ -80,7 +83,8 @@ export const moduleFetch = ({ url, data, res }: Props) =>
if
(
answer
)
{
if
(
answer
)
{
chatResponse
=
{
chatResponse
=
{
...
chatResponse
,
...
chatResponse
,
answer
:
chatResponse
.
answer
?
chatResponse
.
answer
+
answer
:
answer
[
SpecificInputEnum
.
answerText
]:
chatResponse
[
SpecificInputEnum
.
answerText
]
+
answer
};
};
}
}
...
...
client/src/service/models/chat.ts
View file @
b2e2f60e
...
@@ -8,21 +8,11 @@ const ChatSchema = new Schema({
...
@@ -8,21 +8,11 @@ const ChatSchema = new Schema({
ref
:
'user'
,
ref
:
'user'
,
required
:
true
required
:
true
},
},
model
Id
:
{
app
Id
:
{
type
:
Schema
.
Types
.
ObjectId
,
type
:
Schema
.
Types
.
ObjectId
,
ref
:
'model'
,
ref
:
'model'
,
required
:
true
required
:
true
},
},
expiredTime
:
{
// 过期时间
type
:
Number
,
default
:
()
=>
new
Date
()
},
loadAmount
:
{
// 剩余加载次数
type
:
Number
,
default
:
-
1
},
updateTime
:
{
updateTime
:
{
type
:
Date
,
type
:
Date
,
default
:
()
=>
new
Date
()
default
:
()
=>
new
Date
()
...
@@ -35,13 +25,13 @@ const ChatSchema = new Schema({
...
@@ -35,13 +25,13 @@ const ChatSchema = new Schema({
type
:
String
,
type
:
String
,
default
:
''
default
:
''
},
},
latestChat
:
{
type
:
String
,
default
:
''
},
top
:
{
top
:
{
type
:
Boolean
type
:
Boolean
},
},
variables
:
{
type
:
Object
,
default
:
{}
},
content
:
{
content
:
{
type
:
[
type
:
[
{
{
...
...
client/src/service/models/collection.ts
View file @
b2e2f60e
...
@@ -7,7 +7,7 @@ const CollectionSchema = new Schema({
...
@@ -7,7 +7,7 @@ const CollectionSchema = new Schema({
ref
:
'user'
,
ref
:
'user'
,
required
:
true
required
:
true
},
},
model
Id
:
{
app
Id
:
{
type
:
Schema
.
Types
.
ObjectId
,
type
:
Schema
.
Types
.
ObjectId
,
ref
:
'model'
,
ref
:
'model'
,
required
:
true
required
:
true
...
...
client/src/service/models/installApp.ts
deleted
100644 → 0
View file @
eb768d9c
import
{
Schema
,
model
,
models
,
Model
}
from
'mongoose'
;
import
{
ChatSchema
as
ChatType
}
from
'@/types/mongoSchema'
;
import
{
ChatRoleMap
}
from
'@/constants/chat'
;
const
InstallAppSchema
=
new
Schema
({
userId
:
{
type
:
Schema
.
Types
.
ObjectId
,
ref
:
'user'
,
required
:
true
},
modelId
:
{
type
:
Schema
.
Types
.
ObjectId
,
ref
:
'model'
,
required
:
true
}
});
export
const
InstallApp
:
Model
<
ChatType
>
=
models
[
'installApp'
]
||
model
(
'chat'
,
InstallAppSchema
);
client/src/service/utils/auth.ts
View file @
b2e2f60e
...
@@ -258,65 +258,6 @@ export const authKb = async ({ kbId, userId }: { kbId: string; userId: string })
...
@@ -258,65 +258,6 @@ export const authKb = async ({ kbId, userId }: { kbId: string; userId: string })
return
Promise
.
reject
(
ERROR_ENUM
.
unAuthKb
);
return
Promise
.
reject
(
ERROR_ENUM
.
unAuthKb
);
};
};
// 获取对话校验
export
const
authChat
=
async
({
modelId
,
chatId
,
req
}:
{
modelId
:
string
;
chatId
?:
string
;
req
:
NextApiRequest
;
})
=>
{
const
{
userId
}
=
await
authUser
({
req
,
authToken
:
true
});
// 获取 app 数据
const
{
app
,
showModelDetail
}
=
await
authApp
({
appId
:
modelId
,
userId
,
authOwner
:
false
,
reserveDetail
:
true
});
// 聊天内容
let
content
:
ChatItemType
[]
=
[];
if
(
chatId
)
{
// 获取 chat 数据
content
=
await
Chat
.
aggregate
([
{
$match
:
{
_id
:
new
mongoose
.
Types
.
ObjectId
(
chatId
)
}
},
{
$project
:
{
content
:
{
$slice
:
[
'$content'
,
-
50
]
// 返回 content 数组的最后50个元素
}
}
},
{
$unwind
:
'$content'
},
{
$project
:
{
obj
:
'$content.obj'
,
value
:
'$content.value'
,
quote
:
'$content.quote'
}
}
]);
}
// 获取 user 的 apiKey
const
{
userOpenAiKey
,
systemAuthKey
}
=
await
getApiKey
({
model
:
app
.
chat
.
chatModel
,
userId
});
return
{
userOpenAiKey
,
systemAuthKey
,
content
,
userId
,
model
:
app
,
showModelDetail
};
};
export
const
authShareChat
=
async
({
shareId
}:
{
shareId
:
string
})
=>
{
export
const
authShareChat
=
async
({
shareId
}:
{
shareId
:
string
})
=>
{
// get shareChat
// get shareChat
const
shareChat
=
await
ShareChat
.
findOne
({
shareId
});
const
shareChat
=
await
ShareChat
.
findOne
({
shareId
});
...
...
client/src/store/chat.ts
View file @
b2e2f60e
import
{
create
}
from
'zustand'
;
import
{
create
}
from
'zustand'
;
import
{
devtools
,
persist
}
from
'zustand/middleware'
;
import
{
devtools
,
persist
}
from
'zustand/middleware'
;
import
{
immer
}
from
'zustand/middleware/immer'
;
import
{
immer
}
from
'zustand/middleware/immer'
;
import
{
OpenAiChatEnum
}
from
'@/constants/model'
;
import
{
ChatSiteItemType
,
HistoryItemType
,
ChatType
}
from
'@/types/chat'
;
import
{
ChatHistoryItemType
}
from
'@/types/chat'
;
import
type
{
InitChatResponse
}
from
'@/api/response/chat'
;
import
{
getChatHistory
}
from
'@/api/chat'
;
import
{
getChatHistory
}
from
'@/api/chat'
;
import
{
HUMAN_ICON
}
from
'@/constants/chat'
;
import
{
HUMAN_ICON
}
from
'@/constants/chat'
;
type
SetShareChatHistoryItem
=
{
historyId
:
string
;
shareId
:
string
;
title
:
string
;
latestChat
:
string
;
chats
:
ChatSiteItemType
[];
};
type
State
=
{
type
State
=
{
history
:
HistoryItemType
[];
history
:
ChatHistoryItemType
[];
loadHistory
:
(
data
:
{
pageNum
:
number
;
init
?:
boolean
})
=>
Promise
<
null
>
;
loadHistory
:
(
data
:
{
appId
?:
string
})
=>
Promise
<
null
>
;
forbidLoadChatData
:
boolean
;
updateHistory
:
(
history
:
ChatHistoryItemType
)
=>
void
;
setForbidLoadChatData
:
(
val
:
boolean
)
=>
void
;
chatData
:
InitChatResponse
;
chatData
:
ChatType
;
setChatData
:
(
e
:
InitChatResponse
|
((
e
:
InitChatResponse
)
=>
InitChatResponse
))
=>
void
;
setChatData
:
(
e
?:
ChatType
|
((
e
:
ChatType
)
=>
ChatType
))
=>
void
;
lastChatAppId
:
string
;
lastChatModelId
:
string
;
setLastChatAppId
:
(
id
:
string
)
=>
void
;
setLastChatModelId
:
(
id
:
string
)
=>
void
;
lastChatId
:
string
;
lastChatId
:
string
;
setLastChatId
:
(
id
:
string
)
=>
void
;
setLastChatId
:
(
id
:
string
)
=>
void
;
};
};
const
defaultChatData
:
ChatTyp
e
=
{
const
defaultChatData
:
InitChatRespons
e
=
{
chatId
:
'chatId
'
,
historyId
:
'
'
,
modelId
:
'modelId
'
,
appId
:
'
'
,
model
:
{
app
:
{
name
:
''
,
name
:
''
,
avatar
:
'/icon/logo.png'
,
avatar
:
'/icon/logo.png'
,
intro
:
''
,
intro
:
''
,
canUse
:
false
canUse
:
false
},
},
chatModel
:
OpenAiChatEnum
.
GPT3516k
,
title
:
'新对话'
,
variables
:
{},
history
:
[]
history
:
[]
};
};
...
@@ -45,10 +37,10 @@ export const useChatStore = create<State>()(
...
@@ -45,10 +37,10 @@ export const useChatStore = create<State>()(
devtools
(
devtools
(
persist
(
persist
(
immer
((
set
,
get
)
=>
({
immer
((
set
,
get
)
=>
({
lastChat
Model
Id
:
''
,
lastChat
App
Id
:
''
,
setLastChat
Model
Id
(
id
:
string
)
{
setLastChat
App
Id
(
id
:
string
)
{
set
((
state
)
=>
{
set
((
state
)
=>
{
state
.
lastChat
Model
Id
=
id
;
state
.
lastChat
App
Id
=
id
;
});
});
},
},
lastChatId
:
''
,
lastChatId
:
''
,
...
@@ -58,10 +50,12 @@ export const useChatStore = create<State>()(
...
@@ -58,10 +50,12 @@ export const useChatStore = create<State>()(
});
});
},
},
history
:
[],
history
:
[],
async
loadHistory
({
pageNum
,
init
=
false
}:
{
pageNum
:
number
;
init
?:
boolean
})
{
async
loadHistory
({
appId
})
{
if
(
get
().
history
.
length
>
0
&&
!
init
)
return
null
;
const
oneHistory
=
get
().
history
[
0
];
if
(
oneHistory
&&
oneHistory
.
appId
===
appId
)
return
null
;
const
data
=
await
getChatHistory
({
const
data
=
await
getChatHistory
({
pageNum
,
appId
,
pageNum
:
1
,
pageSize
:
20
pageSize
:
20
});
});
set
((
state
)
=>
{
set
((
state
)
=>
{
...
@@ -69,14 +63,23 @@ export const useChatStore = create<State>()(
...
@@ -69,14 +63,23 @@ export const useChatStore = create<State>()(
});
});
return
null
;
return
null
;
},
},
forbidLoadChatData
:
false
,
updateHistory
(
history
)
{
setForbidLoadChatData
(
val
:
boolean
)
{
const
index
=
get
().
history
.
findIndex
((
item
)
=>
item
.
_id
===
history
.
_id
);
set
((
state
)
=>
{
set
((
state
)
=>
{
state
.
forbidLoadChatData
=
val
;
if
(
index
>
-
1
)
{
const
newHistory
=
[
history
,
...
get
().
history
.
slice
(
0
,
index
),
...
get
().
history
.
slice
(
index
+
1
)
];
state
.
history
=
newHistory
;
}
else
{
state
.
history
=
[
history
,
...
state
.
history
];
}
});
});
},
},
chatData
:
defaultChatData
,
chatData
:
defaultChatData
,
setChatData
(
e
:
ChatType
|
((
e
:
ChatType
)
=>
ChatType
)
=
defaultChatData
)
{
setChatData
(
e
=
defaultChatData
)
{
if
(
typeof
e
===
'function'
)
{
if
(
typeof
e
===
'function'
)
{
set
((
state
)
=>
{
set
((
state
)
=>
{
state
.
chatData
=
e
(
state
.
chatData
);
state
.
chatData
=
e
(
state
.
chatData
);
...
@@ -91,7 +94,7 @@ export const useChatStore = create<State>()(
...
@@ -91,7 +94,7 @@ export const useChatStore = create<State>()(
{
{
name
:
'chatStore'
,
name
:
'chatStore'
,
partialize
:
(
state
)
=>
({
partialize
:
(
state
)
=>
({
lastChat
ModelId
:
state
.
lastChatModel
Id
,
lastChat
AppId
:
state
.
lastChatApp
Id
,
lastChatId
:
state
.
lastChatId
lastChatId
:
state
.
lastChatId
})
})
}
}
...
...
client/src/store/user.ts
View file @
b2e2f60e
...
@@ -74,8 +74,7 @@ export const useUserStore = create<State>()(
...
@@ -74,8 +74,7 @@ export const useUserStore = create<State>()(
async
loadMyModels
()
{
async
loadMyModels
()
{
const
res
=
await
getMyModels
();
const
res
=
await
getMyModels
();
set
((
state
)
=>
{
set
((
state
)
=>
{
state
.
myApps
=
res
.
myApps
;
state
.
myApps
=
res
;
state
.
myCollectionApps
=
res
.
myCollectionApps
;
});
});
return
null
;
return
null
;
},
},
...
...
client/src/types/chat.d.ts
View file @
b2e2f60e
...
@@ -18,10 +18,6 @@ export type ChatSiteItemType = {
...
@@ -18,10 +18,6 @@ export type ChatSiteItemType = {
status
:
'loading'
|
'finish'
;
status
:
'loading'
|
'finish'
;
}
&
ChatItemType
;
}
&
ChatItemType
;
export
interface
ChatType
extends
InitChatResponse
{
history
:
ChatSiteItemType
[];
}
export
type
HistoryItemType
=
{
export
type
HistoryItemType
=
{
_id
:
string
;
_id
:
string
;
updateTime
:
Date
;
updateTime
:
Date
;
...
...
client/src/types/mongoSchema.d.ts
View file @
b2e2f60e
...
@@ -58,7 +58,7 @@ export interface AppSchema {
...
@@ -58,7 +58,7 @@ export interface AppSchema {
}
}
export
interface
CollectionSchema
{
export
interface
CollectionSchema
{
model
Id
:
string
;
app
Id
:
string
;
userId
:
string
;
userId
:
string
;
}
}
...
@@ -78,19 +78,14 @@ export interface TrainingDataSchema {
...
@@ -78,19 +78,14 @@ export interface TrainingDataSchema {
export
interface
ChatSchema
{
export
interface
ChatSchema
{
_id
:
string
;
_id
:
string
;
userId
:
string
;
userId
:
string
;
modelId
:
string
;
appId
:
string
;
expiredTime
:
number
;
updateTime
:
Date
;
updateTime
:
Date
;
title
:
string
;
title
:
string
;
customTitle
:
string
;
customTitle
:
string
;
latestChat
:
string
;
top
:
boolean
;
top
:
boolean
;
variables
:
Record
<
string
,
any
>
;
content
:
ChatItemType
[];
content
:
ChatItemType
[];
}
}
export
interface
ChatPopulate
extends
ChatSchema
{
userId
:
UserModelSchema
;
modelId
:
AppSchema
;
}
export
interface
BillSchema
{
export
interface
BillSchema
{
_id
:
string
;
_id
:
string
;
...
...
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