davideuler commited on
Commit
2527e5c
·
1 Parent(s): 8ebaba1

refactored

Browse files
Files changed (2) hide show
  1. app.py +191 -100
  2. run_translator_web.sh +0 -0
app.py CHANGED
@@ -9,6 +9,7 @@ from deep_translator import (
9
  )
10
  from deep_translator.openai_compatible import OpenAICompatibleTranslator
11
  import logging
 
12
 
13
  # Constants
14
  DEFAULT_PAGES_PER_LOAD = 2
@@ -19,7 +20,7 @@ DEFAULT_API_BASE = "http://localhost:8080/v1"
19
  TRANSLATORS = {
20
  'OpenAI Compatible': OpenAICompatibleTranslator,
21
  'OpenAI': OpenAICompatibleTranslator,
22
- 'google': GoogleTranslator,
23
  }
24
 
25
  # Color options
@@ -56,6 +57,65 @@ SOURCE_LANGUAGE_OPTIONS = {
56
  "Auto": "auto",
57
  }
58
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  def get_cache_dir():
60
  """Get or create cache directory"""
61
  cache_dir = Path('.cached')
@@ -88,6 +148,10 @@ def save_translation_cache(doc: pymupdf.Document, cache_key: str):
88
 
89
  def translate_pdf_pages(doc, doc_bytes, start_page, num_pages, translator, text_color, translator_name, target_lang):
90
  """Translate specific pages of a PDF document with progress and caching"""
 
 
 
 
91
  WHITE = pymupdf.pdfcolor["white"]
92
  rgb_color = COLOR_MAP.get(text_color.lower(), COLOR_MAP["darkred"])
93
 
@@ -138,6 +202,7 @@ def translate_pdf_pages(doc, doc_bytes, start_page, num_pages, translator, text_
138
  bbox = block[:4]
139
  text = block[4]
140
  translated = translator.translate(text)
 
141
 
142
  # Cover original text with white and add translation in color
143
  page.draw_rect(bbox, color=None, fill=WHITE)
@@ -187,6 +252,10 @@ def translate_all_pages(
187
  **kwargs
188
  ):
189
  """Translate all pages of the PDF document"""
 
 
 
 
190
  # Define colors
191
  WHITE = pymupdf.pdfcolor["white"]
192
  rgb_color = COLOR_MAP.get(kwargs.get('text_color', 'darkred').lower(), COLOR_MAP["darkred"])
@@ -240,8 +309,8 @@ def init_session_state():
240
  st.session_state.api_settings = {}
241
 
242
  def main():
243
- st.set_page_config(layout="wide", page_title="PDF Translator for Human: with Local-LLM/GPT")
244
- st.title("PDF Translator for Human: with Local-LLM/GPT")
245
 
246
  # Initialize session state
247
  init_session_state()
@@ -270,12 +339,6 @@ def main():
270
  )
271
  source_lang = SOURCE_LANGUAGE_OPTIONS[source_lang_name]
272
 
273
- translator_name = st.selectbox(
274
- "Select Translator",
275
- options=list(TRANSLATORS.keys()),
276
- index=0
277
- )
278
-
279
  pages_per_load = st.number_input(
280
  "Pages per load",
281
  min_value=1,
@@ -289,54 +352,44 @@ def main():
289
  index=0
290
  )
291
 
292
- # OpenAI specific settings
293
- if translator_name in ['OpenAI', 'OpenAI Compatible']:
294
- st.subheader(f"{translator_name} Settings")
295
- target_lang = st.selectbox(
296
- "Target Language",
297
- options=list(LANGUAGE_OPTIONS.keys()),
298
- index=0
 
 
 
 
 
 
 
299
  )
