Spaces:
Running
Running
Update app-BACKUP.py
Browse files- app-BACKUP.py +123 -116
app-BACKUP.py
CHANGED
@@ -34,6 +34,19 @@ except ImportError:
|
|
34 |
PPTX_AVAILABLE = False
|
35 |
logger.warning("python-pptx ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ค์น๋์ง ์์์ต๋๋ค. pip install python-pptx")
|
36 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
##############################################################################
|
38 |
# API Configuration
|
39 |
##############################################################################
|
@@ -94,26 +107,9 @@ def initialize_flux_api():
|
|
94 |
return False
|
95 |
|
96 |
##############################################################################
|
97 |
-
# Diagram Generation API Configuration
|
98 |
##############################################################################
|
99 |
-
|
100 |
-
DIAGRAM_API_ENABLED = False
|
101 |
-
diagram_api_client = None
|
102 |
-
|
103 |
-
def initialize_diagram_api():
|
104 |
-
"""๋ค์ด์ด๊ทธ๋จ ์์ฑ API ์ด๊ธฐํ"""
|
105 |
-
global DIAGRAM_API_ENABLED, diagram_api_client
|
106 |
-
|
107 |
-
try:
|
108 |
-
logger.info("Connecting to Diagram Generation API...")
|
109 |
-
diagram_api_client = Client(DIAGRAM_API_URL)
|
110 |
-
DIAGRAM_API_ENABLED = True
|
111 |
-
logger.info("Diagram API connected successfully")
|
112 |
-
return True
|
113 |
-
except Exception as e:
|
114 |
-
logger.error(f"Failed to connect to Diagram API: {e}")
|
115 |
-
DIAGRAM_API_ENABLED = False
|
116 |
-
return False
|
117 |
|
118 |
##############################################################################
|
119 |
# Design Themes and Color Schemes
|
@@ -354,32 +350,40 @@ def get_emoji_for_content(text: str) -> str:
|
|
354 |
return 'โถ๏ธ'
|
355 |
|
356 |
##############################################################################
|
357 |
-
# Diagram Type Detection
|
358 |
##############################################################################
|
359 |
def detect_diagram_type(title: str, content: str) -> Optional[str]:
|
360 |
"""์ฌ๋ผ์ด๋ ๋ด์ฉ์ ๋ถ์ํ์ฌ ์ ์ ํ ๋ค์ด์ด๊ทธ๋จ ํ์
๊ฒฐ์ """
|
361 |
combined_text = f"{title} {content}".lower()
|
362 |
|
363 |
# Process Flow keywords
|
364 |
-
if any(word in combined_text for word in ['ํ๋ก์ธ์ค', 'process', '์ ์ฐจ', 'procedure', '๋จ๊ณ', 'step', 'flow', 'ํ๋ฆ', '์ํฌํ๋ก์ฐ', 'workflow']):
|
365 |
return "Process Flow"
|
366 |
|
367 |
# WBS keywords
|
368 |
-
elif any(word in combined_text for word in ['wbs', '์์
๋ถํด', 'ํ๋ก์ ํธ', 'project', '์
๋ฌด๋ถํด', 'breakdown', '๊ตฌ์กฐ๋']):
|
369 |
return "WBS Diagram"
|
370 |
|
371 |
# Concept Map keywords
|
372 |
-
elif any(word in combined_text for word in ['๊ฐ๋
', 'concept', '๊ด๊ณ', 'relationship', '์ฐ๊ด', 'connection', '๋ง์ธ๋๋งต', 'mindmap']):
|
373 |
return "Concept Map"
|
374 |
|
375 |
# Radial Diagram keywords
|
376 |
-
elif any(word in combined_text for word in ['์ค์ฌ', 'central', '๋ฐฉ์ฌํ', 'radial', 'ํต์ฌ', 'core', '์ฃผ์', 'main']):
|
377 |
return "Radial Diagram"
|
378 |
|
379 |
# Synoptic Chart keywords
|
380 |
-
elif any(word in combined_text for word in ['๊ฐ์', 'overview', '์ ์ฒด', 'overall', '์์ฝ', 'summary', '์๋ํฑ', 'synoptic']):
|
381 |
return "Synoptic Chart"
|
382 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
383 |
return None
|
384 |
|
385 |
##############################################################################
|
@@ -390,7 +394,7 @@ def generate_diagram_json(title: str, content: str, diagram_type: str) -> Option
|
|
390 |
if not FRIENDLI_TOKEN:
|
391 |
return None
|
392 |
|
393 |
-
# ๋ค์ด์ด๊ทธ๋จ ํ์
๋ณ JSON ๊ตฌ์กฐ ๊ฐ์ด๋
|
394 |
json_guides = {
|
395 |
"Concept Map": """Generate a JSON for a concept map with the EXACT following structure:
|
396 |
{
|
@@ -476,7 +480,9 @@ Important rules:
|
|
476 |
2. The JSON must follow the EXACT structure shown above
|
477 |
3. Create content based on the provided title and content
|
478 |
4. Use the user's language (Korean or English) for the content values
|
479 |
-
5. Keep it simple with 3-5 main nodes/steps
|
|
|
|
|
480 |
|
481 |
messages = [
|
482 |
{"role": "system", "content": system_prompt},
|
@@ -520,37 +526,40 @@ Important rules:
|
|
520 |
return None
|
521 |
|
522 |
##############################################################################
|
523 |
-
# Generate Diagram using
|
524 |
##############################################################################
|
525 |
-
def
|
526 |
-
"""
|
527 |
-
if not
|
|
|
528 |
return None
|
529 |
|
530 |
try:
|
531 |
-
#
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
|
|
|
|
|
|
|
|
|
|
540 |
|
541 |
-
#
|
542 |
-
if isinstance(result,
|
543 |
-
|
544 |
-
|
545 |
-
# ์์ ํ์ผ๋ก ๋ณต์ฌ
|
546 |
-
with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmp:
|
547 |
-
shutil.copy2(image_path, tmp.name)
|
548 |
-
return tmp.name
|
549 |
|
550 |
-
|
|
|
551 |
|
552 |
except Exception as e:
|
553 |
-
logger.error(f"Failed to generate diagram
|
554 |
return None
|
555 |
|
556 |
##############################################################################
|
@@ -1042,43 +1051,6 @@ def generate_ai_image_via_3d_api(prompt: str) -> Optional[str]:
|
|
1042 |
logger.error(f"Failed to generate 3D image: {e}")
|
1043 |
return None
|
1044 |
|
1045 |
-
def generate_flux_image_via_api(prompt: str) -> Optional[str]:
|
1046 |
-
"""FLUX API๋ฅผ ํตํด ํฌํ ๋ฆฌ์ผ๋ฆฌ์คํฑ ์ด๋ฏธ์ง ์์ฑ"""
|
1047 |
-
if not FLUX_API_ENABLED or not flux_api_client:
|
1048 |
-
return None
|
1049 |
-
|
1050 |
-
try:
|
1051 |
-
logger.info(f"Generating FLUX photorealistic image with prompt: {prompt[:100]}...")
|
1052 |
-
|
1053 |
-
result = flux_api_client.predict(
|
1054 |
-
prompt=prompt,
|
1055 |
-
width=768,
|
1056 |
-
height=768,
|
1057 |
-
guidance=3.5,
|
1058 |
-
inference_steps=8,
|
1059 |
-
seed=random.randint(1, 1000000),
|
1060 |
-
do_img2img=False,
|
1061 |
-
init_image=None,
|
1062 |
-
image2image_strength=0.8,
|
1063 |
-
resize_img=True,
|
1064 |
-
api_name="/generate_image"
|
1065 |
-
)
|
1066 |
-
|
1067 |
-
if isinstance(result, tuple) and len(result) > 0:
|
1068 |
-
image_path = result[0]
|
1069 |
-
if image_path and os.path.exists(image_path):
|
1070 |
-
with Image.open(image_path) as img:
|
1071 |
-
png_tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".png")
|
1072 |
-
img.save(png_tmp.name, format="PNG")
|
1073 |
-
logger.info(f"FLUX image generated and saved to {png_tmp.name}")
|
1074 |
-
return png_tmp.name
|
1075 |
-
|
1076 |
-
return None
|
1077 |
-
|
1078 |
-
except Exception as e:
|
1079 |
-
logger.error(f"Failed to generate FLUX image: {e}")
|
1080 |
-
return None
|
1081 |
-
|
1082 |
def generate_images_parallel(prompt_3d: str, prompt_photo: str) -> Tuple[Optional[str], Optional[str]]:
|
1083 |
"""๋ API๋ฅผ ๋ณ๋ ฌ๋ก ํธ์ถํ์ฌ ์ด๋ฏธ์ง ์์ฑ"""
|
1084 |
import concurrent.futures
|
@@ -1738,13 +1710,13 @@ def create_advanced_ppt_from_content(
|
|
1738 |
# ์ฐ์ธก์ ์๊ฐ์ ์์ ์ถ๊ฐ
|
1739 |
visual_added = False
|
1740 |
|
1741 |
-
if visual_type[0] == 'diagram':
|
1742 |
# ๋ค์ด์ด๊ทธ๋จ ์์ฑ
|
1743 |
logger.info(f"Generating {visual_type[1]} for slide {i+1}")
|
1744 |
diagram_json = generate_diagram_json(slide_title, slide_content, visual_type[1])
|
1745 |
|
1746 |
if diagram_json:
|
1747 |
-
diagram_path =
|
1748 |
if diagram_path and os.path.exists(diagram_path):
|
1749 |
try:
|
1750 |
# ๋ค์ด์ด๊ทธ๋จ ์ด๋ฏธ์ง ์ถ๊ฐ
|
@@ -1755,8 +1727,22 @@ def create_advanced_ppt_from_content(
|
|
1755 |
)
|
1756 |
visual_added = True
|
1757 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1758 |
# ์์ ํ์ผ ์ญ์
|
1759 |
-
|
|
|
|
|
|
|
1760 |
except Exception as e:
|
1761 |
logger.error(f"Failed to add diagram: {e}")
|
1762 |
|
@@ -2264,14 +2250,10 @@ def generate_ppt(
|
|
2264 |
include_flux_images = False
|
2265 |
yield None, "โ ๏ธ FLUX API ์ฐ๊ฒฐ ์คํจ. ํฌํ ๋ฆฌ์ผ๋ฆฌ์คํฑ ์ด๋ฏธ์ง ์์ด ์งํํฉ๋๋ค.", ""
|
2266 |
|
2267 |
-
# ๋ค์ด์ด๊ทธ๋จ
|
2268 |
-
if include_diagrams and not
|
2269 |
-
yield None, "
|
2270 |
-
|
2271 |
-
yield None, "โ
๋ค์ด์ด๊ทธ๋จ API ์ฐ๊ฒฐ ์ฑ๊ณต!", ""
|
2272 |
-
else:
|
2273 |
-
include_diagrams = False
|
2274 |
-
yield None, "โ ๏ธ ๋ค์ด์ด๊ทธ๋จ API ์ฐ๊ฒฐ ์คํจ. ๋ค์ด์ด๊ทธ๋จ ์์ด ์งํํฉ๋๋ค.", ""
|
2275 |
|
2276 |
# Process reference files if provided
|
2277 |
additional_context = ""
|
@@ -2347,7 +2329,7 @@ def generate_ppt(
|
|
2347 |
visual_features = []
|
2348 |
if include_ai_image and FLUX_API_ENABLED:
|
2349 |
visual_features.append("AI 3D ํ์ง ์ด๋ฏธ์ง")
|
2350 |
-
if include_diagrams and
|
2351 |
visual_features.append("๋ค์ด์ด๊ทธ๋จ")
|
2352 |
if include_flux_images and FLUX_API_ENABLED:
|
2353 |
visual_features.append("AI ์์ฑ ์ด๋ฏธ์ง")
|
@@ -2374,7 +2356,7 @@ def generate_ppt(
|
|
2374 |
|
2375 |
if include_ai_image and FLUX_API_ENABLED:
|
2376 |
success_msg += f"๐ผ๏ธ AI ์์ฑ ํ์ง ์ด๋ฏธ์ง ํฌํจ\n"
|
2377 |
-
if include_diagrams and
|
2378 |
success_msg += f"๐ AI ์์ฑ ๋ค์ด์ด๊ทธ๋จ ํฌํจ\n"
|
2379 |
if include_flux_images and FLUX_API_ENABLED:
|
2380 |
success_msg += f"๐จ AI ์์ฑ ์ฌ๋ผ์ด๋ ์ด๋ฏธ์ง ํฌํจ\n"
|
@@ -2574,6 +2556,23 @@ input[type="checkbox"] {
|
|
2574 |
max-height: 500px;
|
2575 |
overflow-y: auto;
|
2576 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2577 |
"""
|
2578 |
|
2579 |
with gr.Blocks(css=css, title="AI PPT Generator Pro") as demo:
|
@@ -2582,7 +2581,7 @@ with gr.Blocks(css=css, title="AI PPT Generator Pro") as demo:
|
|
2582 |
# ๐ฏ AI ๊ธฐ๋ฐ PPT ์๋ ์์ฑ ์์คํ
Pro
|
2583 |
|
2584 |
๊ณ ๊ธ ๋์์ธ ํ
๋ง์ ๋ ์ด์์์ ํ์ฉํ ์ ๋ฌธ์ ์ธ ํ๋ ์ ํ
์ด์
์ ์๋์ผ๋ก ์์ฑํฉ๋๋ค.
|
2585 |
-
|
2586 |
"""
|
2587 |
)
|
2588 |
|
@@ -2678,7 +2677,7 @@ with gr.Blocks(css=css, title="AI PPT Generator Pro") as demo:
|
|
2678 |
include_diagrams = gr.Checkbox(
|
2679 |
label="๐ AI ๋ค์ด์ด๊ทธ๋จ",
|
2680 |
value=False,
|
2681 |
-
info="
|
2682 |
)
|
2683 |
|
2684 |
include_flux_images = gr.Checkbox(
|
@@ -2733,18 +2732,19 @@ with gr.Blocks(css=css, title="AI PPT Generator Pro") as demo:
|
|
2733 |
5. **์ฐธ๊ณ ์๋ฃ ์
๋ก๋**: PDF, CSV, TXT ํ์ผ ์ง์
|
2734 |
6. **์์ฑ ๋ฒํผ ํด๋ฆญ**: AI๊ฐ ์๋์ผ๋ก PPT ์์ฑ
|
2735 |
|
2736 |
-
### ๐จ ์๋ก์ด ๊ธฐ๋ฅ
|
2737 |
-
-
|
2738 |
-
-
|
2739 |
-
- **
|
2740 |
-
-
|
2741 |
-
-
|
|
|
2742 |
|
2743 |
### ๐ก ๊ณ ๊ธ ํ
|
2744 |
-
-
|
2745 |
-
- 3D ์คํ์ผ๊ณผ ํฌํ ๋ฆฌ์ผ๋ฆฌ์คํฑ ์ด๋ฏธ์ง๊ฐ
|
2746 |
-
-
|
2747 |
-
-
|
2748 |
"""
|
2749 |
)
|
2750 |
|
@@ -2755,6 +2755,8 @@ with gr.Blocks(css=css, title="AI PPT Generator Pro") as demo:
|
|
2755 |
["2024๋
๋์งํธ ๋ง์ผํ
ํธ๋ ๋", 12, True, True, [], "modern", "modern", "consistent", False, True, True, True],
|
2756 |
["๊ธฐํ๋ณํ์ ์ง์๊ฐ๋ฅํ ๋ฐ์ ", 15, True, True, [], "nature", "classic", "consistent", False, True, True, True],
|
2757 |
["์คํํธ์
์ฌ์
๊ณํ์", 8, False, True, [], "creative", "modern", "varied", False, True, True, True],
|
|
|
|
|
2758 |
],
|
2759 |
inputs=[topic_input, num_slides, use_web_search, use_korean, reference_files,
|
2760 |
design_theme, font_style, layout_style, include_charts, include_ai_image,
|
@@ -2784,14 +2786,12 @@ with gr.Blocks(css=css, title="AI PPT Generator Pro") as demo:
|
|
2784 |
# Initialize APIs on startup
|
2785 |
if __name__ == "__main__":
|
2786 |
# Try to initialize APIs in parallel
|
2787 |
-
with concurrent.futures.ThreadPoolExecutor(max_workers=
|
2788 |
futures = []
|
2789 |
if AI_IMAGE_API_URL:
|
2790 |
futures.append(executor.submit(initialize_ai_image_api))
|
2791 |
if FLUX_API_URL:
|
2792 |
futures.append(executor.submit(initialize_flux_api))
|
2793 |
-
if DIAGRAM_API_URL:
|
2794 |
-
futures.append(executor.submit(initialize_diagram_api))
|
2795 |
|
2796 |
# Wait for all to complete
|
2797 |
for future in concurrent.futures.as_completed(futures):
|
@@ -2800,4 +2800,11 @@ if __name__ == "__main__":
|
|
2800 |
except Exception as e:
|
2801 |
logger.error(f"API initialization failed: {e}")
|
2802 |
|
2803 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
PPTX_AVAILABLE = False
|
35 |
logger.warning("python-pptx ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ค์น๋์ง ์์์ต๋๋ค. pip install python-pptx")
|
36 |
|
37 |
+
# ๋ค์ด์ด๊ทธ๋จ ์์ฑ๊ธฐ ๋ชจ๋ import ์ถ๊ฐ
|
38 |
+
try:
|
39 |
+
from concept_map_generator import generate_concept_map
|
40 |
+
from synoptic_chart_generator import generate_synoptic_chart
|
41 |
+
from radial_diagram_generator import generate_radial_diagram
|
42 |
+
from process_flow_generator import generate_process_flow_diagram
|
43 |
+
from wbs_diagram_generator import generate_wbs_diagram
|
44 |
+
DIAGRAM_GENERATORS_AVAILABLE = True
|
45 |
+
logger.info("๋ค์ด์ด๊ทธ๋จ ์์ฑ๊ธฐ ๋ชจ๋ ๋ก๋ ์ฑ๊ณต")
|
46 |
+
except ImportError as e:
|
47 |
+
DIAGRAM_GENERATORS_AVAILABLE = False
|
48 |
+
logger.warning(f"๋ค์ด์ด๊ทธ๋จ ์์ฑ๊ธฐ ๋ชจ๋์ ์ฐพ์ ์ ์์ต๋๋ค: {e}")
|
49 |
+
|
50 |
##############################################################################
|
51 |
# API Configuration
|
52 |
##############################################################################
|
|
|
107 |
return False
|
108 |
|
109 |
##############################################################################
|
110 |
+
# Diagram Generation API Configuration - REMOVED (using local generators)
|
111 |
##############################################################################
|
112 |
+
# ๊ธฐ์กด Diagram API ๊ด๋ จ ์ฝ๋ ์ ๊ฑฐํ๊ณ ๋ก์ปฌ ์์ฑ๊ธฐ ์ฌ์ฉ
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
|
114 |
##############################################################################
|
115 |
# Design Themes and Color Schemes
|
|
|
350 |
return 'โถ๏ธ'
|
351 |
|
352 |
##############################################################################
|
353 |
+
# Diagram Type Detection - UPDATED for 6 types
|
354 |
##############################################################################
|
355 |
def detect_diagram_type(title: str, content: str) -> Optional[str]:
|
356 |
"""์ฌ๋ผ์ด๋ ๋ด์ฉ์ ๋ถ์ํ์ฌ ์ ์ ํ ๋ค์ด์ด๊ทธ๋จ ํ์
๊ฒฐ์ """
|
357 |
combined_text = f"{title} {content}".lower()
|
358 |
|
359 |
# Process Flow keywords
|
360 |
+
if any(word in combined_text for word in ['ํ๋ก์ธ์ค', 'process', '์ ์ฐจ', 'procedure', '๋จ๊ณ', 'step', 'flow', 'ํ๋ฆ', '์ํฌํ๋ก์ฐ', 'workflow', '์์', 'sequence']):
|
361 |
return "Process Flow"
|
362 |
|
363 |
# WBS keywords
|
364 |
+
elif any(word in combined_text for word in ['wbs', '์์
๋ถํด', 'ํ๋ก์ ํธ', 'project', '์
๋ฌด๋ถํด', 'breakdown', '๊ตฌ์กฐ๋', '์์
๊ตฌ์กฐ', 'work structure']):
|
365 |
return "WBS Diagram"
|
366 |
|
367 |
# Concept Map keywords
|
368 |
+
elif any(word in combined_text for word in ['๊ฐ๋
', 'concept', '๊ด๊ณ', 'relationship', '์ฐ๊ด', 'connection', '๋ง์ธ๋๋งต', 'mindmap', '๊ตฌ์กฐ', 'structure', '์ฒด๊ณ', 'system']):
|
369 |
return "Concept Map"
|
370 |
|
371 |
# Radial Diagram keywords
|
372 |
+
elif any(word in combined_text for word in ['์ค์ฌ', 'central', '๋ฐฉ์ฌํ', 'radial', 'ํต์ฌ', 'core', '์ฃผ์', 'main', '์ค์', 'center']):
|
373 |
return "Radial Diagram"
|
374 |
|
375 |
# Synoptic Chart keywords
|
376 |
+
elif any(word in combined_text for word in ['๊ฐ์', 'overview', '์ ์ฒด', 'overall', '์์ฝ', 'summary', '์๋ํฑ', 'synoptic', '์ด๊ด', 'comprehensive']):
|
377 |
return "Synoptic Chart"
|
378 |
|
379 |
+
# Default: ํค์๋๊ฐ ์์ผ๋ฉด ๋ด์ฉ์ ํน์ฑ์ ๋ฐ๋ผ ๊ฒฐ์
|
380 |
+
# ๋ฆฌ์คํธ๋ ํญ๋ชฉ์ด ๋ง์ผ๋ฉด Concept Map
|
381 |
+
if content.count('\n-') > 3 or content.count('\nโข') > 3:
|
382 |
+
return "Concept Map"
|
383 |
+
# ์ซ์๊ฐ ์์ผ๋ฉด Process Flow
|
384 |
+
elif any(char in content for char in ['1.', '2.', '3.', 'โ ', 'โก', 'โข']):
|
385 |
+
return "Process Flow"
|
386 |
+
|
387 |
return None
|
388 |
|
389 |
##############################################################################
|
|
|
394 |
if not FRIENDLI_TOKEN:
|
395 |
return None
|
396 |
|
397 |
+
# ๋ค์ด์ด๊ทธ๋จ ํ์
๋ณ JSON ๊ตฌ์กฐ ๊ฐ์ด๋ - paste-2.txt์ ๊ตฌ์กฐ์ ๋์ผํ๊ฒ
|
398 |
json_guides = {
|
399 |
"Concept Map": """Generate a JSON for a concept map with the EXACT following structure:
|
400 |
{
|
|
|
480 |
2. The JSON must follow the EXACT structure shown above
|
481 |
3. Create content based on the provided title and content
|
482 |
4. Use the user's language (Korean or English) for the content values
|
483 |
+
5. Keep it simple with 3-5 main nodes/steps
|
484 |
+
6. For Process Flow: 'type' can be "process", "decision", "start", "end"
|
485 |
+
7. Ensure all connections reference existing node IDs"""
|
486 |
|
487 |
messages = [
|
488 |
{"role": "system", "content": system_prompt},
|
|
|
526 |
return None
|
527 |
|
528 |
##############################################################################
|
529 |
+
# Generate Diagram using Local Generators - NEW
|
530 |
##############################################################################
|
531 |
+
def generate_diagram_locally(json_data: str, diagram_type: str, output_format: str = "png") -> Optional[str]:
|
532 |
+
"""๋ก์ปฌ ์์ฑ๊ธฐ๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์ด์ด๊ทธ๋จ ์์ฑ"""
|
533 |
+
if not DIAGRAM_GENERATORS_AVAILABLE:
|
534 |
+
logger.error("๋ค์ด์ด๊ทธ๋จ ์์ฑ๊ธฐ ๋ชจ๋์ ์ฌ์ฉํ ์ ์์ต๋๋ค")
|
535 |
return None
|
536 |
|
537 |
try:
|
538 |
+
# ์ ์ ํ ์์ฑ๊ธฐ๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์ด์ด๊ทธ๋จ ์์ฑ
|
539 |
+
if diagram_type == "Concept Map":
|
540 |
+
result = generate_concept_map(json_data, output_format)
|
541 |
+
elif diagram_type == "Synoptic Chart":
|
542 |
+
result = generate_synoptic_chart(json_data, output_format)
|
543 |
+
elif diagram_type == "Radial Diagram":
|
544 |
+
result = generate_radial_diagram(json_data, output_format)
|
545 |
+
elif diagram_type == "Process Flow":
|
546 |
+
result = generate_process_flow_diagram(json_data, output_format)
|
547 |
+
elif diagram_type == "WBS Diagram":
|
548 |
+
result = generate_wbs_diagram(json_data, output_format)
|
549 |
+
else:
|
550 |
+
logger.error(f"Unknown diagram type: {diagram_type}")
|
551 |
+
return None
|
552 |
|
553 |
+
# ๊ฒฐ๊ณผ๊ฐ ๋ฌธ์์ด์ด๊ณ ์๋ฌ ๋ฉ์์ง์ธ ๊ฒฝ์ฐ
|
554 |
+
if isinstance(result, str) and result.startswith("Error:"):
|
555 |
+
logger.error(f"Diagram generation error: {result}")
|
556 |
+
return None
|
|
|
|
|
|
|
|
|
557 |
|
558 |
+
# ์ฑ๊ณต์ ์ผ๋ก ์์ฑ๋ ๊ฒฝ์ฐ ํ์ผ ๊ฒฝ๋ก ๋ฐํ
|
559 |
+
return result
|
560 |
|
561 |
except Exception as e:
|
562 |
+
logger.error(f"Failed to generate diagram locally: {e}")
|
563 |
return None
|
564 |
|
565 |
##############################################################################
|
|
|
1051 |
logger.error(f"Failed to generate 3D image: {e}")
|
1052 |
return None
|
1053 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1054 |
def generate_images_parallel(prompt_3d: str, prompt_photo: str) -> Tuple[Optional[str], Optional[str]]:
|
1055 |
"""๋ API๋ฅผ ๋ณ๋ ฌ๋ก ํธ์ถํ์ฌ ์ด๋ฏธ์ง ์์ฑ"""
|
1056 |
import concurrent.futures
|
|
|
1710 |
# ์ฐ์ธก์ ์๊ฐ์ ์์ ์ถ๊ฐ
|
1711 |
visual_added = False
|
1712 |
|
1713 |
+
if visual_type[0] == 'diagram' and DIAGRAM_GENERATORS_AVAILABLE:
|
1714 |
# ๋ค์ด์ด๊ทธ๋จ ์์ฑ
|
1715 |
logger.info(f"Generating {visual_type[1]} for slide {i+1}")
|
1716 |
diagram_json = generate_diagram_json(slide_title, slide_content, visual_type[1])
|
1717 |
|
1718 |
if diagram_json:
|
1719 |
+
diagram_path = generate_diagram_locally(diagram_json, visual_type[1], "png")
|
1720 |
if diagram_path and os.path.exists(diagram_path):
|
1721 |
try:
|
1722 |
# ๋ค์ด์ด๊ทธ๋จ ์ด๋ฏธ์ง ์ถ๊ฐ
|
|
|
1727 |
)
|
1728 |
visual_added = True
|
1729 |
|
1730 |
+
# ๋ค์ด์ด๊ทธ๋จ ์บก์
์ถ๊ฐ
|
1731 |
+
caption_box = slide.shapes.add_textbox(
|
1732 |
+
Inches(5.2), Inches(4.6), Inches(4.3), Inches(0.3)
|
1733 |
+
)
|
1734 |
+
caption_tf = caption_box.text_frame
|
1735 |
+
caption_tf.text = f"{visual_type[1]} Diagram"
|
1736 |
+
caption_p = caption_tf.paragraphs[0]
|
1737 |
+
caption_p.font.size = Pt(10)
|
1738 |
+
caption_p.font.color.rgb = theme['colors']['secondary']
|
1739 |
+
caption_p.alignment = PP_ALIGN.CENTER
|
1740 |
+
|
1741 |
# ์์ ํ์ผ ์ญ์
|
1742 |
+
try:
|
1743 |
+
os.unlink(diagram_path)
|
1744 |
+
except:
|
1745 |
+
pass
|
1746 |
except Exception as e:
|
1747 |
logger.error(f"Failed to add diagram: {e}")
|
1748 |
|
|
|
2250 |
include_flux_images = False
|
2251 |
yield None, "โ ๏ธ FLUX API ์ฐ๊ฒฐ ์คํจ. ํฌํ ๋ฆฌ์ผ๋ฆฌ์คํฑ ์ด๋ฏธ์ง ์์ด ์งํํฉ๋๋ค.", ""
|
2252 |
|
2253 |
+
# ๋ค์ด์ด๊ทธ๋จ ์์ฑ๊ธฐ ํ์ธ
|
2254 |
+
if include_diagrams and not DIAGRAM_GENERATORS_AVAILABLE:
|
2255 |
+
yield None, "โ ๏ธ ๋ค์ด์ด๊ทธ๋จ ์์ฑ๊ธฐ ๋ชจ๋์ ์ฐพ์ ์ ์์ต๋๋ค. ๋ค์ด์ด๊ทธ๋จ ์์ด ์งํํฉ๋๋ค.", ""
|
2256 |
+
include_diagrams = False
|
|
|
|
|
|
|
|
|
2257 |
|
2258 |
# Process reference files if provided
|
2259 |
additional_context = ""
|
|
|
2329 |
visual_features = []
|
2330 |
if include_ai_image and FLUX_API_ENABLED:
|
2331 |
visual_features.append("AI 3D ํ์ง ์ด๋ฏธ์ง")
|
2332 |
+
if include_diagrams and DIAGRAM_GENERATORS_AVAILABLE:
|
2333 |
visual_features.append("๋ค์ด์ด๊ทธ๋จ")
|
2334 |
if include_flux_images and FLUX_API_ENABLED:
|
2335 |
visual_features.append("AI ์์ฑ ์ด๋ฏธ์ง")
|
|
|
2356 |
|
2357 |
if include_ai_image and FLUX_API_ENABLED:
|
2358 |
success_msg += f"๐ผ๏ธ AI ์์ฑ ํ์ง ์ด๋ฏธ์ง ํฌํจ\n"
|
2359 |
+
if include_diagrams and DIAGRAM_GENERATORS_AVAILABLE:
|
2360 |
success_msg += f"๐ AI ์์ฑ ๋ค์ด์ด๊ทธ๋จ ํฌํจ\n"
|
2361 |
if include_flux_images and FLUX_API_ENABLED:
|
2362 |
success_msg += f"๐จ AI ์์ฑ ์ฌ๋ผ์ด๋ ์ด๋ฏธ์ง ํฌํจ\n"
|
|
|
2556 |
max-height: 500px;
|
2557 |
overflow-y: auto;
|
2558 |
}
|
2559 |
+
|
2560 |
+
/* ๋ฐ์ํ ๋์์ธ */
|
2561 |
+
@media (max-width: 768px) {
|
2562 |
+
.main-container {
|
2563 |
+
padding: 15px;
|
2564 |
+
margin: 10px;
|
2565 |
+
}
|
2566 |
+
|
2567 |
+
.header-section h1 {
|
2568 |
+
font-size: 2em;
|
2569 |
+
}
|
2570 |
+
|
2571 |
+
.gr-tab-item {
|
2572 |
+
padding: 10px 15px;
|
2573 |
+
font-size: 1em;
|
2574 |
+
}
|
2575 |
+
}
|
2576 |
"""
|
2577 |
|
2578 |
with gr.Blocks(css=css, title="AI PPT Generator Pro") as demo:
|
|
|
2581 |
# ๐ฏ AI ๊ธฐ๋ฐ PPT ์๋ ์์ฑ ์์คํ
Pro
|
2582 |
|
2583 |
๊ณ ๊ธ ๋์์ธ ํ
๋ง์ ๋ ์ด์์์ ํ์ฉํ ์ ๋ฌธ์ ์ธ ํ๋ ์ ํ
์ด์
์ ์๋์ผ๋ก ์์ฑํฉ๋๋ค.
|
2584 |
+
6๊ฐ์ง ๋ค์ด์ด๊ทธ๋จ ํ์
๊ณผ AI ์์ฑ ์ด๋ฏธ์ง๋ฅผ ํฌํจํ์ฌ ์๊ฐ์ ์ผ๋ก ํ๋ถํ PPT๋ฅผ ๋ง๋ญ๋๋ค.
|
2585 |
"""
|
2586 |
)
|
2587 |
|
|
|
2677 |
include_diagrams = gr.Checkbox(
|
2678 |
label="๐ AI ๋ค์ด์ด๊ทธ๋จ",
|
2679 |
value=False,
|
2680 |
+
info="6๊ฐ์ง ํ์
์ ๋ค์ด์ด๊ทธ๋จ ์๋ ์์ฑ"
|
2681 |
)
|
2682 |
|
2683 |
include_flux_images = gr.Checkbox(
|
|
|
2732 |
5. **์ฐธ๊ณ ์๋ฃ ์
๋ก๋**: PDF, CSV, TXT ํ์ผ ์ง์
|
2733 |
6. **์์ฑ ๋ฒํผ ํด๋ฆญ**: AI๊ฐ ์๋์ผ๋ก PPT ์์ฑ
|
2734 |
|
2735 |
+
### ๐จ ์๋ก์ด ๊ธฐ๋ฅ - 6๊ฐ์ง ๋ค์ด์ด๊ทธ๋จ ํ์
|
2736 |
+
- **Process Flow**: ํ๋ก์ธ์ค์ ์ํฌํ๋ก์ฐ๋ฅผ ์๊ฐํ
|
2737 |
+
- **Concept Map**: ๊ฐ๋
๊ณผ ๊ด๊ณ๋ฅผ ๊ตฌ์กฐํํ์ฌ ํํ
|
2738 |
+
- **WBS Diagram**: ํ๋ก์ ํธ ์์
๋ถํด ๊ตฌ์กฐ๋
|
2739 |
+
- **Radial Diagram**: ์ค์ฌ ๊ฐ๋
๊ณผ ๊ด๋ จ ์์๋ค์ ๋ฐฉ์ฌํ ํํ
|
2740 |
+
- **Synoptic Chart**: ์ ์ฒด ๊ฐ์์ ์์ฝ์ ํ๋์ ๋ณด์ฌ์ฃผ๋ ์ฐจํธ
|
2741 |
+
- **์๋ ๊ฐ์ง**: ์ฌ๋ผ์ด๋ ๋ด์ฉ์ ๋ถ์ํ์ฌ ์ ์ ํ ๋ค์ด์ด๊ทธ๋จ ํ์
์๋ ์ ํ
|
2742 |
|
2743 |
### ๐ก ๊ณ ๊ธ ํ
|
2744 |
+
- **๋ค์ด์ด๊ทธ๋จ ์๋ ์์ฑ**: ์ฌ๋ผ์ด๋ ๋ด์ฉ์ ๋ฐ๋ผ 6๊ฐ์ง ๋ค์ด์ด๊ทธ๋จ ์ค ๊ฐ์ฅ ์ ํฉํ ํ์
์ด ์๋์ผ๋ก ์ ํ๋ฉ๋๋ค
|
2745 |
+
- **๋ณ๋ ฌ ์ด๋ฏธ์ง ์์ฑ**: 3D ์คํ์ผ๊ณผ ํฌํ ๋ฆฌ์ผ๋ฆฌ์คํฑ ์ด๋ฏธ์ง๊ฐ ๋์์ ์์ฑ๋์ด ์๊ฐ์ด ์ ์ฝ๋ฉ๋๋ค
|
2746 |
+
- **์ค๋งํธ ๋ฐฐ์น**: ๋ค์ด์ด๊ทธ๋จ๊ณผ ์ด๋ฏธ์ง๋ ํ
์คํธ์ ๊ฒน์น์ง ์๋๋ก ์ฐ์ธก์ ์๋ ๋ฐฐ์น๋ฉ๋๋ค
|
2747 |
+
- **ํค์๋ ๊ธฐ๋ฐ ๊ฐ์ง**: ํ๋ก์ธ์ค, ๊ฐ๋
, ํ๋ก์ ํธ, ์ค์ฌ, ๊ฐ์ ๋ฑ์ ํค์๋๋ฅผ ๊ฐ์งํ์ฌ ๋ค์ด์ด๊ทธ๋จ ํ์
์ ๊ฒฐ์ ํฉ๋๋ค
|
2748 |
"""
|
2749 |
)
|
2750 |
|
|
|
2755 |
["2024๋
๋์งํธ ๋ง์ผํ
ํธ๋ ๋", 12, True, True, [], "modern", "modern", "consistent", False, True, True, True],
|
2756 |
["๊ธฐํ๋ณํ์ ์ง์๊ฐ๋ฅํ ๋ฐ์ ", 15, True, True, [], "nature", "classic", "consistent", False, True, True, True],
|
2757 |
["์คํํธ์
์ฌ์
๊ณํ์", 8, False, True, [], "creative", "modern", "varied", False, True, True, True],
|
2758 |
+
["ํ๋ก์ ํธ ๊ด๋ฆฌ ๋ฐฉ๋ฒ๋ก ", 10, False, True, [], "professional", "modern", "consistent", False, False, True, False],
|
2759 |
+
["๋จธ์ ๋ฌ๋ ํ๋ก์ธ์ค ๊ฐ์ด๋", 12, False, True, [], "modern", "modern", "consistent", False, False, True, False],
|
2760 |
],
|
2761 |
inputs=[topic_input, num_slides, use_web_search, use_korean, reference_files,
|
2762 |
design_theme, font_style, layout_style, include_charts, include_ai_image,
|
|
|
2786 |
# Initialize APIs on startup
|
2787 |
if __name__ == "__main__":
|
2788 |
# Try to initialize APIs in parallel
|
2789 |
+
with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor:
|
2790 |
futures = []
|
2791 |
if AI_IMAGE_API_URL:
|
2792 |
futures.append(executor.submit(initialize_ai_image_api))
|
2793 |
if FLUX_API_URL:
|
2794 |
futures.append(executor.submit(initialize_flux_api))
|
|
|
|
|
2795 |
|
2796 |
# Wait for all to complete
|
2797 |
for future in concurrent.futures.as_completed(futures):
|
|
|
2800 |
except Exception as e:
|
2801 |
logger.error(f"API initialization failed: {e}")
|
2802 |
|
2803 |
+
# ๋ค์ด์ด๊ทธ๋จ ์์ฑ๊ธฐ ๋ชจ๋ ์ํ ํ์ธ
|
2804 |
+
if DIAGRAM_GENERATORS_AVAILABLE:
|
2805 |
+
logger.info("โ
๋ค์ด์ด๊ทธ๋จ ์์ฑ๊ธฐ ๋ชจ๋์ด ์ ์์ ์ผ๋ก ๋ก๋๋์์ต๋๋ค")
|
2806 |
+
logger.info("์ง์๋๋ ๋ค์ด์ด๊ทธ๋จ ํ์
: Process Flow, Concept Map, WBS, Radial, Synoptic Chart")
|
2807 |
+
else:
|
2808 |
+
logger.warning("โ ๏ธ ๋ค์ด์ด๊ทธ๋จ ์์ฑ๊ธฐ ๋ชจ๋์ ์ฐพ์ ์ ์์ต๋๋ค. ๋ค์ด์ด๊ทธ๋จ ๊ธฐ๋ฅ์ด ๋นํ์ฑํ๋ฉ๋๋ค.")
|
2809 |
+
|
2810 |
+
demo.launch()
|