fix: 对话增量修复

master
xjs 2025-04-25 14:38:29 +08:00
parent 669b55e367
commit 470dc3ab9e
6 changed files with 72 additions and 67 deletions

View File

@ -1,2 +1,2 @@
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/index-DCCuNddn.js","assets/.pnpm-CAIuqsZ0.js","assets/use-toast-DO4tfD4I.js","assets/index-PFueeGmc.css"])))=>i.map(i=>d[i]);
import{_ as t}from"./index-CN-hwWKH.js";import{j as r,r as a}from"./.pnpm-CAIuqsZ0.js";const o=a.lazy(()=>t(()=>import("./index-DCCuNddn.js"),__vite__mapDeps([0,1,2,3])));function i(){return r.jsx("div",{className:"h-full bg-[#F4F6FA]",children:r.jsx(o,{})})}export{i as default};
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/index-CQS1KRBf.js","assets/.pnpm-CAIuqsZ0.js","assets/use-toast-DO4tfD4I.js","assets/index-PFueeGmc.css"])))=>i.map(i=>d[i]);
import{_ as t}from"./index-mKhgCiGE.js";import{j as r,r as a}from"./.pnpm-CAIuqsZ0.js";const o=a.lazy(()=>t(()=>import("./index-CQS1KRBf.js"),__vite__mapDeps([0,1,2,3])));function i(){return r.jsx("div",{className:"h-full bg-[#F4F6FA]",children:r.jsx(o,{})})}export{i as default};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/App-D4RUlINY.js","assets/.pnpm-CAIuqsZ0.js","assets/MainLayout-BMCWJnk-.js","assets/use-toast-DO4tfD4I.js"])))=>i.map(i=>d[i]);
var v=Object.defineProperty;var x=(s,t,n)=>t in s?v(s,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):s[t]=n;var m=(s,t,n)=>x(s,typeof t!="symbol"?t+"":t,n);import{r as d,c as P,j as a,a as _,R as L}from"./.pnpm-CAIuqsZ0.js";(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const e of document.querySelectorAll('link[rel="modulepreload"]'))f(e);new MutationObserver(e=>{for(const o of e)if(o.type==="childList")for(const r of o.addedNodes)r.tagName==="LINK"&&r.rel==="modulepreload"&&f(r)}).observe(document,{childList:!0,subtree:!0});function n(e){const o={};return e.integrity&&(o.integrity=e.integrity),e.referrerPolicy&&(o.referrerPolicy=e.referrerPolicy),e.crossOrigin==="use-credentials"?o.credentials="include":e.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function f(e){if(e.ep)return;e.ep=!0;const o=n(e);fetch(e.href,o)}})();const j="modulepreload",O=function(s){return"/"+s},h={},p=function(t,n,f){let e=Promise.resolve();if(n&&n.length>0){document.getElementsByTagName("link");const r=document.querySelector("meta[property=csp-nonce]"),i=(r==null?void 0:r.nonce)||(r==null?void 0:r.getAttribute("nonce"));e=Promise.allSettled(n.map(c=>{if(c=O(c),c in h)return;h[c]=!0;const u=c.endsWith(".css"),E=u?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${c}"]${E}`))return;const l=document.createElement("link");if(l.rel=u?"stylesheet":j,u||(l.as="script"),l.crossOrigin="",l.href=c,i&&l.setAttribute("nonce",i),document.head.appendChild(l),u)return new Promise((y,g)=>{l.addEventListener("load",y),l.addEventListener("error",()=>g(new Error(`Unable to preload CSS for ${c}`)))})}))}function o(r){const i=new Event("vite:preloadError",{cancelable:!0});if(i.payload=r,window.dispatchEvent(i),!i.defaultPrevented)throw r}return e.then(r=>{for(const i of r||[])i.status==="rejected"&&o(i.reason);return t().catch(o)})},R=d.lazy(()=>p(()=>import("./App-D4RUlINY.js"),__vite__mapDeps([0,1]))),S=d.lazy(()=>p(()=>import("./MainLayout-BMCWJnk-.js"),__vite__mapDeps([2,1,3])));class w extends d.Component{constructor(){super(...arguments);m(this,"state",{hasError:!1})}static getDerivedStateFromError(n){return{hasError:!0}}render(){return this.state.hasError?a.jsx("h1",{children:"出错了,请稍后再试。"}):this.props.children}}const b=P([{path:"/",element:a.jsx(S,{}),errorElement:a.jsx(w,{children:a.jsx("div",{className:"flex-auto flex flex-col p-6",children:"出错了,请稍后再试。"})}),children:[{path:"/",element:a.jsx(R,{})}]}]);_(document.getElementById("root")).render(a.jsx(d.StrictMode,{children:a.jsx(L,{router:b})}));export{p as _};
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/App-Bxrx0fG0.js","assets/.pnpm-CAIuqsZ0.js","assets/MainLayout-BMCWJnk-.js","assets/use-toast-DO4tfD4I.js"])))=>i.map(i=>d[i]);
var v=Object.defineProperty;var x=(s,t,n)=>t in s?v(s,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):s[t]=n;var m=(s,t,n)=>x(s,typeof t!="symbol"?t+"":t,n);import{r as d,c as P,j as a,a as _,R as L}from"./.pnpm-CAIuqsZ0.js";(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const e of document.querySelectorAll('link[rel="modulepreload"]'))f(e);new MutationObserver(e=>{for(const o of e)if(o.type==="childList")for(const r of o.addedNodes)r.tagName==="LINK"&&r.rel==="modulepreload"&&f(r)}).observe(document,{childList:!0,subtree:!0});function n(e){const o={};return e.integrity&&(o.integrity=e.integrity),e.referrerPolicy&&(o.referrerPolicy=e.referrerPolicy),e.crossOrigin==="use-credentials"?o.credentials="include":e.crossOrigin==="anonymous"?o.credentials="omit":o.credentials="same-origin",o}function f(e){if(e.ep)return;e.ep=!0;const o=n(e);fetch(e.href,o)}})();const j="modulepreload",O=function(s){return"/"+s},h={},p=function(t,n,f){let e=Promise.resolve();if(n&&n.length>0){document.getElementsByTagName("link");const r=document.querySelector("meta[property=csp-nonce]"),i=(r==null?void 0:r.nonce)||(r==null?void 0:r.getAttribute("nonce"));e=Promise.allSettled(n.map(c=>{if(c=O(c),c in h)return;h[c]=!0;const u=c.endsWith(".css"),E=u?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${c}"]${E}`))return;const l=document.createElement("link");if(l.rel=u?"stylesheet":j,u||(l.as="script"),l.crossOrigin="",l.href=c,i&&l.setAttribute("nonce",i),document.head.appendChild(l),u)return new Promise((y,g)=>{l.addEventListener("load",y),l.addEventListener("error",()=>g(new Error(`Unable to preload CSS for ${c}`)))})}))}function o(r){const i=new Event("vite:preloadError",{cancelable:!0});if(i.payload=r,window.dispatchEvent(i),!i.defaultPrevented)throw r}return e.then(r=>{for(const i of r||[])i.status==="rejected"&&o(i.reason);return t().catch(o)})},R=d.lazy(()=>p(()=>import("./App-Bxrx0fG0.js"),__vite__mapDeps([0,1]))),S=d.lazy(()=>p(()=>import("./MainLayout-BMCWJnk-.js"),__vite__mapDeps([2,1,3])));class w extends d.Component{constructor(){super(...arguments);m(this,"state",{hasError:!1})}static getDerivedStateFromError(n){return{hasError:!0}}render(){return this.state.hasError?a.jsx("h1",{children:"出错了,请稍后再试。"}):this.props.children}}const b=P([{path:"/",element:a.jsx(S,{}),errorElement:a.jsx(w,{children:a.jsx("div",{className:"flex-auto flex flex-col p-6",children:"出错了,请稍后再试。"})}),children:[{path:"/",element:a.jsx(R,{})}]}]);_(document.getElementById("root")).render(a.jsx(d.StrictMode,{children:a.jsx(L,{router:b})}));export{p as _};

View File

@ -23,7 +23,7 @@
// VConsole will be exported to `window.VConsole` by default.
var vConsole = new window.VConsole();
</script> -->
<script type="module" crossorigin src="/assets/index-CN-hwWKH.js"></script>
<script type="module" crossorigin src="/assets/index-mKhgCiGE.js"></script>
<link rel="modulepreload" crossorigin href="/assets/.pnpm-CAIuqsZ0.js">
<link rel="stylesheet" crossorigin href="/assets/index-DPqYJA2j.css">
</head>

View File

@ -32,12 +32,11 @@ export const RealtimeClientContext = createContext<{
messageList: { content: string; role: RoleType }[];
isAiTalking: boolean;
roomInfo: RoomInfo | null;
initClient: (initMessage?:string) => void;
handleConnect: (initMessage?:string) => Promise<void>;
initClient: (initMessage?: string) => void;
handleConnect: (initMessage?: string) => Promise<void>;
handleInterrupt: () => void;
handleDisconnect: () => void;
toggleMicrophone: () => void;
}>({
client: null,
isConnecting: false,
@ -52,7 +51,6 @@ export const RealtimeClientContext = createContext<{
handleInterrupt: () => {},
handleDisconnect: () => {},
toggleMicrophone: () => {},
});
// 添加自定义hook
@ -92,13 +90,11 @@ export const RealtimeClientProvider = ({
// 是否正在说话
const [isAiTalking, setIsAiTalking] = useState(false);
const [roomInfo, setRoomInfo] = useState<RoomInfo | null>(null);
const { toast } = useToast();
const initClient = async (_initMessage?:string) => {
const initClient = async (_initMessage?: string) => {
const permission = await RealtimeUtils.checkDevicePermission(false);
const device = await RealtimeUtils.getAudioDevices();
@ -129,14 +125,12 @@ export const RealtimeClientProvider = ({
clientRef.current = client;
setupEventListeners(client);
setupMessageEventListeners(client,_initMessage ?? '');
setupInitMessageEventListener(client,_initMessage)
setupMessageEventListeners(client, _initMessage ?? "");
setupInitMessageEventListener(client, _initMessage);
};
const handleConnect = async (initMessage?:string) => {
const handleConnect = async (initMessage?: string) => {
try {
if (!clientRef.current) {
await initClient(initMessage);
@ -173,7 +167,7 @@ export const RealtimeClientProvider = ({
}
};
const handleDisconnect = async() => {
const handleDisconnect = async () => {
try {
// 关闭客户的时候清除一些信息
setIsAiTalking(false);
@ -199,53 +193,62 @@ export const RealtimeClientProvider = ({
}
};
const setupInitMessageEventListener = useCallback(
(client: RealtimeClient, _initMessage?: string) => {
client.on(EventNames.ALL_SERVER, async (eventName, _event: any) => {
if (eventName === "server.session.created") {
await client.sendMessage({
id: "",
event_type: "session.update",
data: {
chat_config: {
allow_voice_interrupt: false,
},
},
});
}
if (eventName === "server.bot.join" && _initMessage) {
// 这里需要加个 server. 前缀
await clientRef.current?.sendMessage({
id: "",
event_type: "conversation.message.create",
data: {
role: "user",
content_type: "text",
content: _initMessage,
},
});
}
});
},
[clientRef.current]
);
const setupInitMessageEventListener = useCallback((client: RealtimeClient,_initMessage?:string) => {
client.on(EventNames.ALL_SERVER, async(eventName, _event: any) => {
if (eventName === "server.session.created") {
await client.sendMessage({
id:'',
"event_type":"session.update",
data:{
chat_config:{
allow_voice_interrupt:false
}
}
})
}
if(eventName === "server.bot.join" && _initMessage){
// 这里需要加个 server. 前缀
await clientRef.current?.sendMessage({
id: "",
event_type: "conversation.message.create",
data: {
role: "user",
content_type: "text",
content: _initMessage,
},
});
}
});
},[clientRef.current]);
const setupMessageEventListeners = (client: RealtimeClient,_initMessage:string) => {
const setupMessageEventListeners = (
client: RealtimeClient,
_initMessage: string
) => {
let lastEvent: any;
client.on(EventNames.ALL, (_eventName, event: any) => {
// AI智能体设置
if (
event.event_type !== ChatEventType.CONVERSATION_MESSAGE_DELTA &&
event.event_type !== ChatEventType.CONVERSATION_MESSAGE_COMPLETED &&
event.event_type !== "conversation.created"
event.event_type !== "conversation.created" &&
event.event_type !== "conversation.message.create"
) {
return;
}
const content = event.data.content;
setMessageList((prev) => {
// 如果上一个事件是增量更新,则附加到最后一条消息
// 如果上一个事件是增量更新,则附加到最后一条消息
if (
lastEvent?.event_type === ChatEventType.CONVERSATION_MESSAGE_DELTA &&
(event.data.type === "answer")
event.event_type === ChatEventType.CONVERSATION_MESSAGE_DELTA &&
lastEvent.data.type === event.data.type &&
lastEvent.data.answer_id === event.data.answer_id
) {
return [
...prev.slice(0, -1),
@ -254,7 +257,21 @@ export const RealtimeClientProvider = ({
role: prev[prev.length - 1].role,
},
];
}else if ( // 否则添加新消息
}
// 添加AI的欢迎语
if (
_initMessage === "" &&
event.event_type === "conversation.created"
) {
return [
...prev,
{ content: event.data.prologue, role: RoleType.Assistant },
];
}
// 否则添加新消息
if (
(content !== "" &&
event.event_type === ChatEventType.CONVERSATION_MESSAGE_DELTA) ||
(event.event_type === ChatEventType.CONVERSATION_MESSAGE_COMPLETED &&
@ -263,20 +280,9 @@ export const RealtimeClientProvider = ({
) {
return [...prev, { content: content, role: event.data.role }];
}
// 添加AI的欢迎语
if (_initMessage === "" && event.event_type === "conversation.created") {
return [
...prev,
{ content: event.data.prologue, role: RoleType.Assistant },
];
}
return prev;
});
if(event.data.type === "answer" || event.data.type === "question"){
lastEvent = event;
}
lastEvent = event;
});
};
@ -284,7 +290,7 @@ export const RealtimeClientProvider = ({
const setupEventListeners = useCallback(
(client: RealtimeClient) => {
// 监听 AI 开始说话事件
client.on(EventNames.AUDIO_AGENT_SPEECH_STARTED, async() => {
client.on(EventNames.AUDIO_AGENT_SPEECH_STARTED, async () => {
// console.log("AI开始说话");
setIsAiTalking(true);
await clientRef.current?.setAudioEnable(false);
@ -292,7 +298,7 @@ export const RealtimeClientProvider = ({
});
// 监听 AI 结束说话事件
client.on(EventNames.AUDIO_AGENT_SPEECH_STOPPED, async() => {
client.on(EventNames.AUDIO_AGENT_SPEECH_STOPPED, async () => {
// console.log("AI结束说话");
setIsAiTalking(false);
await clientRef.current?.setAudioEnable(true);
@ -348,7 +354,6 @@ export const RealtimeClientProvider = ({
handleInterrupt,
handleDisconnect,
toggleMicrophone,
}}
>
{children}