|
|
|
@ -1,6 +1,13 @@ |
|
|
|
import PyPDF2 |
|
|
|
import requests |
|
|
|
import json |
|
|
|
from reportlab.lib.pagesizes import letter |
|
|
|
from reportlab.lib.units import inch |
|
|
|
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer |
|
|
|
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle |
|
|
|
from reportlab.lib.enums import TA_JUSTIFY |
|
|
|
from reportlab.pdfbase import pdfmetrics |
|
|
|
from reportlab.pdfbase.ttfonts import TTFont |
|
|
|
import os |
|
|
|
from datetime import datetime |
|
|
|
|
|
|
|
@ -14,6 +21,149 @@ TEMP_OUTPUT_TXT = "output_temp.txt" |
|
|
|
FINAL_OUTPUT_PDF = PDF_PATH.replace(".pdf",f" ({TARGET_LANGUAGE.upper()[:2]})_V2.pdf") |
|
|
|
FINAL_OUTPUT_TXT = PDF_PATH.replace(".pdf",f" ({TARGET_LANGUAGE.upper()[:2]})_V2.txt") |
|
|
|
|
|
|
|
def extract_parameters_from_template(template_str): |
|
|
|
"""Extrait les paramètres du modèle à partir du template.""" |
|
|
|
import re |
|
|
|
|
|
|
|
parameters = {} |
|
|
|
|
|
|
|
if not template_str or not isinstance(template_str, str): |
|
|
|
return parameters |
|
|
|
|
|
|
|
# Si la chaîne contient "parameters:", récupère ce qui suit |
|
|
|
if 'parameters:' in template_str: |
|
|
|
params_section = template_str.split('parameters:', 1)[1] |
|
|
|
else: |
|
|
|
# Sinon, utilise la chaîne directement (elle contient déjà les paramètres) |
|
|
|
params_section = template_str |
|
|
|
|
|
|
|
# Parse les lignes de paramètres |
|
|
|
# Format: "stop "<end_of_turn>"" |
|
|
|
# "temperature 0.1" |
|
|
|
lines = params_section.split('\n') |
|
|
|
|
|
|
|
for line in lines: |
|
|
|
if not line.strip(): |
|
|
|
continue |
|
|
|
|
|
|
|
# Divise par le premier groupe d'espaces blancs |
|
|
|
# Cela sépare la clé des valeurs avec leurs espaces |
|
|
|
parts = line.split(None, 1) # split() avec maxsplit=1 divise sur les espaces |
|
|
|
|
|
|
|
if len(parts) == 2: |
|
|
|
param_name = parts[0].strip() |
|
|
|
param_value = parts[1].strip() |
|
|
|
parameters[param_name] = param_value |
|
|
|
|
|
|
|
return parameters |
|
|
|
|
|
|
|
def get_llm_model_info(model=OLLAMA_MODEL): |
|
|
|
""" |
|
|
|
Extrait les informations du modèle LLM depuis Ollama, y compris le nom depuis la ligne FROM du Modelfile. |
|
|
|
|
|
|
|
@param model: Nom du modèle à interroger. |
|
|
|
@type model: str |
|
|
|
@return: Dictionnaire contenant les informations du modèle, ou None en cas d'erreur. |
|
|
|
@rtype: dict | None |
|
|
|
""" |
|
|
|
try: |
|
|
|
# Chemin vers le fichier Modelfile (supposé être dans le même répertoire que le script) |
|
|
|
modelfile_path = os.path.join(os.path.dirname(__file__), "Modelfile") |
|
|
|
|
|
|
|
# Initialisation de model_name |
|
|
|
model_name = "none" |
|
|
|
|
|
|
|
# Lecture du fichier Modelfile pour extraire le nom du modèle |
|
|
|
if os.path.exists(modelfile_path): |
|
|
|
with open(modelfile_path, 'r', encoding='utf-8') as file: |
|
|
|
for line in file: |
|
|
|
if line.strip().startswith('FROM '): |
|
|
|
model_name = line.strip().split('FROM ')[1].strip() |
|
|
|
break |
|
|
|
|
|
|
|
# URL pour obtenir les informations du modèle |
|
|
|
info_url = OLLAMA_URL.replace("/api/generate", "/api/show") |
|
|
|
payload = {"name": model} |
|
|
|
|
|
|
|
response = requests.post(info_url, json=payload) |
|
|
|
|
|
|
|
if response.status_code == 200: |
|
|
|
model_data = response.json() |
|
|
|
|
|
|
|
# Gère le cas où model_data est une chaîne |
|
|
|
if isinstance(model_data, str): |
|
|
|
model_data = json.loads(model_data) |
|
|
|
|
|
|
|
# Extrait les paramètres du template |
|
|
|
parameters = model_data.get('parameters', '') |
|
|
|
parsed_params = extract_parameters_from_template(parameters) |
|
|
|
|
|
|
|
# Extraction du nom depuis la ligne FROM |
|
|
|
modelfile_content = model_data.get('Modelfile', '') |
|
|
|
|
|
|
|
# Extraction des informations principales |
|
|
|
info = { |
|
|
|
"temperature": parsed_params.get('temperature', model_data.get("temperature", "Not available")), |
|
|
|
"name": model_name, |
|
|
|
"num_ctx": parsed_params.get('num_ctx', "Not available"), |
|
|
|
"top_k": parsed_params.get('top_k', "Not available"), |
|
|
|
"top_p": parsed_params.get('top_p', "Not available"), |
|
|
|
"system": model_data.get("system", "Not available"), |
|
|
|
"modified_at": model_data.get("modified_at", "Not available"), |
|
|
|
} |
|
|
|
return info |
|
|
|
else: |
|
|
|
print(f"Erreur lors de la récupération du modèle : {response.text}") |
|
|
|
return None |
|
|
|
except Exception as e: |
|
|
|
print(f"Erreur lors de l'accès aux informations du modèle : {e}") |
|
|
|
return None |
|
|
|
|
|
|
|
def display_llm_info(): |
|
|
|
"""Retourne les informations du modèle LLM formatées.""" |
|
|
|
from datetime import datetime |
|
|
|
|
|
|
|
info = get_llm_model_info(OLLAMA_MODEL) |
|
|
|
|
|
|
|
if info: |
|
|
|
# Formate la date en jj/mm/AAAA |
|
|
|
modified_at = info.get('modified_at', 'Not available') |
|
|
|
if modified_at and modified_at != 'Not available': |
|
|
|
try: |
|
|
|
# Parse la date ISO |
|
|
|
date_obj = datetime.fromisoformat(modified_at.replace('Z', '+00:00')) |
|
|
|
# Formate en jj/mm/AAAA |
|
|
|
formatted_date = date_obj.strftime("%d/%m/%Y") |
|
|
|
except: |
|
|
|
formatted_date = modified_at |
|
|
|
else: |
|
|
|
formatted_date = 'Not available' |
|
|
|
|
|
|
|
return f"LLM Modèle: {info['name']}<br//>\nDate de modification: {formatted_date}<br//>\nSystem: {info['system']}<br//>\nTemperature: {info['temperature']}" |
|
|
|
else: |
|
|
|
return "Informations du modèle non disponibles" |
|
|
|
|
|
|
|
def register_unicode_font(): |
|
|
|
"""Enregistre une police TrueType qui supporte le cyrilique.""" |
|
|
|
# Recherche une police système qui supporte le cyrilique |
|
|
|
font_paths = [ |
|
|
|
r"C:\Windows\Fonts\DejaVuSans.ttf", |
|
|
|
r"C:\Windows\Fonts\Calibri.ttf", |
|
|
|
r"C:\Windows\Fonts\arial.ttf", |
|
|
|
] |
|
|
|
|
|
|
|
for font_path in font_paths: |
|
|
|
if os.path.exists(font_path): |
|
|
|
try: |
|
|
|
pdfmetrics.registerFont(TTFont('UnicodeFont', font_path)) |
|
|
|
return 'UnicodeFont' |
|
|
|
except Exception as e: |
|
|
|
print(f"Erreur lors de l'enregistrement de {font_path}: {e}") |
|
|
|
|
|
|
|
# Si aucune police spéciale trouvée, utilise Helvetica par défaut |
|
|
|
print("Aucune police Unicode trouvée, utilisation d'Helvetica") |
|
|
|
return 'Helvetica' |
|
|
|
|
|
|
|
# Charge ou initialise le checkpoint |
|
|
|
def load_checkpoint(): |
|
|
|
if os.path.exists(CHECKPOINT_FILE): |
|
|
|
@ -63,24 +213,81 @@ def send_to_ollama(text, target_lang=TARGET_LANGUAGE, model=OLLAMA_MODEL): |
|
|
|
|
|
|
|
# Création du PDF final (inchangée) |
|
|
|
def create_pdf_from_results(results, output_path): |
|
|
|
from reportlab.lib.pagesizes import letter |
|
|
|
from reportlab.lib.units import inch |
|
|
|
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer |
|
|
|
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle |
|
|
|
from reportlab.lib.enums import TA_JUSTIFY |
|
|
|
from reportlab.pdfbase import pdfmetrics |
|
|
|
from reportlab.pdfbase.ttfonts import TTFont |
|
|
|
|
|
|
|
doc = SimpleDocTemplate(output_path, pagesize=letter) |
|
|
|
"""Crée un PDF à partir des résultats de traduction.""" |
|
|
|
doc = SimpleDocTemplate(output_path, pagesize=letter, topMargin=inch, bottomMargin=inch) |
|
|
|
story = [] |
|
|
|
|
|
|
|
# Enregistre une police qui supporte le cyrilique |
|
|
|
font_name = register_unicode_font() |
|
|
|
|
|
|
|
# Style personnalisé |
|
|
|
styles = getSampleStyleSheet() |
|
|
|
body_style = styles["BodyText"] |
|
|
|
title_style = ParagraphStyle( |
|
|
|
'CustomTitle', |
|
|
|
parent=styles['Heading1'], |
|
|
|
fontSize=16, |
|
|
|
textColor='#1f4788', |
|
|
|
spaceAfter=0.3*inch, |
|
|
|
alignment=TA_JUSTIFY, |
|
|
|
fontName=font_name |
|
|
|
) |
|
|
|
|
|
|
|
page_style = ParagraphStyle( |
|
|
|
'PageHeading', |
|
|
|
parent=styles['Heading2'], |
|
|
|
fontSize=12, |
|
|
|
textColor='#1f4788', |
|
|
|
spaceAfter=0.2*inch, |
|
|
|
spaceBefore=0.2*inch, |
|
|
|
fontName=font_name |
|
|
|
) |
|
|
|
|
|
|
|
body_style = ParagraphStyle( |
|
|
|
'CustomBody', |
|
|
|
parent=styles['BodyText'], |
|
|
|
fontSize=11, |
|
|
|
alignment=TA_JUSTIFY, |
|
|
|
spaceAfter=0.2*inch, |
|
|
|
fontName=font_name |
|
|
|
) |
|
|
|
|
|
|
|
# Titre avec la langue cible |
|
|
|
story.append(Paragraph(f"Traduction - Ukrainien vers {TARGET_LANGUAGE.capitalize()}", title_style)) |
|
|
|
story.append(Paragraph(f"Document : {PDF_PATH}", title_style)) |
|
|
|
story.append(Spacer(1, 0.2*inch)) |
|
|
|
|
|
|
|
for idx, translation in results.items(): |
|
|
|
story.append(Paragraph(translation, body_style)) |
|
|
|
# Contenu |
|
|
|
for page_num, translation in results.items(): |
|
|
|
# Préserver la mise en page en convertissant les sauts de ligne |
|
|
|
formatted_text = translation.replace("\n", "<br/>") |
|
|
|
story.append(Paragraph(formatted_text, body_style)) |
|
|
|
# story.append(Spacer(1, 0.1*inch)) |
|
|
|
|
|
|
|
# Infos sur le LLM |
|
|
|
story.append(Spacer(1, 0.2*inch)) |
|
|
|
story.append(Paragraph(display_llm_info(), page_style)) |
|
|
|
|
|
|
|
# Construction du PDF |
|
|
|
doc.build(story) |
|
|
|
print(f"PDF final généré : {output_path}") |
|
|
|
print(f"PDF généré avec succès : {output_path}") |
|
|
|
|
|
|
|
def create_txt_from_results(results, output_path): |
|
|
|
"""Crée un fichier TXT à partir des résultats de traduction.""" |
|
|
|
OUTPUT_TXT_PATH = output_path.replace(".pdf", f".txt") # Chemin du fichier TXT de sortie |
|
|
|
|
|
|
|
# Titre avec la langue cible |
|
|
|
title_text = f"Traduction - Ukrainien vers {TARGET_LANGUAGE.capitalize()}" |
|
|
|
with open(OUTPUT_TXT_PATH, 'w', encoding='utf-8') as txt_file: |
|
|
|
txt_file.write(title_text + "\n\n") |
|
|
|
|
|
|
|
# Contenu |
|
|
|
for page_num, translation in results.items(): |
|
|
|
# Préserver la mise en page en convertissant les sauts de ligne |
|
|
|
txt_file.write(translation + "\n\n") |
|
|
|
|
|
|
|
# Infos sur le LLM |
|
|
|
txt_file.write("\n") |
|
|
|
txt_file.write(display_llm_info() + "\n") |
|
|
|
|
|
|
|
# Fonction principale |
|
|
|
def main(): |
|
|
|
@ -114,7 +321,7 @@ def main(): |
|
|
|
# Génération des fichiers finaux |
|
|
|
save_temp_results(results) |
|
|
|
create_pdf_from_results(results, FINAL_OUTPUT_PDF) |
|
|
|
os.rename(TEMP_OUTPUT_TXT, FINAL_OUTPUT_TXT) |
|
|
|
create_txt_from_results(results, FINAL_OUTPUT_TXT) |
|
|
|
print("Traduction terminée !") |
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
|
|