-
Notifications
You must be signed in to change notification settings - Fork 1
/
client.py
175 lines (149 loc) · 4.81 KB
/
client.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# client.py
import sys
import argparse
import logging
import pyperclip
import win32file
import pywintypes
import time
import json
from pathlib import Path
from configure_enc_utils import load_config
# Configure logging
def setup_logging():
if getattr(sys, "frozen", False):
# If the application is run as a bundle, use the AppData directory
log_dir = os.path.join(
os.path.expanduser("~"),
"AppData",
"Roaming",
"Ace Centre",
"AACSpeakHelper",
)
else:
# If run from a Python environment, use the current directory
log_dir = os.path.dirname(os.path.abspath(__file__))
if not os.path.exists(log_dir):
os.makedirs(log_dir)
log_file = os.path.join(log_dir, "client.log")
logging.basicConfig(
filename=log_file,
filemode="a",
format="%(asctime)s — %(name)s — %(levelname)s — %(funcName)s:%(lineno)d — %(message)s",
level=logging.DEBUG,
)
return log_file
logfile = setup_logging()
def get_clipboard_text():
"""
Retrieves the current text from the clipboard.
Returns:
str: The clipboard text.
"""
try:
return pyperclip.paste()
except pyperclip.PyperclipException as e:
logging.error(f"Failed to get clipboard text: {e}")
return ""
def send_to_pipe(data, retries=3, delay=1):
"""
Sends data to a named pipe.
Args:
data (dict): The data to send.
retries (int): Number of retries if the pipe is unavailable.
delay (int): Delay in seconds between retries.
Returns:
None
"""
pipe_name = r"\\.\pipe\AACSpeakHelper"
attempt = 0
while attempt < retries:
try:
handle = win32file.CreateFile(
pipe_name,
win32file.GENERIC_READ | win32file.GENERIC_WRITE,
0,
None,
win32file.OPEN_EXISTING,
0,
None,
)
message = json.dumps(data).encode()
win32file.WriteFile(handle, message)
logging.info(f"Sent data to pipe: {data}")
try:
result, response = win32file.ReadFile(handle, 128 * 1024)
if result == 0:
available_voices = response.decode()
logging.info(f"Available Voices: {available_voices}")
except Exception as read_error:
if "109" not in str(read_error):
logging.error(f"Error reading from pipe: {read_error}")
win32file.CloseHandle(handle)
break
except pywintypes.error as e:
logging.error(
f"Attempt {attempt + 1}: Error communicating with the pipe server: {e}"
)
time.sleep(delay)
attempt += 1
else:
logging.error(
"Failed to communicate with the pipe server after multiple attempts."
)
def main():
"""
Main function to execute the client logic.
"""
parser = argparse.ArgumentParser(description="AACSpeakHelper Client")
parser.add_argument(
"-c",
"--config",
help="Path to a defined config file",
required=False,
default="",
)
parser.add_argument(
"-l",
"--listvoices",
help="List Voices to see what's available",
action="store_true",
)
parser.add_argument("-p", "--preview", help="Preview Only", action="store_true")
parser.add_argument("-s", "--style", help="Voice style for Azure TTS", default="")
parser.add_argument(
"-sd",
"--styledegree",
type=float,
help="Degree of style for Azure TTS",
default=None,
)
args = vars(parser.parse_args())
config_path = args["config"]
try:
# Check if a custom configuration file was provided
if config_path:
# If a custom config path is provided, load config with that path
config = load_config(custom_config_path=config_path)
logging.info(f"Primary configuration loaded from {config_path}.")
else:
# Load the default configuration
config = load_config()
logging.info("Primary configuration loaded successfully.")
except Exception as error:
logging.error(f"Error loading primary configuration: {error}")
sys.exit(1)
logging.info("All configurations are validated successfully.")
# Retrieve clipboard text
clipboard_text = get_clipboard_text()
logging.debug(f"Clipboard text: {clipboard_text}")
# Prepare data to send
data_to_send = {
"args": args,
"config": config,
"clipboard_text": clipboard_text,
}
# Send data to the named pipe
send_to_pipe(data_to_send)
if __name__ == "__main__":
main()