Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -651,122 +651,7 @@ EXAMPLE_PROMPTS: dict[str, str] = {
|
|
| 651 |
}
|
| 652 |
STYLE_KEYS = list(EXAMPLE_PROMPTS.keys())
|
| 653 |
|
| 654 |
-
def create_advanced_ppt_from_content(
|
| 655 |
-
slides_data: list,
|
| 656 |
-
topic: str,
|
| 657 |
-
theme_name: str = "professional",
|
| 658 |
-
include_charts: bool = False,
|
| 659 |
-
include_ai_image: bool = False,
|
| 660 |
-
include_diagrams: bool = False,
|
| 661 |
-
include_flux_images: bool = False,
|
| 662 |
-
max_images_per_api: int = 3,
|
| 663 |
-
max_diagrams: int = 2,
|
| 664 |
-
) -> str:
|
| 665 |
-
"""
|
| 666 |
-
Build a fully-styled 16:9 PowerPoint file from parsed slide data.
|
| 667 |
-
|
| 668 |
-
โข ์ฌ๋ผ์ด๋ ํ
๋ง/ํฐํธ/์์์ DESIGN_THEMES์์ ๋์ด์จ๋ค.
|
| 669 |
-
โข AI ์ด๋ฏธ์ง: 3D-API์ FLUX-API ๊ฐ๊ฐ ์ต๋ `max_images_per_api` ์ฅ.
|
| 670 |
-
โข ๋ค์ด์ด๊ทธ๋จ: detect_diagram_type_with_score() ์ฐ์ ์์ ์์ `max_diagrams` ๊ฐ.
|
| 671 |
-
โข ํจ์๊ฐ ๋๋๋ฉด ์์ํ์ผ(.pptx) ๊ฒฝ๋ก๋ฅผ ๋๋ ค์ค๋ค.
|
| 672 |
-
"""
|
| 673 |
-
if not PPTX_AVAILABLE:
|
| 674 |
-
raise ImportError("python-pptx ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ํ์ํฉ๋๋ค (pip install python-pptx)")
|
| 675 |
|
| 676 |
-
prs = Presentation()
|
| 677 |
-
theme = DESIGN_THEMES.get(theme_name, DESIGN_THEMES["professional"])
|
| 678 |
-
|
| 679 |
-
# --- ์ฌ๋ผ์ด๋ ์บ๋ฒ์ค ํฌ๊ธฐ (16:9) ---
|
| 680 |
-
prs.slide_width = Inches(10)
|
| 681 |
-
prs.slide_height = Inches(5.625)
|
| 682 |
-
|
| 683 |
-
# ๋ด๋ถ ์นด์ดํฐ
|
| 684 |
-
img_cnt_3d, img_cnt_flux, dia_cnt = 0, 0, 0
|
| 685 |
-
|
| 686 |
-
# โธโธโธ 0. ๋ค์ด์ด๊ทธ๋จ ํ์ ์ฌ๋ผ์ด๋ ๋ฏธ๋ฆฌ ์ ์
|
| 687 |
-
diagram_targets: list[tuple[int, str]] = []
|
| 688 |
-
if include_diagrams:
|
| 689 |
-
scored = []
|
| 690 |
-
for idx, s in enumerate(slides_data):
|
| 691 |
-
d_type, score = detect_diagram_type_with_score(s["title"], s["content"])
|
| 692 |
-
if d_type:
|
| 693 |
-
scored.append((idx, d_type, score))
|
| 694 |
-
scored.sort(key=lambda x: x[2], reverse=True)
|
| 695 |
-
diagram_targets = [(i, t) for i, t, _ in scored[:max_diagrams]]
|
| 696 |
-
|
| 697 |
-
# โธโธโธ 1. ํ์ง ์ฌ๋ผ์ด๋ --------------------------------------------------
|
| 698 |
-
cover = prs.slides.add_slide(prs.slide_layouts[0])
|
| 699 |
-
add_gradient_background(cover, theme["colors"]["primary"], theme["colors"]["secondary"])
|
| 700 |
-
cover.shapes.title.text = topic
|
| 701 |
-
cover.shapes.title.text_frame.paragraphs[0].font.size = Pt(36)
|
| 702 |
-
cover.shapes.title.text_frame.paragraphs[0].font.bold = True
|
| 703 |
-
if include_ai_image and (AI_IMAGE_ENABLED or FLUX_API_ENABLED):
|
| 704 |
-
p3d, pph = generate_cover_image_prompts(topic, slides_data)
|
| 705 |
-
img3d, imgph = generate_images_parallel(p3d, pph)
|
| 706 |
-
pick = img3d if img3d and img_cnt_3d < max_images_per_api else imgph
|
| 707 |
-
if pick:
|
| 708 |
-
cover.shapes.add_picture(pick, Inches(6.2), Inches(2.0), width=Inches(3.3))
|
| 709 |
-
if pick == img3d: img_cnt_3d += 1
|
| 710 |
-
else: img_cnt_flux += 1
|
| 711 |
-
|
| 712 |
-
# โธโธโธ 2. ๋ณธ๋ฌธ ์ฌ๋ผ์ด๋ ---------------------------------------------------
|
| 713 |
-
for idx, s in enumerate(slides_data):
|
| 714 |
-
layout = prs.slide_layouts[1]
|
| 715 |
-
sl = prs.slides.add_slide(layout)
|
| 716 |
-
apply_theme_to_slide(sl, theme)
|
| 717 |
-
sl.shapes.title.text = s["title"]
|
| 718 |
-
|
| 719 |
-
# ์ผ์ชฝ ํ
์คํธ
|
| 720 |
-
left = sl.shapes.add_textbox(Inches(0.6), Inches(1.4), Inches(4.4), Inches(3.6))
|
| 721 |
-
tf = left.text_frame
|
| 722 |
-
tf.text = s["content"]
|
| 723 |
-
force_font_size(tf, 16, theme)
|
| 724 |
-
|
| 725 |
-
# ์ค๋ฅธ์ชฝ ์๊ฐ ์์
|
| 726 |
-
right_x, right_y = Inches(5.2), Inches(1.5)
|
| 727 |
-
visual_done = False
|
| 728 |
-
|
| 729 |
-
# ๋ค์ด์ด๊ทธ๋จ ์ฐ์
|
| 730 |
-
if (idx, _) := next(((i, t) for i, t in diagram_targets if i == idx), None):
|
| 731 |
-
if dia_cnt < max_diagrams:
|
| 732 |
-
j = generate_diagram_json(s["title"], s["content"], _)
|
| 733 |
-
if j:
|
| 734 |
-
p = generate_diagram_locally(j, _, "png")
|
| 735 |
-
if p:
|
| 736 |
-
sl.shapes.add_picture(p, right_x, right_y, width=Inches(4.0))
|
| 737 |
-
visual_done, dia_cnt = True, dia_cnt + 1
|
| 738 |
-
|
| 739 |
-
# ์ด๋ฏธ์ง (3D / FLUX)
|
| 740 |
-
if not visual_done and include_flux_images and (img_cnt_3d + img_cnt_flux) < max_images_per_api * 2:
|
| 741 |
-
p3d, pph = generate_diverse_prompt(s["title"], s["content"], idx)
|
| 742 |
-
pic = None
|
| 743 |
-
if img_cnt_3d < max_images_per_api:
|
| 744 |
-
pic = generate_ai_image_via_3d_api(p3d)
|
| 745 |
-
if pic: img_cnt_3d += 1
|
| 746 |
-
if not pic and img_cnt_flux < max_images_per_api:
|
| 747 |
-
pic = generate_flux_image_via_api(pph)
|
| 748 |
-
if pic: img_cnt_flux += 1
|
| 749 |
-
if pic:
|
| 750 |
-
sl.shapes.add_picture(pic, right_x, right_y, width=Inches(4.0))
|
| 751 |
-
|
| 752 |
-
# ์ฐจํธ
|
| 753 |
-
if include_charts and s.get("chart_data"):
|
| 754 |
-
create_chart_slide(sl, s["chart_data"], theme)
|
| 755 |
-
|
| 756 |
-
# ์ฌ๋ผ์ด๋ ๋ฒํธ
|
| 757 |
-
num_box = sl.shapes.add_textbox(Inches(9.0), Inches(5.1), Inches(1.0), Inches(0.3))
|
| 758 |
-
num_box.text_frame.text = f"{idx+1}/{len(slides_data)}"
|
| 759 |
-
num_box.text_frame.paragraphs[0].font.size = Pt(10)
|
| 760 |
-
|
| 761 |
-
# โธโธโธ 3. ๋ง๋ฌด๋ฆฌ ์ฌ๋ผ์ด๋ -------------------------------------------------
|
| 762 |
-
thanks = prs.slides.add_slide(prs.slide_layouts[5])
|
| 763 |
-
add_gradient_background(thanks, theme["colors"]["secondary"], theme["colors"]["primary"])
|
| 764 |
-
thanks.shapes.title.text = "๊ฐ์ฌํฉ๋๋ค"
|
| 765 |
-
|
| 766 |
-
# โธโธโธ 4. ์ ์ฅ -----------------------------------------------------------
|
| 767 |
-
tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".pptx")
|
| 768 |
-
prs.save(tmp.name)
|
| 769 |
-
return tmp.name
|
| 770 |
|
| 771 |
# ------------------------------------------------------------------
|
| 772 |
# 2) generate_flux_prompt ํจ์ ์ ์ฒด โ
์์ ์๋ฃ
|
|
@@ -1642,6 +1527,7 @@ def add_decorative_shapes(slide, theme: Dict):
|
|
| 1642 |
except Exception as e:
|
| 1643 |
logger.warning(f"Failed to add decorative shapes: {e}")
|
| 1644 |
|
|
|
|
| 1645 |
def create_chart_slide(slide, chart_data: Dict, theme: Dict):
|
| 1646 |
"""Create a chart on the slide based on data"""
|
| 1647 |
try:
|
|
@@ -1689,6 +1575,8 @@ def create_chart_slide(slide, chart_data: Dict, theme: Dict):
|
|
| 1689 |
text_frame.paragraphs[0].font.size = Pt(16) # Increased font size
|
| 1690 |
text_frame.paragraphs[0].font.color.rgb = theme['colors']['secondary']
|
| 1691 |
|
|
|
|
|
|
|
| 1692 |
def create_advanced_ppt_from_content(
|
| 1693 |
slides_data: list,
|
| 1694 |
topic: str,
|
|
|
|
| 651 |
}
|
| 652 |
STYLE_KEYS = list(EXAMPLE_PROMPTS.keys())
|
| 653 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 654 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 655 |
|
| 656 |
# ------------------------------------------------------------------
|
| 657 |
# 2) generate_flux_prompt ํจ์ ์ ์ฒด โ
์์ ์๋ฃ
|
|
|
|
| 1527 |
except Exception as e:
|
| 1528 |
logger.warning(f"Failed to add decorative shapes: {e}")
|
| 1529 |
|
| 1530 |
+
|
| 1531 |
def create_chart_slide(slide, chart_data: Dict, theme: Dict):
|
| 1532 |
"""Create a chart on the slide based on data"""
|
| 1533 |
try:
|
|
|
|
| 1575 |
text_frame.paragraphs[0].font.size = Pt(16) # Increased font size
|
| 1576 |
text_frame.paragraphs[0].font.color.rgb = theme['colors']['secondary']
|
| 1577 |
|
| 1578 |
+
|
| 1579 |
+
|
| 1580 |
def create_advanced_ppt_from_content(
|
| 1581 |
slides_data: list,
|
| 1582 |
topic: str,
|