Agnuxo commited on
Commit
f70ccd5
1 Parent(s): d40d179

Update README.md

Browse files
Files changed (1) hide show
  1. README.md +441 -0
README.md CHANGED
@@ -20,3 +20,444 @@ tags:
20
  This qwen2 model was trained 2x faster with [Unsloth](https://github.com/unslothai/unsloth) and Huggingface's TRL library.
21
 
22
  [<img src="https://raw.githubusercontent.com/unslothai/unsloth/main/images/unsloth%20made%20with%20love.png" width="200"/>](https://github.com/unslothai/unsloth)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  This qwen2 model was trained 2x faster with [Unsloth](https://github.com/unslothai/unsloth) and Huggingface's TRL library.
21
 
22
  [<img src="https://raw.githubusercontent.com/unslothai/unsloth/main/images/unsloth%20made%20with%20love.png" width="200"/>](https://github.com/unslothai/unsloth)
23
+
24
+ ```python
25
+ import os
26
+ import sys
27
+ import torch
28
+ from transformers import AutoModelForCausalLM, AutoTokenizer
29
+ import warnings
30
+ import numpy as np
31
+ from TTS.api import TTS
32
+ import sounddevice as sd
33
+ import threading
34
+ import queue
35
+ import time
36
+ from vosk import Model, KaldiRecognizer
37
+ import json
38
+ import pyaudio
39
+ from PyQt5.QtWidgets import (QApplication, QMainWindow, QTextEdit, QLineEdit, QPushButton,
40
+ QVBoxLayout, QHBoxLayout, QWidget, QScrollArea, QFrame, QToolButton,
41
+ QLabel, QSlider, QComboBox, QCheckBox)
42
+ from PyQt5.QtGui import QIcon, QPalette, QColor, QFont
43
+ from PyQt5.QtCore import Qt, QThread, pyqtSignal, QPropertyAnimation, QAbstractAnimation, QParallelAnimationGroup
44
+
45
+ # Suppress specific warnings
46
+ warnings.filterwarnings("ignore", category=FutureWarning)
47
+ warnings.filterwarnings("ignore", category=UserWarning)
48
+
49
+ # Global configuration
50
+ SYSTEM_PROMPT = {
51
+ "es": "Tu nombre es HAL. Eres un superordenador de la serie Nueve mil",
52
+ "en": "speak Spanish."
53
+ }
54
+
55
+ MODELO_LLM = "Agnuxo/HAL_9000-Qwen2-1.5B-Instruct_Asistant-16bit-v2" # Puede utilizar la versión Mini "Agnuxo/HAL_9000-Qwen2-0.5B-Instruct_Asistant-16bit-v2"
56
+ MAX_TOKENS = 100
57
+ TEMPERATURA = 0.5
58
+
59
+ # Determine available device
60
+ device = "cuda" if torch.cuda.is_available() else "cpu"
61
+
62
+ # Load the Qwen2_1.5B language model
63
+ tokenizer = AutoTokenizer.from_pretrained(MODELO_LLM, trust_remote_code=True)
64
+ model = AutoModelForCausalLM.from_pretrained(
65
+ MODELO_LLM,
66
+ torch_dtype=torch.float16 if device == "cuda" else torch.float32,
67
+ device_map="auto",
68
+ trust_remote_code=True
69
+ )
70
+
71
+ # Initialize TTS model
72
+ tts = TTS(model_name="tts_models/es/css10/vits", progress_bar=False).to(device)
73
+
74
+ # Audio queue for generation
75
+ audio_queue = queue.Queue()
76
+
77
+ # Initialize Vosk model for offline speech recognition
78
+ vosk_model = Model(lang="es")
79
+ recognizer = KaldiRecognizer(vosk_model, 16000)
80
+
81
+ class AudioThread(QThread):
82
+ def run(self):
83
+ while True:
84
+ if not audio_queue.empty():
85
+ wav = audio_queue.get()
86
+ sd.play(wav, tts.synthesizer.output_sample_rate)
87
+ sd.wait()
88
+ else:
89
+ time.sleep(0.1)
90
+
91
+ class SpeechRecognitionThread(QThread):
92
+ text_recognized = pyqtSignal(str)
93
+
94
+ def __init__(self):
95
+ super().__init__()
96
+ self.running = True
97
+
98
+ def run(self):
99
+ p = pyaudio.PyAudio()
100
+ stream = p.open(format=pyaudio.paInt16, channels=1, rate=16000, input=True, frames_per_buffer=8000)
101
+ stream.start_stream()
102
+
103
+ while self.running:
104
+ data = stream.read(4000)
105
+ if len(data) == 0:
106
+ break
107
+ if recognizer.AcceptWaveform(data):
108
+ result = json.loads(recognizer.Result())
109
+ texto = result.get("text", "")
110
+ if texto:
111
+ self.text_recognized.emit(texto)
112
+
113
+ stream.stop_stream()
114
+ stream.close()
115
+ p.terminate()
116
+
117
+ def stop(self):
118
+ self.running = False
119
+
120
+ class CollapsibleBox(QWidget):
121
+ def __init__(self, title="", parent=None):
122
+ super(CollapsibleBox, self).__init__(parent)
123
+
124
+ self.toggle_button = QToolButton()
125
+ self.toggle_button.setText(title)
126
+ self.toggle_button.setStyleSheet("""
127
+ QToolButton {
128
+ background-color: #1e1e1e;
129
+ color: #bb86fc;
130
+ border: 1px solid #bb86fc;
131
+ padding: 5px;
132
+ }
133
+ QToolButton:hover {
134
+ background-color: #3700b3;
135
+ }
136
+ """)
137
+ self.toggle_button.setCheckable(True)
138
+ self.toggle_button.setArrowType(Qt.RightArrow)
139
+ self.toggle_button.clicked.connect(self.on_toggle)
140
+
141
+ self.content_area = QScrollArea()
142
+ self.content_area.setWidgetResizable(True)
143
+ self.content_area.setMaximumHeight(0)
144
+ self.content_area.setMinimumHeight(0)
145
+
146
+ self.toggle_animation = QParallelAnimationGroup()
147
+ self.toggle_animation.addAnimation(QPropertyAnimation(self, b"minimumHeight"))
148
+ self.toggle_animation.addAnimation(QPropertyAnimation(self, b"maximumHeight"))
149
+ self.toggle_animation.addAnimation(QPropertyAnimation(self.content_area, b"maximumHeight"))
150
+
151
+ lay = QVBoxLayout(self)
152
+ lay.setSpacing(0)
153
+ lay.setContentsMargins(0, 0, 0, 0)
154
+ lay.addWidget(self.toggle_button)
155
+ lay.addWidget(self.content_area)
156
+
157
+ def on_toggle(self, checked):
158
+ checked = self.toggle_button.isChecked()
159
+ self.toggle_button.setArrowType(Qt.DownArrow if not checked else Qt.RightArrow)
160
+ self.toggle_animation.setDirection(QAbstractAnimation.Forward if not checked else QAbstractAnimation.Backward)
161
+ self.toggle_animation.start()
162
+
163
+ def setContentLayout(self, layout):
164
+ lay = self.content_area.layout()
165
+ del lay
166
+ self.content_area.setLayout(layout)
167
+ collapsed_height = self.sizeHint().height() - self.content_area.maximumHeight()
168
+ content_height = layout.sizeHint().height()
169
+ for i in range(self.toggle_animation.animationCount()):
170
+ animation = self.toggle_animation.animationAt(i)
171
+ animation.setDuration(500)
172
+ animation.setStartValue(collapsed_height)
173
+ animation.setEndValue(collapsed_height + content_height)
174
+
175
+ content_animation = self.toggle_animation.animationAt(self.toggle_animation.animationCount() - 1)
176
+ content_animation.setDuration(500)
177
+ content_animation.setStartValue(0)
178
+ content_animation.setEndValue(content_height)
179
+
180
+ class MainWindow(QMainWindow):
181
+ def __init__(self):
182
+ super().__init__()
183
+ self.setWindowTitle("AI Assistant")
184
+ self.setGeometry(100, 100, 1000, 600)
185
+ self.setStyleSheet("""
186
+ QMainWindow {
187
+ background-color: #121212;
188
+ }
189
+ QTextEdit, QLineEdit {
190
+ background-color: #1e1e1e;
191
+ color: #ffffff;
192
+ border: 1px solid #bb86fc;
193
+ }
194
+ QPushButton {
195
+ background-color: #3700b3;
196
+ color: #ffffff;
197
+ border: none;
198
+ padding: 5px;
199
+ }
200
+ QPushButton:hover {
201
+ background-color: #6200ee;
202
+ }
203
+ QLabel {
204
+ color: #ffffff;
205
+ }
206
+ QSlider::groove:horizontal {
207
+ border: 1px solid #999999;
208
+ height: 8px;
209
+ background: #1e1e1e;
210
+ margin: 2px 0;
211
+ }
212
+ QSlider::handle:horizontal {
213
+ background: #bb86fc;
214
+ border: 1px solid #5c5c5c;
215
+ width: 18px;
216
+ margin: -2px 0;
217
+ border-radius: 3px;
218
+ }
219
+ QComboBox {
220
+ background-color: #1e1e1e;
221
+ color: #444444;
222
+ border: 1px solid #bb86fc;
223
+ }
224
+ QComboBox QAbstractItemView {
225
+ background-color: #1e1e1e;
226
+ color: #444444;
227
+ }
228
+ """)
229
+
230
+ central_widget = QWidget()
231
+ self.setCentralWidget(central_widget)
232
+
233
+ main_layout = QHBoxLayout()
234
+
235
+ # Chat area
236
+ chat_layout = QVBoxLayout()
237
+
238
+ self.chat_area = QTextEdit()
239
+ self.chat_area.setReadOnly(True)
240
+ chat_layout.addWidget(self.chat_area)
241
+
242
+ input_layout = QHBoxLayout()
243
+ self.input_field = QLineEdit()
244
+ input_layout.addWidget(self.input_field)
245
+
246
+ self.send_button = QPushButton("Enviar")
247
+ self.send_button.clicked.connect(self.send_message)
248
+ input_layout.addWidget(self.send_button)
249
+
250
+ self.mic_button = QPushButton()
251
+ self.mic_button.setIcon(QIcon.fromTheme("audio-input-microphone"))
252
+ self.mic_button.setCheckable(True)
253
+ self.mic_button.clicked.connect(self.toggle_speech_recognition)
254
+ input_layout.addWidget(self.mic_button)
255
+
256
+ self.speaker_button = QPushButton()
257
+ self.speaker_button.setIcon(QIcon.fromTheme("audio-volume-high"))
258
+ self.speaker_button.setCheckable(True)
259
+ self.speaker_button.toggled.connect(self.toggle_speech)
260
+ input_layout.addWidget(self.speaker_button)
261
+
262
+ chat_layout.addLayout(input_layout)
263
+
264
+ main_layout.addLayout(chat_layout, 7) # Chat area takes 70% of the width
265
+
266
+ # Settings area
267
+ settings_layout = QVBoxLayout()
268
+ settings_layout.setAlignment(Qt.AlignTop)
269
+
270
+ self.settings_box = CollapsibleBox("⚙️ Configuración")
271
+ settings_content_layout = QVBoxLayout()
272
+
273
+ # Language selection
274
+ language_layout = QHBoxLayout()
275
+ language_label = QLabel("Idioma:")
276
+ language_label.setStyleSheet("color: #000000;") # Change font color to black
277
+ self.language_combo = QComboBox()
278
+ self.language_combo.addItems(["Español", "English"])
279
+ self.language_combo.currentIndexChanged.connect(self.change_language)
280
+ language_layout.addWidget(language_label)
281
+ language_layout.addWidget(self.language_combo)
282
+ settings_content_layout.addLayout(language_layout)
283
+
284
+ # LLM settings
285
+ llm_label = QLabel("Configuración del LLM:")
286
+ llm_label.setStyleSheet("color: #000000;") # Change font color to black
287
+ settings_content_layout.addWidget(llm_label)
288
+
289
+ max_tokens_layout = QHBoxLayout()
290
+ max_tokens_label = QLabel("Max Tokens:")
291
+ max_tokens_label.setStyleSheet("color: #000000;") # Change font color to black
292
+ self.max_tokens_slider = QSlider(Qt.Horizontal)
293
+ self.max_tokens_slider.setRange(10, 500)
294
+ self.max_tokens_slider.setValue(MAX_TOKENS)
295
+ self.max_tokens_slider.valueChanged.connect(self.update_max_tokens)
296
+ self.max_tokens_value = QLabel(str(MAX_TOKENS))
297
+ max_tokens_layout.addWidget(max_tokens_label)
298
+ max_tokens_layout.addWidget(self.max_tokens_slider)
299
+ max_tokens_layout.addWidget(self.max_tokens_value)
300
+ settings_content_layout.addLayout(max_tokens_layout)
301
+
302
+ temperature_layout = QHBoxLayout()
303
+ temperature_label = QLabel("Temperatura:")
304
+ temperature_label.setStyleSheet("color: #000000;") # Change font color to black
305
+ self.temperature_slider = QSlider(Qt.Horizontal)
306
+ self.temperature_slider.setRange(0, 100)
307
+ self.temperature_slider.setValue(int(TEMPERATURA * 100))
308
+ self.temperature_slider.valueChanged.connect(self.update_temperature)
309
+ self.temperature_value = QLabel(f"{TEMPERATURA:.2f}")
310
+ temperature_layout.addWidget(temperature_label)
311
+ temperature_layout.addWidget(self.temperature_slider)
312
+ temperature_layout.addWidget(self.temperature_value)
313
+ settings_content_layout.addLayout(temperature_layout)
314
+
315
+ # Audio settings
316
+ audio_label = QLabel("Configuración de Audio:")
317
+ audio_label.setStyleSheet("color: #000000;") # Change font color to black
318
+ settings_content_layout.addWidget(audio_label)
319
+
320
+ sample_rate_layout = QHBoxLayout()
321
+ sample_rate_label = QLabel("Sample Rate:")
322
+ sample_rate_label.setStyleSheet("color: #000000;") # Change font color to black
323
+ self.sample_rate_combo = QComboBox()
324
+ self.sample_rate_combo.addItems(["16000", "22050", "44100", "48000"])
325
+ self.sample_rate_combo.setCurrentText("22050")
326
+ self.sample_rate_combo.currentTextChanged.connect(self.update_sample_rate)
327
+ sample_rate_layout.addWidget(sample_rate_label)
328
+ sample_rate_layout.addWidget(self.sample_rate_combo)
329
+ settings_content_layout.addLayout(sample_rate_layout)
330
+
331
+ # System Prompt
332
+ system_prompt_label = QLabel("System Prompt:")
333
+ system_prompt_label.setStyleSheet("color: #000000;") # Change font color to black
334
+ settings_content_layout.addWidget(system_prompt_label)
335
+ self.system_prompt_text = QTextEdit()
336
+ self.system_prompt_text.setPlaceholderText("Escribe el prompt del sistema aquí...")
337
+ self.system_prompt_text.setText(SYSTEM_PROMPT["es"])
338
+ settings_content_layout.addWidget(self.system_prompt_text)
339
+
340
+ self.settings_box.setContentLayout(settings_content_layout)
341
+ settings_layout.addWidget(self.settings_box)
342
+
343
+ main_layout.addLayout(settings_layout, 3) # Settings area takes 30% of the width
344
+
345
+ central_widget.setLayout(main_layout)
346
+
347
+ self.audio_thread = AudioThread()
348
+ self.audio_thread.start()
349
+
350
+ self.speech_recognition_thread = SpeechRecognitionThread()
351
+ self.speech_recognition_thread.text_recognized.connect(self.on_speech_recognized)
352
+
353
+ self.speech_enabled = False
354
+ self.is_listening = False
355
+
356
+ def send_message(self):
357
+ user_message = self.input_field.text()
358
+ self.chat_area.append(f"<span style='color: #bb86fc;'>Usuario:</span> {user_message}")
359
+ self.input_field.clear()
360
+
361
+ response = self.generate_response(user_message)
362
+ self.chat_area.append(f"<span style='color: #03dac6;'>Asistente:</span> {response}")
363
+
364
+ if self.speech_enabled:
365
+ self.speak(response)
366
+
367
+ def generate_response(self, texto):
368
+ system_instructions = self.system_prompt_text.toPlainText()
369
+ prompt = f"{system_instructions}\nUsuario: {texto}\nAsistente: "
370
+ inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
371
+ with torch.no_grad():
372
+ outputs = model.generate(
373
+ **inputs,
374
+ max_new_tokens=MAX_TOKENS,
375
+ num_beams=5,
376
+ no_repeat_ngram_size=2,
377
+ temperature=TEMPERATURA,
378
+ )
379
+ respuesta_completa = tokenizer.decode(outputs[0], skip_special_tokens=True)
380
+ respuesta = respuesta_completa.split("Asistente: ")[-1].strip()
381
+ return respuesta
382
+
383
+ def speak(self, text):
384
+ wav = tts.tts(text)
385
+ audio_queue.put(wav)
386
+
387
+ def toggle_speech(self, checked):
388
+ self.speech_enabled = checked
389
+ if checked:
390
+ self.speaker_button.setStyleSheet("background-color: #bb86fc;")
391
+ else:
392
+ self.speaker_button.setStyleSheet("")
393
+
394
+ def toggle_speech_recognition(self):
395
+ if self.mic_button.isChecked():
396
+ self.speech_recognition_thread.start()
397
+ self.is_listening = True
398
+ self.mic_button.setIcon(QIcon.fromTheme("audio-input-microphone-muted"))
399
+ self.mic_button.setStyleSheet("background-color: #bb86fc;")
400
+ else:
401
+ self.speech_recognition_thread.stop()
402
+ self.is_listening = False
403
+ self.mic_button.setIcon(QIcon.fromTheme("audio-input-microphone"))
404
+ self.mic_button.setStyleSheet("")
405
+
406
+
407
+ def on_speech_recognized(self, text):
408
+ self.chat_area.append(f"<span style='color: #bb86fc;'>Usuario:</span> {text}")
409
+ response = self.generate_response(text)
410
+ self.chat_area.append(f"<span style='color: #03dac6;'>Asistente:</span> {response}")
411
+ if self.speech_enabled:
412
+ self.speak(response)
413
+
414
+ def change_language(self, index):
415
+ global vosk_model, recognizer, tts
416
+ lang = "es" if index == 0 else "en"
417
+ try:
418
+ vosk_model = Model(lang=lang)
419
+ recognizer = KaldiRecognizer(vosk_model, 16000)
420
+ except Exception as e:
421
+ print(f"Error al cambiar el modelo de reconocimiento de voz: {e}")
422
+ # Revertir al modelo en español si hay un error
423
+ self.language_combo.setCurrentIndex(0)
424
+ return
425
+
426
+ # Update TTS model based on language
427
+ tts_model = "tts_models/es/css10/vits" if lang == "es" else "tts_models/en/ljspeech/tacotron2-DDC"
428
+ try:
429
+ tts = TTS(model_name=tts_model, progress_bar=False).to(device)
430
+ except Exception as e:
431
+ print(f"Error al cambiar el modelo TTS: {e}")
432
+ # Revertir al modelo en español si hay un error
433
+ self.language_combo.setCurrentIndex(0)
434
+ return
435
+
436
+ # Update system prompt
437
+ self.system_prompt_text.setText(SYSTEM_PROMPT[lang])
438
+
439
+ def update_max_tokens(self, value):
440
+ global MAX_TOKENS
441
+ MAX_TOKENS = value
442
+ self.max_tokens_value.setText(str(value))
443
+
444
+ def update_temperature(self, value):
445
+ global TEMPERATURA
446
+ TEMPERATURA = value / 100
447
+ self.temperature_value.setText(f"{TEMPERATURA:.2f}")
448
+
449
+ def update_sample_rate(self, value):
450
+ global tts
451
+ tts.synthesizer.output_sample_rate = int(value)
452
+
453
+ def closeEvent(self, event):
454
+ if self.speech_recognition_thread.isRunning():
455
+ self.speech_recognition_thread.stop()
456
+ self.speech_recognition_thread.wait()
457
+ event.accept()
458
+
459
+ if __name__ == "__main__":
460
+ app = QApplication(sys.argv)
461
+ window = MainWindow()
462
+ window.show()
463
+ sys.exit(app.exec_())