300
-
301
- # Get API key from environment or user input
302
- api_key = os.getenv("OPENAI_API_KEY", "")
303
- if not api_key:
304
- api_key = st.text_input(
305
- "API Key",
306
- value="sk-xxx",
307
- type="password"
308
- )
309
-
310
- # Different default API base for OpenAI and OpenAI Compatible
311
- default_base = "https://api.openai.com/v1" if translator_name == 'OpenAI' else DEFAULT_API_BASE
312
  api_base = st.text_input(
313
  "API Base URL",
314
- value=os.getenv("OPENAI_API_BASE", default_base)
315
  )
316
-
317
- # Different default model for OpenAI and OpenAI Compatible
318
- default_model = "gpt-4o-mini" if translator_name == 'OpenAI' else DEFAULT_MODEL
319
  model = st.text_input(
320
  "Model Name",
321
- value=os.getenv("OPENAI_MODEL", default_model)
322
  )
323
 
324
- # Store API settings in session state
325
  st.session_state.api_settings.update({
326
  'api_key': api_key,
327
  'api_base': api_base,
328
  'model': model
329
  })
330
-
331
- target_lang = LANGUAGE_OPTIONS[target_lang]
332
- else:
333
- # For Google Translator, show target language selection
334
- target_lang_name = st.selectbox(
335
- "Target Language",
336
- options=list(SOURCE_LANGUAGE_OPTIONS.keys())[:-1], # Remove "Auto" option
337
- index=0 # Default to first language
338
  )
339
- target_lang = SOURCE_LANGUAGE_OPTIONS[target_lang_name]
 
 
340
 
341
  # Main content area
342
  if uploaded_file is not None:
@@ -346,7 +399,7 @@ def main():
346
  # Create two columns for side-by-side display
347
  col1, col2 = st.columns(2)
348
 
349
- # Display original pages immediately
350
  with col1:
351
  st.header("Original")
352
  for page_num in range(st.session_state.current_page,
@@ -359,35 +412,46 @@ def main():
359
  with col2:
360
  st.header("Translated")
361
 
362
- # Configure translator with selected source language and API settings
363
- TranslatorClass = TRANSLATORS[translator_name]
364
- translator = TranslatorClass(
365
- source=source_lang,
366
- target=target_lang,
367
- api_key=st.session_state.api_settings.get('api_key'),
368
- base_url=st.session_state.api_settings.get('api_base'),
369
- model=st.session_state.api_settings.get('model')
370
- )
371
-
372
- # Translate current batch of pages
373
- translated_pages = translate_pdf_pages(
374
- doc,
375
- doc_bytes,
376
- st.session_state.current_page,
377
- pages_per_load,
378
- translator,
379
- text_color,
380
- translator_name,
381
- target_lang
382
- )
 
 
 
 
 
 
 
 
 
 
 
 
383
 
384
- # Display translated pages
385
- for i, trans_doc in enumerate(translated_pages):
386
- page = trans_doc[0]
387
- pix = get_page_image(page)
388
- st.image(pix.tobytes(), caption=f"Page {st.session_state.current_page + i + 1}", use_container_width=True)
389
-
390
- # Navigation and action buttons in one row
391
  st.markdown("---") # Add a separator
392
  button_col1, button_col2, button_col3, button_col4 = st.columns(4)
393
 
@@ -417,34 +481,44 @@ def main():
417
  if st.button("Translate All",
418
  disabled=st.session_state.all_translated,
419
  use_container_width=True):
420
- # Configure translator
421
- TranslatorClass = TRANSLATORS[translator_name]
422
- translator = TranslatorClass(
423
- source=source_lang,
424
- target=target_lang,
425
- api_key=st.session_state.api_settings.get('api_key'),
426
- base_url=st.session_state.api_settings.get('api_base'),
427
- model=st.session_state.api_settings.get('model')
428
- )
429
-
430
- # Translate all pages
431
- output_doc = pymupdf.open()
432
- output_path = f"translated_{uploaded_file.name}"
433
- output_doc = translate_all_pages(
434
- doc,
435
- output_doc,
436
- translator,
437
- st.empty(),
438
- pages_per_load,
439
- text_color=text_color,
440
- translator_name=translator_name,
441
- target_lang=target_lang,
442
- output_path=output_path # 提供输出路径
443
- )
444
-
445
- st.session_state.all_translated = True
446
- st.session_state.translated_doc = output_path
447
- st.rerun()
 
 
 
 
 
 
 
 
 
 
448
 
449
  # Download button
450
  with button_col4:
@@ -469,5 +543,22 @@ def main():
469
  else:
470
  st.info("Please upload a PDF file to begin translation")
471
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
472
  if __name__ == "__main__":
 
 
 
473
  main()
 
9
  )
