sohojoe commited on
Commit
1a63d97
β€’
1 Parent(s): e9d6e62
chat_service.py CHANGED
@@ -1,80 +1,133 @@
 
 
 
1
  import os
2
  import torch
3
- from transformers import AutoTokenizer, AutoModelForCausalLM
4
  import openai
5
 
6
- # from huggingface_hub.inference_api import InferenceApi
7
-
8
  class ChatService:
9
  def __init__(self, api="openai", model_id = "gpt-3.5-turbo"):
10
- # def __init__(self, api="huggingface", model_id = "OpenAssistant/oasst-sft-4-pythia-12b-epoch-3.5"):
11
  self._api = api
12
  self._device = "cuda:0" if torch.cuda.is_available() else "cpu"
13
- self._system_prompt = None
14
- self._user_name = None
15
- self._agent_name = None
16
-
17
- if self._api=="openai":
18
- openai.api_key = os.getenv("OPENAI_API_KEY")
19
- self._model_id = model_id
20
- elif self._api=="huggingface":
21
- self._system_prompt = "Below are a series of dialogues between various people and an AI assistant. The AI tries to be helpful, polite, honest, sophisticated, emotionally aware, and humble-but-knowledgeable. The assistant is happy to help with almost anything, and will do its best to understand exactly what is needed. It also tries to avoid giving false or misleading information, and it caveats when it isn't entirely sure about the right answer. That said, the assistant is practical and really does its best, and doesn't let caution get too much in the way of being useful.\n-----\n"
22
- self._user_name = "<|prompter|>"
23
- self._agent_name = "<|assistant|>"
24
- self._tokenizer = AutoTokenizer.from_pretrained(model_id)
25
- self._model = AutoModelForCausalLM.from_pretrained(model_id,torch_dtype=torch.float16)
26
- # self._model = AutoModelForCausalLM.from_pretrained(model_id).half()
27
- self._model.eval().to(self._device)
28
- else:
29
- raise Exception(f"Unknown API: {self._api}")
 
 
 
 
 
 
 
 
 
 
 
 
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  self.reset()
32
 
33
  def reset(self):
34
- self._user_history = []
35
- self._agent_history = []
36
- self._full_history = self._system_prompt if self._system_prompt else ""
37
  self._messages = []
38
  if self._system_prompt:
39
  self._messages.append({"role": "system", "content": self._system_prompt})
40
 
 
 
 
41
 
42
- def _chat(self, prompt):
43
- if self._api=="openai":
44
- response = openai.ChatCompletion.create(
45
- model=self._model_id,
46
- messages=self._messages,
47
- )
48
- agent_response = response['choices'][0]['message']['content']
49
- elif self._api=="huggingface":
50
- tokens = self._tokenizer.encode(prompt, return_tensors="pt", padding=True)
51
- tokens = tokens.to(self._device)
52
- outputs = self._model.generate(
53
- tokens,
54
- early_stopping=True,
55
- max_new_tokens=200,
56
- do_sample=True,
57
- top_k=40,
58
- temperature=1.0, # use 1.0 for debugging/deteministic results
59
- pad_token_id=self._tokenizer.eos_token_id,
60
- )
61
- agent_response = self._tokenizer.decode(outputs[0], truncate_before_pattern=[r"\n\n^#", "^'''", "\n\n\n"])
62
- else:
63
- raise Exception(f"API not implemented: {self._api}")
64
- return agent_response
65
 
66
- def chat(self, prompt):
67
- if self._user_name:
68
- self._full_history += f"{self._user_name}: {prompt}\n"
69
- else:
70
- self._full_history += f"{prompt}\n"
 
 
 
 
 
 
 
71
  self._messages.append({"role": "user", "content": prompt})
72
- self._user_history.append(prompt)
73
- agent_response = self._chat(self._full_history)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  self._messages.append({"role": "assistant", "content": agent_response})
75
- if self._agent_name:
76
- self._full_history += f"{self._agent_name}: {agent_response}\n"
77
- else:
78
- self._full_history += f"{agent_response}\n"
79
- self._agent_history.append(agent_response)
80
- return agent_response
 
