perf: 对话框优化;feat: 模糊搜索

This commit is contained in:
archer
2023-04-20 23:06:30 +08:00
parent 02abe42afe
commit 3c0fa30aaf
7 changed files with 86 additions and 26 deletions

View File

@@ -1,9 +1,10 @@
## 常见问题
### 常见问题
**请求次数太多了**
一般是因为自己的 openai 账号异常。请先检查自己的账号是否正常使用。
**内容长度**
chatgpt 上下文最长 4096 tokens, 上下文超长时会报错。
**删除和复制**
点击对话头像,可以选择复制删除该条内容
电脑端:聊天内容右侧有复制删除的图标
移动端:点击对话头像,可以选择复制或删除该条内容。
**代理出错**
服务器代理不稳定,可以过一会儿再尝试。
服务器代理不稳定,可以过一会儿再尝试。 或者可以访问国外服务器: [FastGpt](https://fastgpt.run/)

View File

@@ -1,3 +1,5 @@
## Fast GPT V2.7
* FastGpt Api 允许你将 Fast Gpt 的部分功能通过 api 的形式,将知识库接入到自己的应用中,例如:飞书、企业微信、客服助手.
* 通过 csv 文件导入和导出你的问答对。你可以将你的 csv 文件放置在飞书文档上,以便团队共享
### Fast GPT V2.8.1
* 优化 - 知识库升级,内容条数不上限!
* 优化 - 导入去重效果,可防止导出后的 csv 重复导入
* 优化 - 聊天框,电脑端复制删除图标。
* 优化 - 聊天框,生成内容时,如果滚动条触底,则会自动向下滚动,不需要手动下滑。

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1681997838051" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4520" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48"><path d="M898 178.7H665.3c4.3-9.8 6.7-20.6 6.7-32 0-44-36-80-80-80H432c-44 0-80 36-80 80 0 11.4 2.4 22.2 6.7 32H126c-13.2 0-24 10.8-24 24s10.8 24 24 24h772c13.2 0 24-10.8 24-24s-10.8-24-24-24z m-466 0c-8.5 0-16.5-3.4-22.6-9.4-6.1-6.1-9.4-14.1-9.4-22.6s3.4-16.5 9.4-22.6c6.1-6.1 14.1-9.4 22.6-9.4h160c8.5 0 16.5 3.4 22.6 9.4 6.1 6.1 9.4 14.1 9.4 22.6 0 8.5-3.4 16.5-9.4 22.6-6.1 6.1-14.1 9.4-22.6 9.4H432zM513 774.7c18.1 0 33-14.8 33-33v-334c0-18.1-14.9-33-33-33h-2c-18.1 0-33 14.8-33 33v334c0 18.2 14.8 33 33 33h2zM363 774.7c18.1 0 33-14.8 33-33v-334c0-18.1-14.9-33-33-33h-2c-18.1 0-33 14.8-33 33v334c0 18.2 14.8 33 33 33h2zM663 774.7c18.1 0 33-14.8 33-33v-334c0-18.1-14.9-33-33-33h-2c-18.1 0-33 14.8-33 33v334c0 18.2 14.8 33 33 33h2z" p-id="4521"></path><path d="M812 280.7c-13.3 0-24 10.7-24 24v530c0 41.9-34.1 76-76 76H312c-41.9 0-76-34.1-76-76v-530c0-13.3-10.7-24-24-24s-24 10.7-24 24v530c0 68.4 55.6 124 124 124h400c68.4 0 124-55.6 124-124v-530c0-13.2-10.7-24-24-24z" p-id="4522"></path></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -13,14 +13,23 @@ const map = {
board: require('./icons/board.svg').default,
develop: require('./icons/develop.svg').default,
user: require('./icons/user.svg').default,
chatting: require('./icons/chatting.svg').default
chatting: require('./icons/chatting.svg').default,
delete: require('./icons/delete.svg').default
};
export type IconName = keyof typeof map;
const MyIcon = ({ name, w = 'auto', h = 'auto', ...props }: { name: IconName } & IconProps) => {
return map[name] ? (
<Icon as={map[name]} w={w} h={h} boxSizing={'content-box'} verticalAlign={'top'} {...props} />
<Icon
as={map[name]}
w={w}
h={h}
boxSizing={'content-box'}
verticalAlign={'top'}
fill={'currentcolor'}
{...props}
/>
) : null;
};

View File

