Completed
Pull Request — master (#164)
by Jace
02:59 queued 01:45
created

Application.clear()   A

Complexity

Conditions 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 1
dl 0
loc 3
rs 10
1
#!env/bin/python
2
3
import os
4
import sys
5
import logging
6
7
ROOT = os.path.join(os.path.dirname(__file__), '..')
8
sys.path.append(ROOT)
9
10
import tkinter as tk
11
from tkinter import ttk
12
from PIL import Image, ImageTk
13
import speech_recognition
14
15
from memegen import __project__, __version__
16
from memegen.settings import ProdConfig
17
from memegen.app import create_app
18
from memegen.domain import Text
19
20
log = logging.getLogger(__name__)
21
22
23
class Application:
24
25
    def __init__(self, app):
26
        self.app = app
27
        self.label = None
28
        self.text = None
29
        self._image = None
30
        self._update_event = None
31
        self._clear_event = None
32
        self._recogizer = speech_recognition.Recognizer()
33
        self._microphone = speech_recognition.Microphone()
34
        with self._microphone as source:
35
            log.info("Adjusting for ambient noise...")
36
            self._recogizer.adjust_for_ambient_noise(source)
37
        log.info("Listening in the background...")
38
        self._recogizer.listen_in_background(self._microphone, self.listen)
39
40
        # Configure root window
41
        self.root = tk.Tk()
42
        self.root.title("{} (v{})".format(__project__, __version__))
43
        self.root.minsize(500, 500)
44
45
        # Initialize the GUI
46
        self.label = None
47
        frame = self.init(self.root)
48
        frame.pack(fill=tk.BOTH, expand=1)
49
50
        # Start the event loop
51
        self.restart()
52
        self.root.mainloop()
53
54
    def init(self, root):
55
        padded = {'padding': 5}
56
        sticky = {'sticky': tk.NSEW}
57
58
        # Configure grid
59
        frame = ttk.Frame(root, **padded)
60
        frame.rowconfigure(0, weight=1)
61
        frame.rowconfigure(1, weight=0)
62
        frame.columnconfigure(0, weight=1)
63
64
        def frame_image(root):
65
            frame = ttk.Frame(root, **padded)
66
67
            # Configure grid
68
            frame.rowconfigure(0, weight=1)
69
            frame.columnconfigure(0, weight=1)
70
71
            # Place widgets
72
            self.label = ttk.Label(frame)
73
            self.label.grid(row=0, column=0)
74
75
            return frame
76
77
        def frame_text(root):
78
            frame = ttk.Frame(root, **padded)
79
80
            # Configure grid
81
            frame.rowconfigure(0, weight=1)
82
            frame.rowconfigure(1, weight=1)
83
            frame.columnconfigure(0, weight=1)
84
85
            # Place widgets
86
            self.text = ttk.Entry(frame)
87
            self.text.bind("<Key>", self.restart)
88
            self.text.grid(row=0, column=0, **sticky)
89
            self.text.focus_set()
90
91
            return frame
92
93
        def separator(root):
94
            return ttk.Separator(root)
95
96
        # Place widgets
97
        frame_image(frame).grid(row=0, **sticky)
98
        separator(frame).grid(row=1, padx=10, pady=5, **sticky)
99
        frame_text(frame).grid(row=2, **sticky)
100
101
        return frame
102
103
    def listen(self, recognizer, audio):
104
        log.info("Recognizing speech...")
105
        try:
106
            value = recognizer.recognize_google(audio)
107
        except speech_recognition.UnknownValueError:
108
            log.warning("No text matched")
109
        else:
110
            log.info("Matched text: %s", value)
111
            self.clear()
112
            self.text.insert(0, value)
113
114
    def update(self):
115
        text = Text(self.text.get())
116
117
        ratio = 0
118
        match = None
119
120
        for template in self.app.template_service.all():
121
            _ratio, path = template.match(str(text).lower())
122
            if _ratio > ratio:
123
                ratio = _ratio
124
                log.info("Matched at %s: %s - %s", ratio, template, path)
125
                match = template, Text(path)
126
127
        if match:
128
            domain = self.app.image_service.create(*match)
129
            image = Image.open(domain.path)
130
            old_size = image.size
131
            max_size = self.root.winfo_width(), self.root.winfo_height()
132
            ratio = min(max_size[0]/old_size[0], max_size[1]/old_size[1]) * .9
133
            new_size = [int(s * ratio) for s in old_size]
134
            image = image.resize(new_size, Image.ANTIALIAS)
135
            self.image = ImageTk.PhotoImage(image)
136
            self.label.configure(image=self.image)
137
138
            self.clear()
139
140
        self.restart(update=True, clear=False)
141
142
    def clear(self, *_):
143
        self.text.delete(0, tk.END)
144
        self.restart()
145
146
    def restart(self, *_, update=True, clear=True):
147
        if update:
148
            if self._update_event:
149
                self.root.after_cancel(self._update_event)
150
            self._update_event = self.root.after(1000, self.update)
151
        if clear:
152
            if self._clear_event:
153
                self.root.after_cancel(self._clear_event)
154
            self._clear_event = self.root.after(5000, self.clear)
155
156
157
if __name__ == '__main__':
158
    Application(create_app(ProdConfig))
159