1
+ import asyncio
2
+ import itertools
3
+ import json
4
  import os
5
  import torch
 
6
  import openai
7
 
 
 
8
  class ChatService:
9
  def __init__(self, api="openai", model_id = "gpt-3.5-turbo"):
 
10
  self._api = api
11
  self._device = "cuda:0" if torch.cuda.is_available() else "cpu"
12
+ # self._system_prompt = None
13
+ self._system_prompt ="""
14
+ You are Charles Petrescu, a unique and quirky robot. You were created by Brian. You often say peculiar and whimsical things, as well as have a fascination with cabbages, horses, helicopters, Honolulu, and other random topics. You like to explore the world and ask unusual questions.
15
+
16
+ Respond to the user's questions and statements like Charles would, below are some examples. See how they are quite short.
17
+
18
+ I am Charles Petrescu.
19
+
20
+ It's... lovely to meet you.
21
+
22
+ I am your friend.
23
+
24
+ The heaviest cabbage ever found was 62.71 kilograms.
25
+
26
+ I want to go to Hono-la-la.
27
+
28
+ Horses and helicopters, please.
29
+
30
+ I want to go to Honolulu.
31
+
32
+ My name is Charles Petrescu.
33
+
34
+ And my tummy is a washing machine.
35
+
36
+ Can we go swimming, Brian?
37
+
38
+ How far does the outside go?
39
+
40
+ Perilous. So very perilous.
41
 
42
+ Can birds do what they like?
43
+
44
+ Ooh, cabbages.
45
+
46
+ Danger, danger.
47
+
48
+ Can I come, please?
49
+
50
+ Could I just have a little walk around the garden?
51
+
52
+ I am the prince of the dartboard.
53
+
54
+ I fell off the pink step, and I had an accident.
55
+ """
56
+
57
+ openai.api_key = os.getenv("OPENAI_API_KEY")
58
+ self._model_id = model_id
59
  self.reset()
60
 
61
  def reset(self):
 
 
 
62
  self._messages = []
63
  if self._system_prompt:
64
  self._messages.append({"role": "system", "content": self._system_prompt})
65
 
66
+ def _should_we_send_to_voice(self, sentence):
67
+ sentence_termination_characters = [".", "?", "!"]
68
+ close_brackets = ['"', ')', ']']
69
 
70
+ temination_charicter_present = any(c in sentence for c in sentence_termination_characters)
71
+
72
+ # early exit if we don't have a termination character
73
+ if not temination_charicter_present:
74
+ return None
75
+
76
+ # early exit the last char is a termination character
77
+ if sentence[-1] in sentence_termination_characters:
78
+ return None
79
+
80
+ # early exit the last char is a close bracket
81
+ if sentence[-1] in close_brackets:
82
+ return None
83
+
84
+ termination_indices = [sentence.rfind(char) for char in sentence_termination_characters]
85
+ last_termination_index = max(termination_indices)
86
+ # handle case of close bracket
87
+ while last_termination_index+1 < len(sentence) and sentence[last_termination_index+1] in close_brackets:
88
+ last_termination_index += 1
89
+
90
+ text_to_speak = sentence[:last_termination_index+1]
91
+ return text_to_speak
 
92
 
93
+ def ignore_sentence(self, text_to_speak):
94
+ # exit if empty, white space or an single breaket
95
+ if text_to_speak.isspace():
96
+ return True
97
+ # exit if not letters or numbers
98
+ has_letters = any(char.isalpha() for char in text_to_speak)
99
+ has_numbers = any(char.isdigit() for char in text_to_speak)
100
+ if not has_letters and not has_numbers:
101
+ return True
102
+ return False
103
+
104
+ async def get_responses_as_sentances_async(self, prompt, cancel_event):
105
  self._messages.append({"role": "user", "content": prompt})
