(Επειδή ζηλεύω την Αλέξα και το γκουγκλ ασίσταντ - επειδή είμαι καμένος - επειδή είναι το μεράκι μου - πάντως σε καμία περίπτωση αυτό που λένε οι κανονικοί άνθρωποι "Χρειάζομαι... αυτό", "Είναι ανάγκη να έχω ένα εργαλείο για..." κλπ κλπ.
Καμία σχέση. Το χόμπι μου είναι. Οπότε δεν το προτείνω σοβαρά (κι έτσι θα γλιτώσω την κριτική χα!

Έχω δει ότι όταν δημιουργούν πρότζεκτς οι προτζεκτοποιοί (

Με παρακίνησε ο φίλος και αγαπημένος χρήστης, σε συζύητηση σχετικά με τον εκτυπωτή και σε αναφορά για φωνητική εντολή εκτύπωσης.
Maras έγραψε:
Αναμένουμε τον κώδικα για την φωνητική εντολή!
Αυτό λοιπόν είναι ένα μόνο κομμάτι του όλου κώδικα και πιάνει τις γραμμές 298-310 και 375-381.
Όλος ο υπόλοιπος κώδικας κάνει διαφορετικές δουλίτσες. Αυτός είναι
- Κώδικας: Επιλογή όλων
import mimetypes
import datetime
import subprocess
from fuzzywuzzy import process
import sys
import re
import os
import json
import sounddevice
import speech_recognition as sr
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QTextEdit, QPushButton, QGraphicsOpacityEffect, QMessageBox, QScrollArea, QFrame, QHBoxLayout
from PyQt5.QtCore import Qt, QTimer, QEvent, QUrl, pyqtSignal
from PyQt5.QtGui import QIcon, QPixmap, QKeyEvent, QMovie, QFont, QDesktopServices, QGuiApplication, QColor
from unidecode import unidecode
import unicodedata
class ResultsWindow(QWidget): #Παράθυρο που ανοίγει αφού του πω την εντολή δείξε" και αφορά το να ψάξει και βρει αρχεία στον προσωπικό μου φάκελο και στους υποφακέςους του
def __init__(self, results):
super().__init__()
self.setWindowTitle("Αποτελέσματα αναζήτησης")
self.setGeometry(80, 450, 1200, 410)
self.set_background_color("#D9B47B") # Ορίζουμε το χρώμα του φόντου
layout = QVBoxLayout()
self.setLayout(layout)
scroll_area = QScrollArea()
scroll_area.setWidgetResizable(True)
layout.addWidget(scroll_area)
content = QWidget()
scroll_area.setWidget(content)
content_layout = QVBoxLayout(content)
#Στα αποτελέσματα (ονόματα και διαδρομές αρχείων) που θα μου βγάλει αυτό το παράθυρο, να κοτσάρει δίπλα κι ένα εικονίδιο ανάλογα τον τύπο αρχείου
file_icons = {
".pdf": "./script-icons/pdf.png",
".txt": "./script-icons/text_icon.png",
".html": "./script-icons/html_icon.png",
".mp3": "./script-icons/mp3.png",
".mp4": "./script-icons/mp4.png",
".docx": "./script-icons/docx.png",
".doc": "./script-icons/doc.png",
".jpg": "./script-icons/other.png",
".odt": "./script-icons/odt.png",
".3gp": "./script-icons/other.png",
".avi": "./script-icons/other.png",
".mov": "./script-icons/other.png",
".wav": "./script-icons/other.png",
".ogg": "./script-icons/other.png",
".exe": "./script-icons/other.png",
".xml": "./script-icons/xml.png",
".html": "./script-icons/html.jpg",
".png": "./script-icons/png.png"
}
for result in results:
file_extension = os.path.splitext(result)[1]
if file_extension in file_icons:
icon_label = QLabel()
icon_label.setPixmap(QPixmap(file_icons[file_extension]))
label = ClickableLabel(result)
label.setFont(QFont("FreeSans", 14, QFont.Bold))
label.setTextInteractionFlags(Qt.TextBrowserInteraction)
label.setOpenExternalLinks(False)
label.setOpenExternalLinks(True)
label.clicked.connect(lambda link=result: self.open_file(link))
label.setStyleSheet("color: black;") # Ορίζουμε το χρώμα του κειμένου σε μαύρο
label_layout = QHBoxLayout() # Χρησιμοποιούμε οριζόντιο layout
label_layout.addWidget(label) # Προσθέτουμε πρώτα το label με το όνομα του αρχείου
label_layout.addWidget(icon_label) # Στη συνέχεια προσθέτουμε το εικονίδιο
content_layout.addLayout(label_layout) # Προσθέτουμε το οριζόντιο layout στον κατακόρυφο layout
def set_background_color(self, color):
self.setAutoFillBackground(True)
p = self.palette()
p.setColor(self.backgroundRole(), QColor(color))
self.setPalette(p)
def open_file(self, filepath):
mime_type, _ = mimetypes.guess_type(filepath)
if mime_type:
if mime_type.startswith('text'):
os.system(f"xdg-open {filepath}") # Ανοίξτε το αρχείο με το προεπιλεγμένο κειμενογράφο
else:
subprocess.run(["xdg-open", filepath]) # Ανοίξτε το αρχείο με το προεπιλεγμένο πρόγραμμα
else:
os.system(f'notify-send "Τύπος αρχείου μη υποστηριζόμενο" ')
#Κλάση στο Παράθυρο αποτελεσμάτων που λέγαμε προηγουμένως για να κάνεις κλικ τα αποτελέσματα και να ανοίγουν στο αντίστοιχο πρόγραμμα
class ClickableLabel(QLabel):
clicked = pyqtSignal()
def __init__(self, text):
super().__init__(text)
def mousePressEvent(self, event):
self.clicked.emit()
def enterEvent(self, event):
if self.underMouse():
self.setCursor(Qt.PointingHandCursor)
def leaveEvent(self, event):
self.unsetCursor()
class Separator(QFrame):
def __init__(self):
super().__init__()
self.setFrameShape(QFrame.HLine)
self.setFrameShadow(QFrame.Sunken)
#Κλάση για την εμφάνιση του παραθύρου και τις λειτουργίες του. Ο Βασιλιάς του κιτς λέμε.
class VasikoWindow(QWidget):
#Ενέργειες. Αρχίζουν με μικρό γράμμα γιατί όταν εκφωνείς κείμενο και σε ακοιύει στο αποδίδει με μικρά. Έχω να προσθέσψ κι άλλες. Ενδεικτικά μόνο έβαλα αυτές και λειτουργούν άψογα. Αυτά: "αναγνώστης", "συνδυασμοί", "διαδικοί αριθμοί" είναι κώδικες επίσης python και ανοίγουν εφαρμογάκια για μετατροπή δεκαδικών σε διαδικό, ανάγνωση κειμένου με τη φωνή της google, συνδυασμοί ν αντικειμένων από τα κ. Θα βάλω τους κώδικες σε άλλα νήματα.
actions = {
"firefox": "firefox",
"ubuntu forum": "firefox https://forum.ubuntu-gr.org/",
"καιρός σαλαμίνα": "firefox https://www.meteo.gr/cf.cfm?city_id=60",
"καιρός αθήνα": "firefox https://www.meteo.gr/cf.cfm",
"καιρός πειραιάς": "firefox https://www.meteo.gr/cf.cfm?city_id=61",
"ποσειδώνας": "firefox https://poseidon.hcmr.gr/el/map?model=meteo¶m=cloud&date=2024-02-26T00:00:00Z&coords=38,24,5",
"ποσειδών": "firefox https://poseidon.hcmr.gr/el/map?model=meteo¶m=cloud&date=2024-02-26T00:00:00Z&coords=38,24,5",
"zoom": "/home/family/scripts/pamp",
"ζουμ": "/home/family/scripts/pamp",
"ζουν": "/home/family/scripts/pamp",
"zum": "/home/family/scripts/pamp",
"ελαχιστοποίηση": "/home/family/scripts/pomp",
"κανονική οθόνη": "/home/family/scripts/pimp",
"αρνητικό": "/home/family/scripts/roc",
"άναψε κουζίνα": "/home/family/scripts/routines/kitchenon",
"κλείσε κουζίνα": "/home/family/scripts/routines/kitchenoff",
"θερμοσίφωνας": "/home/family/scripts/routines/thermos-on",
"κλείσε θερμοσίφωνα": "/home/family/scripts/routines/thermos-off",
"εορτολόγιο": "/home/family/eortologio/giorti",
"το κινητό μου": "/home/family/scripts/scrcpy/for-scrcpy",
"δείξε το κινητό μου": "/home/family/scripts/scrcpy/for-scrcpy",
"κινητό": "/home/family/scripts/scrcpy/for-scrcpy",
"viber": "/opt/viber/Viber",
"αναγνώστης": "/home/family/scripts/reader/Ανάγνωση",
"αναγνώστρια": "/home/family/scripts/reader/Ανάγνωση",
"ανάγνωση": "/home/family/scripts/reader/Ανάγνωση",
"συνδυασμοί": "/home/family/scripts/combinations/compan.py",
"διαδικός": "/home/family/scripts/convert-num/metatropi9.py",
"διαδικός αριθμός": "/home/family/scripts/convert-num/metatropi9.py",
"διαδικτή αριθμοί": "/home/family/scripts/convert-num/metatropi9.py",
"διαδικοί αριθμοί": "/home/family/scripts/convert-num/metatropi9.py",
"κάμερα": "mplayer tv:// -vf mirror",
"spotify": "spotify",
"caja": "caja",
"κάτσε": "caja",
"προσωπικός φάκελος": "caja /home/family",
"λευτέρης": "caja /home/family/Επιφάνεια\ εργασίας/ΛΕΥΤΕΡΗΣ",
"εικόνες": "caja /home/family/Εικόνες",
"σελήνη": "caja /media/SELINI",
"σε λίγη": "caja /media/SELINI",
"τον πούλο": "shutdown now"
}
def __init__(self):
super().__init__()
self.setWindowFlag(Qt.FramelessWindowHint)
self.setGeometry(1655, 350, 265, 115)
self.setFixedSize(265, 115)
self.setWindowFlag(Qt.WindowStaysOnTopHint)
self.setStyleSheet("background-color: #040102;")
self.recognizer = sr.Recognizer()
vbox = QVBoxLayout(self)
vbox.setContentsMargins(0, 0, 0, 0)
self.label_animation = QLabel(self)
self.label_animation.setGeometry(0, 0, 265, 115) #Είπαμε το καρακιτσαριό του κερατά. Άμ δεν έχει ένα gifάκι για φόντο δεν κάνουμε δουλειά
self.movie = QMovie("gifs/ink.gif") #Σε υποφάκελο μέσα στο φάκελο που βρίσκεται ο κώδικας έχω διάφορα gifάκια
self.label_animation.setMovie(self.movie)
self.movie.start()
self.text_input = QTextEdit(self)
font = QFont("FreeSans", 14, QFont.Bold)
self.text_input.setFont(font)
self.text_input.setStyleSheet("border: 3px double #FF00FD; background-color: #000000; color: yellow; font-weight: bold;")
self.text_input.setFixedHeight(115)
self.text_input.setAlignment(Qt.AlignTop | Qt.AlignLeft)
vbox.addWidget(self.text_input, stretch=5)
self.start_recognition_button = QPushButton(self)
pixmap = QPixmap("png/mic4.png") #εικονιδιάκι μικρόφωνο. Το πατάς και μιλάς.
icon = QIcon(pixmap)
self.start_recognition_button.setIcon(icon)
self.start_recognition_button.setIconSize(pixmap.rect().size())
self.start_recognition_button.setMaximumSize(40, 40)
self.start_recognition_button.move(self.start_recognition_button.x() - 5, self.start_recognition_button.y() - 5)
self.start_recognition_button.clicked.connect(self.start_recognition)
self.history_file = "history-special.json" #Κρατάμε και ιστορικό εντολών άμα λάχει, έτσι για να γουστάρουμε
self.load_history()
self.timer = QTimer(self)
self.timer.timeout.connect(self.update_animation)
self.timer.start(50)
self.start_recognition_button.move(10, 70)
self.opacity_effect = QGraphicsOpacityEffect(self.text_input)
self.text_input.setGraphicsEffect(self.opacity_effect)
self.opacity_effect.setOpacity(0.7)
self.text_input.installEventFilter(self)
#Είπαμε το καρακιτσαριό του κερατά. Άμ δεν έχει ένα gifάκι για φόντο δεν κάνουμε δουλειά
def update_animation(self):
if not self.movie.currentPixmap().isNull():
self.repaint()
def start_recognition(self): #και ξεκινάμε την εκφώνηση των εντολών.
with sr.Microphone() as source:
print("Ακούει...")
audio = self.recognizer.listen(source, timeout=5, phrase_time_limit=6)
try:
recognized_text = self.recognizer.recognize_google(audio, language="el-GR")
self.text_input.setPlainText(recognized_text)
self.add_to_history(recognized_text)
self.execute_command(recognized_text.lower())
except sr.UnknownValueError:
os.system(f'notify-send "η φωνητική αναγνώριση google δεν καταλαβαίνει τον ήχο" ')
print("η φωνητική αναγνώριση google δεν καταλαβαίνει τον ήχο")
except sr.RequestError as e:
os.system(f'notify-send "Συνέβη ένα λάθος κατά τη φωνητική αναγνώριση" "{e}"')
print(f"Συνέβη ένα λάθος κατά τη φωνητική αναγνώριση; {e}")
def load_history(self): #Το ιστορικό εντολών μας. Το κουλαντρίζεις με τα βελάκια του πληκτρολογίου άνω και κάτω σαν το history του τερματικού
try:
with open(self.history_file, "r") as file:
self.history = json.load(file)
except FileNotFoundError:
self.history = []
self.history_index = len(self.history)
def save_history(self):
with open(self.history_file, "w") as json_file: #και σε Τζέσον
json.dump(self.history, json_file)
with open("history-special.txt", "w") as txt_file:#και σε τιεξτί
for item in self.history:
txt_file.write("%s\n" % item)
def add_to_history(self, text):
self.history.append(text)
self.save_history()
def retrieve_from_history(self, forward=True):
if forward:
if self.history_index < len(self.history) - 1:
self.history_index += 1
else:
if self.history_index > 0:
self.history_index -= 1
if 0 <= self.history_index < len(self.history):
self.text_input.setPlainText(self.history[self.history_index])
def eventFilter(self, obj, event):
if obj is self.text_input and event.type() == event.KeyPress:#Τα βελάκια που λέγαμε
if event.key() == Qt.Key_Up:
self.retrieve_from_history(forward=False)
return False
elif event.key() == Qt.Key_Down:
self.retrieve_from_history(forward=True)
return False
return super().eventFilter(obj, event)
def execute_command(self, command):
if command:
if command.startswith("ψάξε τοπικά") or command.startswith("δείξε") or command.startswith("μείξε") or command.startswith("λήξη") or command.startswith("ρίξε") or command.startswith("ληξε"): #Καμιά φορά δεςν ακούει καλά και γι αυτό του έβαλα κι άλλες πιθανές λέξεις που θα πιάσει
query = command.split(" ", 2)[-1] # Αφαιρούμε τις πρώτες δύο λέξεις
period = None
if "χθες" in command: #ΠΡΟΣΠΑΘΕΙΑ ΝΑ ΚΑΝΕΙ
period = "yesterday"
elif "πριν δυο μέρες" in command: #ΑΝΑΖΗΤΗΣΗ
period = "two days ago"
elif "προηγούμενη εβδομάδα" in command: #ΜΕ ΚΡΙΤΗΡΙΟ ΤΙΣ ΗΜΕΡΟΜΗΝΙΕΣ
period = "last week"
#ΑΠΟΘΗΚΕΥΣΗΣ
search_results = self.search_files(query, period)
if search_results: #ΤΖΙΦΟΣ! ΑΥΤΟ ΔΕΝ ΜΟΥ ΔΟΥΛΕΨΕ. ΔΥΣΤΥΧΩΣ!
print("Αποτελέσματα αναζήτησης:")
for result in search_results:
print(result)
self.show_results_window(search_results) # Εμφάνισε όλα τα αποτελέσματα μαζί
else:
print("Δεν βρέθηκαν αρχεία που να ταιριάζουν στην αναζήτηση.")
elif command.startswith("ψάξε") or command.startswith("δείξε"): #Εδώ ανοίγει ο firefox και κάνει αναζήτηση google
search_query = command.split(" ", 1)[1] # Αφαιρούμε τη λέξη "ψάξε" ή "δείξε" και το κενό μετά από αυτήν
search_url = f"https://www.google.com/search?q={search_query}"
os.system(f"firefox \"{search_url}\"")
print(f"Αναζήτηση στο Google για: {search_query}")
elif command in self.actions:
os.system(self.actions[command])
print(f"Εκτέλεση εντολής: {self.actions[command]}")
elif command.startswith(("εκτύπωσε", "τύπωσε", "εκτύπωση")): #Εδώ τυπώνει αυτό που υποθέτει ότι του είπες. Ψάχνει μόνο σε ένα φάκελο.
file_to_print = next((keyword for keyword in ["εκτύπωσε", "τύπωσε", "εκτύπωση"] if keyword in command), None)
file_to_print = command.split(file_to_print, 1)[-1].strip() # Παίρνουμε το όνομα του αρχείου που θέλει να εκτυπώσει ο χρήστη
file_path = self.find_matching_file(file_to_print)
if file_path:
os.system(f"lp {file_path}") # Εκτελούμε την εντολή lp με το συγκεκριμένο αρχείο
print(f'Εκτύπωση αρχείου: "{file_path}" ')
else:
print("Δεν βρέθηκε αρχείο προς εκτύπωση.")
else:
os.system(f'notify-send "Η εντολή δεν αναγνωρίζεται" ')
print("Η εντολή δεν αναγνωρίζεται.")
def search_files(self, query, period=None): #Εδώ ψάχνει αρχεία που του ζητήσαμε με την εντολή δείξε
query = unidecode(query).lower()
results = []
# Αναζήτηση σε ολόκληρο τον φάκελο /home/family
for root, dirs, files in os.walk("/home/family"):
for file in files:
file_name = unidecode(file).lower()
if query in file_name:
if period:
today = datetime.date.today()
if period == "χθες":
search_date = today - datetime.timedelta(days=1)
elif period == "προχθές":
search_date = today - datetime.timedelta(days=2)
elif period == "προηγούμενη εβδομάδα":
search_date = today - datetime.timedelta(weeks=1)
else:
raise ValueError("Μη έγκυρη περίοδος αναζήτησης")
# Ελέγχουμε αν το αρχείο ανήκει στην επιθυμητή περίοδο αλλά είπαμε...ΤΖΙΦΟΣ!
file_path = os.path.join(root, file)
file_creation_date = datetime.date.fromtimestamp(os.path.getctime(file_path))
if file_creation_date == search_date:
results.append(file_path)
else:
results.append(os.path.join(root, file))
# Αναζήτηση στον φάκελο που έχω για αποθήκη. Είναι ntfs για να τον βλέπουν και τα windows.
for root, dirs, files in os.walk("/media/family/SELINI"):
for file in files:
file_name = unidecode(file).lower()
if query in file_name:
if period:
today = datetime.date.today()
if period == "σήμερα":
search_date = today - datetime.timedelta(days=0)
elif period == "χθες":
search_date = today - datetime.timedelta(days=1)
elif period == "προχθές":
search_date = today - datetime.timedelta(days=2)
elif period == "εβδομάδα":
search_date = today - datetime.timedelta(weeks=1)
else:
raise ValueError("Μη έγκυρη περίοδος αναζήτησης")
# Ελέγχουμε αν το αρχείο ανήκει στην επιθυμητή περίοδο
file_path = os.path.join(root, file)
file_creation_date = datetime.date.fromtimestamp(os.path.getctime(file_path))
if file_creation_date == search_date:
results.append(file_path)
else:
results.append(os.path.join(root, file))
return results
def show_results_window(self, results):
self.results_window = ResultsWindow(results)
self.results_window.show()
def find_matching_file(self, file_name):
print("Αναζήτηση αρχείου:", file_name)
printer_directory = "/home/family/zzzz-print" # Ο φάκελος με τα αρχεία που μπορούν να εκτυπωθούν
files = os.listdir(printer_directory)
match, score = process.extractOne(file_name, files)
print("Συμφωνία:", match, "Ποσοστό:", score)
return os.path.join(printer_directory, match)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = VasikoWindow()
window.show()
sys.exit(app.exec_())