Script python permettant de traduire un long texte
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

main.py 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. import PyPDF2
  2. import requests
  3. import json
  4. from reportlab.lib.pagesizes import letter
  5. from reportlab.lib.units import inch
  6. from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
  7. from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
  8. from reportlab.lib.enums import TA_JUSTIFY
  9. from reportlab.pdfbase import pdfmetrics
  10. from reportlab.pdfbase.ttfonts import TTFont
  11. import os
  12. # Configuration
  13. PDF_PATH = "TaniaBorecMemoir(Ukr).pdf" # Fichier original
  14. OLLAMA_MODEL = "traductionUkrainienVersFrancais:latest"
  15. OLLAMA_URL = "http://localhost:11434/api/generate" # URL par défaut d'Ollama
  16. OUTPUT_PDF_PATH = PDF_PATH.replace(".pdf", " (FR).pdf") # Chemin du PDF de sortie
  17. def extract_text_from_pdf(pdf_path):
  18. """Extrait le texte page par page d'un PDF sans les numéros de pages."""
  19. import re
  20. text_by_page = []
  21. with open(pdf_path, "rb") as file:
  22. reader = PyPDF2.PdfReader(file)
  23. for page in reader.pages:
  24. text = page.extract_text()
  25. # Supprime les numéros de pages (nombres seuls en début/fin de ligne)
  26. text = re.sub(r'^\d+\s*\n', '', text, flags=re.MULTILINE)
  27. text = re.sub(r'\n\s*\d+\s*$', '', text, flags=re.MULTILINE)
  28. text_by_page.append(text)
  29. return text_by_page
  30. def merge_paragraphs_across_pages(pages_text):
  31. """Divise le texte en chunks raisonnables pour la traduction."""
  32. import re
  33. # Concatène tout le texte
  34. full_text = "\n".join(pages_text)
  35. # Essaie d'abord de diviser par les doubles sauts de ligne
  36. paragraphs = re.split(r'\n\s*\n+', full_text.strip())
  37. # Si on obtient seulement un paragraphe, on divise par une taille maximale
  38. if len(paragraphs) == 1:
  39. print("Aucune séparation par double saut de ligne détectée. Division par taille...")
  40. # Divise par les phrases (points suivis d'un espace)
  41. sentences = re.split(r'(?<=[.!?])\s+', full_text.strip())
  42. # Regroupe les phrases en chunks d'environ 1500 caractères
  43. max_chunk_size = 1500
  44. paragraphs = []
  45. current_chunk = ""
  46. for sentence in sentences:
  47. if len(current_chunk) + len(sentence) < max_chunk_size:
  48. current_chunk += (" " + sentence) if current_chunk else sentence
  49. else:
  50. if current_chunk:
  51. paragraphs.append(current_chunk)
  52. current_chunk = sentence
  53. if current_chunk:
  54. paragraphs.append(current_chunk)
  55. else:
  56. # Normalise les sauts de ligne internes
  57. paragraphs = [re.sub(r'\n+', ' ', p.strip()) for p in paragraphs if p.strip()]
  58. return paragraphs
  59. def send_to_ollama(prompt, model=OLLAMA_MODEL, context_size=128000):
  60. """Envoie une requête à Ollama et retourne la réponse."""
  61. payload = {
  62. "model": model,
  63. "prompt": prompt,
  64. "stream": False,
  65. "options": {"num_ctx": context_size}
  66. }
  67. response = requests.post(OLLAMA_URL, data=json.dumps(payload))
  68. if response.status_code == 200:
  69. return response.json()["response"]
  70. else:
  71. raise Exception(f"Erreur Ollama: {response.text}")
  72. def register_unicode_font():
  73. """Enregistre une police TrueType qui supporte le cyrilique."""
  74. # Recherche une police système qui supporte le cyrilique
  75. font_paths = [
  76. r"C:\Windows\Fonts\DejaVuSans.ttf",
  77. r"C:\Windows\Fonts\Calibri.ttf",
  78. r"C:\Windows\Fonts\arial.ttf",
  79. ]
  80. for font_path in font_paths:
  81. if os.path.exists(font_path):
  82. try:
  83. pdfmetrics.registerFont(TTFont('UnicodeFont', font_path))
  84. return 'UnicodeFont'
  85. except Exception as e:
  86. print(f"Erreur lors de l'enregistrement de {font_path}: {e}")
  87. # Si aucune police spéciale trouvée, utilise Helvetica par défaut
  88. print("Aucune police Unicode trouvée, utilisation d'Helvetica")
  89. return 'Helvetica'
  90. def create_pdf_from_results(results, output_path):
  91. """Crée un PDF à partir des résultats de traduction."""
  92. doc = SimpleDocTemplate(output_path, pagesize=letter, topMargin=inch, bottomMargin=inch)
  93. story = []
  94. # Enregistre une police qui supporte le cyrilique
  95. font_name = register_unicode_font()
  96. # Style personnalisé
  97. styles = getSampleStyleSheet()
  98. title_style = ParagraphStyle(
  99. 'CustomTitle',
  100. parent=styles['Heading1'],
  101. fontSize=16,
  102. textColor='#1f4788',
  103. spaceAfter=0.3*inch,
  104. alignment=TA_JUSTIFY,
  105. fontName=font_name
  106. )
  107. page_style = ParagraphStyle(
  108. 'PageHeading',
  109. parent=styles['Heading2'],
  110. fontSize=12,
  111. textColor='#1f4788',
  112. spaceAfter=0.2*inch,
  113. spaceBefore=0.2*inch,
  114. fontName=font_name
  115. )
  116. body_style = ParagraphStyle(
  117. 'CustomBody',
  118. parent=styles['BodyText'],
  119. fontSize=11,
  120. alignment=TA_JUSTIFY,
  121. spaceAfter=0.2*inch,
  122. fontName=font_name
  123. )
  124. # Titre
  125. story.append(Paragraph("Traduction - Ukrainien vers Français", title_style))
  126. story.append(Spacer(1, 0.2*inch))
  127. # Contenu
  128. for page_num, translation in results.items():
  129. # Préserver la mise en page en convertissant les sauts de ligne
  130. formatted_text = translation.replace("\n", "<br/>")
  131. story.append(Paragraph(formatted_text, body_style))
  132. story.append(Spacer(1, 0.1*inch))
  133. # Construction du PDF
  134. doc.build(story)
  135. print(f"PDF généré avec succès : {output_path}")
  136. def main():
  137. # Extraction du texte page par page
  138. pages = extract_text_from_pdf(PDF_PATH)
  139. print(f"Nombre de pages extraites : {len(pages)}")
  140. # Fusion des paragraphes qui s'étendent sur plusieurs pages
  141. paragraphs = merge_paragraphs_across_pages(pages)
  142. print(f"Nombre de paragraphes complets extraits : {len(paragraphs)}")
  143. # Dictionnaire pour stocker les résultats
  144. results = {}
  145. # Traitement des paragraphes complets
  146. for i, paragraph_text in enumerate(paragraphs, start=1):
  147. print(f"{15 * '-'} Traduction du paragraphe {i}/{len(paragraphs)}...\n{paragraph_text}\n")
  148. prompt = f"Traduis le texte suivant de l'ukrainien vers le français : {paragraph_text}"
  149. try:
  150. result = send_to_ollama(prompt)
  151. print(f"{result}.")
  152. results[i] = result
  153. except Exception as e:
  154. print(f"Erreur lors du traitement du paragraphe {i} : {e}")
  155. results[i] = f"Erreur lors du traitement du paragraphe {i} : {e}"
  156. # Création du PDF avec tous les résultats
  157. create_pdf_from_results(results, OUTPUT_PDF_PATH)
  158. if __name__ == "__main__":
  159. main()