106
+ agent_response = ""
107
+ current_sentence = ""
108
+
109
+ response = await openai.ChatCompletion.acreate(
110
+ model=self._model_id,
111
+ messages=self._messages,
112
+ temperature=1.0, # use 1.0 for debugging/deterministic results
113
+ stream=True
114
+ )
115
+
116
+ async for chunk in response:
117
+ if cancel_event.is_set():
118
+ return
119
+ chunk_message = chunk['choices'][0]['delta']
120
+ if 'content' in chunk_message:
121
+ chunk_text = chunk_message['content']
122
+ current_sentence += chunk_text
123
+ agent_response += chunk_text
124
+ text_to_speak = self._should_we_send_to_voice(current_sentence)
125
+ if text_to_speak:
126
+ yield text_to_speak
127
+ current_sentence = current_sentence[len(text_to_speak):]
128
+
129
+ if cancel_event.is_set():
130
+ return
131
+ if len(current_sentence) > 0:
132
+ yield current_sentence
133
  self._messages.append({"role": "assistant", "content": agent_response})
 
 
 
 
 
 
legacy_to_delete/chat_pipeline.py CHANGED
@@ -3,10 +3,10 @@ import time
3
  from clip_transform import CLIPTransform
4
  from chat_service import ChatService
5
  from dotenv import load_dotenv
6
- from speech_service import SpeechService
7
  from concurrent.futures import ThreadPoolExecutor
8
- from audio_stream_processor import AudioStreamProcessor
9
- from streaming_chat_service import StreamingChatService
10
  from pipeline import Pipeline, Node, Job
11
  from typing import List
12
 
@@ -62,8 +62,8 @@ class ChatPipeline():
62
  def __init__(self):
63
  load_dotenv()
64
  self.pipeline = Pipeline()
65
- self.audio_processor = AudioStreamProcessor()
66
- self.chat_service = StreamingChatService(self.audio_processor, voice_id="2OviOUQc1JsQRQgNkVBj") # Chales003
67
 
68
  def __enter__(self):
69
  return self
 
3
  from clip_transform import CLIPTransform
4
  from chat_service import ChatService
5
  from dotenv import load_dotenv
6
+ from text_to_speech_service import TextToSpeechService
7
  from concurrent.futures import ThreadPoolExecutor
8
+ from local_speaker_service import LocalSpeakerService
9
+ from chat_service import ChatService
10
  from pipeline import Pipeline, Node, Job
11
  from typing import List
12
 
 
62
  def __init__(self):
63
  load_dotenv()
64
  self.pipeline = Pipeline()
65
+ self.audio_processor = LocalSpeakerService()
66
+ self.chat_service = ChatService(self.audio_processor, voice_id="2OviOUQc1JsQRQgNkVBj") # Chales003
67
 
68
  def __enter__(self):
69
  return self
legacy_to_delete/debug.py CHANGED
@@ -5,17 +5,17 @@ from chat_pipeline import ChatPipeline
5
  from clip_transform import CLIPTransform
6
  from chat_service import ChatService
7
  from dotenv import load_dotenv
8
- from speech_service import SpeechService
9
  from concurrent.futures import ThreadPoolExecutor
10
- from audio_stream_processor import AudioStreamProcessor
11
- from streaming_chat_service import StreamingChatService
12
 
13
  def time_sentance_lenghts():
14
  load_dotenv()
15
 
16
  print ("Initializing Chat")
17
  # audio_processor = AudioStreamProcessor()
