Skip to content

Commit 8d7133c

Browse files
authored
v2.1
1 parent cc0381c commit 8d7133c

11 files changed

Lines changed: 185 additions & 50 deletions

config.yaml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,13 @@ AVAILABLE_MODELS:
2929
- sentence-transformers/gtr-t5-large
3030
- sentence-transformers/gtr-t5-base
3131
COMPUTE_DEVICE: cuda
32-
EMBEDDING_MODEL_NAME: C:/PATH/Scripts/LM Search Vector Database/v1_7 - working/Embedding_Models/sentence-transformers--all-mpnet-base-v2
32+
EMBEDDING_MODEL_NAME: C:/PATH/Scripts/LM Search Vector Database/v2_0_1 - working/Embedding_Models/hkunlp--instructor-xl
33+
styles:
34+
button: 'background-color: #323842; color: light gray; font: 10pt "Segoe UI Historic";
35+
width: 29;'
36+
frame: 'background-color: #161b22;'
37+
input: 'background-color: #2e333b; color: light gray; font: 13pt "Segoe UI Historic";'
38+
text: 'background-color: #092327; color: light gray; font: 12pt "Segoe UI Historic";'
3339
tabs:
3440
- name: Settings
3541
placeholder: Placeholder text for Settings tab.

gui.py

Lines changed: 26 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -14,33 +14,15 @@
1414
from metrics_gpu import GPU_Monitor
1515
from metrics_system import SystemMonitor
1616
from initialize import determine_compute_device, is_nvidia_gpu, get_os_name
17-
18-
styles = {
19-
"button": 'background-color: #323842; color: light gray; font: 10pt "Segoe UI Historic"; width: 29;',
20-
"frame": 'background-color: #161b22;',
21-
"input": 'background-color: #2e333b; color: light gray; font: 13pt "Segoe UI Historic";',
22-
"text": 'background-color: #092327; color: light gray; font: 12pt "Segoe UI Historic";'
23-
}
17+
from voice_recorder_module import VoiceRecorder
18+
from gui_tabs import create_tabs
19+
from gui_threads import CreateDatabaseThread, SubmitButtonThread
2420

2521
with open('config.yaml', 'r') as config_file:
2622
config = yaml.safe_load(config_file)
2723

2824
tabs_config = config.get('tabs', [])
29-
30-
class CreateDatabaseThread(QThread):
31-
def run(self):
32-
create_database.main()
33-
34-
class SubmitButtonThread(QThread):
35-
responseSignal = Signal(str)
36-
37-
def __init__(self, user_question, parent=None):
38-
super(SubmitButtonThread, self).__init__(parent)
39-
self.user_question = user_question
40-
41-
def run(self):
42-
response = server_connector.ask_local_chatgpt(self.user_question)
43-
self.responseSignal.emit(response['answer'])
25+
styles = config.get('styles', {})
4426

4527
class DocQA_GUI(QWidget):
4628
def __init__(self):
@@ -64,20 +46,10 @@ def init_ui(self):
6446
self.setGeometry(300, 300, 850, 910)
6547
self.setMinimumSize(550, 610)
6648

67-
self.left_frame = QFrame() # Changed here
49+
self.left_frame = QFrame()
6850
left_vbox = QVBoxLayout()
69-
tab_widget = QTabWidget()
70-
tab_widget.setTabPosition(QTabWidget.South)
71-
72-
tab_widgets = [QTextEdit(tab.get('placeholder', '')) for tab in tabs_config]
73-
for i, tab in enumerate(tabs_config):
74-
tab_widget.addTab(tab_widgets[i], tab.get('name', ''))
75-
76-
tutorial_tab = QWebEngineView()
77-
tab_widget.addTab(tutorial_tab, 'Tutorial')
78-
user_manual_folder = os.path.join(os.path.dirname(__file__), 'User_Manual')
79-
html_file_path = os.path.join(user_manual_folder, 'number_format.html')
80-
tutorial_tab.setUrl(QUrl.fromLocalFile(html_file_path))
51+
52+
tab_widget = create_tabs(tabs_config)
8153
left_vbox.addWidget(tab_widget)
8254

