-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathbit_stt_chat.py
More file actions
218 lines (178 loc) Β· 7.61 KB
/
Copy pathbit_stt_chat.py
File metadata and controls
218 lines (178 loc) Β· 7.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
import torch
import torch._dynamo
# Completely disable PyTorch compilation to avoid warnings
torch._dynamo.config.disable = True
from transformers import AutoModelForCausalLM, AutoTokenizer
import sounddevice as sd
import scipy.io.wavfile as wav
import numpy as np
import whisper
import time
import warnings
import sys
import os
warnings.filterwarnings("ignore", category=FutureWarning)
# Audio settings
SAMPLE_RATE = 16000
CHANNELS = 1
OUTPUT_FILE = "recorded_audio.wav"
class VoiceChat:
def __init__(self):
self.recording = []
self.model = None
self.tokenizer = None
self.whisper_model = None
self.messages = [
{"role": "system", "content": "You are a helpful AI assistant. Keep your responses concise and conversational."}
]
def load_models(self):
"""Load both BitNet and Whisper models"""
print("π Loading models...")
# Load Whisper model
print("π± Loading Whisper STT model...")
self.whisper_model = whisper.load_model("tiny.en")
print("β
Whisper model loaded!")
# Load BitNet model
model_id = "microsoft/bitnet-b1.58-2B-4T"
print("π€ Loading BitNet tokenizer...")
self.tokenizer = AutoTokenizer.from_pretrained(model_id)
print("π€ Loading BitNet model (this may take a while)...")
self.model = AutoModelForCausalLM.from_pretrained(
model_id,
torch_dtype=torch.bfloat16,
device_map={"": "cuda:0"}
)
print(f"β
BitNet model loaded on device: {self.model.device}")
print(f"π Model dtype: {self.model.dtype}")
def audio_callback(self, indata, frames, time_info, status):
"""Callback for audio recording"""
self.recording.append(indata.copy())
def record_audio(self):
"""Record audio from microphone"""
self.recording = []
print("π€ Recording... Press [Enter] to stop.")
with sd.InputStream(samplerate=SAMPLE_RATE, channels=CHANNELS, callback=self.audio_callback):
input()
audio_data = np.concatenate(self.recording, axis=0)
wav.write(OUTPUT_FILE, SAMPLE_RATE, audio_data)
print("π΅ Audio recorded!")
def transcribe_audio(self):
"""Convert speech to text using Whisper"""
if not os.path.exists(OUTPUT_FILE):
return None
print("π Converting speech to text...")
result = self.whisper_model.transcribe(OUTPUT_FILE)
transcribed_text = result["text"].strip()
if transcribed_text:
print(f"π You said: {transcribed_text}")
return transcribed_text
else:
print("β No speech detected, please try again.")
return None
def generate_response(self, user_input, max_tokens=100):
"""Generate response from BitNet model"""
try:
# Add user message to conversation
self.messages.append({"role": "user", "content": user_input})
# Apply chat template
prompt = self.tokenizer.apply_chat_template(
self.messages, tokenize=False, add_generation_prompt=True
)
chat_input = self.tokenizer(prompt, return_tensors="pt").to(self.model.device)
print("π€ Generating response...")
# Generate response
with torch.no_grad():
chat_outputs = self.model.generate(
**chat_input,
max_new_tokens=max_tokens,
do_sample=True,
temperature=0.7,
top_p=0.9,
pad_token_id=self.tokenizer.eos_token_id,
eos_token_id=self.tokenizer.eos_token_id
)
# Decode response
response = self.tokenizer.decode(
chat_outputs[0][chat_input['input_ids'].shape[-1]:],
skip_special_tokens=True
).strip()
# Add response to conversation
self.messages.append({"role": "assistant", "content": response})
return response
except Exception as e:
return f"Error generating response: {str(e)}"
def handle_text_commands(self, text):
"""Handle special text commands"""
text_lower = text.lower().strip()
if any(word in text_lower for word in ['quit', 'exit', 'bye', 'goodbye']):
return 'quit'
elif any(word in text_lower for word in ['clear', 'reset', 'new conversation']):
return 'clear'
elif 'help' in text_lower:
return 'help'
return None
def run(self):
"""Main conversation loop"""
print("ποΈ Voice Chat with BitNet")
print("=" * 40)
try:
self.load_models()
except Exception as e:
print(f"β Failed to load models: {e}")
sys.exit(1)
print("\nβ
All models loaded successfully!")
print("\n㪠Voice Chat Instructions:")
print(" β’ Press [Enter] to start recording")
print(" β’ Speak your message")
print(" β’ Press [Enter] again to stop recording")
print(" β’ Say 'quit' or 'goodbye' to exit")
print(" β’ Say 'clear' to reset conversation")
print(" β’ Say 'help' for commands")
print("-" * 40)
while True:
try:
# Record audio
input("\nπ€ Press [Enter] to start recording your message...")
self.record_audio()
# Transcribe audio
transcribed_text = self.transcribe_audio()
if not transcribed_text:
continue
# Handle commands
command = self.handle_text_commands(transcribed_text)
if command == 'quit':
print("π Goodbye!")
break
elif command == 'clear':
self.messages = [
{"role": "system", "content": "You are a helpful AI assistant. Keep your responses concise and conversational."}
]
print("ποΈ Conversation history cleared!")
continue
elif command == 'help':
print("\nπ Voice Commands:")
print(" β’ Say 'quit' or 'goodbye' to exit")
print(" β’ Say 'clear' to reset conversation")
print(" β’ Say 'help' for this message")
continue
# Generate and display response
response = self.generate_response(transcribed_text)
print(f"\nπ€ Assistant: {response}")
# Limit conversation history
if len(self.messages) > 20:
self.messages = self.messages[:1] + self.messages[-19:]
except KeyboardInterrupt:
print("\n\nπ Goodbye!")
break
except Exception as e:
print(f"\nβ Error: {e}")
print("π Continuing conversation...")
# Cleanup
if os.path.exists(OUTPUT_FILE):
os.remove(OUTPUT_FILE)
print("π§Ή Temporary audio file cleaned up.")
def main():
chat = VoiceChat()
chat.run()
if __name__ == "__main__":
main()