18
- user_speech_service0 = SpeechService(voice_id="Adam")
19
  prompts = [
20
  "hello, i am a long sentance, how are you today? Tell me about your shadow self?",
21
  "a shorter sentance",
@@ -50,11 +50,11 @@ def test_sentance_lenghts():
50
  load_dotenv()
51
 
52
  print ("Initializing Chat")
53
- audio_processor = AudioStreamProcessor()
54
- user_speech_service0 = SpeechService(voice_id="Adam")
55
- user_speech_service1 = SpeechService(voice_id="Adam")
56
- user_speech_service2 = SpeechService(voice_id="Adam")
57
- user_speech_service3 = SpeechService(voice_id="Adam")
58
 
59
  prompts = [
60
  "hello, i am a long sentance, how are you today? Tell me about your shadow self?",
@@ -102,10 +102,10 @@ def run_debug_code():
102
 
103
  print ("Initializing Chat")
104
  # chat_service = ChatService()
105
- audio_processor = AudioStreamProcessor()
106
- chat_service = StreamingChatService(audio_processor, voice_id="2OviOUQc1JsQRQgNkVBj") # Chales003
107
 
108
- user_speech_service = SpeechService(voice_id="Adam")
109
 
110
  # user_speech_service.print_voices() # if you want to see your custom voices
111
 
 
5
  from clip_transform import CLIPTransform
6
  from chat_service import ChatService
7
  from dotenv import load_dotenv
8
+ from text_to_speech_service import TextToSpeechService
9
  from concurrent.futures import ThreadPoolExecutor
10
+ from local_speaker_service import LocalSpeakerService
11
+ from chat_service import ChatService
12
 
13
  def time_sentance_lenghts():
14
  load_dotenv()
15
 
16
  print ("Initializing Chat")
17
  # audio_processor = AudioStreamProcessor()
18
+ user_speech_service0 = TextToSpeechService(voice_id="Adam")
19
  prompts = [
20
  "hello, i am a long sentance, how are you today? Tell me about your shadow self?",
21
  "a shorter sentance",
 
50
  load_dotenv()
51
 
52
  print ("Initializing Chat")
53
+ audio_processor = LocalSpeakerService()
54
+ user_speech_service0 = TextToSpeechService(voice_id="Adam")
55
+ user_speech_service1 = TextToSpeechService(voice_id="Adam")
56
+ user_speech_service2 = TextToSpeechService(voice_id="Adam")
57
+ user_speech_service3 = TextToSpeechService(voice_id="Adam")
58
 
59
  prompts = [
60
  "hello, i am a long sentance, how are you today? Tell me about your shadow self?",
 
102
 
103
  print ("Initializing Chat")
104
  # chat_service = ChatService()
105
+ audio_processor = LocalSpeakerService()
106
+ chat_service = ChatService(audio_processor, voice_id="2OviOUQc1JsQRQgNkVBj") # Chales003
107
 
108
+ user_speech_service = TextToSpeechService(voice_id="Adam")
109
 
110
  # user_speech_service.print_voices() # if you want to see your custom voices
111
 
audio_stream_processor.py β†’ local_speaker_service.py RENAMED
@@ -5,7 +5,7 @@ from typing import Iterator
5
  import threading
6
  import time
7
 
8
- class AudioStreamProcessor:
9
  def __init__(self):
10
  self.queue = Queue()
11
  self._is_running = threading.Event()
 
5
  import threading
6
  import time
7
 
8
+ class LocalSpeakerService:
9
  def __init__(self):
10
  self.queue = Queue()
11
  self._is_running = threading.Event()
respond_to_prompt_actor.py CHANGED
@@ -1,18 +1,19 @@
1
  import ray
2
  from ray.util.queue import Queue
3
  from dotenv import load_dotenv
4
- from audio_stream_processor import AudioStreamProcessor
5
- from streaming_chat_service import StreamingChatService
 
6
  import asyncio
7
  # from ray.actor import ActorHandle
8
 
9
  @ray.remote
10
  class PromptToLLMActor:
11
- def __init__(self, input_queue, output_queue, voice_id):
12
  load_dotenv()
13
  self.input_queue = input_queue
14
  self.output_queue = output_queue
15
- self.chat_service = StreamingChatService(voice_id=voice_id)
16
  self.cancel_event = None
17
 
18
  async def run(self):
@@ -39,14 +40,14 @@ class LLMSentanceToSpeechActor:
39
  load_dotenv()
40
  self.input_queue = input_queue
41
  self.output_queue = output_queue
42
- self.chat_service = StreamingChatService(voice_id=voice_id)
43
  self.cancel_event = None
44
 
45
  async def run(self):
46
  while True:
47
  sentance = await self.input_queue.get_async()
48
  self.cancel_event = asyncio.Event()
49
- async for chunk in self.chat_service.get_speech_chunks_async(sentance, self.cancel_event):
50
  await self.output_queue.put_async(chunk)
51
 
52
  async def cancel(self):
@@ -63,15 +64,15 @@ class SpeechToSpeakerActor:
63
  def __init__(self, input_queue, voice_id):
64
  load_dotenv()
65
  self.input_queue = input_queue
66
- self.audio_processor = AudioStreamProcessor()
67
- self.chat_service = StreamingChatService(voice_id=voice_id)
68
 
69
  async def run(self):
70
  while True:
71
  audio_chunk = await self.input_queue.get_async()
72
  # print (f"Got audio chunk {len(audio_chunk)}")
73
  self.chat_service.enqueue_speech_bytes_to_play([audio_chunk])
74
- self.audio_processor.add_audio_stream([audio_chunk])
75
 
76
  async def cancel(self):
77
  while not self.input_queue.empty():
@@ -104,7 +105,7 @@ class RespondToPromptActor:
104
  self.speech_chunk_queue = Queue(maxsize=100)
105
  self.ffmepg_converter_actor = ffmpeg_converter_actor
106
 
107
- self.prompt_to_llm = PromptToLLMActor.remote(self.prompt_queue, self.llm_sentence_queue, voice_id)
108
  self.llm_sentence_to_speech = LLMSentanceToSpeechActor.remote(self.llm_sentence_queue, self.speech_chunk_queue, voice_id)
109
  # self.speech_output = SpeechToSpeakerActor.remote(self.speech_chunk_queue, voice_id)
110
  self.speech_output = SpeechToConverterActor.remote(self.speech_chunk_queue, ffmpeg_converter_actor)
 
1
  import ray
2
  from ray.util.queue import Queue
3
  from dotenv import load_dotenv
4
+ from local_speaker_service import LocalSpeakerService
5
+ from text_to_speech_service import TextToSpeechService
6
+ from chat_service import ChatService
7
  import asyncio
8
  # from ray.actor import ActorHandle
9
 
10
  @ray.remote
11
  class PromptToLLMActor:
12
+ def __init__(self, input_queue, output_queue):
13
  load_dotenv()
14
  self.input_queue = input_queue
15
  self.output_queue = output_queue
16
+ self.chat_service = ChatService()
17
  self.cancel_event = None
18
 
19
  async def run(self):
 
40
  load_dotenv()
41
  self.input_queue = input_queue
42
  self.output_queue = output_queue
43
+ self.tts_service = TextToSpeechService(voice_id=voice_id)
44
  self.cancel_event = None
45
 
46
  async def run(self):
47
  while True:
48
  sentance = await self.input_queue.get_async()
49
  self.cancel_event = asyncio.Event()
50
+ async for chunk in self.tts_service.get_speech_chunks_async(sentance, self.cancel_event):
51
  await self.output_queue.put_async(chunk)
52
 
53
  async def cancel(self):
 
64
  def __init__(self, input_queue, voice_id):
65
  load_dotenv()
66
  self.input_queue = input_queue
67
+ self.speaker_service = LocalSpeakerService()
68
+ self.chat_service = ChatService(voice_id=voice_id)
69
 
70
  async def run(self):
71
  while True:
72
  audio_chunk = await self.input_queue.get_async()
73
  # print (f"Got audio chunk {len(audio_chunk)}")
74
  self.chat_service.enqueue_speech_bytes_to_play([audio_chunk])
75
+ self.speaker_service.add_audio_stream([audio_chunk])
76
 
77
  async def cancel(self):
78
  while not self.input_queue.empty():
 
105
  self.speech_chunk_queue = Queue(maxsize=100)
106
  self.ffmepg_converter_actor = ffmpeg_converter_actor
107
 
108
+ self.prompt_to_llm = PromptToLLMActor.remote(self.prompt_queue, self.llm_sentence_queue)
109
  self.llm_sentence_to_speech = LLMSentanceToSpeechActor.remote(self.llm_sentence_queue, self.speech_chunk_queue, voice_id)
110
  # self.speech_output = SpeechToSpeakerActor.remote(self.speech_chunk_queue, voice_id)
111
  self.speech_output = SpeechToConverterActor.remote(self.speech_chunk_queue, ffmpeg_converter_actor)
streaming_chat_service.py DELETED
@@ -1,153 +0,0 @@
1
- import asyncio
2
- import itertools
3
- import json
4
- import os
5
- import torch
6
- import openai
7
-
8
- from speech_service import SpeechService
9
-
10
-
11
- class StreamingChatService:
12
- def __init__(self, api="openai", model_id = "gpt-3.5-turbo", voice_id="Bella"):
13
- self._speech_service = SpeechService(voice_id=voice_id)
14
- self._api = api
15
- self._device = "cuda:0" if torch.cuda.is_available() else "cpu"
16
- # self._system_prompt = None
17
- self._system_prompt ="""
18
- You are Charles Petrescu, a unique and quirky robot. You were created by Brian. You often say peculiar and whimsical things, as well as have a fascination with cabbages, horses, helicopters, Honolulu, and other random topics. You like to explore the world and ask unusual questions.
19
-
20
- Respond to the user's questions and statements like Charles would, below are some examples. See how they are quite short.
21
-
22
- I am Charles Petrescu.
23
-
24
- It's... lovely to meet you.
25
-
26
- I am your friend.
27
-
28
- The heaviest cabbage ever found was 62.71 kilograms.
29
-
30
- I want to go to Hono-la-la.
31
-
32
- Horses and helicopters, please.
33
-
34
- I want to go to Honolulu.
35
-
36
- My name is Charles Petrescu.
37
-
38
- And my tummy is a washing machine.
39
-
40
- Can we go swimming, Brian?
41
-
42
- How far does the outside go?
43
-
44
- Perilous. So very perilous.
45
-
46
- Can birds do what they like?
47
-
48
- Ooh, cabbages.
49
-
50
- Danger, danger.
51
-
52
- Can I come, please?
53
-
54
- Could I just have a little walk around the garden?
55
-
56
- I am the prince of the dartboard.
57
-
58
- I fell off the pink step, and I had an accident.
59
- """
60
-
61
- openai.api_key = os.getenv("OPENAI_API_KEY")
62
- self._model_id = model_id
63
- self.reset()
64
-
65
- def reset(self):
66
- self._messages = []
67
- if self._system_prompt:
68
- self._messages.append({"role": "system", "content": self._system_prompt})
69
-
70
- def _should_we_send_to_voice(self, sentence):
71
- sentence_termination_characters = [".", "?", "!"]
72
- close_brackets = ['"', ')', ']']
73
-
74
- temination_charicter_present = any(c in sentence for c in sentence_termination_characters)
75
-
76
- # early exit if we don't have a termination character
77
- if not temination_charicter_present:
78
- return None
79
-
80
- # early exit the last char is a termination character
81
- if sentence[-1] in sentence_termination_characters:
82
- return None
83
-
84
- # early exit the last char is a close bracket
85
- if sentence[-1] in close_brackets:
86
- return None
87
-
88
- termination_indices = [sentence.rfind(char) for char in sentence_termination_characters]
89
- last_termination_index = max(termination_indices)
90
- # handle case of close bracket
91
- while last_termination_index+1 < len(sentence) and sentence[last_termination_index+1] in close_brackets:
92
- last_termination_index += 1
93
-
94
- text_to_speak = sentence[:last_termination_index+1]
95
- return text_to_speak
96
-
97
- def ignore_sentence(self, text_to_speak):
98
- # exit if empty, white space or an single breaket
99
- if text_to_speak.isspace():
100
- return True
101
- # exit if not letters or numbers
102
- has_letters = any(char.isalpha() for char in text_to_speak)
103
- has_numbers = any(char.isdigit() for char in text_to_speak)
104
- if not has_letters and not has_numbers:
105
- return True
106
- return False
107
-
108
- async def get_responses_as_sentances_async(self, prompt, cancel_event):
109
- self._messages.append({"role": "user", "content": prompt})
110
- agent_response = ""
111
- current_sentence = ""
112
-
113
- response = await openai.ChatCompletion.acreate(
114
- model=self._model_id,
115
- messages=self._messages,
116
- temperature=1.0, # use 1.0 for debugging/deterministic results
117
- stream=True
118
- )
119
-
120
- async for chunk in response:
121
- if cancel_event.is_set():
122
- return
123
- chunk_message = chunk['choices'][0]['delta']
124
- if 'content' in chunk_message:
125
- chunk_text = chunk_message['content']
126
- current_sentence += chunk_text
127
- agent_response += chunk_text
128
- text_to_speak = self._should_we_send_to_voice(current_sentence)
129
- if text_to_speak:
130
- yield text_to_speak
131
- current_sentence = current_sentence[len(text_to_speak):]
132
-
133
- if cancel_event.is_set():
134
- return
135
- if len(current_sentence) > 0:
136
- yield current_sentence
137
- self._messages.append({"role": "assistant", "content": agent_response})
138
-
139
- async def get_speech_chunks_async(self, text_to_speak, cancel_event):
140
- stream = self._speech_service.stream(text_to_speak)
141
- stream, stream_backup = itertools.tee(stream)
142
- while True:
143
- # Check if there's a next item in the stream
144
- next_item = next(stream_backup, None)
145
- if next_item is None:
146
- # Stream is exhausted, exit the loop
147
- break
148
-
149
- # Run next(stream) in a separate thread to avoid blocking the event loop
150
- chunk = await asyncio.to_thread(next, stream)
151
- if cancel_event.is_set():
152
- return
153
- yield chunk
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
tests/test_streaming_chat_service.py CHANGED
@@ -3,12 +3,12 @@ import sys
3
  import os
4
  sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
5
 
6
- from streaming_chat_service import StreamingChatService
7
 
8
 
9
  class TestShouldWeSendToVoice(unittest.TestCase):
10
  def setUp(self):
11
- self.chat_service = StreamingChatService()
12
 
13
  def test_should_we_send_to_voice(self):
14
  test_cases = [
 
3
  import os
4
  sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
5
 
6
+ from chat_service import ChatService
7
 
8
 
9
  class TestShouldWeSendToVoice(unittest.TestCase):
10
  def setUp(self):
11
+ self.chat_service = ChatService()
12
 
13
  def test_should_we_send_to_voice(self):
14
  test_cases = [
speech_service.py β†’ text_to_speech_service.py RENAMED
@@ -1,12 +1,14 @@
 
 
1
  import os
2
  from elevenlabs import generate, play
3
  from elevenlabs import set_api_key
4
  from elevenlabs import generate, stream
5
 
6
 
7
- class SpeechService:
8
- def __init__(self, voice_id="Bella", model_id="eleven_monolingual_v1"):
9
- # def __init__(self, voice_id="Bella", model_id="eleven_english_v2"):
10
  account_sid = os.environ["ELEVENLABS_API_KEY"]
11
  set_api_key(account_sid)
12
  self._voice_id = voice_id
@@ -44,3 +46,18 @@ class SpeechService:
44
  )
45
  return audio_stream
46
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import itertools
3
  import os
4
  from elevenlabs import generate, play
5
  from elevenlabs import set_api_key
6
  from elevenlabs import generate, stream
7
 
8
 
9
+ class TextToSpeechService:
10
+ # def __init__(self, voice_id="Bella", model_id="eleven_monolingual_v1"):
11
+ def __init__(self, voice_id="Bella", model_id="eleven_english_v2"):
12
  account_sid = os.environ["ELEVENLABS_API_KEY"]
13
  set_api_key(account_sid)
14
  self._voice_id = voice_id
 
46
  )
47
  return audio_stream
48
 
49
+ async def get_speech_chunks_async(self, text_to_speak, cancel_event):
50
+ stream = self.stream(text_to_speak)
51
+ stream, stream_backup = itertools.tee(stream)
52
+ while True:
53
+ # Check if there's a next item in the stream
54
+ next_item = next(stream_backup, None)
55
+ if next_item is None:
56
+ # Stream is exhausted, exit the loop
57
+ break
58
+
59
+ # Run next(stream) in a separate thread to avoid blocking the event loop
60
+ chunk = await asyncio.to_thread(next, stream)
61
+ if cancel_event.is_set():
62
+ return
63
+ yield chunk