speech-queue.ts 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. interface SpeechRequest {
  2. text: string;
  3. voiceId: string;
  4. resolve: (url: string) => void;
  5. reject: (error: unknown) => void;
  6. }
  7. class SpeechQueue {
  8. private queue: SpeechRequest[] = [];
  9. private processing = 0;
  10. private maxConcurrent = 1;
  11. constructor() {
  12. this.processQueue = this.processQueue.bind(this);
  13. }
  14. async add(text: string, voiceId: string): Promise<string> {
  15. return new Promise((resolve, reject) => {
  16. this.queue.push({ text, voiceId, resolve, reject });
  17. this.processQueue();
  18. });
  19. }
  20. private async processQueue() {
  21. if (this.processing >= this.maxConcurrent || this.queue.length === 0) {
  22. return;
  23. }
  24. const request = this.queue.shift();
  25. if (!request) return;
  26. this.processing++;
  27. try {
  28. const response = await fetch("/api/text-to-speech", {
  29. method: "POST",
  30. headers: { "Content-Type": "application/json" },
  31. body: JSON.stringify({
  32. text: request.text,
  33. voiceId: request.voiceId,
  34. }),
  35. });
  36. if (!response.ok) {
  37. const errorData = await response.json();
  38. throw new Error(errorData.error || "Failed to generate speech");
  39. }
  40. const data = await response.json();
  41. request.resolve(data.audioUrl);
  42. } catch (error) {
  43. request.reject(error);
  44. } finally {
  45. this.processing--;
  46. this.processQueue();
  47. }
  48. }
  49. }
  50. const speechQueue = new SpeechQueue();
  51. export default speechQueue;