commit 301abf1b7ef8cc796a4c995c870252f6bea90cde Author: Rafał Paluch Date: Sun Apr 6 10:47:44 2025 +0200 Start diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..d6acbae --- /dev/null +++ b/requirements.txt @@ -0,0 +1,16 @@ +jupytext +python-lsp-server +ocp_vscode +pyright +vosk +sounddevice +pyperclip +pyautogui +black +jupyter +flake8 +pyflakes +# pylint +git+https://github.com/gumyr/bd_warehouse +git+https://github.com/gumyr/build123d + diff --git a/venv_create.py b/venv_create.py new file mode 100644 index 0000000..c58c4d4 --- /dev/null +++ b/venv_create.py @@ -0,0 +1,50 @@ +import os +import subprocess +import sys +import urllib.request +import zipfile +import shutil + +VENV_DIR = "venv" +REQUIREMENTS_FILE = "requirements.txt" +MODEL_URL = "https://alphacephei.com/vosk/models/vosk-model-small-pl-0.22.zip" +MODEL_ZIP = "vosk-model-small-pl-0.22.zip" +MODEL_DIR = "vosk-model-small-pl-0.22" + + +def create_virtualenv(): + print("[+] Tworzenie środowiska wirtualnego...") + subprocess.check_call([sys.executable, "-m", "venv", VENV_DIR]) + + +def install_requirements(): + print("[+] Instalacja pakietów z requirements.txt...") + pip_path = os.path.join(VENV_DIR, "bin", "pip") if os.name != "nt" else os.path.join(VENV_DIR, "Scripts", "pip.exe") + subprocess.check_call([pip_path, "install", "-r", REQUIREMENTS_FILE]) + + +def download_model(): + if os.path.exists(MODEL_DIR): + print("[i] Model już istnieje, pomijam pobieranie.") + return + + print(f"[+] Pobieranie modelu z {MODEL_URL}...") + urllib.request.urlretrieve(MODEL_URL, MODEL_ZIP) + + print("[+] Rozpakowywanie modelu...") + with zipfile.ZipFile(MODEL_ZIP, 'r') as zip_ref: + zip_ref.extractall(".") + + print("[+] Usuwanie archiwum ZIP...") + os.remove(MODEL_ZIP) + + +def main(): + create_virtualenv() + install_requirements() + download_model() + print("[✓] Gotowe!") + + +if __name__ == "__main__": + main() diff --git a/voskpl.py b/voskpl.py new file mode 100644 index 0000000..fb8764a --- /dev/null +++ b/voskpl.py @@ -0,0 +1,118 @@ +from vosk import Model, KaldiRecognizer +import sounddevice as sd +import json +import pyperclip # Biblioteka do obsługi schowka +import pyautogui +import sys +import tkinter as tk +from threading import Thread + +# Ścieżka do modelu +model_path = "./vosk-model-small-pl-0.22" +model = Model(model_path) +recognizer = KaldiRecognizer(model, 16000) + +listening = False # Flaga stanu nasłuchiwania +emacs_mode = False # Flaga trybu Emacs + +# Funkcja obsługi danych audio +def callback(indata, frames, time, status): + if status: + print(f"Status: {status}", file=sys.stderr) + # Konwersja danych na `bytes` + data = bytes(indata) + if recognizer.AcceptWaveform(data): + result = json.loads(recognizer.Result()) + text = result.get("text", "") + if text: + print(f"Rozpoznano: {text}") + insert_text_with_clipboard(text) + +# Funkcja kopiowania do schowka i wklejania +def insert_text_with_clipboard(text): + try: + pyperclip.copy(text) # Kopiowanie tekstu do schowka + if emacs_mode: + pyautogui.hotkey('shift', 'insert') # Wklejanie w trybie Emacs + else: + pyautogui.hotkey('ctrl', 'v') # Standardowe wklejanie + pyautogui.press('space') # Dodanie spacji (opcjonalne) + except Exception as e: + print(f"Błąd podczas wklejania tekstu: {e}", file=sys.stderr) + +# Funkcja nasłuchiwania i rozpoznawania mowy +def listen_and_type(): + global listening + print("Słucham... (naciśnij Stop, aby zatrzymać)") + try: + with sd.RawInputStream(samplerate=16000, blocksize=8000, dtype='int16', + channels=1, callback=callback): + while listening: + pass # Nasłuchiwanie trwa w pętli + except Exception as e: + print(f"Błąd podczas nasłuchiwania: {e}", file=sys.stderr) + +# Funkcje sterujące GUI +def toggle_listening(): + global listening + if listening: + listening = False + update_button_state() + print("Nasłuchiwanie zatrzymane.") + else: + listening = True + update_button_state() + thread = Thread(target=listen_and_type) + thread.daemon = True + thread.start() + +def toggle_emacs_mode(): + global emacs_mode + emacs_mode = not emacs_mode + update_emacs_button_state() + mode = "Emacs" if emacs_mode else "Standard" + print(f"Tryb wklejania: {mode}") + +# Aktualizacja stanu przycisków +def update_button_state(): + if listening: + toggle_button.config(text="Stop", bg="red", fg="white") + else: + toggle_button.config(text="Start", bg="lightgrey", fg="black") + +def update_emacs_button_state(): + if emacs_mode: + emacs_button.config(text="Tryb: Emacs", bg="blue", fg="white") + else: + emacs_button.config(text="Tryb: Standard", bg="lightgrey", fg="black") + +# Funkcja obsługi skrótu klawiszowego +def handle_shortcut(event): + if event.keysym == 'F1': # F1 jako skrót klawiszowy + toggle_listening() + +# Tworzenie GUI +def create_gui(): + global toggle_button, emacs_button + + root = tk.Tk() + root.title("Vosk Rozpoznawanie Mowy") + root.geometry("300x200") + + toggle_button = tk.Button(root, text="Start", command=toggle_listening, width=15, bg="lightgrey", fg="black") + toggle_button.pack(pady=10) + + emacs_button = tk.Button(root, text="Tryb: Standard", command=toggle_emacs_mode, width=15, bg="lightgrey", fg="black") + emacs_button.pack(pady=10) + + exit_button = tk.Button(root, text="Wyjście", command=root.destroy, width=15) + exit_button.pack(pady=10) + + # Dodanie skrótu klawiszowego + root.bind("", handle_shortcut) + + root.mainloop() + +# Uruchomienie GUI +if __name__ == "__main__": + create_gui()