@@ -13,8 +13,8 @@ import styles from './index.module.scss';
import { codeLight } from './codeLight';
const Markdown = ({ source, isChatting = false }: { source: string; isChatting?: boolean }) => {
const formatSource = useMemo(() => source, [source]);
const { copyData } = useCopyData();
const formatSource = useMemo(() => source, [source]);
return (
<ReactMarkdown

View File

@@ -36,9 +36,16 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
await connectToDatabase();
const where: any = [
['user_id', userId],
'AND',
['model_id', modelId],
...(searchText ? ['AND', `(q LIKE '%${searchText}%' OR a LIKE '%${searchText}%')`] : [])
];
const searchRes = await PgClient.select<PgModelDataItemType>('modelData', {
fields: ['id', 'q', 'a', 'status'],
where: [['user_id', userId], 'AND', ['model_id', modelId]],
where,
order: [{ field: 'id', mode: 'DESC' }],
limit: pageSize,
offset: pageSize * (pageNum - 1)
@@ -50,7 +57,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
pageSize,
data: searchRes.rows,
total: await PgClient.count('modelData', {
where: [['user_id', userId], 'AND', ['model_id', modelId]]
where
})
}
});

View File

@@ -28,7 +28,8 @@ import { useChatStore } from '@/store/chat';
import { useCopyData } from '@/utils/tools';
import { streamFetch } from '@/api/fetch';
import Icon from '@/components/Icon';
import { modelList } from '@/constants/model';
import MyIcon from '@/components/Icon';
import { throttle } from 'lodash';
const SlideBar = dynamic(() => import('./components/SlideBar'));
const Empty = dynamic(() => import('./components/Empty'));
@@ -73,16 +74,28 @@ const Chat = ({ chatId }: { chatId: string }) => {
const { pushChatHistory } = useChatStore();
// 滚动到底部
const scrollToBottom = useCallback(() => {
setTimeout(() => {
ChatBox.current &&
ChatBox.current.scrollTo({
top: ChatBox.current.scrollHeight,
behavior: 'smooth'
});
}, 100);
const scrollToBottom = useCallback((behavior: 'smooth' | 'auto' = 'smooth') => {
if (!ChatBox.current) return;
ChatBox.current.scrollTo({
top: ChatBox.current.scrollHeight,
behavior
});
}, []);
// 聊天信息生成中……获取当前滚动条位置,判断是否需要滚动到底部
// eslint-disable-next-line react-hooks/exhaustive-deps
const generatingMessage = useCallback(
throttle(() => {
if (!ChatBox.current) return;
const isBottom =
ChatBox.current.scrollTop + ChatBox.current.clientHeight + 50 >=
ChatBox.current.scrollHeight;
isBottom && scrollToBottom('auto');
}, 100),
[]
);
// 重置输入内容
const resetInputVal = useCallback((val: string) => {
setInputVal(val);
@@ -141,6 +154,7 @@ const Chat = ({ chatId }: { chatId: string }) => {
};
})
}));
generatingMessage();
},
abortSignal: controller.current
});
@@ -178,7 +192,7 @@ const Chat = ({ chatId }: { chatId: string }) => {
})
}));
},
[chatData.modelName, chatId, toast]
[chatData.modelName, chatId, generatingMessage, toast]
);
/**
@@ -226,7 +240,9 @@ const Chat = ({ chatId }: { chatId: string }) => {
// 清空输入内容
resetInputVal('');
scrollToBottom();
setTimeout(() => {
scrollToBottom();
}, 100);
try {
await gptChatPrompt(newChatList[newChatList.length - 2]);
@@ -313,8 +329,8 @@ const Chat = ({ chatId }: { chatId: string }) => {
});
if (res.history.length > 0) {
setTimeout(() => {
scrollToBottom();
}, 500);
scrollToBottom('auto');
}, 2000);
}
},
onError(e: any) {
@@ -340,6 +356,7 @@ const Chat = ({ chatId }: { chatId: string }) => {
controller.current?.abort();
};
}, [chatId]);
return (
<Flex
h={'100%'}
@@ -433,6 +450,29 @@ const Chat = ({ chatId }: { chatId: string }) => {
<Box whiteSpace={'pre-wrap'}>{item.value}</Box>
)}
</Box>
{isPc && (
<Flex h={'100%'} flexDirection={'column'} ml={2} w={'14px'} height={'100%'}>
<Box minH={'40px'} flex={1}>
<MyIcon
name="copy"
w={'14px'}
cursor={'pointer'}
color={'alphaBlack.400'}
onClick={() => onclickCopy(item.value)}
/>
</Box>
<MyIcon
name="delete"
w={'14px'}
cursor={'pointer'}
color={'alphaBlack.400'}
_hover={{
color: 'red.600'
}}
onClick={() => delChatRecord(index)}
/>
</Flex>
)}
</Flex>
</Box>
))}