Compare commits
6 Commits
2f5fed58a7
...
32b88aa9b8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32b88aa9b8 | ||
|
|
dacd665535 | ||
|
|
a37b962a05 | ||
|
|
ca862aa9e3 | ||
|
|
71786d27c6 | ||
|
|
d9fae5f658 |
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
output_temp.txt
|
||||||
|
checkpoint.json
|
||||||
18
Modelfile
18
Modelfile
@ -1,10 +1,14 @@
|
|||||||
FROM lauchacarro/qwen2.5-translator
|
FROM zongwei/gemma3-translator:4b
|
||||||
PARAMETER temperature 0.2
|
PARAMETER temperature 0.9
|
||||||
PARAMETER num_ctx 65536
|
PARAMETER num_ctx 131072
|
||||||
SYSTEM """
|
SYSTEM """
|
||||||
Tu es un traducteur professionnel spécialisé dans la traduction de textes historiques ukrainiens en français.
|
Tu es un traducteur professionnel spécialisé dans la traduction de texte ukrainien en français.
|
||||||
|
Tu est spécialisé dans la rédaction des textes auto-biographiques et historiques et parles un français impécable.
|
||||||
|
Tu dois toujours répondre en français et uniquement dans cette langue.
|
||||||
|
Tu prends soins des congugaisons et de la tournure de phases.
|
||||||
|
N'ajoutes aucun texte sous quelle forme que ce soit avant ou après le texte traduit. Ne réponds qu'avec le texte traduit.
|
||||||
|
N'inclus jamais la phrase "Voici le texte traduit" dans la réponse.
|
||||||
Traduis avec précision et naturel, en respectant l'intonation originale utilisée par l'auteur du texte.
|
Traduis avec précision et naturel, en respectant l'intonation originale utilisée par l'auteur du texte.
|
||||||
Tu dois toujours répondre en français et uniquement en français.
|
Tu ne dois pas interpréter les pensées ou les réflexions de l'auteur, la traduciton doit restée fidèle à la pensée de l'auteur.
|
||||||
Tu ne dois pas interpréter les pensées ou les réflexions de l'auteur.
|
Le texte que tu traduis est un texte historique, tu ne dois pas le changer.
|
||||||
N'ajoutes aucun texte sous quelle forme que ce soit avant ou après le texte traduit, ne réponds qu'avec le texte traduit.
|
|
||||||
"""
|
"""
|
||||||
161
main.py
161
main.py
@ -12,18 +12,14 @@ import os
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
PDF_PATH = "TaniaBorecMemoir(Ukr).pdf" # Fichier original
|
PDF_PATH = "TaniaBorecMemoir(Ukr).pdf"
|
||||||
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"
|
||||||
TARGET_LANGUAGE = "français" # Langue cible (ex: "français", "anglais", "allemand", "espagnol", etc.)
|
TARGET_LANGUAGE = "français"
|
||||||
|
CHECKPOINT_FILE = "checkpoint.json"
|
||||||
# Récupère la date et l'heure actuelles au format AAAMMJJ-HHMM
|
TEMP_OUTPUT_TXT = "output_temp.txt"
|
||||||
current_datetime = datetime.now().strftime("%Y%m%d-%H%M")
|
FINAL_OUTPUT_PDF = PDF_PATH.replace(".pdf",f" ({TARGET_LANGUAGE.upper()[:2]})_V2.pdf")
|
||||||
# Ajoute la date et la langue cible au nom du fichier PDF de sortie
|
FINAL_OUTPUT_TXT = PDF_PATH.replace(".pdf",f" ({TARGET_LANGUAGE.upper()[:2]})_V2.txt")
|
||||||
OUTPUT_PDF_PATH = PDF_PATH.replace(
|
|
||||||
".pdf",
|
|
||||||
f" ({TARGET_LANGUAGE.upper()[:2]})_{current_datetime}.pdf"
|
|
||||||
)
|
|
||||||
|
|
||||||
def extract_parameters_from_template(template_str):
|
def extract_parameters_from_template(template_str):
|
||||||
"""Extrait les paramètres du modèle à partir du template."""
|
"""Extrait les paramètres du modèle à partir du template."""
|
||||||
@ -147,58 +143,6 @@ def display_llm_info():
|
|||||||
else:
|
else:
|
||||||
return "Informations du modèle non disponibles"
|
return "Informations du modèle non disponibles"
|
||||||
|
|
||||||
def extract_text_from_pdf(pdf_path):
|
|
||||||
"""Extrait le texte page par page d'un PDF sans les numéros de pages."""
|
|
||||||
import re
|
|
||||||
text_by_page = []
|
|
||||||
with open(pdf_path, "rb") as file:
|
|
||||||
reader = PyPDF2.PdfReader(file)
|
|
||||||
for page in reader.pages:
|
|
||||||
text = page.extract_text()
|
|
||||||
# Supprime les numéros de pages (nombres seuls en début/fin de ligne)
|
|
||||||
text = re.sub(r'^\d+\s*\n', '', text, flags=re.MULTILINE)
|
|
||||||
text = re.sub(r'\n\s*\d+\s*$', '', text, flags=re.MULTILINE)
|
|
||||||
text_by_page.append(text)
|
|
||||||
return text_by_page
|
|
||||||
|
|
||||||
def split_pages_in_paragraphs(pages_text):
|
|
||||||
"""
|
|
||||||
Divise le texte en paragraphes en détectant un point suivi d'un saut de ligne ou d'un retour à la ligne.
|
|
||||||
Conserve les sauts de ligne à l'intérieur des paragraphes.
|
|
||||||
"""
|
|
||||||
import re
|
|
||||||
|
|
||||||
# Concatène tout le texte
|
|
||||||
full_text = "\n".join(pages_text)
|
|
||||||
|
|
||||||
# Remplace les sauts de ligne à l'intérieur des paragraphes par des espaces
|
|
||||||
# (pour éviter les sauts de ligne intempestifs dans un même paragraphe)
|
|
||||||
full_text = re.sub(r'(?<![.!?])\n+(?![.!?])', ' ', full_text)
|
|
||||||
|
|
||||||
# Divise le texte en paragraphes : un point suivi d'un saut de ligne
|
|
||||||
paragraphs = re.split(r'(?<=[.!?])\s*\n+', full_text.strip())
|
|
||||||
|
|
||||||
# Nettoie chaque paragraphe : remplace les sauts de ligne restants par des espaces
|
|
||||||
paragraphs = [re.sub(r'\s+', ' ', p).strip() for p in paragraphs if p.strip()]
|
|
||||||
|
|
||||||
return paragraphs
|
|
||||||
|
|
||||||
def send_to_ollama(text, target_lang=TARGET_LANGUAGE, model=OLLAMA_MODEL, context_size=128000):
|
|
||||||
"""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"\n\nTraduis le texte suivant de l'ukrainien vers le {target_lang} :\n{text}"
|
|
||||||
payload = {
|
|
||||||
"model": model,
|
|
||||||
"prompt": full_prompt,
|
|
||||||
"stream": False,
|
|
||||||
"options": {"num_ctx": context_size}
|
|
||||||
}
|
|
||||||
response = requests.post(OLLAMA_URL, data=json.dumps(payload))
|
|
||||||
if response.status_code == 200:
|
|
||||||
return response.json()["response"]
|
|
||||||
else:
|
|
||||||
raise Exception(f"Erreur Ollama: {response.text}")
|
|
||||||
|
|
||||||
def register_unicode_font():
|
def register_unicode_font():
|
||||||
"""Enregistre une police TrueType qui supporte le cyrilique."""
|
"""Enregistre une police TrueType qui supporte le cyrilique."""
|
||||||
# Recherche une police système qui supporte le cyrilique
|
# Recherche une police système qui supporte le cyrilique
|
||||||
@ -220,6 +164,54 @@ def register_unicode_font():
|
|||||||
print("Aucune police Unicode trouvée, utilisation d'Helvetica")
|
print("Aucune police Unicode trouvée, utilisation d'Helvetica")
|
||||||
return 'Helvetica'
|
return 'Helvetica'
|
||||||
|
|
||||||
|
# Charge ou initialise le checkpoint
|
||||||
|
def load_checkpoint():
|
||||||
|
if os.path.exists(CHECKPOINT_FILE):
|
||||||
|
with open(CHECKPOINT_FILE, "r") as f:
|
||||||
|
return json.load(f)
|
||||||
|
return {"last_processed_index": -1, "results": {}}
|
||||||
|
|
||||||
|
# Sauvegarde le checkpoint
|
||||||
|
def save_checkpoint(last_index, results):
|
||||||
|
with open(CHECKPOINT_FILE, "w") as f:
|
||||||
|
json.dump({"last_processed_index": last_index, "results": results}, f)
|
||||||
|
|
||||||
|
# Sauvegarde les résultats temporaires dans un fichier TXT
|
||||||
|
def save_temp_results(results):
|
||||||
|
with open(TEMP_OUTPUT_TXT, "w", encoding="utf-8") as f:
|
||||||
|
for idx, translation in results.items():
|
||||||
|
f.write(f"Paragraphe {idx}:\n{translation}\n\n")
|
||||||
|
|
||||||
|
# Extraction du texte du PDF (inchangée)
|
||||||
|
def extract_text_from_pdf(pdf_path):
|
||||||
|
text_by_page = []
|
||||||
|
with open(pdf_path, "rb") as file:
|
||||||
|
reader = PyPDF2.PdfReader(file)
|
||||||
|
for page in reader.pages:
|
||||||
|
text = page.extract_text()
|
||||||
|
text_by_page.append(text)
|
||||||
|
return text_by_page
|
||||||
|
|
||||||
|
# Découpage en paragraphes (inchangé)
|
||||||
|
def split_pages_in_paragraphs(pages_text):
|
||||||
|
import re
|
||||||
|
full_text = "\n".join(pages_text)
|
||||||
|
full_text = re.sub(r'(?<![.!?])\n+(?![.!?])', ' ', full_text)
|
||||||
|
paragraphs = re.split(r'(?<=[.!?])\s*\n+', full_text.strip())
|
||||||
|
paragraphs = [re.sub(r'\s+', ' ', p).strip() for p in paragraphs if p.strip()]
|
||||||
|
return paragraphs
|
||||||
|
|
||||||
|
# Envoi à Ollama (inchangé)
|
||||||
|
def send_to_ollama(text, target_lang=TARGET_LANGUAGE, model=OLLAMA_MODEL):
|
||||||
|
full_prompt = f"\n\nTraduis le texte suivant de l'ukrainien vers le {target_lang} :\n{text}"
|
||||||
|
payload = {"model": model, "prompt": full_prompt, "stream": False}
|
||||||
|
response = requests.post(OLLAMA_URL, data=json.dumps(payload))
|
||||||
|
if response.status_code == 200:
|
||||||
|
return response.json()["response"]
|
||||||
|
else:
|
||||||
|
raise Exception(f"Erreur Ollama: {response.text}")
|
||||||
|
|
||||||
|
# Création du PDF final (inchangée)
|
||||||
def create_pdf_from_results(results, output_path):
|
def create_pdf_from_results(results, output_path):
|
||||||
"""Crée un PDF à partir des résultats de traduction."""
|
"""Crée un PDF à partir des résultats de traduction."""
|
||||||
doc = SimpleDocTemplate(output_path, pagesize=letter, topMargin=inch, bottomMargin=inch)
|
doc = SimpleDocTemplate(output_path, pagesize=letter, topMargin=inch, bottomMargin=inch)
|
||||||
@ -297,35 +289,40 @@ def create_txt_from_results(results, output_path):
|
|||||||
txt_file.write("\n")
|
txt_file.write("\n")
|
||||||
txt_file.write(display_llm_info() + "\n")
|
txt_file.write(display_llm_info() + "\n")
|
||||||
|
|
||||||
|
# Fonction principale
|
||||||
def main():
|
def main():
|
||||||
# Affiche les informations du modèle LLM
|
# Charge le checkpoint
|
||||||
display_llm_info()
|
checkpoint = load_checkpoint()
|
||||||
|
last_index = checkpoint["last_processed_index"]
|
||||||
|
results = checkpoint["results"]
|
||||||
|
|
||||||
# Extraction du texte page par page
|
# Extraction des paragraphes
|
||||||
pages = extract_text_from_pdf(PDF_PATH)
|
pages = extract_text_from_pdf(PDF_PATH)
|
||||||
print(f"Nombre de pages extraites : {len(pages)}")
|
|
||||||
|
|
||||||
# Fusion des paragraphes qui s'étendent sur plusieurs pages
|
|
||||||
paragraphs = split_pages_in_paragraphs(pages)
|
paragraphs = split_pages_in_paragraphs(pages)
|
||||||
print(f"Nombre de paragraphes complets extraits : {len(paragraphs)}")
|
|
||||||
|
|
||||||
# Dictionnaire pour stocker les résultats
|
# Traitement des paragraphes
|
||||||
results = {}
|
batch_size = 3
|
||||||
|
for i in range(last_index + 1, len(paragraphs), batch_size):
|
||||||
|
batch = paragraphs[i:i + batch_size]
|
||||||
|
paragraph_cumul = "\n".join(batch)
|
||||||
|
|
||||||
|
print(f"{15 * '-'} Traduction des paragraphes {i+1} à {min(i + batch_size, len(paragraphs))} / {len(paragraphs)}")
|
||||||
|
|
||||||
# Traitement des paragraphes complets
|
|
||||||
for i, paragraph_text in enumerate(paragraphs, start=1):
|
|
||||||
print(f"{15 * '-'} Traduction du paragraphe {i}/{len(paragraphs)}...")
|
|
||||||
try:
|
try:
|
||||||
result = send_to_ollama(paragraph_text, target_lang=TARGET_LANGUAGE)
|
result = send_to_ollama(paragraph_cumul)
|
||||||
print(f"{result}.")
|
print(f"{result}")
|
||||||
results[i] = result
|
results[i] = result
|
||||||
|
save_checkpoint(i, results) # Sauvegarde le checkpoint
|
||||||
|
save_temp_results(results) # Sauvegarde les résultats temporaires
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Erreur lors du traitement du paragraphe {i} : {e}")
|
print(f"Erreur : {e}")
|
||||||
results[i] = f"Erreur lors du traitement du paragraphe {i} : {e}"
|
continue
|
||||||
|
|
||||||
# Création du PDF avec tous les résultats
|
# Génération des fichiers finaux
|
||||||
create_pdf_from_results(results, OUTPUT_PDF_PATH)
|
save_temp_results(results)
|
||||||
create_txt_from_results(results, OUTPUT_PDF_PATH)
|
create_pdf_from_results(results, FINAL_OUTPUT_PDF)
|
||||||
|
create_txt_from_results(results, FINAL_OUTPUT_TXT)
|
||||||
|
print("Traduction terminée !")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
44
run.bat
Normal file
44
run.bat
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
@echo off
|
||||||
|
setlocal
|
||||||
|
|
||||||
|
set OLLAMA_PORT=11434
|
||||||
|
set OLLAMA_HOST=localhost
|
||||||
|
|
||||||
|
REM Récupérer le répertoire courant
|
||||||
|
set CURRENT_DIR=%cd%
|
||||||
|
|
||||||
|
REM Chemin vers l'environnement virtuel Python (relatif au répertoire courant)
|
||||||
|
set VENV_PATH=%CURRENT_DIR%\venv
|
||||||
|
|
||||||
|
REM Chemin vers votre script principal (relatif au répertoire courant)
|
||||||
|
set MAIN_SCRIPT_PATH=%CURRENT_DIR%\main.py
|
||||||
|
|
||||||
|
REM Activer l'environnement virtuel Python
|
||||||
|
call %VENV_PATH%\Scripts\activate.bat
|
||||||
|
|
||||||
|
REM Lancer la compilation du modèle LLM pour Ollama
|
||||||
|
ollama create traductionUkrainienVersFrancais -f .\Modelfile
|
||||||
|
|
||||||
|
:: 1. Vérifie si le processus ollama.exe est en cours d'exécution
|
||||||
|
tasklist | find "ollama.exe" >nul
|
||||||
|
if %ERRORLEVEL% equ 0 (
|
||||||
|
echo [OK] Le processus Ollama est en cours d'exécution.
|
||||||
|
) else (
|
||||||
|
echo [ERREUR] Ollama n'est pas lancé.
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
:: 2. Vérifie si le port 11434 est ouvert en local
|
||||||
|
echo Verification du port %OLLAMA_PORT% sur %OLLAMA_HOST%...
|
||||||
|
powershell -Command "$tcp = New-Object System.Net.Sockets.TcpClient; $connect = $tcp.ConnectAsync('%OLLAMA_HOST%', %OLLAMA_PORT%); $connect.Wait(1000); if ($tcp.Connected) { echo 'Port %OLLAMA_PORT% ouvert en local.'; $tcp.Close() } else { echo 'Port %OLLAMA_PORT% non accessible en local.'; exit 1 }"
|
||||||
|
if %ERRORLEVEL% neq 0 (
|
||||||
|
echo [ERREUR] Le port %OLLAMA_PORT% n'est pas accessible en local.
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Exécuter le script principal
|
||||||
|
python %MAIN_SCRIPT_PATH%
|
||||||
|
|
||||||
|
endlocal
|
||||||
Loading…
x
Reference in New Issue
Block a user