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
00b90f07
authored
Mar 18, 2023
by
Archer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 模型介绍和温度调整。完善聊天页提示
parent
1c364eca
Show whitespace changes
Inline
Side-by-side
Showing
32 changed files
with
578 additions
and
277 deletions
+578
-277
src/api/model.ts
+4
-4
src/api/response/chat.d.ts
+1
-0
src/components/Markdown/index.module.scss
+1
-1
src/components/Markdown/index.tsx
+1
-1
src/components/Slider/index.tsx
+82
-0
src/constants/common.ts
+22
-0
src/constants/model.ts
+46
-6
src/pages/api/chat/chatGpt.ts
+12
-2
src/pages/api/chat/gpt3.ts
+12
-2
src/pages/api/chat/init.ts
+1
-0
src/pages/api/model/create.ts
+17
-6
src/pages/api/model/detail.tsx
+2
-2
src/pages/api/model/getTrainings.ts
+1
-1
src/pages/api/model/putTrainStatus.ts
+2
-2
src/pages/api/model/train.ts
+2
-2
src/pages/api/model/update.ts
+5
-2
src/pages/chat/components/Empty.tsx
+34
-13
src/pages/chat/components/SlideBar.tsx
+73
-45
src/pages/chat/index.tsx
+6
-1
src/pages/model/components/CreateModel.tsx
+5
-5
src/pages/model/components/ModelEditForm.tsx
+97
-91
src/pages/model/components/ModelPhoneList.tsx
+2
-2
src/pages/model/components/ModelTable.tsx
+6
-6
src/pages/model/components/Training.tsx
+2
-2
src/pages/model/detail.tsx
+105
-29
src/pages/model/list.tsx
+2
-2
src/service/models/chat.ts
+5
-2
src/service/models/model.ts
+16
-4
src/store/user.ts
+4
-4
src/types/chat.d.ts
+0
-2
src/types/model.d.ts
+5
-35
src/types/mongoSchema.d.ts
+5
-3
No files found.
src/api/model.ts
View file @
00b90f07
import
{
GET
,
POST
,
DELETE
,
PUT
}
from
'./request'
;
import
{
GET
,
POST
,
DELETE
,
PUT
}
from
'./request'
;
import
type
{
Model
Type
}
from
'@/types/model
'
;
import
type
{
Model
Schema
}
from
'@/types/mongoSchema
'
;
import
{
ModelUpdateParams
}
from
'@/types/model'
;
import
{
ModelUpdateParams
}
from
'@/types/model'
;
import
{
TrainingItemType
}
from
'../types/training'
;
import
{
TrainingItemType
}
from
'../types/training'
;
export
const
getMyModels
=
()
=>
GET
<
Model
Type
[]
>
(
'/model/list'
);
export
const
getMyModels
=
()
=>
GET
<
Model
Schema
[]
>
(
'/model/list'
);
export
const
postCreateModel
=
(
data
:
{
name
:
string
;
serviceModelName
:
string
})
=>
export
const
postCreateModel
=
(
data
:
{
name
:
string
;
serviceModelName
:
string
})
=>
POST
<
Model
Type
>
(
'/model/create'
,
data
);
POST
<
Model
Schema
>
(
'/model/create'
,
data
);
export
const
delModelById
=
(
id
:
string
)
=>
DELETE
(
`/model/del?modelId=
${
id
}
`
);
export
const
delModelById
=
(
id
:
string
)
=>
DELETE
(
`/model/del?modelId=
${
id
}
`
);
export
const
getModelById
=
(
id
:
string
)
=>
GET
<
Model
Type
>
(
`/model/detail?modelId=
${
id
}
`
);
export
const
getModelById
=
(
id
:
string
)
=>
GET
<
Model
Schema
>
(
`/model/detail?modelId=
${
id
}
`
);
export
const
putModelById
=
(
id
:
string
,
data
:
ModelUpdateParams
)
=>
export
const
putModelById
=
(
id
:
string
,
data
:
ModelUpdateParams
)
=>
PUT
(
`/model/update?modelId=
${
id
}
`
,
data
);
PUT
(
`/model/update?modelId=
${
id
}
`
,
data
);
...
...
src/api/response/chat.d.ts
View file @
00b90f07
...
@@ -6,6 +6,7 @@ export type InitChatResponse = {
...
@@ -6,6 +6,7 @@ export type InitChatResponse = {
modelId
:
string
;
modelId
:
string
;
name
:
string
;
name
:
string
;
avatar
:
string
;
avatar
:
string
;
intro
:
string
;
secret
:
ModelSchema
.
secret
;
secret
:
ModelSchema
.
secret
;
chatModel
:
ModelSchema
.
service
.
ChatModel
;
// 模型名
chatModel
:
ModelSchema
.
service
.
ChatModel
;
// 模型名
history
:
ChatItemType
[];
history
:
ChatItemType
[];
...
...
src/components/Markdown/index.module.scss
View file @
00b90f07
...
@@ -172,7 +172,7 @@
...
@@ -172,7 +172,7 @@
}
}
.markdown
ul
,
.markdown
ul
,
.markdown
ol
{
.markdown
ol
{
padding-left
:
30px
;
padding-left
:
1em
;
}
}
.markdown
ul
.no-list
,
.markdown
ul
.no-list
,
.markdown
ol
.no-list
{
.markdown
ol
.no-list
{
...
...
src/components/Markdown/index.tsx
View file @
00b90f07
...
@@ -12,7 +12,7 @@ import 'katex/dist/katex.min.css';
...
@@ -12,7 +12,7 @@ import 'katex/dist/katex.min.css';
import
styles
from
'./index.module.scss'
;
import
styles
from
'./index.module.scss'
;
import
{
codeLight
}
from
'./codeLight'
;
import
{
codeLight
}
from
'./codeLight'
;
const
Markdown
=
({
source
,
isChatting
}:
{
source
:
string
;
isChatting
:
boolean
})
=>
{
const
Markdown
=
({
source
,
isChatting
=
false
}:
{
source
:
string
;
isChatting
?
:
boolean
})
=>
{
const
formatSource
=
useMemo
(()
=>
source
,
[
source
]);
const
formatSource
=
useMemo
(()
=>
source
,
[
source
]);
const
{
copyData
}
=
useCopyData
();
const
{
copyData
}
=
useCopyData
();
...
...
src/components/Slider/index.tsx
0 → 100644
View file @
00b90f07
import
React
,
{
useMemo
}
from
'react'
;
import
{
Slider
,
SliderTrack
,
SliderFilledTrack
,
SliderThumb
,
SliderMark
,
Box
}
from
'@chakra-ui/react'
;
const
MySlider
=
({
markList
,
setVal
,
activeVal
,
max
=
100
,
min
=
0
,
step
=
1
}:
{
markList
:
{
label
:
string
|
number
;
value
:
number
;
}[];
activeVal
?:
number
;
setVal
:
(
index
:
number
)
=>
void
;
max
?:
number
;
min
?:
number
;
step
?:
number
;
})
=>
{
const
startEndPointStyle
=
{
content
:
'""'
,
borderRadius
:
'10px'
,
width
:
'10px'
,
height
:
'10px'
,
backgroundColor
:
'#ffffff'
,
border
:
'2px solid #D7DBE2'
,
position
:
'absolute'
,
zIndex
:
1
,
top
:
0
,
transform
:
'translateY(-3px)'
};
const
value
=
useMemo
(()
=>
{
const
index
=
markList
.
findIndex
((
item
)
=>
item
.
value
===
activeVal
);
return
index
>
-
1
?
index
:
0
;
},
[
activeVal
,
markList
]);
return
(
<
Slider
max=
{
max
}
min=
{
min
}
step=
{
step
}
size=
{
'lg'
}
value=
{
value
}
onChange=
{
setVal
}
>
{
markList
.
map
((
item
,
i
)
=>
(
<
SliderMark
key=
{
item
.
value
}
value=
{
i
}
mt=
{
3
}
fontSize=
{
'sm'
}
transform=
{
'translateX(-50%)'
}
{
...
(
activeVal
===
item
.
value
?
{
color
:
'
blue
.
500',
fontWeight
:
'
bold
'
}
:
{})}
>
<
Box
px=
{
3
}
cursor=
{
'pointer'
}
>
{
item
.
label
}
</
Box
>
</
SliderMark
>
))
}
<
SliderTrack
bg=
{
'#EAEDF3'
}
overflow=
{
'visible'
}
h=
{
'4px'
}
_before=
{
{
...
startEndPointStyle
,
left
:
'-5px'
}
}
_after=
{
{
...
startEndPointStyle
,
right
:
'-5px'
}
}
>
<
SliderFilledTrack
/>
</
SliderTrack
>
<
SliderThumb
border=
{
'2.5px solid'
}
borderColor=
{
'blue.500'
}
></
SliderThumb
>
</
Slider
>
);
};
export
default
MySlider
;
src/constants/common.ts
View file @
00b90f07
...
@@ -39,3 +39,25 @@ export const introPage = `
...
@@ -39,3 +39,25 @@ export const introPage = `
### 其他问题
### 其他问题
还有其他问题,可以加我 wx: YNyiqi,拉个交流群大家一起聊聊。
还有其他问题,可以加我 wx: YNyiqi,拉个交流群大家一起聊聊。
`
;
`
;
export
const
chatProblem
=
`
**代理出错**
服务器代理不稳定,可以过一会儿再尝试。
**API key 问题**
请把 openai 的 API key 粘贴到账号里再创建对话。如果是使用分享的对话,不需要填写 API key。
`
;
export
const
versionIntro
=
`
* 分享对话:使用的是分享者的 Api Key 生成一个对话窗口进行分享。
* 分享空白对话:为该模型创建一个空白的聊天分享出去。
* 分享当前对话:会把当前聊天的内容也分享出去,但是要注意不要多个人同时用一个聊天内容。
* 增加模型介绍:可以在模型编辑页添加对模型的介绍,方便提示模型的范围。
* 温度调整:可以在模型编辑页调整模型温度,以便适应不同类型的对话。例如,翻译类的模型可以把温度拉低;创作类的模型可以把温度拉高。
`
;
export
const
shareHint
=
`
你正准备分享对话,请确保分享链接不会滥用,因为它是使用的是你的 API key。
* 分享空白对话:为该模型创建一个空白的聊天分享出去。
* 分享当前对话:会把当前聊天的内容也分享出去,但是要注意不要多个人同时用一个聊天内容。
`
;
src/constants/model.ts
View file @
00b90f07
import
type
{
ServiceName
}
from
'@/types/mongoSchema'
;
import
{
ModelSchema
}
from
'../types/mongoSchema'
;
export
enum
ChatModelNameEnum
{
export
enum
ChatModelNameEnum
{
GPT35
=
'gpt-3.5-turbo'
,
GPT35
=
'gpt-3.5-turbo'
,
GPT3
=
'text-davinci-003'
GPT3
=
'text-davinci-003'
}
}
export
const
OpenAiList
=
[
export
type
ModelConstantsData
=
{
name
:
string
;
model
:
`
${
ChatModelNameEnum
}
`
;
trainName
:
string
;
// 空字符串代表不能训练
maxToken
:
number
;
maxTemperature
:
number
;
};
export
const
ModelList
:
Record
<
ServiceName
,
ModelConstantsData
[]
>
=
{
openai
:
[
{
{
name
:
'chatGPT'
,
name
:
'chatGPT'
,
model
:
ChatModelNameEnum
.
GPT35
,
model
:
ChatModelNameEnum
.
GPT35
,
trainName
:
'turbo'
,
trainName
:
'turbo'
,
canTraining
:
false
,
maxToken
:
4000
,
maxToken
:
4060
maxTemperature
:
2
},
},
{
{
name
:
'GPT3'
,
name
:
'GPT3'
,
model
:
ChatModelNameEnum
.
GPT3
,
model
:
ChatModelNameEnum
.
GPT3
,
trainName
:
'davinci'
,
trainName
:
'davinci'
,
canTraining
:
true
,
maxToken
:
4000
,
maxToken
:
4060
maxTemperature
:
2
}
}
];
]
};
export
enum
TrainingStatusEnum
{
export
enum
TrainingStatusEnum
{
pending
=
'pending'
,
pending
=
'pending'
,
...
@@ -51,3 +65,29 @@ export const formatModelStatus = {
...
@@ -51,3 +65,29 @@ export const formatModelStatus = {
text
:
'已关闭'
text
:
'已关闭'
}
}
};
};
export
const
defaultModel
:
ModelSchema
=
{
_id
:
''
,
userId
:
''
,
name
:
''
,
avatar
:
''
,
status
:
ModelStatusEnum
.
pending
,
updateTime
:
Date
.
now
(),
trainingTimes
:
0
,
systemPrompt
:
''
,
intro
:
''
,
temperature
:
5
,
service
:
{
company
:
'openai'
,
trainId
:
''
,
chatModel
:
ChatModelNameEnum
.
GPT35
,
modelName
:
ChatModelNameEnum
.
GPT35
},
security
:
{
domain
:
[
'*'
],
contextMaxLen
:
1
,
contentMaxLen
:
1
,
expiredTime
:
9999
,
maxLoadAmount
:
1
}
};
src/pages/api/chat/chatGpt.ts
View file @
00b90f07
...
@@ -8,6 +8,7 @@ import { ChatItemType } from '@/types/chat';
...
@@ -8,6 +8,7 @@ import { ChatItemType } from '@/types/chat';
import
{
jsonRes
}
from
'@/service/response'
;
import
{
jsonRes
}
from
'@/service/response'
;
import
type
{
ModelSchema
}
from
'@/types/mongoSchema'
;
import
type
{
ModelSchema
}
from
'@/types/mongoSchema'
;
import
{
PassThrough
}
from
'stream'
;
import
{
PassThrough
}
from
'stream'
;
import
{
ModelList
}
from
'@/constants/model'
;
/* 发送提示词 */
/* 发送提示词 */
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
)
{
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
)
{
...
@@ -56,6 +57,15 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
...
@@ -56,6 +57,15 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
});
});
}
}
// 计算温度
const
modelConstantsData
=
ModelList
[
'openai'
].
find
(
(
item
)
=>
item
.
model
===
model
.
service
.
modelName
);
if
(
!
modelConstantsData
)
{
throw
new
Error
(
'模型异常'
);
}
const
temperature
=
modelConstantsData
.
maxTemperature
*
(
model
.
temperature
/
10
);
// 获取 chatAPI
// 获取 chatAPI
const
chatAPI
=
getOpenAIApi
(
userApiKey
);
const
chatAPI
=
getOpenAIApi
(
userApiKey
);
let
startTime
=
Date
.
now
();
let
startTime
=
Date
.
now
();
...
@@ -63,8 +73,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
...
@@ -63,8 +73,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const
chatResponse
=
await
chatAPI
.
createChatCompletion
(
const
chatResponse
=
await
chatAPI
.
createChatCompletion
(
{
{
model
:
model
.
service
.
chatModel
,
model
:
model
.
service
.
chatModel
,
temperature
:
1
,
temperature
:
temperature
,
// max_tokens: model.security.contentMaxL
en,
max_tokens
:
modelConstantsData
.
maxTok
en
,
messages
:
formatPrompts
,
messages
:
formatPrompts
,
stream
:
true
stream
:
true
},
},
...
...
src/pages/api/chat/gpt3.ts
View file @
00b90f07
...
@@ -5,6 +5,7 @@ import { connectToDatabase } from '@/service/mongo';
...
@@ -5,6 +5,7 @@ import { connectToDatabase } from '@/service/mongo';
import
{
getOpenAIApi
,
authChat
}
from
'@/service/utils/chat'
;
import
{
getOpenAIApi
,
authChat
}
from
'@/service/utils/chat'
;
import
{
ChatItemType
}
from
'@/types/chat'
;
import
{
ChatItemType
}
from
'@/types/chat'
;
import
{
httpsAgent
}
from
'@/service/utils/tools'
;
import
{
httpsAgent
}
from
'@/service/utils/tools'
;
import
{
ModelList
}
from
'@/constants/model'
;
/* 发送提示词 */
/* 发送提示词 */
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
)
{
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
)
{
...
@@ -27,13 +28,22 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
...
@@ -27,13 +28,22 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
// prompt处理
// prompt处理
const
formatPrompt
=
prompt
.
map
((
item
)
=>
`
${
item
.
value
}
\n\n###\n\n`
).
join
(
''
);
const
formatPrompt
=
prompt
.
map
((
item
)
=>
`
${
item
.
value
}
\n\n###\n\n`
).
join
(
''
);
// 计算温度
const
modelConstantsData
=
ModelList
[
'openai'
].
find
(
(
item
)
=>
item
.
model
===
model
.
service
.
modelName
);
if
(
!
modelConstantsData
)
{
throw
new
Error
(
'模型异常'
);
}
const
temperature
=
modelConstantsData
.
maxTemperature
*
(
model
.
temperature
/
10
);
// 发送请求
// 发送请求
const
response
=
await
chatAPI
.
createCompletion
(
const
response
=
await
chatAPI
.
createCompletion
(
{
{
model
:
model
.
service
.
modelName
,
model
:
model
.
service
.
modelName
,
prompt
:
formatPrompt
,
prompt
:
formatPrompt
,
temperature
:
0.5
,
temperature
:
temperature
,
max_tokens
:
model
.
security
.
contentMaxL
en
,
max_tokens
:
model
ConstantsData
.
maxTok
en
,
top_p
:
1
,
top_p
:
1
,
frequency_penalty
:
0
,
frequency_penalty
:
0
,
presence_penalty
:
0.6
,
presence_penalty
:
0.6
,
...
...
src/pages/api/chat/init.ts
View file @
00b90f07
...
@@ -47,6 +47,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
...
@@ -47,6 +47,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
modelId
:
model
.
_id
,
modelId
:
model
.
_id
,
name
:
model
.
name
,
name
:
model
.
name
,
avatar
:
model
.
avatar
,
avatar
:
model
.
avatar
,
intro
:
model
.
intro
,
secret
:
model
.
security
,
secret
:
model
.
security
,
chatModel
:
model
.
service
.
chatModel
,
chatModel
:
model
.
service
.
chatModel
,
history
:
chat
.
content
history
:
chat
.
content
...
...
src/pages/api/model/create.ts
View file @
00b90f07
...
@@ -3,12 +3,21 @@ import type { NextApiRequest, NextApiResponse } from 'next';
...
@@ -3,12 +3,21 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import
{
jsonRes
}
from
'@/service/response'
;
import
{
jsonRes
}
from
'@/service/response'
;
import
{
connectToDatabase
}
from
'@/service/mongo'
;
import
{
connectToDatabase
}
from
'@/service/mongo'
;
import
{
authToken
}
from
'@/service/utils/tools'
;
import
{
authToken
}
from
'@/service/utils/tools'
;
import
{
ModelStatusEnum
,
OpenAiList
}
from
'@/constants/model'
;
import
{
ModelStatusEnum
,
ModelList
,
ChatModelNameEnum
}
from
'@/constants/model'
;
import
type
{
ServiceName
}
from
'@/types/mongoSchema'
;
import
{
Model
}
from
'@/service/models/model'
;
import
{
Model
}
from
'@/service/models/model'
;
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
<
any
>
)
{
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
<
any
>
)
{
try
{
try
{
const
{
name
,
serviceModelName
,
serviceModelCompany
=
'openai'
}
=
req
.
body
;
const
{
name
,
serviceModelName
,
serviceModelCompany
=
'openai'
}
=
req
.
body
as
{
name
:
string
;
serviceModelName
:
`
${
ChatModelNameEnum
}
`
;
serviceModelCompany
:
ServiceName
;
};
const
{
authorization
}
=
req
.
headers
;
const
{
authorization
}
=
req
.
headers
;
if
(
!
authorization
)
{
if
(
!
authorization
)
{
...
@@ -22,10 +31,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
...
@@ -22,10 +31,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
// 凭证校验
// 凭证校验
const
userId
=
await
authToken
(
authorization
);
const
userId
=
await
authToken
(
authorization
);
const
modelItem
=
OpenAiList
.
find
((
item
)
=>
item
.
model
===
serviceModelName
);
const
modelItem
=
ModelList
[
serviceModelCompany
].
find
(
(
item
)
=>
item
.
model
===
serviceModelName
);
if
(
!
modelItem
)
{
if
(
!
modelItem
)
{
throw
new
Error
(
'模型
错误
'
);
throw
new
Error
(
'模型
不存在
'
);
}
}
await
connectToDatabase
();
await
connectToDatabase
();
...
@@ -43,8 +54,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
...
@@ -43,8 +54,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
const
authCount
=
await
Model
.
countDocuments
({
const
authCount
=
await
Model
.
countDocuments
({
userId
userId
});
});
if
(
authCount
>=
1
0
)
{
if
(
authCount
>=
2
0
)
{
throw
new
Error
(
'上限
1
0 个模型'
);
throw
new
Error
(
'上限
2
0 个模型'
);
}
}
// 创建模型
// 创建模型
...
...
src/pages/api/model/detail.tsx
View file @
00b90f07
...
@@ -3,7 +3,7 @@ import { jsonRes } from '@/service/response';
...
@@ -3,7 +3,7 @@ import { jsonRes } from '@/service/response';
import
{
connectToDatabase
}
from
'@/service/mongo'
;
import
{
connectToDatabase
}
from
'@/service/mongo'
;
import
{
authToken
}
from
'@/service/utils/tools'
;
import
{
authToken
}
from
'@/service/utils/tools'
;
import
{
Model
}
from
'@/service/models/model'
;
import
{
Model
}
from
'@/service/models/model'
;
import
{
ModelType
}
from
'@/types/model
'
;
import
type
{
ModelSchema
}
from
'@/types/mongoSchema
'
;
/* 获取我的模型 */
/* 获取我的模型 */
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
<
any
>
)
{
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
<
any
>
)
{
...
@@ -26,7 +26,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
...
@@ -26,7 +26,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
await
connectToDatabase
();
await
connectToDatabase
();
// 根据 userId 获取模型信息
// 根据 userId 获取模型信息
const
model
:
ModelType
|
null
=
await
Model
.
findOne
({
const
model
=
await
Model
.
findOne
<
ModelSchema
>
({
userId
,
userId
,
_id
:
modelId
_id
:
modelId
});
});
...
...
src/pages/api/model/getTrainings.ts
View file @
00b90f07
...
@@ -6,7 +6,7 @@ import formidable from 'formidable';
...
@@ -6,7 +6,7 @@ import formidable from 'formidable';
import
{
authToken
,
getUserOpenaiKey
}
from
'@/service/utils/tools'
;
import
{
authToken
,
getUserOpenaiKey
}
from
'@/service/utils/tools'
;
import
{
join
}
from
'path'
;
import
{
join
}
from
'path'
;
import
fs
from
'fs'
;
import
fs
from
'fs'
;
import
type
{
Model
Type
}
from
'@/types/model
'
;
import
type
{
Model
Schema
}
from
'@/types/mongoSchema
'
;
import
type
{
OpenAIApi
}
from
'openai'
;
import
type
{
OpenAIApi
}
from
'openai'
;
import
{
ModelStatusEnum
,
TrainingStatusEnum
}
from
'@/constants/model'
;
import
{
ModelStatusEnum
,
TrainingStatusEnum
}
from
'@/constants/model'
;
import
{
httpsAgent
}
from
'@/service/utils/tools'
;
import
{
httpsAgent
}
from
'@/service/utils/tools'
;
...
...
src/pages/api/model/putTrainStatus.ts
View file @
00b90f07
...
@@ -3,7 +3,7 @@ import { jsonRes } from '@/service/response';
...
@@ -3,7 +3,7 @@ import { jsonRes } from '@/service/response';
import
{
connectToDatabase
,
Model
,
Training
}
from
'@/service/mongo'
;
import
{
connectToDatabase
,
Model
,
Training
}
from
'@/service/mongo'
;
import
{
getOpenAIApi
}
from
'@/service/utils/chat'
;
import
{
getOpenAIApi
}
from
'@/service/utils/chat'
;
import
{
authToken
,
getUserOpenaiKey
}
from
'@/service/utils/tools'
;
import
{
authToken
,
getUserOpenaiKey
}
from
'@/service/utils/tools'
;
import
type
{
Model
Type
}
from
'@/types/model
'
;
import
type
{
Model
Schema
}
from
'@/types/mongoSchema
'
;
import
{
TrainingItemType
}
from
'@/types/training'
;
import
{
TrainingItemType
}
from
'@/types/training'
;
import
{
ModelStatusEnum
,
TrainingStatusEnum
}
from
'@/constants/model'
;
import
{
ModelStatusEnum
,
TrainingStatusEnum
}
from
'@/constants/model'
;
import
{
OpenAiTuneStatusEnum
}
from
'@/service/constants/training'
;
import
{
OpenAiTuneStatusEnum
}
from
'@/service/constants/training'
;
...
@@ -26,7 +26,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
...
@@ -26,7 +26,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
await
connectToDatabase
();
await
connectToDatabase
();
// 获取模型
// 获取模型
const
model
:
ModelType
|
null
=
await
Model
.
findById
(
modelId
);
const
model
=
await
Model
.
findById
<
ModelSchema
>
(
modelId
);
if
(
!
model
||
model
.
status
!==
'training'
)
{
if
(
!
model
||
model
.
status
!==
'training'
)
{
throw
new
Error
(
'模型不在训练中'
);
throw
new
Error
(
'模型不在训练中'
);
...
...
src/pages/api/model/train.ts
View file @
00b90f07
...
@@ -7,7 +7,7 @@ import formidable from 'formidable';
...
@@ -7,7 +7,7 @@ import formidable from 'formidable';
import
{
authToken
,
getUserOpenaiKey
}
from
'@/service/utils/tools'
;
import
{
authToken
,
getUserOpenaiKey
}
from
'@/service/utils/tools'
;
import
{
join
}
from
'path'
;
import
{
join
}
from
'path'
;
import
fs
from
'fs'
;
import
fs
from
'fs'
;
import
type
{
Model
Type
}
from
'@/types/model
'
;
import
type
{
Model
Schema
}
from
'@/types/mongoSchema
'
;
import
type
{
OpenAIApi
}
from
'openai'
;
import
type
{
OpenAIApi
}
from
'openai'
;
import
{
ModelStatusEnum
,
TrainingStatusEnum
}
from
'@/constants/model'
;
import
{
ModelStatusEnum
,
TrainingStatusEnum
}
from
'@/constants/model'
;
import
{
httpsAgent
}
from
'@/service/utils/tools'
;
import
{
httpsAgent
}
from
'@/service/utils/tools'
;
...
@@ -38,7 +38,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
...
@@ -38,7 +38,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
await
connectToDatabase
();
await
connectToDatabase
();
// 获取模型的状态
// 获取模型的状态
const
model
:
ModelType
|
null
=
await
Model
.
findById
(
modelId
);
const
model
=
await
Model
.
findById
<
ModelSchema
>
(
modelId
);
if
(
!
model
||
model
.
status
!==
'running'
)
{
if
(
!
model
||
model
.
status
!==
'running'
)
{
throw
new
Error
(
'模型正忙'
);
throw
new
Error
(
'模型正忙'
);
...
...
src/pages/api/model/update.ts
View file @
00b90f07
...
@@ -8,7 +8,8 @@ import type { ModelUpdateParams } from '@/types/model';
...
@@ -8,7 +8,8 @@ import type { ModelUpdateParams } from '@/types/model';
/* 获取我的模型 */
/* 获取我的模型 */
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
<
any
>
)
{
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
<
any
>
)
{
try
{
try
{
const
{
name
,
service
,
security
,
systemPrompt
}
=
req
.
body
as
ModelUpdateParams
;
const
{
name
,
service
,
security
,
systemPrompt
,
intro
,
temperature
}
=
req
.
body
as
ModelUpdateParams
;
const
{
modelId
}
=
req
.
query
as
{
modelId
:
string
};
const
{
modelId
}
=
req
.
query
as
{
modelId
:
string
};
const
{
authorization
}
=
req
.
headers
;
const
{
authorization
}
=
req
.
headers
;
...
@@ -33,8 +34,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
...
@@ -33,8 +34,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
},
},
{
{
name
,
name
,
service
,
systemPrompt
,
systemPrompt
,
intro
,
temperature
,
service
,
security
security
}
}
);
);
...
...
src/pages/chat/components/Empty.tsx
View file @
00b90f07
import
React
from
'react'
;
import
React
from
'react'
;
import
{
Card
,
Flex
,
Box
}
from
'@chakra-ui/react'
;
import
{
Card
,
Box
,
Mark
}
from
'@chakra-ui/react'
;
import
{
versionIntro
,
chatProblem
}
from
'@/constants/common'
;
import
Markdown
from
'@/components/Markdown'
;
const
Empty
=
()
=>
{
const
Empty
=
({
intro
}:
{
intro
:
string
})
=>
{
return
(
const
Header
=
({
children
}:
{
children
:
string
})
=>
(
<
Flex
h=
{
'100%'
}
alignItems=
{
'center'
}
justifyContent=
{
'center'
}
>
<
Box
fontSize=
{
'lg'
}
fontWeight=
{
'bold'
}
textAlign=
{
'center'
}
pb=
{
2
}
>
<
Card
p=
{
5
}
w=
{
'70%'
}
>
{
children
}
<
Box
fontSize=
{
'xl'
}
fontWeight=
{
'bold'
}
textAlign=
{
'center'
}
pb=
{
2
}
>
Fast Gpt version1.3
</
Box
>
</
Box
>
);
return
(
<
Box
minH=
{
'100%'
}
w=
{
'85%'
}
maxW=
{
'600px'
}
m=
{
'auto'
}
py=
{
'5vh'
}
alignItems=
{
'center'
}
justifyContent=
{
'center'
}
>
{
!!
intro
&&
(
<
Card
p=
{
4
}
mb=
{
10
}
>
<
Header
>
模型介绍
</
Header
>
<
Box
>
{
intro
}
</
Box
>
</
Card
>
)
}
<
Card
p=
{
4
}
mb=
{
10
}
>
<
Header
>
常见问题
</
Header
>
<
Markdown
source=
{
chatProblem
}
/>
</
Card
>
{
/* version intro */
}
<
Card
p=
{
4
}
>
<
Header
>
Fast Gpt version1.4
</
Header
>
<
Box
>
<
Box
>
更新了聊天的数据结构,
如果出现问题,请手动删除左侧旧的历史记录,并重新从模型页生成对话框进入。
聊天的数据结构发生了比较大的改动。
如果出现问题,请手动删除左侧旧的历史记录,并重新从模型页生成对话框进入。
</
Box
>
</
Box
>
<
Box
>
分享聊天使用的是分享者的 Api Key 进行收费,请确认分享安全
</
Box
>
<
br
/>
<
Box
>
分享空白聊天,会分享一个该模型的空白聊天页
</
Box
>
<
br
/>
<
br
/>
<
Box
>
分享当前聊天,会把当前聊天的内容分享出去,请注意不会多人同时使用一个对话框
</
Box
>
<
Markdown
source=
{
versionIntro
}
/
>
</
Card
>
</
Card
>
</
Fle
x
>
</
Bo
x
>
);
);
};
};
...
...
src/pages/chat/components/SlideBar.tsx
View file @
00b90f07
import
React
,
{
useState
,
useEffect
}
from
'react'
;
import
React
,
{
useState
,
useEffect
}
from
'react'
;
import
{
Box
,
Button
}
from
'@chakra-ui/react'
;
import
{
AddIcon
,
ChatIcon
,
DeleteIcon
}
from
'@chakra-ui/icons'
;
import
{
AddIcon
,
ChatIcon
,
EditIcon
,
DeleteIcon
}
from
'@chakra-ui/icons'
;
import
{
import
{
Box
,
Button
,
Accordion
,
Accordion
,
AccordionItem
,
AccordionItem
,
AccordionButton
,
AccordionButton
,
...
@@ -9,16 +10,26 @@ import {
...
@@ -9,16 +10,26 @@ import {
AccordionIcon
,
AccordionIcon
,
Flex
,
Flex
,
Divider
,
Divider
,
IconButton
IconButton
,
Modal
,
ModalOverlay
,
ModalContent
,
ModalHeader
,
ModalFooter
,
ModalBody
,
ModalCloseButton
,
useDisclosure
}
from
'@chakra-ui/react'
;
}
from
'@chakra-ui/react'
;
import
{
useUserStore
}
from
'@/store/user'
;
import
{
useUserStore
}
from
'@/store/user'
;
import
{
useChatStore
}
from
'@/store/chat'
;
import
{
useChatStore
}
from
'@/store/chat'
;
import
{
useQuery
}
from
'@tanstack/react-query'
;
import
{
useQuery
}
from
'@tanstack/react-query'
;
import
{
useRouter
}
from
'next/router'
;
import
{
useRouter
}
from
'next/router'
;
import
{
useScreen
}
from
'@/hooks/useScreen'
;
import
{
getToken
}
from
'@/utils/user'
;
import
{
getToken
}
from
'@/utils/user'
;
import
MyIcon
from
'@/components/Icon'
;
import
MyIcon
from
'@/components/Icon'
;
import
{
useCopyData
}
from
'@/utils/tools'
;
import
{
useCopyData
}
from
'@/utils/tools'
;
import
Markdown
from
'@/components/Markdown'
;
import
{
shareHint
}
from
'@/constants/common'
;
import
{
getChatSiteId
}
from
'@/api/chat'
;
const
SlideBar
=
({
const
SlideBar
=
({
name
,
name
,
...
@@ -36,10 +47,13 @@ const SlideBar = ({
...
@@ -36,10 +47,13 @@ const SlideBar = ({
const
router
=
useRouter
();
const
router
=
useRouter
();
const
{
copyData
}
=
useCopyData
();
const
{
copyData
}
=
useCopyData
();
const
{
myModels
,
getMyModels
}
=
useUserStore
();
const
{
myModels
,
getMyModels
}
=
useUserStore
();
const
{
chatHistory
,
removeChatHistoryByWindowId
,
generateChatWindow
,
updateChatHistory
}
=
const
{
chatHistory
,
removeChatHistoryByWindowId
}
=
useChatStore
();
useChatStore
();
const
{
isSuccess
}
=
useQuery
([
'init'
],
getMyModels
);
const
[
hasReady
,
setHasReady
]
=
useState
(
false
);
const
[
hasReady
,
setHasReady
]
=
useState
(
false
);
const
{
isOpen
:
isOpenShare
,
onOpen
:
onOpenShare
,
onClose
:
onCloseShare
}
=
useDisclosure
();
const
{
isSuccess
}
=
useQuery
([
'init'
],
getMyModels
,
{
cacheTime
:
5
*
60
*
1000
});
useEffect
(()
=>
{
useEffect
(()
=>
{
setHasReady
(
true
);
setHasReady
(
true
);
...
@@ -119,19 +133,8 @@ const SlideBar = ({
...
@@ -119,19 +133,8 @@ const SlideBar = ({
{
/* 我的模型 & 历史记录 折叠框*/
}
{
/* 我的模型 & 历史记录 折叠框*/
}
<
Box
flex=
{
'1 0 0'
}
px=
{
3
}
h=
{
0
}
overflowY=
{
'auto'
}
>
<
Box
flex=
{
'1 0 0'
}
px=
{
3
}
h=
{
0
}
overflowY=
{
'auto'
}
>
{
isSuccess
?
(
<
Accordion
defaultIndex=
{
[
0
]
}
allowToggle
>
<
Accordion
defaultIndex=
{
[
0
]
}
allowToggle
>
<
AccordionItem
borderTop=
{
0
}
borderBottom=
{
0
}
>
{
isSuccess
&&
(
<
AccordionButton
borderRadius=
{
'md'
}
pl=
{
1
}
>
<
Box
as=
"span"
flex=
"1"
textAlign=
"left"
>
历史记录
</
Box
>
<
AccordionIcon
/>
</
AccordionButton
>
<
AccordionPanel
pb=
{
0
}
px=
{
0
}
>
{
hasReady
&&
<
RenderHistory
/>
}
</
AccordionPanel
>
</
AccordionItem
>
<
AccordionItem
borderTop=
{
0
}
borderBottom=
{
0
}
>
<
AccordionItem
borderTop=
{
0
}
borderBottom=
{
0
}
>
<
AccordionButton
borderRadius=
{
'md'
}
pl=
{
1
}
>
<
AccordionButton
borderRadius=
{
'md'
}
pl=
{
1
}
>
<
Box
as=
"span"
flex=
"1"
textAlign=
"left"
>
<
Box
as=
"span"
flex=
"1"
textAlign=
"left"
>
...
@@ -161,7 +164,7 @@ const SlideBar = ({
...
@@ -161,7 +164,7 @@ const SlideBar = ({
:
{})}
:
{})}
onClick=
{
async
()
=>
{
onClick=
{
async
()
=>
{
if
(
item
.
name
===
name
)
return
;
if
(
item
.
name
===
name
)
return
;
router
.
push
(
`/chat?chatId=${await ge
nerateChatWindow
(item._id)}`
);
router
.
push
(
`/chat?chatId=${await ge
tChatSiteId
(item._id)}`
);
onClose
();
onClose
();
}
}
}
}
>
>
...
@@ -173,22 +176,24 @@ const SlideBar = ({
...
@@ -173,22 +176,24 @@ const SlideBar = ({
))
}
))
}
</
AccordionPanel
>
</
AccordionPanel
>
</
AccordionItem
>
</
AccordionItem
>
</
Accordion
>
)
}
)
:
(
<
AccordionItem
borderTop=
{
0
}
borderBottom=
{
0
}
>
<
>
<
AccordionButton
borderRadius=
{
'md'
}
pl=
{
1
}
>
<
Box
mb=
{
4
}
textAlign=
{
'center'
}
>
<
Box
as=
"span"
flex=
"1"
textAlign=
"left"
>
历史记录
历史记录
</
Box
>
</
Box
>
<
RenderHistory
/>
<
AccordionIcon
/>
</>
</
AccordionButton
>
)
}
<
AccordionPanel
pb=
{
0
}
px=
{
0
}
>
{
hasReady
&&
<
RenderHistory
/>
}
</
AccordionPanel
>
</
AccordionItem
>
</
Accordion
>
</
Box
>
</
Box
>
<
Divider
my=
{
4
}
/>
<
Divider
my=
{
4
}
/>
<
Box
px=
{
3
}
>
<
Box
px=
{
3
}
>
{
/* 分享 */
}
{
getToken
()
&&
(
<
Flex
<
Flex
alignItems=
{
'center'
}
alignItems=
{
'center'
}
p=
{
2
}
p=
{
2
}
...
@@ -197,34 +202,57 @@ const SlideBar = ({
...
@@ -197,34 +202,57 @@ const SlideBar = ({
_hover=
{
{
_hover=
{
{
backgroundColor
:
'rgba(255,255,255,0.2)'
backgroundColor
:
'rgba(255,255,255,0.2)'
}
}
}
}
onClick=
{
()
=>
{
onOpenShare
();
onClose
();
}
}
>
<
MyIcon
name=
"share"
fill=
{
'white'
}
w=
{
'16px'
}
h=
{
'16px'
}
mr=
{
4
}
/>
分享对话
</
Flex
>
</
Box
>
{
/* 分享提示modal */
}
<
Modal
isOpen=
{
isOpenShare
}
onClose=
{
onCloseShare
}
>
<
ModalOverlay
/>
<
ModalContent
>
<
ModalHeader
>
分享对话
</
ModalHeader
>
<
ModalCloseButton
/>
<
ModalBody
>
<
Markdown
source=
{
shareHint
}
/>
</
ModalBody
>
<
ModalFooter
>
<
Button
colorScheme=
"gray"
variant=
{
'outline'
}
mr=
{
3
}
onClick=
{
onCloseShare
}
>
Close
</
Button
>
{
getToken
()
&&
(
<
Button
variant=
"outline"
mr=
{
3
}
onClick=
{
async
()
=>
{
onClick=
{
async
()
=>
{
copyData
(
copyData
(
`${location.origin}/chat?chatId=${await generateChatWindow
(modelId)}`
,
`${location.origin}/chat?chatId=${await getChatSiteId
(modelId)}`
,
'已复制分享链接'
'已复制分享链接'
);
);
onCloseShare
();
}
}
}
}
>
>
<
MyIcon
name=
"share"
fill=
{
'white'
}
w=
{
'16px'
}
h=
{
'16px'
}
mr=
{
4
}
/>
分享空白对话
分享空白对话
</
Flex
>
</
Button
>
)
}
)
}
<
Flex
mt=
{
4
}
<
Button
alignItems=
{
'center'
}
onClick=
{
()
=>
{
p=
{
2
}
cursor=
{
'pointer'
}
borderRadius=
{
'md'
}
_hover=
{
{
backgroundColor
:
'rgba(255,255,255,0.2)'
}
}
onClick=
{
async
()
=>
{
copyData
(
`${location.origin}/chat?chatId=${chatId}`
,
'已复制分享链接'
);
copyData
(
`${location.origin}/chat?chatId=${chatId}`
,
'已复制分享链接'
);
onCloseShare
();
}
}
}
}
>
>
<
MyIcon
name=
"share"
fill=
{
'white'
}
w=
{
'16px'
}
h=
{
'16px'
}
mr=
{
4
}
/>
分享当前对话
分享当前对话
</
Flex
>
</
Button
>
</
Box
>
</
ModalFooter
>
</
ModalContent
>
</
Modal
>
</
Flex
>
</
Flex
>
);
);
};
};
...
...
src/pages/chat/index.tsx
View file @
00b90f07
...
@@ -51,6 +51,7 @@ const Chat = ({ chatId }: { chatId: string }) => {
...
@@ -51,6 +51,7 @@ const Chat = ({ chatId }: { chatId: string }) => {
modelId
:
''
,
modelId
:
''
,
name
:
''
,
name
:
''
,
avatar
:
''
,
avatar
:
''
,
intro
:
''
,
secret
:
{},
secret
:
{},
chatModel
:
''
,
chatModel
:
''
,
history
:
[],
history
:
[],
...
@@ -113,7 +114,11 @@ const Chat = ({ chatId }: { chatId: string }) => {
...
@@ -113,7 +114,11 @@ const Chat = ({ chatId }: { chatId: string }) => {
status
:
'finish'
status
:
'finish'
}))
}))
});
});
if
(
res
.
history
.
length
>
0
)
{
setTimeout
(()
=>
{
scrollToBottom
();
scrollToBottom
();
},
500
);
}
},
},
onError
(
e
:
any
)
{
onError
(
e
:
any
)
{
toast
({
toast
({
...
@@ -433,7 +438,7 @@ const Chat = ({ chatId }: { chatId: string }) => {
...
@@ -433,7 +438,7 @@ const Chat = ({ chatId }: { chatId: string }) => {
</
Flex
>
</
Flex
>
</
Box
>
</
Box
>
))
}
))
}
{
chatData
.
history
.
length
===
0
&&
<
Empty
/>
}
{
chatData
.
history
.
length
===
0
&&
<
Empty
intro=
{
chatData
.
intro
}
/>
}
</
Box
>
</
Box
>
{
/* 发送区 */
}
{
/* 发送区 */
}
<
Box
<
Box
...
...
src/pages/model/components/CreateModel.tsx
View file @
00b90f07
...
@@ -16,8 +16,8 @@ import {
...
@@ -16,8 +16,8 @@ import {
}
from
'@chakra-ui/react'
;
}
from
'@chakra-ui/react'
;
import
{
useForm
}
from
'react-hook-form'
;
import
{
useForm
}
from
'react-hook-form'
;
import
{
postCreateModel
}
from
'@/api/model'
;
import
{
postCreateModel
}
from
'@/api/model'
;
import
{
ModelType
}
from
'@/types/model
'
;
import
type
{
ModelSchema
}
from
'@/types/mongoSchema
'
;
import
{
OpenAi
List
}
from
'@/constants/model'
;
import
{
Model
List
}
from
'@/constants/model'
;
interface
CreateFormType
{
interface
CreateFormType
{
name
:
string
;
name
:
string
;
...
@@ -29,7 +29,7 @@ const CreateModel = ({
...
@@ -29,7 +29,7 @@ const CreateModel = ({
onSuccess
onSuccess
}:
{
}:
{
setCreateModelOpen
:
Dispatch
<
boolean
>
;
setCreateModelOpen
:
Dispatch
<
boolean
>
;
onSuccess
:
Dispatch
<
Model
Type
>
;
onSuccess
:
Dispatch
<
Model
Schema
>
;
})
=>
{
})
=>
{
const
[
requesting
,
setRequesting
]
=
useState
(
false
);
const
[
requesting
,
setRequesting
]
=
useState
(
false
);
const
toast
=
useToast
({
const
toast
=
useToast
({
...
@@ -42,7 +42,7 @@ const CreateModel = ({
...
@@ -42,7 +42,7 @@ const CreateModel = ({
formState
:
{
errors
}
formState
:
{
errors
}
}
=
useForm
<
CreateFormType
>
({
}
=
useForm
<
CreateFormType
>
({
defaultValues
:
{
defaultValues
:
{
serviceModelName
:
OpenAiList
[
0
].
model
serviceModelName
:
ModelList
[
'openai'
]
[
0
].
model
}
}
});
});
...
@@ -95,7 +95,7 @@ const CreateModel = ({
...
@@ -95,7 +95,7 @@ const CreateModel = ({
required
:
'底层模型不能为空'
required
:
'底层模型不能为空'
})}
})}
>
>
{
OpenAiList
.
map
((
item
)
=>
(
{
ModelList
[
'openai'
]
.
map
((
item
)
=>
(
<
option
key=
{
item
.
model
}
value=
{
item
.
model
}
>
<
option
key=
{
item
.
model
}
value=
{
item
.
model
}
>
{
item
.
name
}
{
item
.
name
}
</
option
>
</
option
>
...
...
src/pages/model/components/ModelEditForm.tsx
View file @
00b90f07
import
React
,
{
useCallback
,
useEffect
,
useRef
}
from
'react'
;
import
React
,
{
useState
}
from
'react'
;
import
{
Grid
,
Box
,
Card
,
Flex
,
Button
,
FormControl
,
Input
,
Textarea
}
from
'@chakra-ui/react'
;
import
{
import
type
{
ModelType
}
from
'@/types/model'
;
Box
,
import
{
useForm
}
from
'react-hook-form'
;
Card
,
import
{
useToast
}
from
'@/hooks/useToast'
;
Flex
,
import
{
putModelById
}
from
'@/api/model'
;
FormControl
,
import
{
useScreen
}
from
'@/hooks/useScreen'
;
Input
,
import
{
useGlobalStore
}
from
'@/store/global'
;
Textarea
,
Slider
,
SliderTrack
,
SliderFilledTrack
,
SliderThumb
,
SliderMark
,
Tooltip
}
from
'@chakra-ui/react'
;
import
{
QuestionOutlineIcon
}
from
'@chakra-ui/icons'
;
import
type
{
ModelSchema
}
from
'@/types/mongoSchema'
;
import
{
UseFormReturn
}
from
'react-hook-form'
;
const
ModelEditForm
=
({
model
}:
{
model
?:
ModelType
})
=>
{
const
ModelEditForm
=
({
formHooks
}:
{
formHooks
:
UseFormReturn
<
ModelSchema
>
})
=>
{
const
isInit
=
useRef
(
false
);
const
{
register
,
setValue
,
getValues
}
=
formHooks
;
const
{
const
[
refresh
,
setRefresh
]
=
useState
(
false
);
register
,
handleSubmit
,
reset
,
formState
:
{
errors
}
}
=
useForm
<
ModelType
>
();
const
{
setLoading
}
=
useGlobalStore
();
const
{
toast
}
=
useToast
();
const
{
media
}
=
useScreen
();
const
onclickSave
=
useCallback
(
async
(
data
:
ModelType
)
=>
{
setLoading
(
true
);
try
{
await
putModelById
(
data
.
_id
,
{
name
:
data
.
name
,
systemPrompt
:
data
.
systemPrompt
,
service
:
data
.
service
,
security
:
data
.
security
});
toast
({
title
:
'更新成功'
,
status
:
'success'
});
}
catch
(
err
)
{
console
.
log
(
'error->'
,
err
);
toast
({
title
:
err
as
string
,
status
:
'success'
});
}
setLoading
(
false
);
},
[
setLoading
,
toast
]
);
const
submitError
=
useCallback
(()
=>
{
// deep search message
const
deepSearch
=
(
obj
:
any
):
string
=>
{
if
(
!
obj
)
return
'提交表单错误'
;
if
(
!!
obj
.
message
)
{
return
obj
.
message
;
}
return
deepSearch
(
Object
.
values
(
obj
)[
0
]);
};
toast
({
title
:
deepSearch
(
errors
),
status
:
'error'
,
duration
:
4000
,
isClosable
:
true
});
},
[
errors
,
toast
]);
/* model 只会改变一次 */
useEffect
(()
=>
{
if
(
model
&&
!
isInit
.
current
)
{
reset
(
model
);
isInit
.
current
=
true
;
}
},
[
model
,
reset
]);
return
(
return
(
<
Grid
gridTemplateColumns=
{
media
(
'1fr 1fr'
,
'1fr'
)
}
gridGap=
{
5
}
>
<>
<
Card
p=
{
4
}
>
<
Card
p=
{
4
}
>
<
Flex
justifyContent=
{
'space-between'
}
alignItems=
{
'center'
}
>
<
Flex
justifyContent=
{
'space-between'
}
alignItems=
{
'center'
}
>
<
Box
fontWeight=
{
'bold'
}
fontSize=
{
'lg'
}
>
<
Box
fontWeight=
{
'bold'
}
>
基本信息
</
Box
>
修改模型信息
</
Box
>
<
Button
onClick=
{
handleSubmit
(
onclickSave
,
submitError
)
}
>
保存
</
Button
>
</
Flex
>
</
Flex
>
<
FormControl
mt=
{
5
}
>
<
FormControl
mt=
{
4
}
>
<
Flex
alignItems=
{
'center'
}
>
<
Flex
alignItems=
{
'center'
}
>
<
Box
flex=
{
'0 0 80px'
}
>
展示名称:
</
Box
>
<
Box
flex=
{
'0 0 50px'
}
w=
{
0
}
>
名称:
</
Box
>
<
Input
<
Input
{
...
register
('
name
',
{
{
...
register
('
name
',
{
required
:
'展示名称不能为空'
required
:
'展示名称不能为空'
...
@@ -88,30 +39,79 @@ const ModelEditForm = ({ model }: { model?: ModelType }) => {
...
@@ -88,30 +39,79 @@ const ModelEditForm = ({ model }: { model?: ModelType }) => {
></
Input
>
></
Input
>
</
Flex
>
</
Flex
>
</
FormControl
>
</
FormControl
>
<
FormControl
mt=
{
5
}
>
<
FormControl
mt=
{
4
}
>
<
Box
mb=
{
1
}
>
介绍:
</
Box
>
<
Textarea
rows=
{
5
}
maxLength=
{
500
}
{
...
register
('
intro
')}
placeholder=
{
'模型的介绍,仅做展示,不影响模型的效果'
}
/>
</
FormControl
>
</
Card
>
<
Card
p=
{
4
}
>
<
Box
fontWeight=
{
'bold'
}
>
模型效果
</
Box
>
<
FormControl
mt=
{
4
}
>
<
Flex
alignItems=
{
'center'
}
>
<
Flex
alignItems=
{
'center'
}
>
<
Box
flex=
{
'0 0 80px'
}
>
对话模型:
</
Box
>
<
Box
flex=
{
'0 0 80px'
}
w=
{
0
}
>
<
Box
>
{
model
?.
service
.
modelName
}
</
Box
>
<
Box
as=
{
'span'
}
mr=
{
2
}
>
温度
</
Box
>
<
Tooltip
label=
{
'温度越高,模型的发散能力越强;温度越低,内容越严谨。'
}
>
<
QuestionOutlineIcon
/>
</
Tooltip
>
</
Box
>
<
Slider
aria
-
label=
"slider-ex-1"
min=
{
1
}
max=
{
10
}
step=
{
1
}
value=
{
getValues
(
'temperature'
)
}
onChange=
{
(
e
)
=>
{
setValue
(
'temperature'
,
e
);
setRefresh
(
!
refresh
);
}
}
>
<
SliderMark
value=
{
getValues
(
'temperature'
)
}
textAlign=
"center"
bg=
"blue.500"
color=
"white"
w=
{
'18px'
}
h=
{
'18px'
}
borderRadius=
{
'100px'
}
fontSize=
{
'xs'
}
transform=
{
'translate(-50%, -200%)'
}
>
{
getValues
(
'temperature'
)
}
</
SliderMark
>
<
SliderTrack
>
<
SliderFilledTrack
/>
</
SliderTrack
>
<
SliderThumb
/>
</
Slider
>
</
Flex
>
</
Flex
>
</
FormControl
>
</
FormControl
>
<
FormControl
mt=
{
5
}
>
<
Box
mt=
{
4
}
>
<
Box
mb=
{
1
}
>
系统提示词
</
Box
>
<
Textarea
<
Textarea
rows=
{
4
}
rows=
{
6
}
maxLength=
{
500
}
maxLength=
{
500
}
{
...
register
('
systemPrompt
')}
{
...
register
('
systemPrompt
')}
placeholder=
{
placeholder=
{
'模型默认的 prompt 词,
可以通过调整该内容,生成一个限定范围的模型,更方便的去使用。
'
'模型默认的 prompt 词,
通过调整该内容,可以生成一个限定范围的模型。\n\n注意,改功能会影响对话的整体朝向!
'
}
}
/>
/>
</
FormControl
>
</
Box
>
</
Card
>
</
Card
>
<
Card
p=
{
4
}
>
<
Card
p=
{
4
}
>
<
Box
fontWeight=
{
'bold'
}
fontSize=
{
'lg'
}
>
<
Box
fontWeight=
{
'bold'
}
>
安全策略
</
Box
>
安全策略
</
Box
>
<
FormControl
mt=
{
2
}
>
<
FormControl
mt=
{
2
}
>
<
Flex
alignItems=
{
'center'
}
>
<
Flex
alignItems=
{
'center'
}
>
<
Box
flex=
{
'0 0 120px'
}
>
单句最大长度:
</
Box
>
<
Box
flex=
{
'0 0 120px'
}
w=
{
0
}
>
单句最大长度:
</
Box
>
<
Input
<
Input
flex=
{
1
}
flex=
{
1
}
type=
{
'number'
}
type=
{
'number'
}
...
@@ -132,7 +132,9 @@ const ModelEditForm = ({ model }: { model?: ModelType }) => {
...
@@ -132,7 +132,9 @@ const ModelEditForm = ({ model }: { model?: ModelType }) => {
</
FormControl
>
</
FormControl
>
<
FormControl
mt=
{
5
}
>
<
FormControl
mt=
{
5
}
>
<
Flex
alignItems=
{
'center'
}
>
<
Flex
alignItems=
{
'center'
}
>
<
Box
flex=
{
'0 0 120px'
}
>
上下文最大长度:
</
Box
>
<
Box
flex=
{
'0 0 120px'
}
w=
{
0
}
>
上下文最大长度:
</
Box
>
<
Input
<
Input
flex=
{
1
}
flex=
{
1
}
type=
{
'number'
}
type=
{
'number'
}
...
@@ -153,7 +155,9 @@ const ModelEditForm = ({ model }: { model?: ModelType }) => {
...
@@ -153,7 +155,9 @@ const ModelEditForm = ({ model }: { model?: ModelType }) => {
</
FormControl
>
</
FormControl
>
<
FormControl
mt=
{
5
}
>
<
FormControl
mt=
{
5
}
>
<
Flex
alignItems=
{
'center'
}
>
<
Flex
alignItems=
{
'center'
}
>
<
Box
flex=
{
'0 0 120px'
}
>
聊天过期时间:
</
Box
>
<
Box
flex=
{
'0 0 120px'
}
w=
{
0
}
>
聊天过期时间:
</
Box
>
<
Input
<
Input
flex=
{
1
}
flex=
{
1
}
type=
{
'number'
}
type=
{
'number'
}
...
@@ -175,7 +179,9 @@ const ModelEditForm = ({ model }: { model?: ModelType }) => {
...
@@ -175,7 +179,9 @@ const ModelEditForm = ({ model }: { model?: ModelType }) => {
</
FormControl
>
</
FormControl
>
<
FormControl
mt=
{
5
}
pb=
{
5
}
>
<
FormControl
mt=
{
5
}
pb=
{
5
}
>
<
Flex
alignItems=
{
'center'
}
>
<
Flex
alignItems=
{
'center'
}
>
<
Box
flex=
{
'0 0 130px'
}
>
聊天最大加载次数:
</
Box
>
<
Box
flex=
{
'0 0 130px'
}
w=
{
0
}
>
聊天最大加载次数:
</
Box
>
<
Box
flex=
{
1
}
>
<
Box
flex=
{
1
}
>
<
Input
<
Input
type=
{
'number'
}
type=
{
'number'
}
...
@@ -196,7 +202,7 @@ const ModelEditForm = ({ model }: { model?: ModelType }) => {
...
@@ -196,7 +202,7 @@ const ModelEditForm = ({ model }: { model?: ModelType }) => {
</
Flex
>
</
Flex
>
</
FormControl
>
</
FormControl
>
</
Card
>
</
Card
>
</
Grid
>
</>
);
);
};
};
...
...
src/pages/model/components/ModelPhoneList.tsx
View file @
00b90f07
import
React
,
{
useEffect
}
from
'react'
;
import
React
,
{
useEffect
}
from
'react'
;
import
{
Box
,
Button
,
Flex
,
Tag
}
from
'@chakra-ui/react'
;
import
{
Box
,
Button
,
Flex
,
Tag
}
from
'@chakra-ui/react'
;
import
type
{
Model
Type
}
from
'@/types/model
'
;
import
type
{
Model
Schema
}
from
'@/types/mongoSchema
'
;
import
{
formatModelStatus
}
from
'@/constants/model'
;
import
{
formatModelStatus
}
from
'@/constants/model'
;
import
dayjs
from
'dayjs'
;
import
dayjs
from
'dayjs'
;
import
{
useRouter
}
from
'next/router'
;
import
{
useRouter
}
from
'next/router'
;
...
@@ -9,7 +9,7 @@ const ModelPhoneList = ({
...
@@ -9,7 +9,7 @@ const ModelPhoneList = ({
models
,
models
,
handlePreviewChat
handlePreviewChat
}:
{
}:
{
models
:
Model
Type
[];
models
:
Model
Schema
[];
handlePreviewChat
:
(
_
:
string
)
=>
void
;
handlePreviewChat
:
(
_
:
string
)
=>
void
;
})
=>
{
})
=>
{
const
router
=
useRouter
();
const
router
=
useRouter
();
...
...
src/pages/model/components/ModelTable.tsx
View file @
00b90f07
...
@@ -14,14 +14,14 @@ import {
...
@@ -14,14 +14,14 @@ import {
}
from
'@chakra-ui/react'
;
}
from
'@chakra-ui/react'
;
import
{
formatModelStatus
}
from
'@/constants/model'
;
import
{
formatModelStatus
}
from
'@/constants/model'
;
import
dayjs
from
'dayjs'
;
import
dayjs
from
'dayjs'
;
import
type
{
Model
Type
}
from
'@/types/model
'
;
import
type
{
Model
Schema
}
from
'@/types/mongoSchema
'
;
import
{
useRouter
}
from
'next/router'
;
import
{
useRouter
}
from
'next/router'
;
const
ModelTable
=
({
const
ModelTable
=
({
models
=
[],
models
=
[],
handlePreviewChat
handlePreviewChat
}:
{
}:
{
models
:
Model
Type
[];
models
:
Model
Schema
[];
handlePreviewChat
:
(
_
:
string
)
=>
void
;
handlePreviewChat
:
(
_
:
string
)
=>
void
;
})
=>
{
})
=>
{
const
router
=
useRouter
();
const
router
=
useRouter
();
...
@@ -34,13 +34,13 @@ const ModelTable = ({
...
@@ -34,13 +34,13 @@ const ModelTable = ({
{
{
title
:
'最后更新时间'
,
title
:
'最后更新时间'
,
key
:
'updateTime'
,
key
:
'updateTime'
,
render
:
(
item
:
Model
Type
)
=>
dayjs
(
item
.
updateTime
).
format
(
'YYYY-MM-DD HH:mm'
)
render
:
(
item
:
Model
Schema
)
=>
dayjs
(
item
.
updateTime
).
format
(
'YYYY-MM-DD HH:mm'
)
},
},
{
{
title
:
'状态'
,
title
:
'状态'
,
key
:
'status'
,
key
:
'status'
,
dataIndex
:
'status'
,
dataIndex
:
'status'
,
render
:
(
item
:
Model
Type
)
=>
(
render
:
(
item
:
Model
Schema
)
=>
(
<
Tag
<
Tag
colorScheme=
{
formatModelStatus
[
item
.
status
].
colorTheme
}
colorScheme=
{
formatModelStatus
[
item
.
status
].
colorTheme
}
variant=
"solid"
variant=
"solid"
...
@@ -54,7 +54,7 @@ const ModelTable = ({
...
@@ -54,7 +54,7 @@ const ModelTable = ({
{
{
title
:
'AI模型'
,
title
:
'AI模型'
,
key
:
'service'
,
key
:
'service'
,
render
:
(
item
:
Model
Type
)
=>
(
render
:
(
item
:
Model
Schema
)
=>
(
<
Box
wordBreak=
{
'break-all'
}
whiteSpace=
{
'pre-wrap'
}
maxW=
{
'200px'
}
>
<
Box
wordBreak=
{
'break-all'
}
whiteSpace=
{
'pre-wrap'
}
maxW=
{
'200px'
}
>
{
item
.
service
.
modelName
}
{
item
.
service
.
modelName
}
</
Box
>
</
Box
>
...
@@ -68,7 +68,7 @@ const ModelTable = ({
...
@@ -68,7 +68,7 @@ const ModelTable = ({
{
{
title
:
'操作'
,
title
:
'操作'
,
key
:
'control'
,
key
:
'control'
,
render
:
(
item
:
Model
Type
)
=>
(
render
:
(
item
:
Model
Schema
)
=>
(
<>
<>
<
Button
mr=
{
3
}
onClick=
{
()
=>
handlePreviewChat
(
item
.
_id
)
}
>
<
Button
mr=
{
3
}
onClick=
{
()
=>
handlePreviewChat
(
item
.
_id
)
}
>
对话
对话
...
...
src/pages/model/components/Training.tsx
View file @
00b90f07
import
React
,
{
useEffect
,
useCallback
,
useState
}
from
'react'
;
import
React
,
{
useEffect
,
useCallback
,
useState
}
from
'react'
;
import
{
Box
,
TableContainer
,
Table
,
Thead
,
Tbody
,
Tr
,
Th
,
Td
}
from
'@chakra-ui/react'
;
import
{
Box
,
TableContainer
,
Table
,
Thead
,
Tbody
,
Tr
,
Th
,
Td
}
from
'@chakra-ui/react'
;
import
{
ModelType
}
from
'@/types/model
'
;
import
type
{
ModelSchema
}
from
'@/types/mongoSchema
'
;
import
{
getModelTrainings
}
from
'@/api/model'
;
import
{
getModelTrainings
}
from
'@/api/model'
;
import
type
{
TrainingItemType
}
from
'@/types/training'
;
import
type
{
TrainingItemType
}
from
'@/types/training'
;
const
Training
=
({
model
}:
{
model
:
Model
Type
})
=>
{
const
Training
=
({
model
}:
{
model
:
Model
Schema
})
=>
{
const
columns
:
{
const
columns
:
{
title
:
string
;
title
:
string
;
key
:
keyof
TrainingItemType
;
key
:
keyof
TrainingItemType
;
...
...
src/pages/model/detail.tsx
View file @
00b90f07
import
React
,
{
useCallback
,
useState
,
use
Effect
,
useRef
,
useMemo
}
from
'react'
;
import
React
,
{
useCallback
,
useState
,
use
Ref
,
useMemo
,
useEffect
}
from
'react'
;
import
{
useRouter
}
from
'next/router'
;
import
{
useRouter
}
from
'next/router'
;
import
{
getModelById
,
delModelById
,
postTrainModel
,
putModelTrainingStatus
}
from
'@/api/model'
;
import
{
getModelById
,
delModelById
,
postTrainModel
,
putModelTrainingStatus
,
putModelById
}
from
'@/api/model'
;
import
{
getChatSiteId
}
from
'@/api/chat'
;
import
{
getChatSiteId
}
from
'@/api/chat'
;
import
type
{
Model
Type
}
from
'@/types/model
'
;
import
type
{
Model
Schema
}
from
'@/types/mongoSchema
'
;
import
{
Card
,
Box
,
Flex
,
Button
,
Tag
,
Grid
}
from
'@chakra-ui/react'
;
import
{
Card
,
Box
,
Flex
,
Button
,
Tag
,
Grid
}
from
'@chakra-ui/react'
;
import
{
useToast
}
from
'@/hooks/useToast'
;
import
{
useToast
}
from
'@/hooks/useToast'
;
import
{
useConfirm
}
from
'@/hooks/useConfirm'
;
import
{
useConfirm
}
from
'@/hooks/useConfirm'
;
import
{
formatModelStatus
,
ModelStatusEnum
,
OpenAiList
}
from
'@/constants/model'
;
import
{
useForm
}
from
'react-hook-form'
;
import
{
formatModelStatus
,
ModelStatusEnum
,
ModelList
,
defaultModel
}
from
'@/constants/model'
;
import
{
useGlobalStore
}
from
'@/store/global'
;
import
{
useGlobalStore
}
from
'@/store/global'
;
import
{
useScreen
}
from
'@/hooks/useScreen'
;
import
{
useScreen
}
from
'@/hooks/useScreen'
;
import
ModelEditForm
from
'./components/ModelEditForm'
;
import
ModelEditForm
from
'./components/ModelEditForm'
;
import
Icon
from
'@/components/Iconfont'
;
import
Icon
from
'@/components/Iconfont'
;
import
{
useQuery
}
from
'@tanstack/react-query'
;
import
dynamic
from
'next/dynamic'
;
import
dynamic
from
'next/dynamic'
;
const
Training
=
dynamic
(()
=>
import
(
'./components/Training'
));
const
Training
=
dynamic
(()
=>
import
(
'./components/Training'
));
const
ModelDetail
=
()
=>
{
const
ModelDetail
=
(
{
modelId
}:
{
modelId
:
string
}
)
=>
{
const
{
toast
}
=
useToast
();
const
{
toast
}
=
useToast
();
const
router
=
useRouter
();
const
router
=
useRouter
();
const
{
isPc
,
media
}
=
useScreen
();
const
{
isPc
,
media
}
=
useScreen
();
...
@@ -24,33 +32,35 @@ const ModelDetail = () => {
...
@@ -24,33 +32,35 @@ const ModelDetail = () => {
content
:
'确认删除该模型?'
content
:
'确认删除该模型?'
});
});
const
SelectFileDom
=
useRef
<
HTMLInputElement
>
(
null
);
const
SelectFileDom
=
useRef
<
HTMLInputElement
>
(
null
);
const
[
model
,
setModel
]
=
useState
<
ModelSchema
>
(
defaultModel
);
const
{
modelId
}
=
router
.
query
as
{
modelId
:
string
};
const
formHooks
=
useForm
<
ModelSchema
>
({
const
[
model
,
setModel
]
=
useState
<
ModelType
>
();
defaultValues
:
model
});
const
canTrain
=
useMemo
(()
=>
{
const
canTrain
=
useMemo
(()
=>
{
const
openai
=
OpenAiList
.
find
((
item
)
=>
item
.
model
===
model
?.
service
.
modelName
);
const
openai
=
ModelList
[
model
.
service
.
company
].
find
(
return
openai
&&
openai
.
canTraining
===
true
;
(
item
)
=>
item
.
model
===
model
?.
service
.
modelName
);
return
openai
&&
openai
.
trainName
;
},
[
model
]);
},
[
model
]);
/* 加载模型数据 */
/* 加载模型数据 */
const
loadModel
=
useCallback
(
async
()
=>
{
const
loadModel
=
useCallback
(
async
()
=>
{
if
(
!
modelId
)
return
;
setLoading
(
true
);
setLoading
(
true
);
try
{
try
{
const
res
=
await
getModelById
(
modelId
as
string
);
const
res
=
await
getModelById
(
modelId
);
console
.
log
(
res
);
res
.
security
.
expiredTime
/=
60
*
60
*
1000
;
res
.
security
.
expiredTime
/=
60
*
60
*
1000
;
setModel
(
res
);
setModel
(
res
);
formHooks
.
reset
(
res
);
}
catch
(
err
)
{
}
catch
(
err
)
{
console
.
log
(
'error->'
,
err
);
console
.
log
(
'error->'
,
err
);
}
}
setLoading
(
false
);
setLoading
(
false
);
},
[
modelId
,
setLoading
]);
return
null
;
},
[
formHooks
,
modelId
,
setLoading
]);
useEffect
(()
=>
{
useQuery
([
modelId
],
loadModel
);
loadModel
();
router
.
prefetch
(
'/chat'
);
},
[
loadModel
,
modelId
,
router
]);
/* 点击删除 */
/* 点击删除 */
const
handleDelModel
=
useCallback
(
async
()
=>
{
const
handleDelModel
=
useCallback
(
async
()
=>
{
...
@@ -71,7 +81,6 @@ const ModelDetail = () => {
...
@@ -71,7 +81,6 @@ const ModelDetail = () => {
/* 点前往聊天预览页 */
/* 点前往聊天预览页 */
const
handlePreviewChat
=
useCallback
(
async
()
=>
{
const
handlePreviewChat
=
useCallback
(
async
()
=>
{
if
(
!
model
)
return
;
setLoading
(
true
);
setLoading
(
true
);
try
{
try
{
const
chatId
=
await
getChatSiteId
(
model
.
_id
);
const
chatId
=
await
getChatSiteId
(
model
.
_id
);
...
@@ -131,6 +140,65 @@ const ModelDetail = () => {
...
@@ -131,6 +140,65 @@ const ModelDetail = () => {
setLoading
(
false
);
setLoading
(
false
);
},
[
model
,
setLoading
,
loadModel
,
toast
]);
},
[
model
,
setLoading
,
loadModel
,
toast
]);
// 提交保存模型修改
const
saveSubmitSuccess
=
useCallback
(
async
(
data
:
ModelSchema
)
=>
{
setLoading
(
true
);
try
{
await
putModelById
(
data
.
_id
,
{
name
:
data
.
name
,
systemPrompt
:
data
.
systemPrompt
,
intro
:
data
.
intro
,
temperature
:
data
.
temperature
,
service
:
data
.
service
,
security
:
data
.
security
});
toast
({
title
:
'更新成功'
,
status
:
'success'
});
}
catch
(
err
)
{
console
.
log
(
'error->'
,
err
);
toast
({
title
:
err
as
string
,
status
:
'success'
});
}
setLoading
(
false
);
},
[
setLoading
,
toast
]
);
// 提交保存表单失败
const
saveSubmitError
=
useCallback
(()
=>
{
// deep search message
const
deepSearch
=
(
obj
:
any
):
string
=>
{
if
(
!
obj
)
return
'提交表单错误'
;
if
(
!!
obj
.
message
)
{
return
obj
.
message
;
}
return
deepSearch
(
Object
.
values
(
obj
)[
0
]);
};
toast
({
title
:
deepSearch
(
formHooks
.
formState
.
errors
),
status
:
'error'
,
duration
:
4000
,
isClosable
:
true
});
},
[
formHooks
.
formState
.
errors
,
toast
]);
useEffect
(()
=>
{
router
.
prefetch
(
'/chat'
);
window
.
onbeforeunload
=
(
e
)
=>
{
e
.
preventDefault
();
e
.
returnValue
=
'内容已修改,确认离开页面吗?'
;
};
return
()
=>
{
window
.
onbeforeunload
=
null
;
};
},
[]);
return
(
return
(
<>
<>
{
/* 头部 */
}
{
/* 头部 */
}
...
@@ -138,9 +206,8 @@ const ModelDetail = () => {
...
@@ -138,9 +206,8 @@ const ModelDetail = () => {
{
isPc
?
(
{
isPc
?
(
<
Flex
alignItems=
{
'center'
}
>
<
Flex
alignItems=
{
'center'
}
>
<
Box
fontSize=
{
'xl'
}
fontWeight=
{
'bold'
}
>
<
Box
fontSize=
{
'xl'
}
fontWeight=
{
'bold'
}
>
{
model
?.
name
||
'模型'
}
配置
{
model
.
name
}
</
Box
>
</
Box
>
{
!!
model
&&
(
<
Tag
<
Tag
ml=
{
2
}
ml=
{
2
}
variant=
"solid"
variant=
"solid"
...
@@ -150,38 +217,37 @@ const ModelDetail = () => {
...
@@ -150,38 +217,37 @@ const ModelDetail = () => {
>
>
{
formatModelStatus
[
model
.
status
].
text
}
{
formatModelStatus
[
model
.
status
].
text
}
</
Tag
>
</
Tag
>
)
}
<
Box
flex=
{
1
}
/>
<
Box
flex=
{
1
}
/>
<
Button
variant=
{
'outline'
}
onClick=
{
handlePreviewChat
}
>
<
Button
variant=
{
'outline'
}
onClick=
{
handlePreviewChat
}
>
对话体验
对话体验
</
Button
>
</
Button
>
<
Button
ml=
{
4
}
onClick=
{
formHooks
.
handleSubmit
(
saveSubmitSuccess
,
saveSubmitError
)
}
>
保存修改
</
Button
>
</
Flex
>
</
Flex
>
)
:
(
)
:
(
<>
<>
<
Flex
alignItems=
{
'center'
}
>
<
Flex
alignItems=
{
'center'
}
>
<
Box
as=
{
'h3'
}
fontSize=
{
'xl'
}
fontWeight=
{
'bold'
}
flex=
{
1
}
>
<
Box
as=
{
'h3'
}
fontSize=
{
'xl'
}
fontWeight=
{
'bold'
}
flex=
{
1
}
>
{
model
?.
name
||
'模型'
}
配置
{
model
?.
name
}
</
Box
>
</
Box
>
{
!!
model
&&
(
<
Tag
ml=
{
2
}
colorScheme=
{
formatModelStatus
[
model
.
status
].
colorTheme
}
>
<
Tag
ml=
{
2
}
colorScheme=
{
formatModelStatus
[
model
.
status
].
colorTheme
}
>
{
formatModelStatus
[
model
.
status
].
text
}
{
formatModelStatus
[
model
.
status
].
text
}
</
Tag
>
</
Tag
>
)
}
</
Flex
>
</
Flex
>
<
Box
mt=
{
4
}
textAlign=
{
'right'
}
>
<
Box
mt=
{
4
}
textAlign=
{
'right'
}
>
<
Button
variant=
{
'outline'
}
onClick=
{
handlePreviewChat
}
>
<
Button
variant=
{
'outline'
}
onClick=
{
handlePreviewChat
}
>
对话体验
对话体验
</
Button
>
</
Button
>
<
Button
ml=
{
4
}
onClick=
{
formHooks
.
handleSubmit
(
saveSubmitSuccess
,
saveSubmitError
)
}
>
保存修改
</
Button
>
</
Box
>
</
Box
>
</>
</>
)
}
)
}
</
Card
>
</
Card
>
{
/* 基本信息编辑 */
}
<
Box
mt=
{
5
}
>
<
ModelEditForm
model=
{
model
}
/>
</
Box
>
{
/* 其他配置 */
}
<
Grid
mt=
{
5
}
gridTemplateColumns=
{
media
(
'1fr 1fr'
,
'1fr'
)
}
gridGap=
{
5
}
>
<
Grid
mt=
{
5
}
gridTemplateColumns=
{
media
(
'1fr 1fr'
,
'1fr'
)
}
gridGap=
{
5
}
>
<
ModelEditForm
formHooks=
{
formHooks
}
/>
<
Card
p=
{
4
}
>
{
!!
model
&&
<
Training
model=
{
model
}
/>
}
</
Card
>
<
Card
p=
{
4
}
>
{
!!
model
&&
<
Training
model=
{
model
}
/>
}
</
Card
>
<
Card
p=
{
4
}
>
<
Card
p=
{
4
}
>
<
Box
fontWeight=
{
'bold'
}
fontSize=
{
'lg'
}
>
<
Box
fontWeight=
{
'bold'
}
fontSize=
{
'lg'
}
>
...
@@ -241,6 +307,8 @@ const ModelDetail = () => {
...
@@ -241,6 +307,8 @@ const ModelDetail = () => {
</
Flex
>
</
Flex
>
</
Card
>
</
Card
>
</
Grid
>
</
Grid
>
{
/* 文件选择 */
}
<
Box
position=
{
'absolute'
}
w=
{
0
}
h=
{
0
}
overflow=
{
'hidden'
}
>
<
Box
position=
{
'absolute'
}
w=
{
0
}
h=
{
0
}
overflow=
{
'hidden'
}
>
<
input
ref=
{
SelectFileDom
}
type=
"file"
accept=
".jsonl"
onChange=
{
startTraining
}
/>
<
input
ref=
{
SelectFileDom
}
type=
"file"
accept=
".jsonl"
onChange=
{
startTraining
}
/>
</
Box
>
</
Box
>
...
@@ -250,3 +318,11 @@ const ModelDetail = () => {
...
@@ -250,3 +318,11 @@ const ModelDetail = () => {
};
};
export
default
ModelDetail
;
export
default
ModelDetail
;
export
async
function
getServerSideProps
(
context
:
any
)
{
const
modelId
=
context
.
query
?.
modelId
||
''
;
return
{
props
:
{
modelId
}
};
}
src/pages/model/list.tsx
View file @
00b90f07
import
React
,
{
useState
,
useCallback
}
from
'react'
;
import
React
,
{
useState
,
useCallback
}
from
'react'
;
import
{
Box
,
Button
,
Flex
,
Card
}
from
'@chakra-ui/react'
;
import
{
Box
,
Button
,
Flex
,
Card
}
from
'@chakra-ui/react'
;
import
{
getChatSiteId
}
from
'@/api/chat'
;
import
{
getChatSiteId
}
from
'@/api/chat'
;
import
{
ModelType
}
from
'@/types/model
'
;
import
type
{
ModelSchema
}
from
'@/types/mongoSchema
'
;
import
{
useRouter
}
from
'next/router'
;
import
{
useRouter
}
from
'next/router'
;
import
ModelTable
from
'./components/ModelTable'
;
import
ModelTable
from
'./components/ModelTable'
;
import
ModelPhoneList
from
'./components/ModelPhoneList'
;
import
ModelPhoneList
from
'./components/ModelPhoneList'
;
...
@@ -27,7 +27,7 @@ const ModelList = () => {
...
@@ -27,7 +27,7 @@ const ModelList = () => {
/* 创建成功回调 */
/* 创建成功回调 */
const
createModelSuccess
=
useCallback
(
const
createModelSuccess
=
useCallback
(
(
data
:
Model
Type
)
=>
{
(
data
:
Model
Schema
)
=>
{
setMyModels
([
data
,
...
myModels
]);
setMyModels
([
data
,
...
myModels
]);
},
},
[
myModels
,
setMyModels
]
[
myModels
,
setMyModels
]
...
...
src/service/models/chat.ts
View file @
00b90f07
...
@@ -25,7 +25,8 @@ const ChatSchema = new Schema({
...
@@ -25,7 +25,8 @@ const ChatSchema = new Schema({
type
:
Number
,
type
:
Number
,
required
:
true
required
:
true
},
},
content
:
[
content
:
{
type
:
[
{
{
obj
:
{
obj
:
{
type
:
String
,
type
:
String
,
...
@@ -37,7 +38,9 @@ const ChatSchema = new Schema({
...
@@ -37,7 +38,9 @@ const ChatSchema = new Schema({
required
:
true
required
:
true
}
}
}
}
]
],
default
:
[]
}
});
});
export
const
Chat
=
models
[
'chat'
]
||
model
(
'chat'
,
ChatSchema
);
export
const
Chat
=
models
[
'chat'
]
||
model
(
'chat'
,
ChatSchema
);
src/service/models/model.ts
View file @
00b90f07
import
{
Schema
,
model
,
models
}
from
'mongoose'
;
import
{
Schema
,
model
,
models
}
from
'mongoose'
;
const
ModelSchema
=
new
Schema
({
const
ModelSchema
=
new
Schema
({
userId
:
{
type
:
Schema
.
Types
.
ObjectId
,
ref
:
'user'
,
required
:
true
},
name
:
{
name
:
{
type
:
String
,
type
:
String
,
required
:
true
required
:
true
...
@@ -10,13 +15,14 @@ const ModelSchema = new Schema({
...
@@ -10,13 +15,14 @@ const ModelSchema = new Schema({
default
:
'/imgs/modelAvatar.png'
default
:
'/imgs/modelAvatar.png'
},
},
systemPrompt
:
{
systemPrompt
:
{
// 系统提示词
type
:
String
,
type
:
String
,
default
:
''
default
:
''
},
},
userId
:
{
intro
:
{
type
:
Schema
.
Types
.
ObjectId
,
// 模型介绍
ref
:
'user'
,
type
:
String
,
required
:
true
default
:
''
},
},
status
:
{
status
:
{
type
:
String
,
type
:
String
,
...
@@ -31,6 +37,12 @@ const ModelSchema = new Schema({
...
@@ -31,6 +37,12 @@ const ModelSchema = new Schema({
type
:
Number
,
type
:
Number
,
default
:
0
default
:
0
},
},
temperature
:
{
type
:
Number
,
min
:
1
,
max
:
10
,
default
:
5
},
service
:
{
service
:
{
company
:
{
company
:
{
type
:
String
,
type
:
String
,
...
...
src/store/user.ts
View file @
00b90f07
...
@@ -2,7 +2,7 @@ import { create } from 'zustand';
...
@@ -2,7 +2,7 @@ import { create } from 'zustand';
import
{
devtools
}
from
'zustand/middleware'
;
import
{
devtools
}
from
'zustand/middleware'
;
import
{
immer
}
from
'zustand/middleware/immer'
;
import
{
immer
}
from
'zustand/middleware/immer'
;
import
type
{
UserType
,
UserUpdateParams
}
from
'@/types/user'
;
import
type
{
UserType
,
UserUpdateParams
}
from
'@/types/user'
;
import
type
{
Model
Type
}
from
'@/types/model
'
;
import
type
{
Model
Schema
}
from
'@/types/mongoSchema
'
;
import
{
setToken
}
from
'@/utils/user'
;
import
{
setToken
}
from
'@/utils/user'
;
import
{
getMyModels
}
from
'@/api/model'
;
import
{
getMyModels
}
from
'@/api/model'
;
...
@@ -10,9 +10,9 @@ type State = {
...
@@ -10,9 +10,9 @@ type State = {
userInfo
:
UserType
|
null
;
userInfo
:
UserType
|
null
;
setUserInfo
:
(
user
:
UserType
,
token
?:
string
)
=>
void
;
setUserInfo
:
(
user
:
UserType
,
token
?:
string
)
=>
void
;
updateUserInfo
:
(
user
:
UserUpdateParams
)
=>
void
;
updateUserInfo
:
(
user
:
UserUpdateParams
)
=>
void
;
myModels
:
Model
Type
[];
myModels
:
Model
Schema
[];
getMyModels
:
()
=>
void
;
getMyModels
:
()
=>
void
;
setMyModels
:
(
data
:
Model
Type
[])
=>
void
;
setMyModels
:
(
data
:
Model
Schema
[])
=>
void
;
};
};
export
const
useUserStore
=
create
<
State
>
()(
export
const
useUserStore
=
create
<
State
>
()(
...
@@ -42,7 +42,7 @@ export const useUserStore = create<State>()(
...
@@ -42,7 +42,7 @@ export const useUserStore = create<State>()(
});
});
return
res
;
return
res
;
}),
}),
setMyModels
(
data
:
Model
Type
[])
{
setMyModels
(
data
:
Model
Schema
[])
{
set
((
state
)
=>
{
set
((
state
)
=>
{
state
.
myModels
=
data
;
state
.
myModels
=
data
;
});
});
...
...
src/types/chat.d.ts
View file @
00b90f07
import
type
{
ModelType
}
from
'./model'
;
export
type
ChatItemType
=
{
export
type
ChatItemType
=
{
obj
:
'Human'
|
'AI'
|
'SYSTEM'
;
obj
:
'Human'
|
'AI'
|
'SYSTEM'
;
value
:
string
;
value
:
string
;
...
...
src/types/model.d.ts
View file @
00b90f07
import
{
ModelStatusEnum
}
from
'@/constants/model'
;
import
{
ModelStatusEnum
}
from
'@/constants/model'
;
export
interface
ModelType
{
import
type
{
ModelSchema
}
from
'./mongoSchema'
;
_id
:
string
;
userId
:
string
;
name
:
string
;
avatar
:
string
;
status
:
`
${
ModelStatusEnum
}
`
;
updateTime
:
Date
;
trainingTimes
:
number
;
systemPrompt
:
string
;
service
:
{
company
:
'openai'
;
// 关联的厂商
trainId
:
string
;
// 训练时需要的ID
chatModel
:
string
;
// 聊天时用的模型
modelName
:
string
;
// 关联的模型
};
security
:
{
domain
:
string
[];
contentMaxLen
:
number
;
contextMaxLen
:
number
;
expiredTime
:
number
;
maxLoadAmount
:
number
;
};
}
export
interface
ModelUpdateParams
{
export
interface
ModelUpdateParams
{
name
:
string
;
name
:
string
;
systemPrompt
:
string
;
systemPrompt
:
string
;
service
:
{
intro
:
string
;
company
:
'openai'
;
// 关联的厂商
temperature
:
number
;
modelName
:
string
;
// 关联的模型
service
:
ModelSchema
.
service
;
};
security
:
ModelSchema
.
security
;
security
:
{
domain
:
string
[];
contentMaxLen
:
number
;
contextMaxLen
:
number
;
expiredTime
:
number
;
maxLoadAmount
:
number
;
};
}
}
src/types/mongoSchema.d.ts
View file @
00b90f07
...
@@ -25,15 +25,17 @@ export interface ModelSchema {
...
@@ -25,15 +25,17 @@ export interface ModelSchema {
name
:
string
;
name
:
string
;
avatar
:
string
;
avatar
:
string
;
systemPrompt
:
string
;
systemPrompt
:
string
;
intro
:
string
;
userId
:
string
;
userId
:
string
;
status
:
`
${
ModelStatusEnum
}
`
;
status
:
`
${
ModelStatusEnum
}
`
;
updateTime
:
number
;
updateTime
:
number
;
trainingTimes
:
number
;
trainingTimes
:
number
;
temperature
:
number
;
service
:
{
service
:
{
company
:
ServiceName
;
company
:
ServiceName
;
trainId
:
string
;
trainId
:
string
;
// 训练的模型,训练后就是训练的模型id
chatModel
:
`
${
ChatModelNameEnum
}
`
;
chatModel
:
string
;
// 聊天时用的模型,训练后就是训练的模型
modelName
:
string
;
modelName
:
`
${
ChatModelNameEnum
}
`
;
// 底层模型名称,不会变
};
};
security
:
{
security
:
{
domain
:
string
[];
domain
:
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