赞
踩
最近AI盛行,关注几个大模型网站都能发现,跟AI对话的时候,返回的文本是逐字展示的,就给人一种AI边解析边返回的感觉(不知道是为了装X还是真的需要这样)。正好部门内也有这么个需求,那就开干呗。
先看看效果:
ok
由于我这边后端返回是一次性返回所有回复,而天煞的产品经理要求做出逐字展示效果,于是我只能纯前端控制展示。
废发不多梭,开始搞代码。
先上个图,看看页面结构
列表的的格式是这样:
const [list, setList] = useState([
{
id: -1,
type: 1,
content: <Introduction chooseChatType={(v) => chatInit(v)} />, // 渲染对象
},
]); // 对话列表, type: 1 机器人, type: 2 用户 -1 初始介绍 -2 loading
整体编码过程不难,有几个细节需要注意:
1.发送消息后到后端返回消息钱,需要展示一个loading过渡
2.后端返回字符串后,需要逐字切割展示。这里我注意考虑两个方案,
第一个:用个定时器,把时差设置为变量delay,每次都随机生成delay,固定展示三个字符,直到展示完全。简单来讲就是,速度不固定,每次展示长度固定
第二个:速度固定,每次展示不同长度内容
这里我选用的第一种方案。
需要注意的是每次更新最后一条的内容都需要把list的最后一项pop出去,需要记录返回的内容切割后的内容,这里我用的useRef生成的变量来记录内容,主要代码如下:
const loading = useCallback(() => {
resetMsgList({
id: -2,
type: 1,
content: (
<Spin indicator={<LoadingOutlined style={{ fontSize: 24 }} spin />} />
),
});
}, []);
// 删除字符串前三位,不满前三位直接返回空
export const deleteStr = (str) => {
try {
if (str.length < 3) return '';
let arr = str.split('');
arr.splice(0, 3);
return arr.join('');
} catch (err) {
console.warn(err);
}
};
// 记录最新的回复内容 const currentReply = useRef(''); // 随机产生时差来展示字符 const clear = useInterval(() => { if (currentReply.current.length < 1) { clear(); } else { // 固定切割字符串三位 const str = currentReply.current.substr(0, 3); currentReply.current = deleteStr(currentReply.current); setList((oldList) => { const last = oldList.pop(); return [ ...oldList, { id: replyId, type: 1, content: typeof last?.content === 'string' && !isRegenerate.current ? last.content + str : str, }, ]; }); // 随机生成时差,1 - 500 毫秒 const randomTime = Math.floor(Math.random() * 10) * 50 + 1; setDelay(randomTime); } isRegenerate.current = false; }, delay); const send = throttle(async (e, msg) => { try { e?.preventDefault(); // 判断是否是alt+enter,是则识别位换行 if (e?.altKey) { setInputMsg(inputMsg + '\n'); return; } // if (eventSourceObj) eventSourceObj.current = null; const input = msg || inputMsg; if (!input) { message.warn('请输入对话内容'); return; } resetMsgList({ id: -1, type: 2, content: input }); loading(); setInputMsg(''); setCompareVisible(false); let res = await sendMsgHttp({ content: input, quType: questionType }); if (res.code === 0) { quId.current = res.data.quId; setReplyId(res.data.replyId); currentReply.current = res.data.reply; setDelay(100); } } catch (err) { console.warn('err'); } }, 300);
整体实现并不难,但要做好每个细节还是需要一点思考的,
ok,,我要拿去装逼了,拜拜!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。