10
  from deep_translator.openai_compatible import OpenAICompatibleTranslator
11
  import logging
12
+ import argparse
13
 
14
  # Constants
15
  DEFAULT_PAGES_PER_LOAD = 2
 
20
  TRANSLATORS = {
21
  'OpenAI Compatible': OpenAICompatibleTranslator,
22
  'OpenAI': OpenAICompatibleTranslator,
23
+ 'Google': GoogleTranslator,
24
  }
25
 
26
  # Color options
 
57
  "Auto": "auto",
58
  }
59
 
60
+ # Global translation configuration
61
+ TRANSLATOR_CONFIG = {
62
+ "type": "Google", # Options: "Google" or "OpenAI"
63
+ # OpenAI settings (used only if type is "OpenAI")
64
+ "openai": {
65
+ "default_api_base": DEFAULT_API_BASE,
66
+ "default_model": DEFAULT_MODEL, # "gpt-4o-mini",
67
+ "default_api_key": "sk-xxx"
68
+ },
69
+ # Google settings (used only if type is "Google")
70
+ "google": {
71
+ "default_api_base": "https://translate.googleapis.com"
72
+ }
73
+ }
74
+
75
+ # Add argument parser
76
+ def parse_args():
77
+ parser = argparse.ArgumentParser(description='PDF Translator Application')
78
+ parser.add_argument(
79
+ '--translator',
80
+ type=str,
81
+ choices=['google', 'openai'],
82
+ default='google',
83
+ help='Specify translator type: google or openai'
84
+ )
85
+ parser.add_argument(
86
+ '--api-base',
87
+ type=str,
88
+ help='API base URL for the translator'
89
+ )
90
+ parser.add_argument(
91
+ '--api-key',
92
+ type=str,
93
+ help='API key for OpenAI compatible translator'
94
+ )
95
+ parser.add_argument(
96
+ '--model',
97
+ type=str,
98
+ help='Model name for OpenAI compatible translator'
99
+ )
100
+ return parser.parse_args()
101
+
102
+ # Update TRANSLATOR_CONFIG based on command line arguments
103
+ def update_translator_config(args):
104
+ global TRANSLATOR_CONFIG
105
+
106
+ TRANSLATOR_CONFIG["type"] = "Google" if args.translator.lower() == "google" else "OpenAI"
107
+
108
+ if args.translator.lower() == "google":
109
+ if args.api_base:
110
+ TRANSLATOR_CONFIG["google"]["default_api_base"] = args.api_base
111
+ else: # OpenAI
112
+ if args.api_base:
113
+ TRANSLATOR_CONFIG["openai"]["default_api_base"] = args.api_base
114
+ if args.api_key:
115
+ TRANSLATOR_CONFIG["openai"]["default_api_key"] = args.api_key
116
+ if args.model:
117
+ TRANSLATOR_CONFIG["openai"]["default_model"] = args.model
118
+
119
  def get_cache_dir():
120
  """Get or create cache directory"""
121
  cache_dir = Path('.cached')
 
148
 
149
  def translate_pdf_pages(doc, doc_bytes, start_page, num_pages, translator, text_color, translator_name, target_lang):
150
  """Translate specific pages of a PDF document with progress and caching"""
