Spaces:
Sleeping
Sleeping
File size: 10,251 Bytes
179eccc | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 | > [!NOTE]
> Cette documentation peut contenir du contenu généré par l'IA. Bien que nous nous efforcions d'être précis, il peut y avoir des inexactitudes. Veuillez signaler tout problème via :
>
> - [GitHub Issues](https://github.com/PDFMathTranslate-next/PDFMathTranslate-next/issues)
> - Contribution de la communauté (les PR sont les bienvenues !)
## Python API : do_translate_async_stream
### Aperçu
- do_translate_async_stream est le point d'entrée asynchrone de bas niveau qui traduit un seul PDF et produit un flux d'événements (progression/erreur/fin).
- Il est adapté pour construire votre propre interface utilisateur ou CLI où vous souhaitez une progression en temps réel et un contrôle total sur les résultats.
- Il accepte un SettingsModel validé et un chemin de fichier et retourne un générateur asynchrone d'événements sous forme de dictionnaires.
### Signature
- Importation : `from pdf2zh_next.high_level import do_translate_async_stream`
- Appel : `async for event in do_translate_async_stream(settings, file): ...`
- Paramètres :
- settings : SettingsModel. Doit être valide ; la fonction appellera `settings.validate_settings()`.
- file : str | pathlib.Path. Le PDF unique à traduire. Doit exister.
NOTE
- `settings.basic.input_files` est ignoré par cette fonction ; seul le `file` donné est traduit.
- Si `settings.basic.debug` est True, la traduction s'exécute dans le processus principal ; sinon, elle s'exécute dans un sous-processus. Le schéma d'événements est identique dans les deux cas.
### Contrat de flux d'événements
Le générateur asynchrone produit des événements de type dict similaires à JSON avec les types suivants :
- Événement de résumé des étapes : `stage_summary` (optionnel, peut apparaître en premier)
- Champs
- `type` : "stage_summary"
- `stages` : liste d'objets `{ "name": str, "percent": float }` décrivant la répartition estimée du travail
- `part_index` : peut être 0 pour cet événement de résumé
- `total_parts` : nombre total de parties (>= 1)
- Événements de progression : `progress_start`, `progress_update`, `progress_end`
- Champs communs
- `type` : l'un des types ci-dessus
- `stage` : nom d'étape lisible par un humain (par exemple, "Analyser le PDF et créer une représentation intermédiaire", "Traduire les paragraphes", "Enregistrer le PDF")
- `stage_progress` : float dans [0, 100] indiquant la progression dans l'étape actuelle
- `overall_progress` : float dans [0, 100] indiquant la progression globale
- `part_index` : index de la partie actuelle (généralement basé sur 1 pour les événements de progression)
- `total_parts` : nombre total de parties (>= 1). Les documents volumineux peuvent être divisés automatiquement.
- `stage_current` : étape actuelle dans la phase
- `stage_total` : nombre total d'étapes dans la phase
- Événement de fin : `finish`
- Champs
- `type` : "finish"
- `translate_result` : un **objet** fournissant les sorties finales (NOTE : pas un dictionnaire, mais une instance de classe)
- `original_pdf_path` : Chemin d'accès au PDF d'entrée
- `mono_pdf_path` : Chemin d'accès au PDF traduit monolingue (ou None)
- `dual_pdf_path` : Chemin d'accès au PDF traduit bilingue (ou None)
- `no_watermark_mono_pdf_path` : Chemin d'accès à la sortie monolingue sans filigrane (si produite), sinon None
- `no_watermark_dual_pdf_path` : Chemin d'accès à la sortie bilingue sans filigrane (si produite), sinon None
- `auto_extracted_glossary_path` : Chemin d'accès au glossaire CSV extrait automatiquement (ou None)
- `total_seconds` : secondes écoulées (float)
- `peak_memory_usage` : utilisation maximale approximative de la mémoire pendant la traduction (float ; unités dépendantes de l'implémentation)
- Événement d'erreur : `error`
- Champs
- `type` : "error"
- `error` : message d'erreur lisible par un humain
- `error_type` : l'un de `BabeldocError`, `SubprocessError`, `IPCError`, `SubprocessCrashError`, etc.
- `details` : détails optionnels (par exemple, erreur originale ou traceback)
Comportement important :
- Un `stage_summary` facultatif peut être émis avant le début de la progression.
- En cas de certains échecs, le générateur produira d'abord un événement `error`, puis lèvera une exception dérivée de `TranslationError`. Vous devez à la fois vérifier les événements d'erreur et être prêt à intercepter les exceptions.
- Les événements `progress_update` peuvent se répéter avec des valeurs identiques ; les consommateurs doivent effectuer un anti-rebond si nécessaire.
- Arrêtez de consommer le flux lorsque vous recevez un événement `finish`.
### Exemple d'utilisation minimale (Asynchrone)
```python
import asyncio
from pathlib import Path
from pdf2zh_next.high_level import do_translate_async_stream
# Assume you already have a valid SettingsModel instance named `settings`
# and a PDF file path
async def translate_one(settings, pdf_path: str | Path):
try:
async for event in do_translate_async_stream(settings, pdf_path):
etype = event.get("type")
if etype == "stage_summary":
# Optional pre-flight summary of stages
stages = event.get("stages", [])
print("Stage summary:", ", ".join(f"{s['name']}:{s['percent']:.2f}" for s in stages))
elif etype in {"progress_start", "progress_update", "progress_end"}:
stage = event.get("stage")
stage_prog = event.get("stage_progress") # 0..100
overall = event.get("overall_progress") # 0..100
part_i = event.get("part_index")
part_n = event.get("total_parts")
print(f"[{etype}] {stage} | stage {stage_prog:.1f}% | overall {overall:.1f}% (part {part_i}/{part_n})")
elif etype == "error":
# You will also get a raised exception after this yield
print("[error]", event.get("error"), event.get("error_type"))
elif etype == "finish":
result = event["translate_result"]
print("Done in", getattr(result, "total_seconds", None), "s")
print("Mono:", getattr(result, "mono_pdf_path", None))
print("Dual:", getattr(result, "dual_pdf_path", None))
print("No-watermark Mono:", getattr(result, "no_watermark_mono_pdf_path", None))
print("No-watermark Dual:", getattr(result, "no_watermark_dual_pdf_path", None))
print("Glossary:", getattr(result, "auto_extracted_glossary_path", None))
print("Peak memory:", getattr(result, "peak_memory_usage", None))
break
except Exception as exc:
# Catch exceptions raised by the stream after an error event
print("Translation failed:", exc)
# asyncio.run(translate_one(settings, "/path/to/file.pdf"))
```
### Annulation
Vous pouvez annuler la tâche consommant le flux. L'annulation est propagée au processus de traduction sous-jacent.
```python
import asyncio
from pdf2zh_next.high_level import do_translate_async_stream
async def cancellable(settings, pdf):
task = asyncio.create_task(_consume(settings, pdf))
await asyncio.sleep(1.0) # let it start
task.cancel()
try:
await task
except asyncio.CancelledError:
print("Cancelled")
async def _consume(settings, pdf):
async for event in do_translate_async_stream(settings, pdf):
if event["type"] == "finish":
break
```
### Formes d'événements exemples
Résumé d'étape (exemple) :
```json
{
"type": "stage_summary",
"stages": [
{"name": "Parse PDF and Create Intermediate Representation", "percent": 0.1086},
{"name": "DetectScannedFile", "percent": 0.0188},
{"name": "Parse Page Layout", "percent": 0.1079}
// ... more stages ...
],
"part_index": 0,
"total_parts": 1
}
```
Événement de progression (exemple) :
```json
{
"type": "progress_update",
"stage": "Translate Paragraphs",
"stage_progress": 2.04,
"stage_current": 1,
"stage_total": 49,
"overall_progress": 53.44,
"part_index": 1,
"total_parts": 1
}
```
Événement de fin (exemple) :
```json
{
"type": "finish",
"translate_result": {
"original_pdf_path": "pdf2zh_files/<session>/table.pdf",
"mono_pdf_path": "pdf2zh_files/<session>/table.zh-CN.mono.pdf",
"dual_pdf_path": "pdf2zh_files/<session>/table.zh-CN.dual.pdf",
"no_watermark_mono_pdf_path": "pdf2zh_files/<session>/table.no_watermark.zh-CN.mono.pdf",
"no_watermark_dual_pdf_path": "pdf2zh_files/<session>/table.no_watermark.zh-CN.dual.pdf",
"auto_extracted_glossary_path": "pdf2zh_files/<session>/table.zh-CN.glossary.csv",
"total_seconds": 42.83,
"peak_memory_usage": 4651.55
}
}
```
Événement d'erreur (exemple) :
```json
{
"type": "error",
"error": "Babeldoc translation error: <message>",
"error_type": "BabeldocError",
"details": "<optional original error or traceback>"
}
```
### Notes & Meilleures pratiques
- Toujours gérer à la fois les événements d'erreur et les exceptions provenant du générateur.
- Interrompre la boucle sur `finish` pour éviter un travail inutile.
- S'assurer que le `file` existe et que `settings.validate_settings()` passe avant d'appeler.
- Les documents volumineux peuvent être divisés ; utiliser `part_index/total_parts` et `overall_progress` pour piloter votre interface utilisateur.
- Débouncer `progress_update` si votre interface utilisateur est sensible aux mises à jour répétées et identiques.
- `report_interval` (SettingsModel) : contrôle uniquement le taux d'émission des événements `progress_update`. Il n'affecte pas `stage_summary`, `progress_start`, `progress_end` ou `finish`. La valeur par défaut est 0,1s et le minimum autorisé est 0,05s. Selon la logique du moniteur de progression, lorsque `stage_total <= 3`, les mises à jour ne sont pas limitées par `report_interval`.
<div align="right">
<h6><small>Une partie du contenu de cette page a été traduite par GPT et peut contenir des erreurs.</small></h6> |