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
6ce727f9
authored
Mar 24, 2023
by
archer
Browse files
Options
Browse Files
Download
Plain Diff
fix: conflict
parents
af35e17f
81e68211
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
226 additions
and
24 deletions
+226
-24
src/constants/common.ts
+4
-3
src/constants/model.ts
+1
-1
src/pages/api/chat/chatGpt.ts
+2
-2
src/pages/api/chat/gpt3.ts
+2
-2
src/pages/api/model/create.ts
+2
-2
src/pages/api/train/generateQA.ts
+103
-0
src/pages/model/components/CreateModel.tsx
+4
-4
src/pages/model/detail.tsx
+2
-2
src/pages/model/list.tsx
+2
-2
src/pages/number/components/PayModal.tsx
+30
-2
src/pages/number/setting.tsx
+3
-0
src/service/events/bill.ts
+10
-3
src/service/models/data.ts
+27
-0
src/service/mongo.ts
+1
-0
src/service/utils/tools.ts
+33
-1
No files found.
src/constants/common.ts
View file @
6ce727f9
...
...
@@ -8,11 +8,12 @@ export const introPage = `
[Git 仓库](https://github.com/c121914yu/FastGPT)
时间比较赶,介绍没来得及完善,先直接上怎么使用:
### 快速开始
1. 使用邮箱注册账号。
2. 进入账号页面,添加关联账号,目前只有 openai 的账号可以添加,直接去 openai 官网,把 API Key 粘贴过来。
3. 进入模型页,创建一个模型,建议直接用 ChatGPT。
4. 在模型列表点击【对话】,即可使用 API 进行聊天。
3. 如果填写了自己的 openai 账号,使用时会直接用你的账号。如果没有填写,需要付费使用平台的账号。
4. 进入模型页,创建一个模型,建议直接用 ChatGPT。
5. 在模型列表点击【对话】,即可使用 API 进行聊天。
### 模型配置
...
...
src/constants/model.ts
View file @
6ce727f9
...
...
@@ -16,7 +16,7 @@ export type ModelConstantsData = {
price
:
number
;
// 多少钱 / 1字,单位: 0.00001元
};
export
const
M
odelList
:
ModelConstantsData
[]
=
[
export
const
m
odelList
:
ModelConstantsData
[]
=
[
{
serviceCompany
:
'openai'
,
name
:
'chatGPT'
,
...
...
src/pages/api/chat/chatGpt.ts
View file @
6ce727f9
...
...
@@ -8,7 +8,7 @@ import { ChatItemType } from '@/types/chat';
import
{
jsonRes
}
from
'@/service/response'
;
import
type
{
ModelSchema
}
from
'@/types/mongoSchema'
;
import
{
PassThrough
}
from
'stream'
;
import
{
M
odelList
}
from
'@/constants/model'
;
import
{
m
odelList
}
from
'@/constants/model'
;
import
{
pushBill
}
from
'@/service/events/bill'
;
/* 发送提示词 */
...
...
@@ -74,7 +74,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
}
// 计算温度
const
modelConstantsData
=
M
odelList
.
find
((
item
)
=>
item
.
model
===
model
.
service
.
modelName
);
const
modelConstantsData
=
m
odelList
.
find
((
item
)
=>
item
.
model
===
model
.
service
.
modelName
);
if
(
!
modelConstantsData
)
{
throw
new
Error
(
'模型异常'
);
}
...
...
src/pages/api/chat/gpt3.ts
View file @
6ce727f9
...
...
@@ -5,7 +5,7 @@ import { connectToDatabase } from '@/service/mongo';
import
{
getOpenAIApi
,
authChat
}
from
'@/service/utils/chat'
;
import
{
ChatItemType
}
from
'@/types/chat'
;
import
{
httpsAgent
}
from
'@/service/utils/tools'
;
import
{
M
odelList
}
from
'@/constants/model'
;
import
{
m
odelList
}
from
'@/constants/model'
;
import
{
pushBill
}
from
'@/service/events/bill'
;
/* 发送提示词 */
...
...
@@ -31,7 +31,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const
formatPrompts
=
prompt
.
map
((
item
)
=>
`
${
item
.
value
}
\n\n###\n\n`
).
join
(
''
);
// 计算温度
const
modelConstantsData
=
M
odelList
.
find
((
item
)
=>
item
.
model
===
model
.
service
.
modelName
);
const
modelConstantsData
=
m
odelList
.
find
((
item
)
=>
item
.
model
===
model
.
service
.
modelName
);
if
(
!
modelConstantsData
)
{
throw
new
Error
(
'模型异常'
);
}
...
...
src/pages/api/model/create.ts
View file @
6ce727f9
...
...
@@ -3,7 +3,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import
{
jsonRes
}
from
'@/service/response'
;
import
{
connectToDatabase
}
from
'@/service/mongo'
;
import
{
authToken
}
from
'@/service/utils/tools'
;
import
{
ModelStatusEnum
,
M
odelList
,
ChatModelNameEnum
}
from
'@/constants/model'
;
import
{
ModelStatusEnum
,
m
odelList
,
ChatModelNameEnum
}
from
'@/constants/model'
;
import
{
Model
}
from
'@/service/models/model'
;
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
<
any
>
)
{
...
...
@@ -25,7 +25,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
// 凭证校验
const
userId
=
await
authToken
(
authorization
);
const
modelItem
=
M
odelList
.
find
((
item
)
=>
item
.
model
===
serviceModelName
);
const
modelItem
=
m
odelList
.
find
((
item
)
=>
item
.
model
===
serviceModelName
);
if
(
!
modelItem
)
{
throw
new
Error
(
'模型不存在'
);
...
...
src/pages/api/train/generateQA.ts
0 → 100644
View file @
6ce727f9
import
type
{
NextApiRequest
,
NextApiResponse
}
from
'next'
;
import
{
jsonRes
}
from
'@/service/response'
;
import
{
connectToDatabase
,
Data
}
from
'@/service/mongo'
;
import
{
getOpenAIApi
}
from
'@/service/utils/chat'
;
import
{
httpsAgent
,
getOpenApiKey
}
from
'@/service/utils/tools'
;
import
type
{
ChatCompletionRequestMessage
,
CreateChatCompletionResponse
}
from
'openai'
;
import
fs
from
'fs'
;
import
{
v4
}
from
'uuid'
;
/* 定时删除那些不活跃的内容 */
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
)
{
const
systemPrompt
:
ChatCompletionRequestMessage
=
{
role
:
'system'
,
content
:
`总结助手。我会向你发送一段长文本,请从中总结出10个以上问题和答案,并转化成中文!请按以下格式返回:
"Q1:"
"A1:"
######
"Q2:"
"A2:"
######
`
};
try
{
const
{
text
}
=
req
.
body
as
{
text
:
string
};
const
{
authorization
}
=
req
.
headers
;
const
replaceText
=
text
.
replace
(
/
\n
/g
,
' '
);
await
connectToDatabase
();
const
{
userId
,
userApiKey
,
systemKey
}
=
await
getOpenApiKey
(
authorization
);
const
chatAPI
=
getOpenAIApi
(
userApiKey
||
systemKey
);
const
docId
=
v4
();
const
queue
:
{
requestPrompts
:
ChatCompletionRequestMessage
;
temperature
:
number
;
}[]
=
[
{
requestPrompts
:
{
role
:
'user'
,
content
:
`跟 AI ChatGPT 聊了 11 个我过去关心的话题\n原创 刘飞Lufy 刘言飞语 2022-12-05 21:40 发表于浙江\n收录于合集\n#行业观察\n33\n个\n#AIGC\n11\n个\n\n\n\n\n这几天沉浸式体验 ChatGPT(OpenAI发布的一款人工智能对话引擎),突发奇想,想知道它对我曾经聊的话题都怎么看。于是我用一些过去公众号发过的文章主题,跟它进行了一轮对话。\n\n以下是我们聊天的内容原始记录,没有做文字篡改,为方便没有用截图,做了文本排版。各位可以直观体会下它的智能程度。\n\n\n(本文内容都是在以上这样的界面里完成的)\n\n\n——\n\n参考:微信搜索的未来\n\n刘飞:\n\n微信搜索现在的使用量大吗?\n\nChatGPT:\n\n微信搜索是一项非常流行的功能,它可以帮助用户快速搜索到想要的信息。由于微信是中国最流行的社交软件,微信搜索的使用量也非常大。根据官方数据,截至2022年,微信的日活跃用户数量已经超过10亿,其中,每天都会有大量用户使用微信搜索功能搜索各种信息。因此,微信搜索的使用量非常大。\n\n刘飞:\n\n跟百度搜索比呢?\n\nChatGPT:\n\n微信搜索和百度搜索都是帮助用户快速搜索到想要的信息的工具。但是,两者有着明显的不同。\n\n首先,微信搜索和百度搜索的使用场景不同。微信搜索主要用于社交场景,因此,它更多地用于搜索好友、群聊、文章等信息,而百度搜索则更加注重为用户提供更丰富的信息,因此它更多地用于搜索各种知识信息和新闻信息。\n\n\n其次,微信搜索和百度搜索的搜索结果也不同。微信搜索的搜索结果主要是来自用户自己的微信聊天记录和朋友圈发布的信息,而百度搜索的搜索结果则是来自互联网上的各种信息,包括网站、新闻、论坛等。因此,微信搜索的搜索结果更加个性化,而百度搜索的搜索结果则更加全面。\n\n总之,微信搜索和百度搜索都是帮助用户快速搜索到想要的信息的工具,但是它们在使用场景、搜索结果等方面存在明显的差异。\n\n刘飞:\n\n那字节跳动的搜索跟它们相比呢?\n\nChatGPT:\n\n字节跳动的搜索也是一款帮助用户快速搜索到想要的信息的工具。但是,字节跳动的搜索主要是针对短视频内容而设计的,因此,它的搜索结果主要是来自抖音、头条等短视频平台上的视频内容。与微信搜索和百度搜索相比,字节跳动的搜索更加专注于短视频内容,并且搜索结果也更加丰富多样。\n\n——\n\n\n参考:我们离财务自由的距离\n\n\n刘飞:\n\n怎样才算财务自由?\n\nChatGPT:\n\n财务自由是指一个人在不必工作的情况下,能够通过自己的财富维持生活的质量和生活水平。通常情况下,一个人可以通过节约开支、投资理财等方式来实现财务自由。\n\n具体来说,要达到财务自由,一个人需要符合以下几个条件:\n\n\n实现收入和支出平衡。要想实现财务自由,首先需要通过节约开支来控制支出,并通过提高收入来提升生活水平。\n\n\n建立良好的投资理财计划。要想实现财务自由,需要通过投资理财来增加财富的增长速度,并且要有一个完善的理财计划来指导投资决策。\n\n\n控制风险。在投资理财的过程中,要尽量降低风险,并通过多样化投资来降低投资的风险。`
},
temperature
:
0.5
}
];
/**
* 生成QA
*/
const
generateQA
=
async
()
=>
{
const
prompt
=
queue
.
pop
();
if
(
!
prompt
)
return
;
try
{
const
response
=
await
chatAPI
.
createChatCompletion
(
{
model
:
'gpt-3.5-turbo'
,
temperature
:
prompt
.
temperature
,
n
:
1
,
messages
:
[
systemPrompt
,
prompt
.
requestPrompts
]
},
{
timeout
:
60000
,
httpsAgent
}
);
return
response
.
data
.
choices
[
0
].
message
?.
content
;
}
catch
(
error
)
{
console
.
log
(
'部分训练出现错误'
);
}
};
// 格式化文本长度
// for (let i = 0; i <= replaceText.length / 2048; i++) {
// const slicePrompts: ChatCompletionRequestMessage = {
// role: 'user',
// content: replaceText.slice(i * 2048, (i + 1) * 2048)
// };
// [0.1, 0.3, 0.5, 0.7, 0.9].forEach((temperature) => {
// queue.push({
// temperature,
// requestPrompts: slicePrompts
// });
// });
// }
jsonRes
(
res
,
{
data
:
await
generateQA
()
});
}
catch
(
err
)
{
jsonRes
(
res
,
{
code
:
500
,
error
:
err
});
}
}
/**
* 检查文本是否按格式返回
*/
function
splitText
(
text
:
string
)
{}
src/pages/model/components/CreateModel.tsx
View file @
6ce727f9
...
...
@@ -18,7 +18,7 @@ import {
import
{
useForm
}
from
'react-hook-form'
;
import
{
postCreateModel
}
from
'@/api/model'
;
import
type
{
ModelSchema
}
from
'@/types/mongoSchema'
;
import
{
M
odelList
}
from
'@/constants/model'
;
import
{
m
odelList
}
from
'@/constants/model'
;
import
{
formatPrice
}
from
'@/utils/user'
;
interface
CreateFormType
{
...
...
@@ -45,7 +45,7 @@ const CreateModel = ({
formState
:
{
errors
}
}
=
useForm
<
CreateFormType
>
({
defaultValues
:
{
serviceModelName
:
M
odelList
[
0
].
model
serviceModelName
:
m
odelList
[
0
].
model
}
});
...
...
@@ -98,7 +98,7 @@ const CreateModel = ({
required
:
'底层模型不能为空'
})}
>
{
M
odelList
.
map
((
item
)
=>
(
{
m
odelList
.
map
((
item
)
=>
(
<
option
key=
{
item
.
model
}
value=
{
item
.
model
}
>
{
item
.
name
}
</
option
>
...
...
@@ -110,7 +110,7 @@ const CreateModel = ({
</
FormControl
>
<
Box
mt=
{
3
}
textAlign=
{
'center'
}
fontSize=
{
'sm'
}
color=
{
'blackAlpha.600'
}
>
{
formatPrice
(
M
odelList
.
find
((
item
)
=>
item
.
model
===
getValues
(
'serviceModelName'
))?.
price
||
0
m
odelList
.
find
((
item
)
=>
item
.
model
===
getValues
(
'serviceModelName'
))?.
price
||
0
)
*
1000
}
元/1000字(包括上下文和标点符号)
</
Box
>
...
...
src/pages/model/detail.tsx
View file @
6ce727f9
...
...
@@ -13,7 +13,7 @@ import { Card, Box, Flex, Button, Tag, Grid } from '@chakra-ui/react';
import
{
useToast
}
from
'@/hooks/useToast'
;
import
{
useConfirm
}
from
'@/hooks/useConfirm'
;
import
{
useForm
}
from
'react-hook-form'
;
import
{
formatModelStatus
,
ModelStatusEnum
,
M
odelList
,
defaultModel
}
from
'@/constants/model'
;
import
{
formatModelStatus
,
ModelStatusEnum
,
m
odelList
,
defaultModel
}
from
'@/constants/model'
;
import
{
useGlobalStore
}
from
'@/store/global'
;
import
{
useScreen
}
from
'@/hooks/useScreen'
;
import
ModelEditForm
from
'./components/ModelEditForm'
;
...
...
@@ -38,7 +38,7 @@ const ModelDetail = ({ modelId }: { modelId: string }) => {
});
const
canTrain
=
useMemo
(()
=>
{
const
openai
=
M
odelList
.
find
((
item
)
=>
item
.
model
===
model
?.
service
.
modelName
);
const
openai
=
m
odelList
.
find
((
item
)
=>
item
.
model
===
model
?.
service
.
modelName
);
return
openai
&&
openai
.
trainName
;
},
[
model
]);
...
...
src/pages/model/list.tsx
View file @
6ce727f9
...
...
@@ -14,7 +14,7 @@ import { useUserStore } from '@/store/user';
const
CreateModel
=
dynamic
(()
=>
import
(
'./components/CreateModel'
));
const
M
odelList
=
()
=>
{
const
m
odelList
=
()
=>
{
const
{
toast
}
=
useToast
();
const
{
isPc
}
=
useScreen
();
const
router
=
useRouter
();
...
...
@@ -87,4 +87,4 @@ const ModelList = () => {
);
};
export
default
M
odelList
;
export
default
m
odelList
;
src/pages/number/components/PayModal.tsx
View file @
6ce727f9
...
...
@@ -10,12 +10,21 @@ import {
Button
,
Input
,
Box
,
Grid
Grid
,
Table
,
Thead
,
Tbody
,
Tr
,
Th
,
Td
,
TableContainer
}
from
'@chakra-ui/react'
;
import
{
getPayCode
,
checkPayResult
}
from
'@/api/user'
;
import
{
useToast
}
from
'@/hooks/useToast'
;
import
{
useQuery
}
from
'@tanstack/react-query'
;
import
{
useRouter
}
from
'next/router'
;
import
{
modelList
}
from
'@/constants/model'
;
import
{
formatPrice
}
from
'../../../utils/user'
;
const
PayModal
=
({
onClose
}:
{
onClose
:
()
=>
void
})
=>
{
const
router
=
useRouter
();
...
...
@@ -82,9 +91,28 @@ const PayModal = ({ onClose }: { onClose: () => void }) => {
<
ModalHeader
>
充值
</
ModalHeader
>
{
!
payId
&&
<
ModalCloseButton
/>
}
<
ModalBody
>
<
ModalBody
py=
{
0
}
>
{
!
payId
&&
(
<>
{
/* 价格表 */
}
<
TableContainer
mb=
{
4
}
>
<
Table
>
<
Thead
>
<
Tr
>
<
Th
>
模型类型
</
Th
>
<
Th
>
价格(元/1000字符,包含所有上下文)
</
Th
>
</
Tr
>
</
Thead
>
<
Tbody
>
{
modelList
.
map
((
item
,
i
)
=>
(
<
Tr
key=
{
item
.
model
}
>
<
Td
>
{
item
.
name
}
</
Td
>
<
Td
>
{
formatPrice
(
item
.
price
)
*
1000
}
</
Td
>
</
Tr
>
))
}
</
Tbody
>
</
Table
>
</
TableContainer
>
<
Grid
gridTemplateColumns=
{
'repeat(4,1fr)'
}
gridGap=
{
5
}
mb=
{
4
}
>
{
[
5
,
10
,
20
,
50
].
map
((
item
)
=>
(
<
Button
...
...
src/pages/number/setting.tsx
View file @
6ce727f9
...
...
@@ -123,6 +123,9 @@ const NumberSetting = () => {
充值
</
Button
>
</
Flex
>
<
Box
fontSize=
{
'xs'
}
color=
{
'blackAlpha.500'
}
>
如果填写了自己的 openai 账号,将不会计费
</
Box
>
</
Box
>
</
Card
>
<
Card
mt=
{
6
}
px=
{
6
}
py=
{
4
}
>
...
...
src/service/events/bill.ts
View file @
6ce727f9
import
{
connectToDatabase
,
Bill
,
User
}
from
'../mongo'
;
import
{
M
odelList
}
from
'@/constants/model'
;
import
{
m
odelList
}
from
'@/constants/model'
;
export
const
pushBill
=
async
({
modelName
,
...
...
@@ -12,16 +12,23 @@ export const pushBill = async ({
chatId
:
string
;
textLen
:
number
;
})
=>
{
await
connectToDatabase
();
const
modelItem
=
modelList
.
find
((
item
)
=>
item
.
model
===
modelName
);
if
(
!
modelItem
)
return
;
let
billId
;
try
{
await
connectToDatabase
();
const
modelItem
=
M
odelList
.
find
((
item
)
=>
item
.
model
===
modelName
);
const
modelItem
=
m
odelList
.
find
((
item
)
=>
item
.
model
===
modelName
);
if
(
!
modelItem
)
return
;
const
price
=
modelItem
.
price
*
textLen
;
let
billId
;
try
{
// 插入 Bill 记录
const
res
=
await
Bill
.
create
({
...
...
src/service/models/data.ts
0 → 100644
View file @
6ce727f9
import
{
Schema
,
model
,
models
}
from
'mongoose'
;
const
DataSchema
=
new
Schema
({
userId
:
{
type
:
Schema
.
Types
.
ObjectId
,
ref
:
'user'
,
required
:
true
},
docId
:
{
type
:
String
,
required
:
true
},
createTime
:
{
type
:
Date
,
default
:
()
=>
new
Date
()
},
q
:
{
type
:
String
,
required
:
true
},
a
:
{
type
:
String
,
required
:
true
}
});
export
const
Data
=
models
[
'data'
]
||
model
(
'data'
,
DataSchema
);
src/service/mongo.ts
View file @
6ce727f9
...
...
@@ -32,3 +32,4 @@ export * from './models/user';
export
*
from
'./models/training'
;
export
*
from
'./models/bill'
;
export
*
from
'./models/pay'
;
export
*
from
'./models/data'
;
src/service/utils/tools.ts
View file @
6ce727f9
...
...
@@ -2,6 +2,8 @@ import crypto from 'crypto';
import
jwt
from
'jsonwebtoken'
;
import
{
User
}
from
'../models/user'
;
import
tunnel
from
'tunnel'
;
import
type
{
UserModelSchema
}
from
'@/types/mongoSchema'
;
import
{
formatPrice
}
from
'@/utils/user'
;
/* 密码加密 */
export
const
hashPassword
=
(
psw
:
string
)
=>
{
...
...
@@ -49,7 +51,37 @@ export const getUserOpenaiKey = async (userId: string) => {
return
Promise
.
reject
(
'缺少ApiKey, 无法请求'
);
}
return
Promise
.
resolve
(
userApiKey
);
return
Promise
.
resolve
(
userApiKey
as
string
);
};
/* 获取key,如果没有就用平台的,用平台记得加账单 */
export
const
getOpenApiKey
=
async
(
authorization
?:
string
)
=>
{
const
userId
=
await
authToken
(
authorization
);
const
user
=
await
User
.
findById
<
UserModelSchema
>
(
userId
);
if
(
!
user
)
return
Promise
.
reject
(
'用户不存在'
);
const
userApiKey
=
user
.
accounts
?.
find
((
item
:
any
)
=>
item
.
type
===
'openai'
)?.
value
;
// 有自己的key, 直接使用
if
(
userApiKey
)
{
return
{
userId
,
userApiKey
:
await
getUserOpenaiKey
(
userId
),
systemKey
:
''
};
}
// 余额校验
if
(
formatPrice
(
user
.
balance
)
<=
0
)
{
return
Promise
.
reject
(
'该账号余额不足'
);
}
return
{
userId
,
userApiKey
:
''
,
systemKey
:
process
.
env
.
OPENAIKEY
as
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