151
+ # Log translator information
152
+ logging.info(f"Using translator: {translator_name}, source: {translator._source}, target: {translator._target}")
153
+ logging.info(f"Selected translator: {translator_name}, Class: {translator.__class__.__name__}")
154
+
155
  WHITE = pymupdf.pdfcolor["white"]
156
  rgb_color = COLOR_MAP.get(text_color.lower(), COLOR_MAP["darkred"])
157
 
 
202
  bbox = block[:4]
203
  text = block[4]
204
  translated = translator.translate(text)
205
+ translated = str(translated) # Ensure the value is a string
206
 
207
  # Cover original text with white and add translation in color
208
  page.draw_rect(bbox, color=None, fill=WHITE)
 
252
  **kwargs
253
  ):
254
  """Translate all pages of the PDF document"""
255
+ # Log translator information for full document translation
256
+ logging.info(f"Starting full document translation with: {kwargs.get('translator_name', 'unknown')}")
257
+ logging.info(f"Translator settings - source: {translator._source}, target: {translator._target}")
258
+
259
  # Define colors
260
  WHITE = pymupdf.pdfcolor["white"]
261
  rgb_color = COLOR_MAP.get(kwargs.get('text_color', 'darkred').lower(), COLOR_MAP["darkred"])
 
309
  st.session_state.api_settings = {}
310
 
311
  def main():
312
+ st.set_page_config(layout="wide", page_title="PDF Translator for Human")
313
+ st.title("PDF Translator for Human")
314
 
315
  # Initialize session state
316
  init_session_state()
 
339
  )
340
  source_lang = SOURCE_LANGUAGE_OPTIONS[source_lang_name]
341
 
 
 
 
 
 
 
342
  pages_per_load = st.number_input(
343
  "Pages per load",
344
  min_value=1,
 
352
  index=0
353
  )
354
 
355
+ target_lang = st.selectbox(
356
+ "Target Language",
357
+ options=list(LANGUAGE_OPTIONS.keys()),
358
+ index=0
359
+ )
360
+ target_lang_code = LANGUAGE_OPTIONS[target_lang]
361
+
362
+ # API Configuration based on translator type
363
+ st.subheader("API Settings")
364
+ if TRANSLATOR_CONFIG["type"] == "OpenAI":
365
+ api_key = st.text_input(
366
+ "API Key",
367
+ value=TRANSLATOR_CONFIG["openai"]["default_api_key"],
368
+ type="password"
369
  )
 
 
 
 
 
 
 
 
 
 
 
 
370
  api_base = st.text_input(
371
  "API Base URL",
372
+ value=TRANSLATOR_CONFIG["openai"]["default_api_base"]
373
  )
 
 
 
374
  model = st.text_input(
375
  "Model Name",
376
+ value=TRANSLATOR_CONFIG["openai"]["default_model"]
377
  )
378
 
379
+ # Store API settings
380
  st.session_state.api_settings.update({
381
  'api_key': api_key,
382
  'api_base': api_base,
383
  'model': model
384
  })
385
+ else: # Google Translator
386
+ api_base = st.text_input(
387
+ "API Base URL",
388
+ value=TRANSLATOR_CONFIG["google"]["default_api_base"]
 
 
 
 
389
  )
390
+ st.session_state.api_settings.update({
391
+ 'api_base': api_base
392
+ })
393
 
394
  # Main content area
395
  if uploaded_file is not None:
 
399
  # Create two columns for side-by-side display
400
  col1, col2 = st.columns(2)
401
 
402
+ # Display original pages
403
  with col1:
404
  st.header("Original")
