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
9c8ca7dd
authored
Apr 07, 2023
by
archer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
perf: 压缩上下文
parent
1409916b
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
18 additions
and
180 deletions
+18
-180
src/constants/common.ts
+3
-4
src/pages/api/chat/gpt3.ts
+0
-170
src/service/utils/tools.ts
+15
-6
No files found.
src/constants/common.ts
View file @
9c8ca7dd
...
...
@@ -60,10 +60,9 @@ export const chatProblem = `
`
;
export
const
versionIntro
=
`
## Fast GPT V2.4
* 优化文件拆分功能,可自定义提示词。
* 优化文件拆分和索引生成的速度。
* 定制知识库:创建模型时可以选择【知识库】模型, 可以手动导入知识点或者直接导入一个文件自动学习。
## Fast GPT V2.5
* 内容压缩,替换中文标点符号和多余符号,减少一些上下文tokens。
* 优化 QA 拆分记账。
`
;
export
const
shareHint
=
`
...
...
src/pages/api/chat/gpt3.ts
deleted
100644 → 0
View file @
1409916b
import
type
{
NextApiRequest
,
NextApiResponse
}
from
'next'
;
import
{
createParser
,
ParsedEvent
,
ReconnectInterval
}
from
'eventsource-parser'
;
import
{
connectToDatabase
}
from
'@/service/mongo'
;
import
{
getOpenAIApi
,
authChat
}
from
'@/service/utils/chat'
;
import
{
httpsAgent
}
from
'@/service/utils/tools'
;
import
{
ChatItemType
}
from
'@/types/chat'
;
import
{
jsonRes
}
from
'@/service/response'
;
import
type
{
ModelSchema
}
from
'@/types/mongoSchema'
;
import
{
PassThrough
}
from
'stream'
;
import
{
modelList
}
from
'@/constants/model'
;
import
{
pushChatBill
}
from
'@/service/events/pushBill'
;
/* 发送提示词 */
export
default
async
function
handler
(
req
:
NextApiRequest
,
res
:
NextApiResponse
)
{
let
step
=
0
;
// step=1时,表示开始了流响应
const
stream
=
new
PassThrough
();
stream
.
on
(
'error'
,
()
=>
{
console
.
log
(
'error: '
,
'stream error'
);
stream
.
destroy
();
});
res
.
on
(
'close'
,
()
=>
{
stream
.
destroy
();
});
res
.
on
(
'error'
,
()
=>
{
console
.
log
(
'error: '
,
'request error'
);
stream
.
destroy
();
});
try
{
const
{
chatId
,
prompt
}
=
req
.
body
as
{
prompt
:
ChatItemType
;
chatId
:
string
;
};
const
{
authorization
}
=
req
.
headers
;
if
(
!
chatId
||
!
prompt
)
{
throw
new
Error
(
'缺少参数'
);
}
await
connectToDatabase
();
const
{
chat
,
userApiKey
,
systemKey
,
userId
}
=
await
authChat
(
chatId
,
authorization
);
const
model
:
ModelSchema
=
chat
.
modelId
;
// 读取对话内容
const
prompts
=
[...
chat
.
content
,
prompt
];
// 上下文长度过滤
const
maxContext
=
model
.
security
.
contextMaxLen
;
const
filterPrompts
=
prompts
.
length
>
maxContext
?
prompts
.
slice
(
prompts
.
length
-
maxContext
)
:
prompts
;
// 格式化文本内容
const
formatPrompts
:
string
[]
=
filterPrompts
.
map
((
item
:
ChatItemType
)
=>
item
.
value
);
// 如果有系统提示词,自动插入
if
(
model
.
systemPrompt
)
{
formatPrompts
.
unshift
(
`
${
model
.
systemPrompt
}
`
);
}
const
promptText
=
formatPrompts
.
join
(
'</s>'
);
// 计算温度
const
modelConstantsData
=
modelList
.
find
((
item
)
=>
item
.
model
===
model
.
service
.
modelName
);
if
(
!
modelConstantsData
)
{
throw
new
Error
(
'模型异常,请用 chatgpt 模型'
);
}
const
temperature
=
modelConstantsData
.
maxTemperature
*
(
model
.
temperature
/
10
);
// 获取 chatAPI
const
chatAPI
=
getOpenAIApi
(
userApiKey
||
systemKey
);
let
startTime
=
Date
.
now
();
// console.log({
// model: model.service.chatModel,
// temperature: temperature,
// prompt: promptText,
// stream: true,
// max_tokens:
// model.trainingTimes > 0 ? modelConstantsData.trainedMaxToken : modelConstantsData.maxToken,
// presence_penalty: -0.5, // 越大,越容易出现新内容
// frequency_penalty: 0.5, // 越大,重复内容越少
// stop: [`###`]
// });
// 发出请求
const
chatResponse
=
await
chatAPI
.
createCompletion
(
{
model
:
model
.
service
.
chatModel
,
temperature
:
temperature
,
prompt
:
promptText
,
stream
:
true
,
max_tokens
:
modelConstantsData
.
maxToken
,
presence_penalty
:
-
0.5
,
// 越大,越容易出现新内容
frequency_penalty
:
0.5
,
// 越大,重复内容越少
stop
:
[
`###`
,
'。!?.!.'
]
},
{
timeout
:
40000
,
responseType
:
'stream'
,
httpsAgent
}
);
console
.
log
(
'api response time:'
,
`
${(
Date
.
now
()
-
startTime
)
/
1000
}
s`
);
// 创建响应流
res
.
setHeader
(
'Content-Type'
,
'text/event-stream;charset-utf-8'
);
res
.
setHeader
(
'Access-Control-Allow-Origin'
,
'*'
);
res
.
setHeader
(
'X-Accel-Buffering'
,
'no'
);
res
.
setHeader
(
'Cache-Control'
,
'no-cache, no-transform'
);
step
=
1
;
let
responseContent
=
''
;
stream
.
pipe
(
res
);
const
onParse
=
async
(
event
:
ParsedEvent
|
ReconnectInterval
)
=>
{
if
(
event
.
type
!==
'event'
)
return
;
const
data
=
event
.
data
;
if
(
data
===
'[DONE]'
)
return
;
try
{
const
json
=
JSON
.
parse
(
data
);
const
content
:
string
=
json
?.
choices
?.[
0
].
text
||
''
;
// console.log('content:', content);
if
(
!
content
||
(
responseContent
===
''
&&
content
===
'\n'
))
return
;
responseContent
+=
content
;
!
stream
.
destroyed
&&
stream
.
push
(
content
.
replace
(
/
\n
/g
,
'<br/>'
));
}
catch
(
error
)
{
error
;
}
};
const
decoder
=
new
TextDecoder
();
try
{
for
await
(
const
chunk
of
chatResponse
.
data
as
any
)
{
if
(
stream
.
destroyed
)
{
// 流被中断了,直接忽略后面的内容
break
;
}
const
parser
=
createParser
(
onParse
);
parser
.
feed
(
decoder
.
decode
(
chunk
));
}
}
catch
(
error
)
{
console
.
log
(
'pipe error'
,
error
);
}
// close stream
!
stream
.
destroyed
&&
stream
.
push
(
null
);
stream
.
destroy
();
// 只有使用平台的 key 才计费
pushChatBill
({
isPay
:
!
userApiKey
,
modelName
:
model
.
service
.
modelName
,
userId
,
chatId
,
text
:
promptText
+
responseContent
});
}
catch
(
err
:
any
)
{
// console.log(err?.response);
if
(
step
===
1
)
{
// 直接结束流
console
.
log
(
'error,结束'
);
stream
.
destroy
();
}
else
{
res
.
status
(
500
);
jsonRes
(
res
,
{
code
:
500
,
error
:
err
});
}
}
}
src/service/utils/tools.ts
View file @
9c8ca7dd
...
...
@@ -54,21 +54,30 @@ export const httpsAgent =
/* tokens 截断 */
export
const
openaiChatFilter
=
(
prompts
:
ChatItemType
[],
maxTokens
:
number
)
=>
{
const
formatPrompts
=
prompts
.
map
((
item
)
=>
({
obj
:
item
.
obj
,
value
:
item
.
value
.
replace
(
/
[\u
3000
\u
3001
\u
ff01-
\u
ff5e
\u
3002
]
/g
,
' '
)
// 中文标点改空格
.
replace
(
/
\n
+/g
,
'\n'
)
// 连续空行
.
replace
(
/
[^\S\r\n]
+/g
,
' '
)
// 连续空白内容
.
trim
()
}));
let
res
:
ChatItemType
[]
=
[];
let
systemPrompt
:
ChatItemType
|
null
=
null
;
// System 词保留
if
(
p
rompts
[
0
]?.
obj
===
'SYSTEM'
)
{
systemPrompt
=
p
rompts
.
shift
()
as
ChatItemType
;
maxTokens
-=
encode
(
p
rompts
[
0
].
value
).
length
;
if
(
formatP
rompts
[
0
]?.
obj
===
'SYSTEM'
)
{
systemPrompt
=
formatP
rompts
.
shift
()
as
ChatItemType
;
maxTokens
-=
encode
(
formatP
rompts
[
0
].
value
).
length
;
}
// 从后往前截取
for
(
let
i
=
p
rompts
.
length
-
1
;
i
>=
0
;
i
--
)
{
const
tokens
=
encode
(
p
rompts
[
i
].
value
).
length
;
for
(
let
i
=
formatP
rompts
.
length
-
1
;
i
>=
0
;
i
--
)
{
const
tokens
=
encode
(
formatP
rompts
[
i
].
value
).
length
;
if
(
maxTokens
>=
tokens
)
{
res
.
unshift
(
p
rompts
[
i
]);
res
.
unshift
(
formatP
rompts
[
i
]);
maxTokens
-=
tokens
;
}
else
{
break
;
...
...
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