Files
pptx-service/app/main.py
T
2026-05-23 21:31:34 +02:00

173 lines
5.0 KiB
Python

from fastapi import FastAPI, HTTPExceptionfrom fastapi import FastAPI, HTTP(BaseModel):
filename: Optional[str] = "presentation"
title: str = "Présentation"
subtitle: Optional[str] = None
slides: List[SlideData] = Field(default_factory=list)
# ----------------------------
# Utilitaires
# ----------------------------
def sanitize_filename(name: str) -> str:
cleaned = re.sub(r"[^a-zA-Z0-9_-]", "_", name.strip())
return cleaned or "presentation"
def add_title_slide(prs: Presentation, title: str, subtitle: Optional[str]) -> None:
slide_layout = prs.slide_layouts[6] # blank
slide = prs.slides.add_slide(slide_layout)
# Fond visuel simple via zone blanche implicite
title_box = slide.shapes.add_textbox(Inches(0.6), Inches(1.0), Inches(11.5), Inches(1.0))
tf = title_box.text_frame
p = tf.paragraphs[0]
p.text = title
p.font.size = Pt(24)
p.font.bold = True
p.alignment = PP_ALIGN.LEFT
if subtitle:
subtitle_box = slide.shapes.add_textbox(Inches(0.6), Inches(1.8), Inches(11.0), Inches(0.8))
tf2 = subtitle_box.text_frame
p2 = tf2.paragraphs[0]
p2.text = subtitle
p2.font.size = Pt(14)
p2.alignment = PP_ALIGN.LEFT
def add_content_slide(prs: Presentation, slide_data: SlideData) -> None:
slide_layout = prs.slide_layouts[6] # blank
slide = prs.slides.add_slide(slide_layout)
# Titre
title_box = slide.shapes.add_textbox(Inches(0.5), Inches(0.4), Inches(12.0), Inches(0.8))
tf_title = title_box.text_frame
p_title = tf_title.paragraphs[0]
p_title.text = slide_data.title
p_title.font.size = Pt(22)
p_title.font.bold = True
p_title.alignment = PP_ALIGN.LEFT
current_top = 1.3
# Texte libre
if slide_data.text:
text_box = slide.shapes.add_textbox(Inches(0.7), Inches(current_top), Inches(11.0), Inches(1.2))
tf_text = text_box.text_frame
tf_text.word_wrap = True
p_text = tf_text.paragraphs[0]
p_text.text = slide_data.text
p_text.font.size = Pt(16)
p_text.alignment = PP_ALIGN.LEFT
current_top += 1.0
# Liste à puces
if slide_data.bullets:
bullets_box = slide.shapes.add_textbox(Inches(1.0), Inches(current_top), Inches(10.8), Inches(4.0))
tf_bullets = bullets_box.text_frame
tf_bullets.word_wrap = True
first = True
for bullet in slide_data.bullets:
if first:
p = tf_bullets.paragraphs[0]
first = False
else:
p = tf_bullets.add_paragraph()
p.text = bullet
p.level = 0
p.font.size = Pt(18)
p.alignment = PP_ALIGN.LEFT
p.bullet = True
def generate_pptx(data: PresentationRequest) -> str:
prs = Presentation()
prs.slide_width = Inches(13.333) # 16:9
prs.slide_height = Inches(7.5)
# Métadonnées
prs.core_properties.title = data.title
prs.core_properties.subject = data.title
prs.core_properties.author = "M365 Copilot"
prs.core_properties.company = "Votre organisation"
# Slide de titre
add_title_slide(prs, data.title, data.subtitle)
# Slides de contenu
for slide in data.slides:
add_content_slide(prs, slide)
filename = sanitize_filename(data.filename)
tmp_dir = tempfile.gettempdir()
full_path = os.path.join(tmp_dir, f"{filename}_{uuid.uuid4().hex}.pptx")
prs.save(full_path)
return full_path
# ----------------------------
# Endpoints
# ----------------------------
@app.get("/health")
def health():
return {"status": "ok"}
@app.post("/generate")
def generate_presentation(payload: PresentationRequest):
try:
output_path = generate_pptx(payload)
download_name = f"{sanitize_filename(payload.filename)}.pptx"
return FileResponse(
path=output_path,
media_type="application/vnd.openxmlformats-officedocument.presentationml.presentation",
filename=download_name
)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Erreur lors de la génération du PPTX : {str(e)}")
@app.get("/")
def root():
return JSONResponse({
"service": "pptx-service",
"status": "running",
"endpoints": {
"health": "/health",
"generate": "/generate"
}
})
from fastapi.responses import FileResponse, JSONResponse
from pydantic import BaseModel, Field
from typing import List, Optional
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.enum.text import PP_ALIGN
import tempfile
import os
import re
import uuid
app = FastAPI(
title="PPTX JSON Service",
description="Génère un fichier PowerPoint (.pptx) à partir d'un JSON",
version="1.0.0"
)
# ----------------------------
# Modèles de données
# ----------------------------
class SlideData(BaseModel):
title: str
text: Optional[str] = None
bullets: Optional[List[str]] = Field(default_factory=list)