8355
button_data = [
@@ -108,9 +80,21 @@ def init_ui(self):
10880
submit_button.setStyleSheet(styles.get('button', ''))
10981
submit_button.clicked.connect(self.on_submit_button_clicked)
11082

111-
right_vbox.addWidget(self.read_only_text, 5)
83+
right_vbox.addWidget(self.read_only_text, 4)
11284
right_vbox.addWidget(self.text_input, 1)
11385
right_vbox.addWidget(submit_button)
86+
87+
self.recorder = VoiceRecorder()
88+
89+
self.start_button = QPushButton("Start Recording")
90+
self.start_button.setStyleSheet(styles.get('button', ''))
91+
self.start_button.clicked.connect(self.start_recording)
92+
right_vbox.addWidget(self.start_button)
93+
94+
self.stop_button = QPushButton("Stop Recording")
95+
self.stop_button.setStyleSheet(styles.get('button', ''))
96+
self.stop_button.clicked.connect(self.stop_recording)
97+
right_vbox.addWidget(self.stop_button)
11498

11599
right_frame.setLayout(right_vbox)
116100
right_frame.setStyleSheet(styles.get('frame', ''))
@@ -140,7 +124,6 @@ def resizeEvent(self, event):
140124
self.left_frame.setMaximumWidth(self.width() * 0.5)
141125
super().resizeEvent(event)
142126

143-
144127
def on_create_button_clicked(self):
145128
self.create_database_thread = CreateDatabaseThread(self)
146129
self.create_database_thread.start()
@@ -151,6 +134,12 @@ def on_submit_button_clicked(self):
151134
self.submit_button_thread.responseSignal.connect(self.update_response)
152135
self.submit_button_thread.start()
153136

137+
def start_recording(self):
138+
self.recorder.start_recording()
139+
140+
def stop_recording(self):
141+
self.recorder.stop_recording()
142+
154143
def update_response(self, response):
155144
self.read_only_text.setPlainText(response)
156145

gui_tabs.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# tabs.py
2+
3+
from PySide6.QtWebEngineWidgets import QWebEngineView
4+
from PySide6.QtWidgets import QTextEdit, QTabWidget
5+
from PySide6.QtCore import QUrl
6+
import os
7+
8+
def create_tabs(tabs_config):
9+
tab_widget = QTabWidget()
10+
tab_widget.setTabPosition(QTabWidget.South)
11+
12+
tab_widgets = [QTextEdit(tab.get('placeholder', '')) for tab in tabs_config]
13+
for i, tab in enumerate(tabs_config):
14+
tab_widget.addTab(tab_widgets[i], tab.get('name', ''))
15+
16+
tutorial_tab = QWebEngineView()
17+
tab_widget.addTab(tutorial_tab, 'Tutorial')
18+
user_manual_folder = os.path.join(os.path.dirname(__file__), 'User_Manual')
19+
html_file_path = os.path.join(user_manual_folder, 'number_format.html')
20+
tutorial_tab.setUrl(QUrl.fromLocalFile(html_file_path))
21+
22+
return tab_widget

gui_threads.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Creates threads for gui functions
2+
3+
from PySide6.QtCore import QThread, Signal
4+
import server_connector
5+
import create_database
6+
7+
class CreateDatabaseThread(QThread):
8+
def run(self):
9+
create_database.main()
10+
11+
class SubmitButtonThread(QThread):
12+
responseSignal = Signal(str)
13+
14+
def __init__(self, user_question, parent=None):
15+
super(SubmitButtonThread, self).__init__(parent)
16+
self.user_question = user_question
17+
18+
def run(self):
19+
response = server_connector.ask_local_chatgpt(self.user_question)
20+
self.responseSignal.emit(response['answer'])

initialize.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# determine OS compute device for gui and save to config and determine whether to display metrics
2+
13
import torch
24
import yaml
35
import platform

main.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import sys
2+
import pyaudio
3+
import wave
4+
import os
5+
import tempfile
6+
import threading
7+
import pyperclip
8+
from faster_whisper import WhisperModel
9+
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QLabel
10+
from PySide6.QtCore import Qt
11+
12+
class VoiceRecorder:
13+
def __init__(self, window, format=pyaudio.paInt16, channels=1, rate=44100, chunk=1024):
14+
self.format, self.channels, self.rate, self.chunk = format, channels, rate, chunk
15+
self.window = window
16+
self.is_recording, self.frames = False, []
17+
self.model = WhisperModel("large-v2", device="cuda", compute_type="int8_float32")
18+
19+
def transcribe_audio(self, audio_file):
20+
segments, _ = self.model.transcribe(audio_file)
21+
pyperclip.copy("\n".join([segment.text for segment in segments]))
22+
self.window.update_status("Audio saved and transcribed")
23+
24+
def record_audio(self):
25+
self.window.update_status("Recording...")
26+
p = pyaudio.PyAudio()
27+
try:
28+
stream = p.open(format=self.format, channels=self.channels, rate=self.rate, input=True, frames_per_buffer=self.chunk)
29+
[self.frames.append(stream.read(self.chunk)) for _ in iter(lambda: self.is_recording, False)]
30+
stream.stop_stream()
31+
stream.close()
32+
finally:
33+
p.terminate()
34+
35+
def save_audio(self):
36+
self.is_recording = False
37+
temp_filename = tempfile.mktemp(suffix=".wav")
38+
with wave.open(temp_filename, "wb") as wf:
39+
wf.setnchannels(self.channels)
40+
wf.setsampwidth(pyaudio.PyAudio().get_sample_size(self.format))
41+
wf.setframerate(self.rate)
42+
wf.writeframes(b"".join(self.frames))
43+
self.transcribe_audio(temp_filename)
44+
os.remove(temp_filename)
45+
self.frames.clear()
46+
47+
def start_recording(self):
48+
if not self.is_recording:
49+
self.is_recording = True
50+
threading.Thread(target=self.record_audio).start()
51+
52+
class MyWindow(QWidget):
53+
def __init__(self):
54+
super().__init__()
55+
self.recorder = VoiceRecorder(self)
56+
layout = QVBoxLayout(self)
57+
58+
for text, callback in [("Record", self.recorder.start_recording),
59+
("Stop and Copy to Clipboard", self.recorder.save_audio)]:
60+
button = QPushButton(text, self)
61+
button.clicked.connect(callback)
62+
layout.addWidget(button)
63+
64+
self.status_label = QLabel('', self)
65+
layout.addWidget(self.status_label)
66+
self.setFixedSize(300, 150)
67+
68+
self.setWindowFlag(Qt.WindowStaysOnTopHint)
69+
70+
def update_status(self, text):
71+
self.status_label.setText(text)
72+
73+
if __name__ == "__main__":
74+
app = QApplication(sys.argv)
75+
app.setStyle('Fusion')
76+
window = MyWindow()
77+
window.show()
78+
sys.exit(app.exec())

metrics_gpu.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from multiprocessing import Process, Pipe, Event
33
import time
44
from PySide6.QtCore import QTimer
5+
import humanize
56

67
def monitor_nvml(pipe, stop_event):
78
nvmlInit()
@@ -11,7 +12,7 @@ def monitor_nvml(pipe, stop_event):
1112
memory_info = nvmlDeviceGetMemoryInfo(handle)
1213
utilization_rates = nvmlDeviceGetUtilizationRates(handle)
1314

14-
memory_used_str = f"{memory_info.used / (1024 * 1024):.2f} MiB"
15+
memory_used_str = humanize.naturalsize(memory_info.used, binary=True)
1516
gpu_utilization = f"{utilization_rates.gpu}%"
1617

1718
data = (memory_used_str, gpu_utilization)
@@ -51,4 +52,4 @@ def update_gpu_info(self):
5152
def stop_and_exit_gpu_monitor(self):
5253
self.timer.stop()
5354
stop_monitoring_gpu(self.process, self.stop_event)
54-
self.root.close()
55+
self.root.close()

metrics_system.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
import time
33
from multiprocessing import Process, Pipe, Event
44
from PySide6.QtCore import QTimer
5+
import humanize
56

67
def monitor_system(pipe, stop_event):
78
while not stop_event.is_set():
89
cpu_percent = collect_cpu_metrics()
9-
ram_percent, ram_used_mib = collect_ram_metrics()
10-
data = (cpu_percent, ram_percent, ram_used_mib)
10+
ram_percent, ram_used = collect_ram_metrics()
11+
data = (cpu_percent, ram_percent, ram_used)
1112
pipe.send(data)
1213
time.sleep(0.5)
1314

@@ -17,8 +18,8 @@ def collect_cpu_metrics():
1718

1819
def collect_ram_metrics():
1920
ram = psutil.virtual_memory()
20-
ram_used_mib = round(ram.used / (1024 ** 2), 2)
21-
return round(ram.percent, 2), ram_used_mib
21+
ram_used = humanize.naturalsize(ram.used, binary=True)
22+
return round(ram.percent, 2), ram_used
2223

2324
def start_monitoring_system():
2425
stop_event = Event()
@@ -44,12 +45,12 @@ def __init__(self, cpu_label, ram_label, ram_usage_label, root):
4445

4546
def update_system_info(self):
4647
if self.parent_conn.poll():
47-
cpu_percent, ram_percent, ram_used_mib = self.parent_conn.recv()
48+
cpu_percent, ram_percent, ram_used = self.parent_conn.recv()
4849
self.cpu_label.setText(f"CPU: {cpu_percent}%")
4950
self.ram_label.setText(f"RAM: {ram_percent}%")
50-
self.ram_usage_label.setText(f"RAM: {ram_used_mib:.2f} MiB")
51+
self.ram_usage_label.setText(f"RAM: {ram_used}")
5152

5253
def stop_and_exit_system_monitor(self):
5354
self.timer.stop()
5455
stop_monitoring_system(self.process, self.stop_event)
55-
self.root.close()
56+
self.root.close()

requirements.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,8 @@ openpyxl==3.1.2
1313
unstructured==0.10.12
1414
nvidia-ml-py==12.535.108
1515
psutil==5.9.5
16-
PySide6==6.5.2
16+
PySide6==6.5.2
17+
Humanize==4.8.0
18+
PyAudio==0.2.13
19+
pyperclip==1.8.2
20+
faster-whisper==0.9.0

server_connector.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def ask_local_chatgpt(query, persist_directory=PERSIST_DIRECTORY, client_setting
6363
retriever = db.as_retriever()
6464
relevant_contexts = retriever.get_relevant_documents(query)
6565
contexts = [document.page_content for document in relevant_contexts]
66-
prepend_string = "Only base your answer to the following question on the provided context. If the provided context does not provide an answer, simply state that is the case."
66+
prepend_string = "Only base your answer to the following question on the provided context."
6767
augmented_query = "\n\n---\n\n".join(contexts) + "\n\n-----\n\n" + query
6868
response_json = connect_to_local_chatgpt(augmented_query)
6969

0 commit comments

Comments
 (0)