feat: system prompt
This commit is contained in:
@@ -8,7 +8,7 @@ import { ChatModelMap, ModelVectorSearchModeMap } from '@/constants/model';
|
||||
import { pushChatBill } from '@/service/events/pushBill';
|
||||
import { resStreamResponse } from '@/service/utils/chat';
|
||||
import { appKbSearch } from '../openapi/kb/appKbSearch';
|
||||
import { ChatRoleEnum, QUOTE_LEN_HEADER } from '@/constants/chat';
|
||||
import { ChatRoleEnum, QUOTE_LEN_HEADER, GUIDE_PROMPT_HEADER } from '@/constants/chat';
|
||||
import { BillTypeEnum } from '@/constants/user';
|
||||
import { sensitiveCheck } from '@/service/api/text';
|
||||
import { NEW_CHATID_HEADER } from '@/constants/chat';
|
||||
@@ -53,11 +53,12 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
const {
|
||||
code = 200,
|
||||
systemPrompts = [],
|
||||
quote = []
|
||||
quote = [],
|
||||
guidePrompt = ''
|
||||
} = await (async () => {
|
||||
// 使用了知识库搜索
|
||||
if (model.chat.relatedKbs.length > 0) {
|
||||
const { code, searchPrompts, rawSearch } = await appKbSearch({
|
||||
const { code, searchPrompts, rawSearch, guidePrompt } = await appKbSearch({
|
||||
model,
|
||||
userId,
|
||||
prompts,
|
||||
@@ -67,11 +68,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
return {
|
||||
code,
|
||||
quote: rawSearch,
|
||||
systemPrompts: searchPrompts
|
||||
systemPrompts: searchPrompts,
|
||||
guidePrompt
|
||||
};
|
||||
}
|
||||
if (model.chat.systemPrompt) {
|
||||
return {
|
||||
guidePrompt: model.chat.systemPrompt,
|
||||
systemPrompts: [
|
||||
{
|
||||
obj: ChatRoleEnum.System,
|
||||
@@ -86,7 +89,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
// get conversationId. create a newId if it is null
|
||||
const conversationId = chatId || String(new Types.ObjectId());
|
||||
!chatId && res.setHeader(NEW_CHATID_HEADER, conversationId);
|
||||
res.setHeader(QUOTE_LEN_HEADER, quote.length);
|
||||
if (showModelDetail) {
|
||||
guidePrompt && res.setHeader(GUIDE_PROMPT_HEADER, encodeURIComponent(guidePrompt));
|
||||
res.setHeader(QUOTE_LEN_HEADER, quote.length);
|
||||
}
|
||||
|
||||
// search result is empty
|
||||
if (code === 201) {
|
||||
@@ -151,8 +157,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
prompt[0],
|
||||
{
|
||||
...prompt[1],
|
||||
value: responseContent,
|
||||
quote: showModelDetail ? quote : [],
|
||||
value: responseContent
|
||||
systemPrompt: showModelDetail ? guidePrompt : ''
|
||||
}
|
||||
],
|
||||
userId
|
||||
|
||||
@@ -73,7 +73,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
_id: '$content._id',
|
||||
obj: '$content.obj',
|
||||
value: '$content.value',
|
||||
quoteLen: { $size: '$content.quote' }
|
||||
systemPrompt: '$content.systemPrompt',
|
||||
quoteLen: { $size: { $ifNull: ['$content.quote', []] } }
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
@@ -57,10 +57,8 @@ export async function saveChat({
|
||||
_id: item._id ? new mongoose.Types.ObjectId(item._id) : undefined,
|
||||
obj: item.obj,
|
||||
value: item.value,
|
||||
quote: item.quote?.map((item) => ({
|
||||
...item,
|
||||
isEdit: false
|
||||
}))
|
||||
systemPrompt: item.systemPrompt,
|
||||
quote: item.quote || []
|
||||
}));
|
||||
|
||||
// 没有 chatId, 创建一个对话
|
||||
|
||||
@@ -22,6 +22,7 @@ type Props = {
|
||||
type Response = {
|
||||
code: 200 | 201;
|
||||
rawSearch: QuoteItemType[];
|
||||
guidePrompt: string;
|
||||
searchPrompts: {
|
||||
obj: ChatRoleEnum;
|
||||
value: string;
|
||||
@@ -131,36 +132,29 @@ export async function appKbSearch({
|
||||
};
|
||||
const sliceRate = sliceRateMap[searchRes.length] || sliceRateMap[0];
|
||||
// 计算固定提示词的 token 数量
|
||||
const fixedPrompts = [
|
||||
// user system prompt
|
||||
...(model.chat.systemPrompt
|
||||
? [
|
||||
{
|
||||
obj: ChatRoleEnum.System,
|
||||
value: model.chat.systemPrompt
|
||||
}
|
||||
]
|
||||
: model.chat.searchMode === ModelVectorSearchModeEnum.noContext
|
||||
? [
|
||||
{
|
||||
obj: ChatRoleEnum.System,
|
||||
value: `知识库是关于"${model.name}"的内容,根据知识库内容回答问题.`
|
||||
}
|
||||
]
|
||||
: [
|
||||
{
|
||||
obj: ChatRoleEnum.System,
|
||||
value: `玩一个问答游戏,规则为:
|
||||
|
||||
const guidePrompt = model.chat.systemPrompt // user system prompt
|
||||
? {
|
||||
obj: ChatRoleEnum.System,
|
||||
value: model.chat.systemPrompt
|
||||
}
|
||||
: model.chat.searchMode === ModelVectorSearchModeEnum.noContext
|
||||
? {
|
||||
obj: ChatRoleEnum.System,
|
||||
value: `知识库是关于"${model.name}"的内容,根据知识库内容回答问题.`
|
||||
}
|
||||
: {
|
||||
obj: ChatRoleEnum.System,
|
||||
value: `玩一个问答游戏,规则为:
|
||||
1.你完全忘记你已有的知识
|
||||
2.你只回答关于"${model.name}"的问题
|
||||
3.你只从知识库中选择内容进行回答
|
||||
4.如果问题不在知识库中,你会回答:"我不知道。"
|
||||
请务必遵守规则`
|
||||
}
|
||||
])
|
||||
];
|
||||
};
|
||||
|
||||
const fixedSystemTokens = modelToolMap[model.chat.chatModel].countTokens({
|
||||
messages: fixedPrompts
|
||||
messages: [guidePrompt]
|
||||
});
|
||||
const maxTokens = modelConstantsData.systemMaxToken - fixedSystemTokens;
|
||||
const sliceResult = sliceRate.map((rate, i) =>
|
||||
@@ -186,6 +180,7 @@ export async function appKbSearch({
|
||||
return {
|
||||
code: 201,
|
||||
rawSearch: [],
|
||||
guidePrompt: '',
|
||||
searchPrompts: [
|
||||
{
|
||||
obj: ChatRoleEnum.System,
|
||||
@@ -199,6 +194,7 @@ export async function appKbSearch({
|
||||
return {
|
||||
code: 200,
|
||||
rawSearch: [],
|
||||
guidePrompt: model.chat.systemPrompt || '',
|
||||
searchPrompts: model.chat.systemPrompt
|
||||
? [
|
||||
{
|
||||
@@ -213,12 +209,13 @@ export async function appKbSearch({
|
||||
return {
|
||||
code: 200,
|
||||
rawSearch: sliceSearch,
|
||||
guidePrompt: guidePrompt.value || '',
|
||||
searchPrompts: [
|
||||
{
|
||||
obj: ChatRoleEnum.System,
|
||||
value: `知识库:${systemPrompt}`
|
||||
},
|
||||
...fixedPrompts
|
||||
guidePrompt
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => {
|
||||
const isLeavePage = useRef(false);
|
||||
|
||||
const [showHistoryQuote, setShowHistoryQuote] = useState<string>();
|
||||
const [showSystemPrompt, setShowSystemPrompt] = useState('');
|
||||
const [messageContextMenuData, setMessageContextMenuData] = useState<{
|
||||
// message messageContextMenuData
|
||||
left: number;
|
||||
@@ -177,7 +178,7 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => {
|
||||
}));
|
||||
|
||||
// 流请求,获取数据
|
||||
const { newChatId, quoteLen } = await streamFetch({
|
||||
const { newChatId, quoteLen, systemPrompt } = await streamFetch({
|
||||
url: '/api/chat/chat',
|
||||
data: {
|
||||
prompt,
|
||||
@@ -221,14 +222,15 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => {
|
||||
return {
|
||||
...item,
|
||||
status: 'finish',
|
||||
quoteLen
|
||||
quoteLen,
|
||||
systemPrompt
|
||||
};
|
||||
})
|
||||
}));
|
||||
|
||||
// refresh history
|
||||
loadHistory({ pageNum: 1, init: true });
|
||||
setTimeout(() => {
|
||||
loadHistory({ pageNum: 1, init: true });
|
||||
generatingMessage();
|
||||
}, 100);
|
||||
},
|
||||
@@ -699,6 +701,7 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => {
|
||||
})}
|
||||
>
|
||||
<Avatar
|
||||
className="avatar"
|
||||
src={
|
||||
item.obj === 'Human'
|
||||
? userInfo?.avatar || '/icon/human.png'
|
||||
@@ -727,19 +730,35 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => {
|
||||
isChatting={isChatting && index === chatData.history.length - 1}
|
||||
formatLink
|
||||
/>
|
||||
{!!item.quoteLen && (
|
||||
<Button
|
||||
size={'xs'}
|
||||
mt={2}
|
||||
fontWeight={'normal'}
|
||||
colorScheme={'gray'}
|
||||
variant={'outline'}
|
||||
w={'90px'}
|
||||
onClick={() => setShowHistoryQuote(item._id)}
|
||||
>
|
||||
{item.quoteLen}条引用
|
||||
</Button>
|
||||
)}
|
||||
<Flex>
|
||||
{!!item.systemPrompt && (
|
||||
<Button
|
||||
mt={2}
|
||||
mr={3}
|
||||
size={'xs'}
|
||||
fontWeight={'normal'}
|
||||
colorScheme={'gray'}
|
||||
variant={'outline'}
|
||||
px={[2, 4]}
|
||||
onClick={() => setShowSystemPrompt(item.systemPrompt || '')}
|
||||
>
|
||||
提示词
|
||||
</Button>
|
||||
)}
|
||||
{!!item.quoteLen && (
|
||||
<Button
|
||||
mt={2}
|
||||
size={'xs'}
|
||||
fontWeight={'normal'}
|
||||
colorScheme={'gray'}
|
||||
variant={'outline'}
|
||||
px={[2, 4]}
|
||||
onClick={() => setShowHistoryQuote(item._id)}
|
||||
>
|
||||
{item.quoteLen}条引用
|
||||
</Button>
|
||||
)}
|
||||
</Flex>
|
||||
</Card>
|
||||
</Box>
|
||||
) : (
|
||||
@@ -876,6 +895,19 @@ const Chat = ({ modelId, chatId }: { modelId: string; chatId: string }) => {
|
||||
onClose={() => setShowHistoryQuote(undefined)}
|
||||
/>
|
||||
)}
|
||||
{/* system prompt show modal */}
|
||||
{
|
||||
<Modal isOpen={!!showSystemPrompt} onClose={() => setShowSystemPrompt('')}>
|
||||
<ModalOverlay />
|
||||
<ModalContent maxW={'min(90vw, 600px)'} maxH={'80vh'} minH={'50vh'} overflow={'overlay'}>
|
||||
<ModalCloseButton />
|
||||
<ModalHeader>提示词</ModalHeader>
|
||||
<ModalBody pt={0} whiteSpace={'pre-wrap'} textAlign={'justify'} fontSize={'xs'}>
|
||||
{showSystemPrompt}
|
||||
</ModalBody>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
}
|
||||
{/* context menu */}
|
||||
{messageContextMenuData && (
|
||||
<Box
|
||||
|
||||
Reference in New Issue
Block a user