405
  for page_num in range(st.session_state.current_page,
 
412
  with col2:
413
  st.header("Translated")
414
 
415
+ try:
416
+ # Initialize translator based on global config
417
+ if TRANSLATOR_CONFIG["type"] == "Google":
418
+ translator = GoogleTranslator(
419
+ source=source_lang,
420
+ target=target_lang_code
421
+ )
422
+ else:
423
+ translator = OpenAICompatibleTranslator(
424
+ source=source_lang,
425
+ target=target_lang_code,
426
+ api_key=st.session_state.api_settings.get('api_key'),
427
+ base_url=st.session_state.api_settings.get('api_base'),
428
+ model=st.session_state.api_settings.get('model')
429
+ )
430
+
431
+ # Translate current batch of pages
432
+ translated_pages = translate_pdf_pages(
433
+ doc,
434
+ doc_bytes,
435
+ st.session_state.current_page,
436
+ pages_per_load,
437
+ translator,
438
+ text_color,
439
+ TRANSLATOR_CONFIG["type"],
440
+ target_lang_code
441
+ )
442
+
443
+ # Display translated pages
444
+ for i, trans_doc in enumerate(translated_pages):
445
+ page = trans_doc[0]
446
+ pix = get_page_image(page)
447
+ st.image(pix.tobytes(), caption=f"Page {st.session_state.current_page + i + 1}", use_container_width=True)
448
 
449
+ except Exception as e:
450
+ st.error(f"Translation error: {str(e)}")
451
+ logging.error(f"Translation error: {str(e)}")
452
+ return
453
+
454
+ # Navigation and action buttons
 
455
  st.markdown("---") # Add a separator
456
  button_col1, button_col2, button_col3, button_col4 = st.columns(4)
457
 
 
481
  if st.button("Translate All",
482
  disabled=st.session_state.all_translated,
483
  use_container_width=True):
484
+ try:
485
+ # Initialize translator based on global config
486
+ if TRANSLATOR_CONFIG["type"] == "Google":
487
+ translator = GoogleTranslator(
488
+ source=source_lang,
489
+ target=target_lang_code
490
+ )
491
+ else:
492
+ translator = OpenAICompatibleTranslator(
493
+ source=source_lang,
494
+ target=target_lang_code,
495
+ api_key=st.session_state.api_settings.get('api_key'),
496
+ base_url=st.session_state.api_settings.get('api_base'),
497
+ model=st.session_state.api_settings.get('model')
498
+ )
499
+
500
+ # Translate all pages
501
+ output_doc = pymupdf.open()
502
+ output_path = f"translated_{uploaded_file.name}"
503
+ output_doc = translate_all_pages(
504
+ doc,
505
+ output_doc,
506
+ translator,
507
+ st.empty(),
508
+ pages_per_load,
509
+ text_color=text_color,
510
+ translator_name=TRANSLATOR_CONFIG["type"],
511
+ target_lang=target_lang_code,
512
+ output_path=output_path
513
+ )
514
+
515
+ st.session_state.all_translated = True
516
+ st.session_state.translated_doc = output_path
517
+ st.rerun()
518
+ except Exception as e:
519
+ st.error(f"Translation error: {str(e)}")
520
+ logging.error(f"Translation error: {str(e)}")
521
+ return
522
 
523
  # Download button
524
  with button_col4:
 
543
  else:
544
  st.info("Please upload a PDF file to begin translation")
545
 
546
+
547
+ # 使用Google翻译(默认):
548
+ # streamlit run app.py
549
+
550
+ # 使用Google翻���并指定API base:
551
+ # streamlit run app.py --translator google --api-base https://translate.googleapis.com
552
+
553
+ # 使用OpenAI兼容模型:
554
+ # python app.py --translator openai --model default_model --api-key sk-xxx --api-base http://localhost:8080/v1
555
+
556
+ # 使用OpenAI翻译并指定API base:
557
+ # python app.py --translator openai --api-base https://api.openai.com/v1 --model gpt-4o-mini --api-key sk-xxx
558
+
559
+
560
  if __name__ == "__main__":
561
+
562
+ args = parse_args()
563
+ update_translator_config(args)
564
  main()
run_translator_web.sh CHANGED
File without changes