Last active
December 24, 2024 16:26
-
-
Save lubobill1990/9fb074255706e7194a9b5920cec57810 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { from, of, Observable, merge, interval } from "rxjs"; | |
import { | |
mergeMap, | |
map, | |
toArray, | |
catchError, | |
distinct, | |
share, | |
take, | |
last, | |
} from "rxjs/operators"; | |
function getIntervalSourceFromArray<T>(stringArray: T[], i: number = 1000) { | |
const observable: Observable<T> = interval(i).pipe( | |
take(stringArray.length), // take as many items as there are in the array | |
map((index) => stringArray[index]) // map the emitted index to the corresponding string from the array | |
); | |
return observable; | |
} | |
let i = 0; | |
function getCachedMeetingInsight( | |
transcriptUrl: string | |
): Promise<string | null> { | |
console.log(`Fetching cached insight for ${transcriptUrl}`); | |
i += 1; | |
if (i % 2 === 0) { | |
// Simulating a cache miss for demonstration | |
console.log(`Insight cache missed of ${transcriptUrl}.`); | |
return Promise.resolve(null); | |
} | |
console.log(`Cached insight fetched of ${transcriptUrl}.`); | |
return Promise.resolve(`This is cached insight of ${transcriptUrl}.`); | |
} | |
function getRawTranscriptFromTranscriptUrl(url: string): Promise<string> { | |
console.log(`Fetching raw transcript from ${url}`); | |
return Promise.resolve(`Raw transcript content for ${url}`); | |
} | |
function getMeetingInsightFromRawTranscript( | |
rawTranscript: string | |
): Promise<string> { | |
console.log(`Generating meeting insight from raw transcript`); | |
return Promise.resolve(`Insight from: ${rawTranscript}`); | |
} | |
function getOpeningScriptAndTopics( | |
rawTranscriptList: string[] | |
): [Observable<string>, Observable<string>] { | |
console.log("Generating opening script and topics"); | |
const openingScriptLines$ = getIntervalSourceFromArray([ | |
"Opening line 1", | |
"Opening line 2", | |
"Opening line 3", | |
]); | |
const topics$ = getIntervalSourceFromArray(["Topic 1", "Topic 2", "Topic 3"]); | |
return [openingScriptLines$, topics$]; | |
} | |
function generateTopicPodcastScript( | |
topic: string, | |
openingScript: string, | |
transcriptList: string[] | |
): Observable<string> { | |
console.log(`Generating podcast script for topic: ${topic}`); | |
return getIntervalSourceFromArray( | |
[ | |
`Script line 1 of topic ${topic} with opening script ${openingScript}`, | |
`Script line 2 of topic ${topic} with opening script ${openingScript}`, | |
`Script line 3 of topic ${topic} with opening script ${openingScript}`, | |
], | |
500 | |
); | |
} | |
function generatePodcastAudioBuffers( | |
podcastScript: string | |
): Observable<ArrayBuffer> { | |
console.log(`Generating audio buffer for: ${podcastScript}`); | |
return getIntervalSourceFromArray( | |
[new ArrayBuffer(1024), new ArrayBuffer(1024), new ArrayBuffer(1024)], | |
500 | |
); | |
} | |
let filePathIndex = 0; | |
function getNextFilePath(): string { | |
filePathIndex += 1; | |
return `file_${filePathIndex}.mp3`; | |
} | |
function writeAudioBufferToFile( | |
filePath: string, | |
audioBuffer: ArrayBuffer | |
): Promise<void> { | |
console.log(`Writing audio buffer to file: ${filePath}`); | |
return Promise.resolve(); | |
} | |
function generatePodcast(transcriptUrls: string[]): Observable<string[]> { | |
return from(transcriptUrls).pipe( | |
// Step 1: For each transcript URL, get the meeting insight | |
mergeMap((url) => | |
from(getCachedMeetingInsight(url)).pipe( | |
mergeMap((cachedInsight) => { | |
if (cachedInsight) { | |
// Use cached insight if available | |
return of(cachedInsight); | |
} else { | |
// Fetch raw transcript and generate meeting insight | |
return from(getRawTranscriptFromTranscriptUrl(url)).pipe( | |
mergeMap((rawTranscript) => | |
getMeetingInsightFromRawTranscript(rawTranscript) | |
), | |
catchError((err) => { | |
console.error(`Failed to process transcript URL: ${url}`, err); | |
return of(""); // Fallback to empty string | |
}) | |
); | |
} | |
}) | |
) | |
), | |
toArray(), // Step 2: Concatenate meeting insights into an array | |
mergeMap((meetingInsights) => { | |
// Step 3: Generate opening script and topics from the insights | |
const [openingScriptLines$, topics$] = | |
getOpeningScriptAndTopics(meetingInsights); | |
const openingfilePath = getNextFilePath(); | |
console.log(`Generated filePath for opening script: ${openingfilePath}`); | |
// Fork openingScriptLines$ so we can reuse it | |
const openingScriptLinesForked$ = openingScriptLines$.pipe(share()); | |
// Step 4: Process and store the opening script audio | |
const openingAudio$ = openingScriptLines$.pipe( | |
mergeMap((line) => | |
generatePodcastAudioBuffers(line).pipe( | |
mergeMap((audioBuffer) => { | |
return from( | |
writeAudioBufferToFile(openingfilePath, audioBuffer) | |
).pipe(map(() => openingfilePath)); | |
}) | |
) | |
) | |
); | |
// Step 5 & 6: Process each topic to generate scripts and audio | |
const topicsAudio$ = from( | |
openingScriptLinesForked$.pipe( | |
toArray(), | |
map((lines) => lines.join(" ")) | |
) | |
).pipe( | |
mergeMap((openingScript) => { | |
return topics$.pipe( | |
mergeMap((topic) => { | |
const filePath = getNextFilePath(); | |
console.log(`Generated filePath for topic script: ${filePath}`); | |
const topicPodcastFile$ = generateTopicPodcastScript( | |
topic, | |
openingScript, // Pass the joined opening script lines | |
meetingInsights | |
).pipe( | |
mergeMap((scriptLine) => | |
generatePodcastAudioBuffers(scriptLine).pipe( | |
mergeMap((audioBuffer) => { | |
return from( | |
writeAudioBufferToFile(filePath, audioBuffer) | |
).pipe(map(() => filePath)); | |
}) | |
) | |
) | |
); | |
return topicPodcastFile$; | |
}), | |
); | |
}) | |
); | |
// Combine the opening audio and topic audios into one observable | |
return merge(openingAudio$, topicsAudio$).pipe(distinct(), toArray()); | |
}) | |
); | |
} | |
// Usage Example | |
const transcriptUrls = [ | |
"https://example.com/transcript1", | |
"https://example.com/transcript2", | |
]; | |
generatePodcast(transcriptUrls).subscribe({ | |
next: (audioFilePaths) => { | |
console.log("Generated podcast audio files:", audioFilePaths); | |
}, | |
error: (err) => { | |
console.error("Error generating podcast:", err); | |
}, | |
complete: () => { | |
console.log("Podcast generation complete."); | |
}, | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment