openfree commited on
Commit
b3fc026
ยท
verified ยท
1 Parent(s): 58eebcc

Update app-BACKUP.py

Browse files
Files changed (1) hide show
  1. 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
- DIAGRAM_API_URL = "http://211.233.58.201:7860" # ChartGPT API URL
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 API
524
  ##############################################################################
525
- def generate_diagram_via_api(json_data: str, diagram_type: str) -> Optional[str]:
526
- """๋‹ค์ด์–ด๊ทธ๋žจ API๋ฅผ ํ†ตํ•ด ๋‹ค์ด์–ด๊ทธ๋žจ ์ƒ์„ฑ"""
527
- if not DIAGRAM_API_ENABLED or not diagram_api_client:
 
528
  return None
529
 
530
  try:
531
- # API ํ˜ธ์ถœ
532
- result = diagram_api_client.predict(
533
- prompt_input=f"Generate {diagram_type}", # ํ”„๋กฌํ”„ํŠธ
534
- diagram_type_select=diagram_type, # ๋‹ค์ด์–ด๊ทธ๋žจ ํƒ€์ž…
535
- design_type_select="None", # ๋””์ž์ธ ํƒ€์ž…์€ None
536
- output_format_radio="png", # PNG ํ˜•์‹
537
- use_search_checkbox=False, # ๊ฒ€์ƒ‰ ์‚ฌ์šฉ ์•ˆํ•จ
538
- api_name="/generate_with_llm"
539
- )
 
 
 
 
 
540
 
541
- # ๊ฒฐ๊ณผ์—์„œ ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ ์ถ”์ถœ
542
- if isinstance(result, tuple) and len(result) > 0:
543
- image_path = result[0]
544
- if image_path and os.path.exists(image_path):
545
- # ์ž„์‹œ ํŒŒ์ผ๋กœ ๋ณต์‚ฌ
546
- with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmp:
547
- shutil.copy2(image_path, tmp.name)
548
- return tmp.name
549
 
550
- return None
 
551
 
552
  except Exception as e:
553
- logger.error(f"Failed to generate diagram via API: {e}")
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 = generate_diagram_via_api(diagram_json, visual_type[1])
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
- os.unlink(diagram_path)
 
 
 
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
- # ๋‹ค์ด์–ด๊ทธ๋žจ API ์ดˆ๊ธฐํ™”
2268
- if include_diagrams and not DIAGRAM_API_ENABLED:
2269
- yield None, "๐Ÿ”„ ๋‹ค์ด์–ด๊ทธ๋žจ ์ƒ์„ฑ API์— ์—ฐ๊ฒฐํ•˜๋Š” ์ค‘...", ""
2270
- if initialize_diagram_api():
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 DIAGRAM_API_ENABLED:
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 DIAGRAM_API_ENABLED:
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
- FLUX AI๋กœ ์ƒ์„ฑํ•œ ๊ณ ํ’ˆ์งˆ ์ด๋ฏธ์ง€์™€ ๋‹ค์ด์–ด๊ทธ๋žจ์„ ํฌํ•จํ•˜์—ฌ ์‹œ๊ฐ์ ์œผ๋กœ ํ’๋ถ€ํ•œ PPT๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
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
- - **๋ณ‘๋ ฌ AI ์ด๋ฏธ์ง€ ์ƒ์„ฑ**: 3D ์Šคํƒ€์ผ๊ณผ ํฌํ† ๋ฆฌ์–ผ๋ฆฌ์Šคํ‹ฑ API๋ฅผ ๋™์‹œ์— ์‚ฌ์šฉํ•˜์—ฌ ์ƒ์„ฑ ์‹œ๊ฐ„ ๋‹จ์ถ•
2738
- - **๋‹ค์–‘ํ•œ ์ด๋ฏธ์ง€ ์Šคํƒ€์ผ**: ๊ฐ ์Šฌ๋ผ์ด๋“œ๋งˆ๋‹ค ๋‹ค๋ฅธ ์Šคํƒ€์ผ๊ณผ ๋ฉ”ํƒ€ํฌ๋กœ ์ด๋ฏธ์ง€ ์ƒ์„ฑ
2739
- - **AI ํ‘œ์ง€ ์ด๋ฏธ์ง€**: ์šฐ์ธก ํ•˜๋‹จ ๋ฐฐ์น˜๋กœ ํ…์ŠคํŠธ์™€ ๊ฒน์น˜์ง€ ์•Š์Œ
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=3) as executor:
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
- demo.launch()
 
 
 
 
 
 
 
 
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()