1
0

media.py 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
  1. """Pièces jointes préparées pour Claude (images et PDF), et ce qu'elles pèsent dans une requête."""
  2. from __future__ import annotations
  3. from dataclasses import dataclass
  4. PDF_MEDIA_TYPE = "application/pdf"
  5. # Budget de pièces jointes par requête. Les messages arrivés pendant une réponse partent ensemble :
  6. # sans budget, plusieurs gros fichiers dépasseraient les limites de l'API (128 Mo par requête ; 100 pages
  7. # de PDF et 100 images pour les modèles à 200 000 tokens de contexte) ou sa fenêtre de contexte, et
  8. # occuperaient beaucoup de mémoire le temps de l'envoi.
  9. REQUEST_MAX_BASE64 = 24_000_000 # octets une fois encodés en base64 (+33 %), soit 18 Mo bruts
  10. REQUEST_MAX_PAGES = 100 # pages de PDF et images, jusqu'à plusieurs milliers de tokens chacune
  11. @dataclass
  12. class ImageData:
  13. """Image ou PDF joint à un message, prêt à être envoyé à Claude."""
  14. media_type: str
  15. data: bytes
  16. name: str | None = None # nom du fichier (PDF)
  17. pages: int = 1 # pages d'un PDF ; une image compte pour une page
  18. @property
  19. def is_pdf(self) -> bool:
  20. return self.media_type == PDF_MEDIA_TYPE
  21. def base64_size(size: int) -> int:
  22. """Taille de size octets une fois encodés en base64."""
  23. return 4 * -(-size // 3)
  24. def request_weight(attachments: list[ImageData]) -> tuple[int, int]:
  25. """Poids de pièces jointes dans une requête : (octets en base64, pages de PDF et images)."""
  26. return sum(base64_size(len(a.data)) for a in attachments), sum(a.pages for a in attachments)
  27. def fit_in_request(messages: list[list[ImageData]]) -> int:
  28. """Nombre de messages, pris dans l'ordre, qui partent ensemble dans la prochaine requête : tant que
  29. leurs pièces jointes (une liste par message) tiennent dans le budget. Le premier part toujours, même
  30. seul au-delà du budget : il tient déjà dans les limites de l'API (voir PDF_MAX_BYTES, MAX_IMAGES)."""
  31. size = pages = 0
  32. for count, attachments in enumerate(messages):
  33. message_size, message_pages = request_weight(attachments)
  34. size, pages = size + message_size, pages + message_pages
  35. if count and (size > REQUEST_MAX_BASE64 or pages > REQUEST_MAX_PAGES):
  36. return count
  37. return len(messages)