1
+ import sys
2
+ from PyQt5 .QtWidgets import (
3
+ QApplication , QMainWindow , QWidget , QVBoxLayout , QHBoxLayout ,
4
+ QPushButton , QTextEdit , QFileDialog , QLabel , QComboBox , QMessageBox , QProgressBar , QDialog , QInputDialog
5
+ )
6
+ from PyQt5 .QtCore import Qt
7
+ from openai import OpenAI
8
+
9
+ # Initialize the OpenAI client with your test API key.
10
+ client = OpenAI (
11
+ api_key = "TOKEN"
12
+ )
13
+
14
+
15
+ class TranslatorApp (QMainWindow ):
16
+ def __init__ (self ):
17
+ super ().__init__ ()
18
+ self .setWindowTitle ("Text Translator" )
19
+ self .resize (1000 , 700 )
20
+ self .translation_history = []
21
+ self .feedback_list = []
22
+ self .initUI ()
23
+
24
+ def initUI (self ):
25
+ # Main widget and layout
26
+ main_widget = QWidget ()
27
+ self .setCentralWidget (main_widget )
28
+ main_layout = QVBoxLayout ()
29
+ main_widget .setLayout (main_layout )
30
+
31
+ # Input text field
32
+ self .input_text_edit = QTextEdit ()
33
+ self .input_text_edit .setPlaceholderText ("Enter or load text to translate..." )
34
+ main_layout .addWidget (QLabel ("Original Text:" ))
35
+ main_layout .addWidget (self .input_text_edit )
36
+
37
+ # Target language selection
38
+ self .language_combo = QComboBox ()
39
+ self .language_combo .addItems (["Spanish" , "French" , "German" , "Chinese" , "Japanese" ])
40
+ self .language_combo .currentIndexChanged .connect (self .change_target_language )
41
+ language_layout = QHBoxLayout ()
42
+ language_layout .addWidget (QLabel ("Target Language:" ))
43
+ language_layout .addWidget (self .language_combo )
44
+ main_layout .addLayout (language_layout )
45
+
46
+ # Translate button
47
+ self .translate_button = QPushButton ("Translate" )
48
+ self .translate_button .clicked .connect (self .translate_and_display )
49
+ main_layout .addWidget (self .translate_button )
50
+
51
+ # Output text field
52
+ self .output_text_edit = QTextEdit ()
53
+ self .output_text_edit .setPlaceholderText ("Translated text will appear here..." )
54
+ main_layout .addWidget (QLabel ("Translated Text:" ))
55
+ main_layout .addWidget (self .output_text_edit )
56
+
57
+ # Buttons for file operations and clipboard
58
+ button_layout = QHBoxLayout ()
59
+ self .open_button = QPushButton ("Open File" )
60
+ self .open_button .clicked .connect (self .open_file )
61
+ button_layout .addWidget (self .open_button )
62
+
63
+ self .save_button = QPushButton ("Save File" )
64
+ self .save_button .clicked .connect (self .save_file )
65
+ button_layout .addWidget (self .save_button )
66
+
67
+ self .clear_button = QPushButton ("Clear" )
68
+ self .clear_button .clicked .connect (self .clear_text )
69
+ button_layout .addWidget (self .clear_button )
70
+
71
+ self .copy_button = QPushButton ("Copy to Clipboard" )
72
+ self .copy_button .clicked .connect (self .copy_to_clipboard )
73
+ button_layout .addWidget (self .copy_button )
74
+
75
+ main_layout .addLayout (button_layout )
76
+
77
+ # Advanced functionalities layout
78
+ adv_layout = QHBoxLayout ()
79
+
80
+ self .batch_button = QPushButton ("Batch Translate" )
81
+ self .batch_button .clicked .connect (self .batch_translate )
82
+ adv_layout .addWidget (self .batch_button )
83
+
84
+ self .tts_button = QPushButton ("Text to Speech" )
85
+ self .tts_button .clicked .connect (self .text_to_speech )
86
+ adv_layout .addWidget (self .tts_button )
87
+
88
+ self .stt_button = QPushButton ("Speech to Text" )
89
+ self .stt_button .clicked .connect (self .speech_to_text )
90
+ adv_layout .addWidget (self .stt_button )
91
+
92
+ self .auto_detect_button = QPushButton ("Auto Language Detection" )
93
+ self .auto_detect_button .clicked .connect (self .auto_language_detection )
94
+ adv_layout .addWidget (self .auto_detect_button )
95
+
96
+ self .history_button = QPushButton ("Translation History" )
97
+ self .history_button .clicked .connect (self .show_translation_history )
98
+ adv_layout .addWidget (self .history_button )
99
+
100
+ self .cost_button = QPushButton ("Show Translation Cost" )
101
+ self .cost_button .clicked .connect (self .show_translation_cost )
102
+ adv_layout .addWidget (self .cost_button )
103
+
104
+ self .feedback_button = QPushButton ("Feedback" )
105
+ self .feedback_button .clicked .connect (self .translation_quality_feedback )
106
+ adv_layout .addWidget (self .feedback_button )
107
+
108
+ main_layout .addLayout (adv_layout )
109
+
110
+ # Progress bar for batch translation
111
+ self .progress_bar = QProgressBar ()
112
+ self .progress_bar .setValue (0 )
113
+ main_layout .addWidget (self .progress_bar )
114
+
115
+ def open_file (self ):
116
+ options = QFileDialog .Options ()
117
+ file_name , _ = QFileDialog .getOpenFileName (
118
+ self , "Open Text File" , "" , "Text Files (*.txt);;All Files (*)" , options = options
119
+ )
120
+ if file_name :
121
+ try :
122
+ with open (file_name , "r" , encoding = "utf-8" ) as f :
123
+ content = f .read ()
124
+ self .input_text_edit .setPlainText (content )
125
+ except Exception as e :
126
+ QMessageBox .critical (self , "Error" , f"Failed to open file:\n { str (e )} " )
127
+
128
+ def save_file (self ):
129
+ options = QFileDialog .Options ()
130
+ file_name , _ = QFileDialog .getSaveFileName (
131
+ self , "Save Translated Text" , "" , "Text Files (*.txt);;All Files (*)" , options = options
132
+ )
133
+ if file_name :
134
+ try :
135
+ with open (file_name , "w" , encoding = "utf-8" ) as f :
136
+ f .write (self .output_text_edit .toPlainText ())
137
+ except Exception as e :
138
+ QMessageBox .critical (self , "Error" , f"Failed to save file:\n { str (e )} " )
139
+
140
+ def translate_and_display (self ):
141
+ original_text = self .input_text_edit .toPlainText ()
142
+ if not original_text .strip ():
143
+ QMessageBox .warning (self , "Warning" , "Please enter some text to translate." )
144
+ return
145
+
146
+ target_language = self .language_combo .currentText ()
147
+ prompt = f"Translate the following text into { target_language } while preserving its original meaning:\n \n { original_text } "
148
+
149
+ try :
150
+ completion = client .chat .completions .create (
151
+ model = "gpt-4o-mini" ,
152
+ store = True ,
153
+ messages = [
154
+ {"role" : "system" , "content" : "You are a helpful translation assistant." },
155
+ {"role" : "user" , "content" : prompt }
156
+ ]
157
+ )
158
+ translated_text = completion .choices [0 ].message ['content' ].strip ()
159
+ self .output_text_edit .setPlainText (translated_text )
160
+ # Save to translation history
161
+ self .translation_history .append ({
162
+ "file" : "Manual Input" ,
163
+ "original" : original_text ,
164
+ "translated" : translated_text ,
165
+ "language" : target_language
166
+ })
167
+ except Exception as e :
168
+ QMessageBox .critical (self , "Error" , f"Translation failed:\n { str (e )} " )
169
+
170
+ def clear_text (self ):
171
+ self .input_text_edit .clear ()
172
+ self .output_text_edit .clear ()
173
+
174
+ def copy_to_clipboard (self ):
175
+ clipboard = QApplication .clipboard ()
176
+ clipboard .setText (self .output_text_edit .toPlainText ())
177
+ QMessageBox .information (self , "Copied" , "Translated text copied to clipboard." )
178
+
179
+ def change_target_language (self ):
180
+ selected_language = self .language_combo .currentText ()
181
+ print (f"Target language changed to: { selected_language } " )
182
+
183
+ def batch_translate (self ):
184
+ files , _ = QFileDialog .getOpenFileNames (self , "Select Text Files" , "" , "Text Files (*.txt)" )
185
+ if not files :
186
+ return
187
+ # Clear existing history and progress bar
188
+ self .translation_history .clear ()
189
+ self .progress_bar .setMaximum (len (files ))
190
+ self .progress_bar .setValue (0 )
191
+ results = ""
192
+ target_language = self .language_combo .currentText ()
193
+ for i , file_name in enumerate (files , start = 1 ):
194
+ try :
195
+ with open (file_name , "r" , encoding = "utf-8" ) as f :
196
+ content = f .read ()
197
+ prompt = f"Translate the following text into { target_language } while preserving its original meaning:\n \n { content } "
198
+ completion = client .chat .completions .create (
199
+ model = "gpt-4o-mini" ,
200
+ store = True ,
201
+ messages = [
202
+ {"role" : "system" , "content" : "You are a helpful translation assistant." },
203
+ {"role" : "user" , "content" : prompt }
204
+ ]
205
+ )
206
+ translated_text = completion .choices [0 ].message ['content' ].strip ()
207
+ results += f"File: { file_name } \n Original:\n { content } \n Translated:\n { translated_text } \n { '-' * 40 } \n "
208
+ # Save to translation history
209
+ self .translation_history .append ({
210
+ "file" : file_name ,
211
+ "original" : content ,
212
+ "translated" : translated_text ,
213
+ "language" : target_language
214
+ })
215
+ self .progress_bar .setValue (i )
216
+ except Exception as e :
217
+ QMessageBox .critical (self , "Error" , f"Failed to translate { file_name } :\n { str (e )} " )
218
+ self .output_text_edit .setPlainText (results )
219
+
220
+ def text_to_speech (self ):
221
+ from gtts import gTTS
222
+ text = self .output_text_edit .toPlainText ()
223
+ if not text .strip ():
224
+ QMessageBox .warning (self , "Warning" , "No translated text available for conversion." )
225
+ return
226
+ try :
227
+ tts = gTTS (text )
228
+ options = QFileDialog .Options ()
229
+ file_name , _ = QFileDialog .getSaveFileName (
230
+ self , "Save Audio File" , "" , "MP3 Files (*.mp3);;All Files (*)" , options = options
231
+ )
232
+ if file_name :
233
+ tts .save (file_name )
234
+ QMessageBox .information (self , "Success" , f"Audio saved to { file_name } " )
235
+ except Exception as e :
236
+ QMessageBox .critical (self , "Error" , f"Text-to-speech conversion failed:\n { str (e )} " )
237
+
238
+ def speech_to_text (self ):
239
+ import speech_recognition as sr
240
+ r = sr .Recognizer ()
241
+ with sr .Microphone () as source :
242
+ QMessageBox .information (self , "Info" , "Please speak now..." )
243
+ audio = r .listen (source )
244
+ try :
245
+ recognized_text = r .recognize_google (audio )
246
+ self .input_text_edit .setPlainText (recognized_text )
247
+ except Exception as e :
248
+ QMessageBox .critical (self , "Error" , f"Speech recognition failed:\n { str (e )} " )
249
+
250
+ def auto_language_detection (self ):
251
+ from langdetect import detect
252
+ text = self .input_text_edit .toPlainText ()
253
+ if not text .strip ():
254
+ QMessageBox .warning (self , "Warning" , "No text available for language detection." )
255
+ return
256
+ try :
257
+ detected_language = detect (text )
258
+ QMessageBox .information (self , "Language Detection" , f"Detected language: { detected_language } " )
259
+ except Exception as e :
260
+ QMessageBox .critical (self , "Error" , f"Language detection failed:\n { str (e )} " )
261
+
262
+ def show_translation_history (self ):
263
+ if not self .translation_history :
264
+ QMessageBox .information (self , "History" , "No translations in history yet." )
265
+ return
266
+ history_str = ""
267
+ for entry in self .translation_history :
268
+ history_str += (f"File: { entry ['file' ]} \n "
269
+ f"Language: { entry ['language' ]} \n "
270
+ f"Original:\n { entry ['original' ]} \n "
271
+ f"Translated:\n { entry ['translated' ]} \n "
272
+ + "-" * 40 + "\n " )
273
+ dialog = QDialog (self )
274
+ dialog .setWindowTitle ("Translation History" )
275
+ layout = QVBoxLayout ()
276
+ text_edit = QTextEdit ()
277
+ text_edit .setReadOnly (True )
278
+ text_edit .setPlainText (history_str )
279
+ layout .addWidget (text_edit )
280
+ dialog .setLayout (layout )
281
+ dialog .exec_ ()
282
+
283
+ def show_translation_cost (self ):
284
+ text = self .input_text_edit .toPlainText ()
285
+ if not text .strip ():
286
+ QMessageBox .warning (self , "Warning" , "No text available to calculate cost." )
287
+ return
288
+ # Estimate cost based on word count (as a rough proxy for tokens)
289
+ estimated_tokens = len (text .split ())
290
+ cost_per_1000_tokens = 0.02 # Example cost rate in USD
291
+ estimated_cost = (estimated_tokens / 1000 ) * cost_per_1000_tokens
292
+ QMessageBox .information (
293
+ self , "Translation Cost" ,
294
+ f"Estimated translation cost: ${ estimated_cost :.4f} USD (based on { estimated_tokens } tokens)"
295
+ )
296
+
297
+ def translation_quality_feedback (self ):
298
+ feedback , ok = QInputDialog .getMultiLineText (
299
+ self , "Translation Feedback" , "Enter your feedback about the translation:"
300
+ )
301
+ if ok and feedback .strip ():
302
+ self .feedback_list .append (feedback )
303
+ QMessageBox .information (self , "Feedback Received" , "Thank you for your feedback!" )
304
+
305
+
306
+ if __name__ == "__main__" :
307
+ app = QApplication (sys .argv )
308
+ translator_app = TranslatorApp ()
309
+ translator_app .show ()
310
+ sys .exit (app .exec_ ())
0 commit comments