feat: enable podcast

This commit is contained in:
Li Xin
2025-04-19 22:11:57 +08:00
parent 4d33aeed6a
commit 2f06f0c433
7 changed files with 172 additions and 33 deletions

View File

@@ -64,9 +64,9 @@ async function* chatStreamMock(
const [, event] = eventRaw.split("event: ", 2) as [string, string];
const [, data] = dataRaw.split("data: ", 2) as [string, string];
if (event === "message_chunk") {
await sleep(100);
await sleep(0);
} else if (event === "tool_call_result") {
await sleep(2000);
await sleep(0);
}
try {
yield {

View File

@@ -0,0 +1,19 @@
// Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
// SPDX-License-Identifier: MIT
export async function generatePodcast(content: string) {
const response = await fetch("/api/podcast/generate", {
method: "post",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ content }),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const arrayBuffer = await response.arrayBuffer();
const blob = new Blob([arrayBuffer], { type: "audio/mp3" });
const audioUrl = URL.createObjectURL(blob);
return audioUrl;
}

View File

@@ -6,7 +6,13 @@ export type MessageRole = "user" | "assistant" | "tool";
export interface Message {
id: string;
threadId: string;
agent?: "coordinator" | "planner" | "researcher" | "coder" | "reporter";
agent?:
| "coordinator"
| "planner"
| "researcher"
| "coder"
| "reporter"
| "podcast";
role: MessageRole;
isStreaming?: boolean;
content: string;

View File

@@ -6,6 +6,7 @@ import { nanoid } from "nanoid";
import { create } from "zustand";
import { chatStream } from "../api";
import { generatePodcast } from "../api/podcast";
import type { Message } from "../messages";
import { mergeMessage } from "../messages";
@@ -88,7 +89,7 @@ export async function sendMessage(
};
appendMessage(message);
}
message ??= findMessage(messageId);
message ??= getMessage(messageId);
if (message) {
message = mergeMessage(message, event);
updateMessage(message);
@@ -107,7 +108,7 @@ function existsMessage(id: string) {
return useStore.getState().messageIds.includes(id);
}
function findMessage(id: string) {
function getMessage(id: string) {
return useStore.getState().messages.get(id);
}
@@ -175,7 +176,7 @@ function appendResearch(researchId: string) {
let planMessage: Message | undefined;
const reversedMessageIds = [...useStore.getState().messageIds].reverse();
for (const messageId of reversedMessageIds) {
const message = findMessage(messageId);
const message = getMessage(messageId);
if (message?.agent === "planner") {
planMessage = message;
break;
@@ -224,6 +225,46 @@ export function openResearch(researchId: string | null) {
});
}
export async function listenToPodcast(researchId: string) {
const planMessageId = useStore.getState().researchPlanIds.get(researchId);
const reportMessageId = useStore.getState().researchReportIds.get(researchId);
if (planMessageId && reportMessageId) {
const planMessage = getMessage(planMessageId)!;
const title = (JSON.parse(planMessage.content) as { title: string }).title;
const reportMessage = getMessage(reportMessageId);
if (reportMessage?.content) {
appendMessage({
id: nanoid(),
threadId: THREAD_ID,
role: "user",
content: "Please generate a podcast for the above research.",
contentChunks: [],
});
const podCastMessageId = nanoid();
const podcastObject = { title, researchId };
const podcastMessage: Message = {
id: podCastMessageId,
threadId: THREAD_ID,
role: "assistant",
agent: "podcast",
content: JSON.stringify(podcastObject),
contentChunks: [],
isStreaming: true,
};
appendMessage(podcastMessage);
// Generating podcast...
const audioUrl = await generatePodcast(reportMessage.content);
useStore.setState((state) => ({
messages: new Map(useStore.getState().messages).set(podCastMessageId, {
...state.messages.get(podCastMessageId)!,
content: JSON.stringify({ ...podcastObject, audioUrl }),
isStreaming: false,
}),
}));
}
}
}
export function useResearchTitle(researchId: string) {
const planMessage = useMessage(
useStore.getState().researchPlanIds.get(researchId),
@@ -236,7 +277,3 @@ export function useMessage(messageId: string | null | undefined) {
messageId ? state.messages.get(messageId) : undefined,
);
}
// void sendMessage(
// "How many times taller is the Eiffel Tower than the tallest building in the world?",
// );