ajout des caractéristiques technique du LLM
This commit is contained in:
parent
2ee58f3310
commit
4525a82f46
29
README.md
29
README.md
|
|
@ -14,17 +14,18 @@ Ce projet permet de traduire un document PDF page par page en utilisant un modè
|
||||||
---
|
---
|
||||||
|
|
||||||
## Création d'un modèle LLM de traduction avec Ollama
|
## Création d'un modèle LLM de traduction avec Ollama
|
||||||
En partant de zongwei/gemma3-translator:4b, voici le fichier de customisation :
|
En partant du LLM [zongwei/gemma3-translator:4b](https://ollama.com/zongwei/gemma3-translator), nous allons créer un modèle optimisé pour la traduction avec Ollama.
|
||||||
|
Pour info : Inutile de le downloader, il le serra automatiquement au lancement de la commande.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
FROM zongwei/gemma3-translator:4b
|
FROM zongwei/gemma3-translator:4b
|
||||||
PARAMETER temperature 0.1
|
PARAMETER temperature 0.1
|
||||||
PARAMETER num_ctx 131072
|
PARAMETER num_ctx 131072
|
||||||
SYSTEM """
|
SYSTEM """
|
||||||
Tu es un traducteur professionnel spécialisé dans la traduction de texte ukrainien vers le français.
|
You are a professional translator specialising in translating Ukrainian text into English.
|
||||||
Traduis fidèlement et naturellement en respectant l'intonation originale utilisée par l'auteur du texte.
|
Translate accurately and naturally, respecting the original intonation used by the author of the text.
|
||||||
Tu ne dois pas interpréter les pensées ou les réflexions de l'auteur.
|
You must not interpret the author's thoughts or reflections.
|
||||||
Ne rajoutes pas de texte avant ou après le texte fourni.
|
Do not add any text before or after the text provided.
|
||||||
Tu dois toujours répondre en français.
|
|
||||||
"""
|
"""
|
||||||
```
|
```
|
||||||
Il faut ensuite compiler le modèle avec la commande :
|
Il faut ensuite compiler le modèle avec la commande :
|
||||||
|
|
@ -64,10 +65,22 @@ ollama create traductionUkrainienVersFrancais -f .\Modelfile
|
||||||
```bash
|
```bash
|
||||||
ollama list
|
ollama list
|
||||||
```
|
```
|
||||||
Vous devez voir `traductionUkrainienVersFrancais:latest` dans la liste.
|
Vous devez voir `traductionUkrainienVersFrancais` dans la liste.
|
||||||
Si ce n'est pas le cas, vous devez le générer en suivant la drescription vue plus haut (Création d'un modèle LLM de traduction avec Ollama)
|
|
||||||
|
Si ce n'est pas le cas, vous devez le générer comme décrit plus haut (paragraphe "Création d'un modèle LLM de traduction avec Ollama")
|
||||||
|
|
||||||
3. **Placer votre PDF** dans le même répertoire que le script `main.py`
|
3. **Placer votre PDF** dans le même répertoire que le script `main.py`
|
||||||
|
### Paramétrage du script
|
||||||
|
`PDF_PATH`= "TaniaBorecMemoir(Ukr).pdf" <- Le nom du fichier pdf à traduire.
|
||||||
|
`OLLAMA_MODEL` = "mitmul/plamo-2-translate:latest" <- Le nom
|
||||||
|
`OLLAMA_URL` = "http://localhost:11434/api/generate" <- URL par défaut d'Ollama
|
||||||
|
`TARGET_LANGUAGE` = "français" <- Langue cible (ex: "français", "anglais", "allemand", "espagnol", etc.)
|
||||||
|
`SYSTEM_PROMPT` = """You are a professional translator specialising in Ukrainian text translation.
|
||||||
|
Translate accurately and naturally, respecting the original intonation used by the author of the text.
|
||||||
|
You must not interpret the author's thoughts or reflections.
|
||||||
|
Do not add any text before or after the text provided.
|
||||||
|
Preserve the layout and structure of the original text."""
|
||||||
|
|
||||||
|
|
||||||
### Exécution
|
### Exécution
|
||||||
|
|
||||||
|
|
|
||||||
129
main.py
129
main.py
|
|
@ -14,7 +14,109 @@ import os
|
||||||
PDF_PATH = "TaniaBorecMemoir(Ukr).pdf" # Fichier original
|
PDF_PATH = "TaniaBorecMemoir(Ukr).pdf" # Fichier original
|
||||||
OLLAMA_MODEL = "traductionUkrainienVersFrancais:latest"
|
OLLAMA_MODEL = "traductionUkrainienVersFrancais:latest"
|
||||||
OLLAMA_URL = "http://localhost:11434/api/generate" # URL par défaut d'Ollama
|
OLLAMA_URL = "http://localhost:11434/api/generate" # URL par défaut d'Ollama
|
||||||
OUTPUT_PDF_PATH = PDF_PATH.replace(".pdf", " (FR).pdf") # Chemin du PDF de sortie
|
TARGET_LANGUAGE = "français" # Langue cible (ex: "français", "anglais", "allemand", "espagnol", etc.)
|
||||||
|
OUTPUT_PDF_PATH = PDF_PATH.replace(".pdf", f" ({TARGET_LANGUAGE.upper()[:2]}).pdf") # Chemin du PDF de sortie
|
||||||
|
|
||||||
|
# Prompt système personnalisé (instructions pour le LLM)
|
||||||
|
SYSTEM_PROMPT = """"""
|
||||||
|
|
||||||
|
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."""
|
||||||
|
try:
|
||||||
|
# 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 des informations principales
|
||||||
|
info = {
|
||||||
|
"temperature": parsed_params.get('temperature', model_data.get("temperature", "Not available")),
|
||||||
|
"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: {OLLAMA_MODEL}<br//>\nSystem: {info['system']}<br//>\nTemperature: {info['temperature']}<br//>\nDate de modification: {formatted_date}"
|
||||||
|
else:
|
||||||
|
return "Informations du modèle non disponibles"
|
||||||
|
|
||||||
def extract_text_from_pdf(pdf_path):
|
def extract_text_from_pdf(pdf_path):
|
||||||
"""Extrait le texte page par page d'un PDF sans les numéros de pages."""
|
"""Extrait le texte page par page d'un PDF sans les numéros de pages."""
|
||||||
|
|
@ -67,11 +169,13 @@ def merge_paragraphs_across_pages(pages_text):
|
||||||
|
|
||||||
return paragraphs
|
return paragraphs
|
||||||
|
|
||||||
def send_to_ollama(prompt, model=OLLAMA_MODEL, context_size=128000):
|
def send_to_ollama(text, target_lang=TARGET_LANGUAGE, model=OLLAMA_MODEL, context_size=128000, system_prompt=SYSTEM_PROMPT):
|
||||||
"""Envoie une requête à Ollama et retourne la réponse."""
|
"""Envoie une requête à Ollama et retourne la réponse traduite."""
|
||||||
|
# Construit le prompt avec les instructions système et la demande de traduction
|
||||||
|
full_prompt = f"{system_prompt}\n\nTraduis le texte suivant de l'ukrainien vers le {target_lang} :\n{text}"
|
||||||
payload = {
|
payload = {
|
||||||
"model": model,
|
"model": model,
|
||||||
"prompt": prompt,
|
"prompt": full_prompt,
|
||||||
"stream": False,
|
"stream": False,
|
||||||
"options": {"num_ctx": context_size}
|
"options": {"num_ctx": context_size}
|
||||||
}
|
}
|
||||||
|
|
@ -141,8 +245,9 @@ def create_pdf_from_results(results, output_path):
|
||||||
fontName=font_name
|
fontName=font_name
|
||||||
)
|
)
|
||||||
|
|
||||||
# Titre
|
# Titre avec la langue cible
|
||||||
story.append(Paragraph("Traduction - Ukrainien vers Français", title_style))
|
title_text = f"Traduction - Ukrainien vers {TARGET_LANGUAGE.capitalize()}"
|
||||||
|
story.append(Paragraph(title_text, title_style))
|
||||||
story.append(Spacer(1, 0.2*inch))
|
story.append(Spacer(1, 0.2*inch))
|
||||||
|
|
||||||
# Contenu
|
# Contenu
|
||||||
|
|
@ -152,11 +257,18 @@ def create_pdf_from_results(results, output_path):
|
||||||
story.append(Paragraph(formatted_text, body_style))
|
story.append(Paragraph(formatted_text, body_style))
|
||||||
story.append(Spacer(1, 0.1*inch))
|
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
|
# Construction du PDF
|
||||||
doc.build(story)
|
doc.build(story)
|
||||||
print(f"PDF généré avec succès : {output_path}")
|
print(f"PDF généré avec succès : {output_path}")
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
# Affiche les informations du modèle LLM
|
||||||
|
display_llm_info()
|
||||||
|
|
||||||
# Extraction du texte page par page
|
# Extraction du texte page par page
|
||||||
pages = extract_text_from_pdf(PDF_PATH)
|
pages = extract_text_from_pdf(PDF_PATH)
|
||||||
print(f"Nombre de pages extraites : {len(pages)}")
|
print(f"Nombre de pages extraites : {len(pages)}")
|
||||||
|
|
@ -170,10 +282,9 @@ def main():
|
||||||
|
|
||||||
# Traitement des paragraphes complets
|
# Traitement des paragraphes complets
|
||||||
for i, paragraph_text in enumerate(paragraphs, start=1):
|
for i, paragraph_text in enumerate(paragraphs, start=1):
|
||||||
print(f"{15 * '-'} Traduction du paragraphe {i}/{len(paragraphs)}...\n{paragraph_text}\n")
|
print(f"{15 * '-'} Traduction du paragraphe {i}/{len(paragraphs)}...")
|
||||||
prompt = f"Traduis le texte suivant de l'ukrainien vers le français : {paragraph_text}"
|
|
||||||
try:
|
try:
|
||||||
result = send_to_ollama(prompt)
|
result = send_to_ollama(paragraph_text, target_lang=TARGET_LANGUAGE)
|
||||||
print(f"{result}.")
|
print(f"{result}.")
|
||||||
results[i] = result
|
results[i] = result
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue