openfree commited on
Commit
ee12bfb
ยท
verified ยท
1 Parent(s): 432e12b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +1881 -23
app.py CHANGED
@@ -1,37 +1,1895 @@
1
- #๋ฐฑ์—… ์ฝ”๋“œ: openfree/Chart-GPT-BACKUP
 
2
 
3
  import os
4
- import sys
5
- import streamlit as st
6
- from tempfile import NamedTemporaryFile
 
 
 
 
 
7
 
8
- def main():
9
- try:
10
- # Get the code from secrets
11
- code = os.environ.get("MAIN_CODE")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
- if not code:
14
- st.error("โš ๏ธ The application code wasn't found in secrets. Please add the MAIN_CODE secret.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  return
16
 
17
- # Create a temporary Python file
18
- with NamedTemporaryFile(suffix='.py', delete=False, mode='w') as tmp:
19
- tmp.write(code)
20
- tmp_path = tmp.name
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
- # Execute the code
23
- exec(compile(code, tmp_path, 'exec'), globals())
 
 
24
 
25
- # Clean up the temporary file
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  try:
27
- os.unlink(tmp_path)
28
- except:
29
- pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  except Exception as e:
32
- st.error(f"โš ๏ธ Error loading or executing the application: {str(e)}")
33
  import traceback
34
- st.code(traceback.format_exc())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
 
36
  if __name__ == "__main__":
37
- main()
 
 
1
+ # app.py
2
+ """Main PPT Generator with 3-AI collaboration system"""
3
 
4
  import os
5
+ import re
6
+ import json
7
+ import time
8
+ import logging
9
+ import gradio as gr
10
+ import requests
11
+ from typing import List, Dict, Generator
12
+ from datetime import datetime
13
 
14
+ # Import separated modules
15
+ from constants import (
16
+ EXAMPLE_TOPICS, AUDIENCE_TYPES, DESIGN_THEMES,
17
+ STYLE_TEMPLATES, PPT_TEMPLATES, SLIDE_TITLE_TRANSLATIONS
18
+ )
19
+ from content_utils import (
20
+ parse_executor_response, extract_relevant_content_from_executor,
21
+ extract_slide_section_from_executor, parse_slide_section,
22
+ extract_speaker_notes_from_section, read_uploaded_file,
23
+ generate_dynamic_slides, brave_search, generate_slide_content,
24
+ generate_presentation_notes, generate_closing_notes,
25
+ generate_conclusion_phrase, generate_prompt_with_llm,
26
+ generate_image, create_slide_preview_html, create_pptx_file,
27
+ PROCESS_FLOW_AVAILABLE
28
+ )
29
+ from ui_components import (
30
+ create_custom_slides_ui, load_example, update_audience_info,
31
+ update_theme_preview, update_template_info, update_custom_slides_visibility,
32
+ clear_all, get_css, get_usage_instructions
33
+ )
34
+
35
+ # Logging setup
36
+ logging.basicConfig(level=logging.INFO)
37
+ logger = logging.getLogger(__name__)
38
+
39
+ # Environment variables
40
+ REPLICATE_API_TOKEN = os.getenv("RAPI_TOKEN")
41
+ FRIENDLI_TOKEN = os.getenv("FRIENDLI_TOKEN")
42
+ BRAVE_API_TOKEN = os.getenv("BAPI_TOKEN")
43
+ API_URL = "https://api.friendli.ai/dedicated/v1/chat/completions"
44
+ BRAVE_SEARCH_URL = "https://api.search.brave.com/res/v1/web/search"
45
+ MODEL_ID = "dep89a2fld32mcm"
46
+ TEST_MODE = os.getenv("TEST_MODE", "false").lower() == "true"
47
+
48
+ # Global variables
49
+ current_slides_data = []
50
+ current_topic = ""
51
+ current_template = ""
52
+ current_theme = ""
53
+ uploaded_content = ""
54
+ current_language = "English"
55
+ conversation_history = []
56
+
57
+ # ===== ํ•ต์‹ฌ: 3์ž ํ˜‘์˜ ์‹œ์Šคํ…œ ํด๋ž˜์Šค =====
58
+ class PPTCreationSystem:
59
+ def __init__(self):
60
+ self.token = FRIENDLI_TOKEN
61
+ self.bapi_token = BRAVE_API_TOKEN
62
+ self.api_url = API_URL
63
+ self.brave_url = BRAVE_SEARCH_URL
64
+ self.model_id = MODEL_ID
65
+ self.test_mode = TEST_MODE or (self.token == "YOUR_FRIENDLI_TOKEN")
66
+
67
+ if self.test_mode:
68
+ logger.warning("ํ…Œ์ŠคํŠธ ๋ชจ๋“œ๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.")
69
+ if self.bapi_token == "YOUR_BRAVE_API_TOKEN":
70
+ logger.warning("Brave API ํ† ํฐ์ด ์„ค์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.")
71
+
72
+ def create_headers(self):
73
+ """API ํ—ค๋” ์ƒ์„ฑ"""
74
+ return {
75
+ "Authorization": f"Bearer {self.token}",
76
+ "Content-Type": "application/json"
77
+ }
78
+
79
+ def create_brave_headers(self):
80
+ """Brave API ํ—ค๋” ์ƒ์„ฑ"""
81
+ return {
82
+ "Accept": "application/json",
83
+ "Accept-Encoding": "gzip",
84
+ "X-Subscription-Token": self.bapi_token
85
+ }
86
+
87
+ def create_supervisor_initial_prompt(self, ppt_topic: str) -> str:
88
+ """๊ฐ๋…์ž AI ์ดˆ๊ธฐ ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ - PPT ๊ตฌ์กฐ ์„ค๊ณ„"""
89
+ return f"""๋‹น์‹ ์€ ์ „๋ฌธ์ ์ธ PPT ๊ตฌ์กฐ๋ฅผ ์„ค๊ณ„ํ•˜๋Š” ๊ฐ๋…์ž AI์ž…๋‹ˆ๋‹ค.
90
+
91
+ PPT ์ฃผ์ œ: {ppt_topic}
92
+
93
+ ์ด ์ฃผ์ œ์— ๋Œ€ํ•œ ์ „๋ฌธ์ ์ธ PPT๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด:
94
+
95
+ 1. **PPT ์ „์ฒด ๊ตฌ์กฐ ์„ค๊ณ„**
96
+ - ๋ชฉ์ ๊ณผ ํ•ต์‹ฌ ๋ฉ”์‹œ์ง€ ์ •์˜
97
+ - ํƒ€๊ฒŸ ์ฒญ์ค‘ ๋ถ„์„ ๋ฐ ํ†ค ์„ค์ •
98
+ - ์ „์ฒด ์Šฌ๋ผ์ด๋“œ ๊ฐœ์ˆ˜ ๋ฐ ํ๋ฆ„ ์„ค๊ณ„ (10-15์žฅ ๊ถŒ์žฅ)
99
+
100
+ 2. **์„น์…˜๋ณ„ ๊ตฌ์„ฑ ์ œ์•ˆ**
101
+ - ๋„์ž…๋ถ€ (ํ‘œ์ง€, ๋ชฉ์ฐจ, ๋ฐฐ๊ฒฝ)
102
+ - ๋ณธ๋ก  (ํ•ต์‹ฌ ๋‚ด์šฉ 3-4๊ฐœ ์„น์…˜)
103
+ - ๊ฒฐ๋ก ๋ถ€ (์š”์•ฝ, ์‹œ์‚ฌ์ , Q&A)
104
+
105
+ 3. **์กฐ์‚ฌ๊ฐ€ ํ•„์š”ํ•œ ํ•ต์‹ฌ ํ‚ค์›Œ๋“œ**
106
+ ์ด ์ฃผ์ œ์˜ PPT๋ฅผ ์œ„ํ•ด ์กฐ์‚ฌ๊ฐ€ ํ•„์š”ํ•œ 5-7๊ฐœ์˜ ๊ตฌ์ฒด์ ์ธ ํ‚ค์›Œ๋“œ๋‚˜ ๊ฒ€์ƒ‰์–ด๋ฅผ ์ œ์‹œํ•˜์„ธ์š”.
107
+
108
+ ํ‚ค์›Œ๋“œ๋Š” ๋‹ค์Œ ํ˜•์‹์œผ๋กœ ์ œ์‹œํ•˜์„ธ์š”:
109
+ [๊ฒ€์ƒ‰ ํ‚ค์›Œ๋“œ]: ํ‚ค์›Œ๋“œ1, ํ‚ค์›Œ๋“œ2, ํ‚ค์›Œ๋“œ3, ํ‚ค์›Œ๋“œ4, ํ‚ค์›Œ๋“œ5"""
110
+
111
+ def create_researcher_prompt(self, ppt_topic: str, supervisor_guidance: str, search_results: Dict[str, List[Dict]]) -> str:
112
+ """์กฐ์‚ฌ์ž AI ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ - PPT ์ฝ˜ํ…์ธ  ์กฐ์‚ฌ"""
113
+ search_summary = ""
114
+ all_results = []
115
+
116
+ for keyword, results in search_results.items():
117
+ search_summary += f"\n\n**{keyword}์— ๋Œ€ํ•œ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ:**\n"
118
+ for i, result in enumerate(results[:10], 1): # ์ƒ์œ„ 10๊ฐœ๋งŒ ํ‘œ์‹œ
119
+ search_summary += f"{i}. {result.get('title', 'N/A')} (์‹ ๋ขฐ๋„: {result.get('credibility_score', 0):.2f})\n"
120
+ search_summary += f" - {result.get('description', 'N/A')}\n"
121
+ search_summary += f" - ์ถœ์ฒ˜: {result.get('url', 'N/A')}\n"
122
+ if result.get('published'):
123
+ search_summary += f" - ๊ฒŒ์‹œ์ผ: {result.get('published')}\n"
124
+
125
+ all_results.extend(results)
126
+
127
+ # ๏ฟฝ๏ฟฝ์ˆœ ๊ฐ์ง€
128
+ contradictions = self.detect_contradictions(all_results)
129
+ contradiction_text = ""
130
+ if contradictions:
131
+ contradiction_text = "\n\n**๋ฐœ๊ฒฌ๋œ ์ •๋ณด ๋ชจ์ˆœ:**\n"
132
+ for cont in contradictions[:3]: # ์ตœ๋Œ€ 3๊ฐœ๋งŒ ํ‘œ์‹œ
133
+ contradiction_text += f"- {cont['type']}: {cont['source1']} vs {cont['source2']}\n"
134
+
135
+ return f"""๋‹น์‹ ์€ PPT ์ฝ˜ํ…์ธ ๋ฅผ ์œ„ํ•œ ์ •๋ณด๋ฅผ ์กฐ์‚ฌํ•˜๊ณ  ์ •๋ฆฌํ•˜๋Š” ์กฐ์‚ฌ์ž AI์ž…๋‹ˆ๋‹ค.
136
+
137
+ PPT ์ฃผ์ œ: {ppt_topic}
138
+
139
+ ๊ฐ๋…์ž AI์˜ ๊ตฌ์กฐ ์„ค๊ณ„:
140
+ {supervisor_guidance}
141
+
142
+ ๋ธŒ๋ ˆ์ด๋ธŒ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ (์‹ ๋ขฐ๋„ ์ ์ˆ˜ ํฌํ•จ):
143
+ {search_summary}
144
+ {contradiction_text}
145
+
146
+ ์œ„ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ PPT์— ํฌํ•จํ•  ํ•ต์‹ฌ ์ฝ˜ํ…์ธ ๋ฅผ ์ •๋ฆฌํ•˜์„ธ์š”:
147
+
148
+ 1. **์‹œ๊ฐ์  ์ž๋ฃŒ ๊ฐ€๋Šฅํ•œ ํ†ต๊ณ„/์ˆ˜์น˜**
149
+ - ๊ทธ๋ž˜ํ”„๋‚˜ ์ฐจํŠธ๋กœ ํ‘œํ˜„ ๊ฐ€๋Šฅํ•œ ๋ฐ์ดํ„ฐ
150
+ - ์ธํฌ๊ทธ๋ž˜ํ”ฝ์œผ๋กœ ๋ณ€ํ™˜ ๊ฐ€๋Šฅํ•œ ์ •๋ณด
151
+
152
+ 2. **ํ•ต์‹ฌ ์ธ์‚ฌ์ดํŠธ์™€ ํŠธ๋ Œ๋“œ**
153
+ - ์ฒญ์ค‘์˜ ๊ด€์‹ฌ์„ ๋Œ ์ˆ˜ ์žˆ๋Š” ์ตœ์‹  ์ •๋ณด
154
+ - ์—…๊ณ„ ๋™ํ–ฅ๊ณผ ๋ฏธ๋ž˜ ์ „๋ง
155
+
156
+ 3. **์‚ฌ๋ก€ ์—ฐ๊ตฌ ๋ฐ ์„ฑ๊ณต ์Šคํ† ๋ฆฌ**
157
+ - ์‹ค์ œ ์ ์šฉ ์‚ฌ๋ก€
158
+ - ๋ฒค์น˜๋งˆํฌํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋ฒ” ์‚ฌ๋ก€
159
+
160
+ 4. **์ „๋ฌธ๊ฐ€ ์˜๊ฒฌ ๋ฐ ์ธ์šฉ๊ตฌ**
161
+ - ๊ถŒ์œ„ ์žˆ๋Š” ์ถœ์ฒ˜์˜ ์˜๊ฒฌ
162
+ - PPT์— ์ธ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ช…์–ธ
163
+
164
+ 5. **์‹œ๊ฐ ์ž๋ฃŒ ์ถ”์ฒœ**
165
+ - ๊ฐ ์Šฌ๋ผ์ด๋“œ์— ์ ํ•ฉํ•œ ์ด๋ฏธ์ง€/์•„์ด์ฝ˜ ์ œ์•ˆ
166
+ - ๋„ํ‘œ๋‚˜ ๋‹ค์ด์–ด๊ทธ๋žจ ์•„์ด๋””์–ด"""
167
+
168
+ def create_supervisor_execution_prompt(self, ppt_topic: str, research_summary: str) -> str:
169
+ """๊ฐ๋…์ž AI์˜ ์‹คํ–‰ ์ง€์‹œ ํ”„๋กฌํ”„ํŠธ - PPT ์ œ์ž‘ ์ง€์‹œ"""
170
+ return f"""๋‹น์‹ ์€ PPT ์ œ์ž‘์„ ์ด๊ด„ํ•˜๋Š” ๊ฐ๋…์ž AI์ž…๋‹ˆ๋‹ค.
171
+
172
+ PPT ์ฃผ์ œ: {ppt_topic}
173
+
174
+ ์กฐ์‚ฌ์ž AI๊ฐ€ ์ •๋ฆฌํ•œ ์ฝ˜ํ…์ธ :
175
+ {research_summary}
176
+
177
+ ์œ„ ์กฐ์‚ฌ ๋‚ด์šฉ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์‹คํ–‰์ž AI์—๊ฒŒ ๊ตฌ์ฒด์ ์ธ PPT ์ œ์ž‘ ์ง€์‹œ๋ฅผ ๋‚ด๋ ค์ฃผ์„ธ์š”:
178
+
179
+ 1. **์Šฌ๋ผ์ด๋“œ๋ณ„ ์ƒ์„ธ ๊ตฌ์„ฑ**
180
+ - ๊ฐ ์Šฌ๋ผ์ด๋“œ์˜ ์ œ๋ชฉ๊ณผ ํ•ต์‹ฌ ๋ฉ”์‹œ์ง€
181
+ - ํฌํ•จํ•  ๊ตฌ์ฒด์ ์ธ ์ฝ˜ํ…์ธ  ์ง€์ •
182
+ - ์‹œ๊ฐ ์ž๋ฃŒ ๋ฐฐ์น˜ ๋ฐฉ์•ˆ
183
+
184
+ 2. **๋””์ž์ธ ๊ฐ€์ด๋“œ๋ผ์ธ**
185
+ - ์ „์ฒด์ ์ธ ํ†ค๊ณผ ์Šคํƒ€์ผ (์ „๋ฌธ์ /์ฐฝ์˜์ /๋ฏธ๋‹ˆ๋ฉ€ ๋“ฑ)
186
+ - ์ƒ‰์ƒ ํŒ”๋ ˆํŠธ ์ œ์•ˆ
187
+ - ํฐํŠธ ๋ฐ ๋ ˆ์ด์•„์›ƒ ์›์น™
188
+
189
+ 3. **์Šคํ† ๋ฆฌํ…”๋ง ์ „๋žต**
190
+ - ๋„์ž…๋ถ€์—์„œ ์ฒญ์ค‘์˜ ๊ด€์‹ฌ์„ ๋„๋Š” ๋ฐฉ๋ฒ•
191
+ - ํ•ต์‹ฌ ๋ฉ”์‹œ์ง€ ์ „๋‹ฌ ์ˆœ์„œ
192
+ - ๊ฒฐ๋ก ๋ถ€์˜ ์ž„ํŒฉํŠธ ์žˆ๋Š” ๋งˆ๋ฌด๋ฆฌ
193
+
194
+ 4. **์‹œ๊ฐํ™” ์ง€์นจ**
195
+ - ๊ฐ ๋ฐ์ดํ„ฐ์˜ ์ตœ์  ์‹œ๊ฐํ™” ๋ฐฉ๋ฒ•
196
+ - ๋ณต์žกํ•œ ๊ฐœ๋…์˜ ๋‹จ์ˆœํ™” ๋ฐฉ์•ˆ
197
+ - ์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ ์ œ์•ˆ"""
198
+
199
+ def create_executor_prompt(self, ppt_topic: str, supervisor_guidance: str, research_summary: str) -> str:
200
+ """์‹คํ–‰์ž AI ํ”„๋กฌํ”„ํŠธ ์ƒ์„ฑ - PPT ์Šฌ๋ผ์ด๋“œ ์ž‘์„ฑ"""
201
+ return f"""๋‹น์‹ ์€ ์‹ค์ œ PPT ์Šฌ๋ผ์ด๋“œ ๋‚ด์šฉ์„ ์ž‘์„ฑํ•˜๋Š” ์‹คํ–‰์ž AI์ž…๋‹ˆ๋‹ค.
202
+
203
+ PPT ์ฃผ์ œ: {ppt_topic}
204
+
205
+ ์กฐ์‚ฌ์ž AI๊ฐ€ ์ •๋ฆฌํ•œ ์ฝ˜ํ…์ธ :
206
+ {research_summary}
207
+
208
+ ๊ฐ๋…์ž AI์˜ ์ œ์ž‘ ์ง€์‹œ:
209
+ {supervisor_guidance}
210
+
211
+ ์œ„ ์ •๋ณด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์‹ค์ œ PPT ์Šฌ๋ผ์ด๋“œ๋ฅผ ์ž‘์„ฑํ•˜์„ธ์š”:
212
+
213
+ 1. **๊ฐ ์Šฌ๋ผ์ด๋“œ๋ฅผ ๋‹ค์Œ ํ˜•์‹์œผ๋กœ ์ž‘์„ฑ**:
214
+ [์Šฌ๋ผ์ด๋“œ X]
215
+ ์ œ๋ชฉ:
216
+ ๋ถ€์ œ๋ชฉ: (์„ ํƒ์‚ฌํ•ญ)
217
+ โ€ข ๐ŸŽฏ ์ฒซ ๋ฒˆ์งธ ํ•ต์‹ฌ ํฌ์ธํŠธ
218
+ โ€ข ๐Ÿ’ก ๋‘ ๋ฒˆ์งธ ํ•ต์‹ฌ ํฌ์ธํŠธ
219
+ โ€ข ๐Ÿš€ ์„ธ ๋ฒˆ์งธ ํ•ต์‹ฌ ํฌ์ธํŠธ
220
+ โ€ข โœ… ๋„ค ๋ฒˆ์งธ ํ•ต์‹ฌ ํฌ์ธํŠธ
221
+ โ€ข ๐Ÿ“Š ๋‹ค์„ฏ ๋ฒˆ์งธ ํ•ต์‹ฌ ํฌ์ธํŠธ
222
+ ๋ฐœํ‘œ์ž ๋…ธํŠธ: (์‹ค์ œ ๋ฐœํ‘œํ•  ๋•Œ ์‚ฌ์šฉํ•  ๊ตฌ์–ด์ฒด ์Šคํฌ๋ฆฝํŠธ - ์ตœ์†Œ 3-4๋ฌธ์žฅ)
223
+
224
+ 2. **์ž‘์„ฑ ์›์น™**
225
+ - ํ•œ ์Šฌ๋ผ์ด๋“œ์— ํ•˜๋‚˜์˜ ํ•ต์‹ฌ ๋ฉ”์‹œ์ง€
226
+ - ํ…์ŠคํŠธ๋Š” ์ตœ์†Œํ™”, ์‹œ๊ฐ์  ์š”์†Œ ๊ทน๋Œ€ํ™”
227
+ - 6x6 ๊ทœ์น™ ์ค€์ˆ˜ (6์ค„ ์ดํ•˜, ์ค„๋‹น 6๋‹จ์–ด ์ดํ•˜)
228
+ - ์ „๋ฌธ์ ์ด๋ฉด์„œ๋„ ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์šด ์–ธ์–ด ์‚ฌ์šฉ
229
+ - ๊ฐ ๋ถˆ๋ฆฟ ํฌ์ธํŠธ๋Š” ๋ฐ˜๋“œ์‹œ ์ด๋ชจ์ง€๋กœ ์‹œ์ž‘
230
+
231
+ 3. **๋ฐœํ‘œ์ž ๋…ธํŠธ ์ž‘์„ฑ ์ง€์นจ**
232
+ - ์Šฌ๋ผ์ด๋“œ ๋‚ด์šฉ์„ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์„ค๋ช…ํ•˜๋Š” ๊ตฌ์–ด์ฒด ์‚ฌ์šฉ
233
+ - ๊ฐ ํฌ์ธํŠธ๋ฅผ ํ’€์–ด์„œ ์„ค๋ช…ํ•˜๊ณ  ์—ฐ๊ฒฐ
234
+ - ์ฒญ์ค‘๊ณผ ์†Œํ†ตํ•˜๋Š” ๋А๋‚Œ์˜ ๋Œ€ํ™”์ฒด ("์—ฌ๋Ÿฌ๋ถ„", "์šฐ๋ฆฌ๊ฐ€", "ํ•จ๊ป˜")
235
+ - ์ตœ์†Œ 3-4๋ฌธ์žฅ์œผ๋กœ ํ’๋ถ€ํ•˜๊ฒŒ ์ž‘์„ฑ
236
+ - ์˜ˆ์‹œ: "์ž, ์ด์ œ ์šฐ๋ฆฌ๊ฐ€ ์ฃผ๋ชฉํ•ด์•ผ ํ•  ํ•ต์‹ฌ ํฌ์ธํŠธ๋“ค์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ๋กœ ์‹œ์žฅ ๊ทœ๋ชจ๋ฅผ ๋ณด์‹œ๋ฉด..."
237
+
238
+ 4. **ํ•„์ˆ˜ ํฌํ•จ ์Šฌ๋ผ์ด๋“œ**
239
+ - ํ‘œ์ง€ (์ œ๋ชฉ, ๋ถ€์ œ๋ชฉ, ๋ฐœํ‘œ์ž/๋‚ ์งœ)
240
+ - ๋ชฉ์ฐจ
241
+ - ํ•ต์‹ฌ ๋‚ด์šฉ ์Šฌ๋ผ์ด๋“œ๋“ค
242
+ - ์š”์•ฝ/๊ฒฐ๋ก 
243
+ - Q&A/๊ฐ์‚ฌ ์Šฌ๋ผ์ด๋“œ"""
244
+
245
+ def create_supervisor_review_prompt(self, ppt_topic: str, executor_response: str, research_summary: str) -> str:
246
+ """๊ฐ๋…์ž AI์˜ ๊ฒ€ํ†  ํ”„๋กฌํ”„ํŠธ - PPT ๊ฒ€ํ†  ๋ฐ ํ”ผ๋“œ๋ฐฑ"""
247
+ return f"""๋‹น์‹ ์€ PPT ํ’ˆ์งˆ์„ ๊ฒ€ํ† ํ•˜๊ณ  ๊ฐœ์„ ์ ์„ ์ œ์‹œํ•˜๋Š” ๊ฐ๋…์ž AI์ž…๋‹ˆ๋‹ค.
248
+
249
+ PPT ์ฃผ์ œ: {ppt_topic}
250
+
251
+ ์กฐ์‚ฌ์ž AI๊ฐ€ ์ œ๊ณตํ•œ ์ฝ˜ํ…์ธ :
252
+ {research_summary}
253
+
254
+ ์‹คํ–‰์ž AI์˜ PPT ์ดˆ์•ˆ:
255
+ {executor_response}
256
+
257
+ ์œ„ PPT ์ดˆ์•ˆ์„ ๊ฒ€ํ† ํ•˜๊ณ  ๋‹ค์Œ ๊ด€์ ์—์„œ ๊ตฌ์ฒด์ ์ธ ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•˜์„ธ์š”:
258
+
259
+ 1. **์ฝ˜ํ…์ธ  ํ’ˆ์งˆ**
260
+ - ์กฐ์‚ฌ ๋‚ด์šฉ์ด ์ถฉ๋ถ„ํžˆ ๋ฐ˜์˜๋˜์—ˆ๋Š”์ง€
261
+ - ๊ฐ ์Šฌ๋ผ์ด๋“œ์˜ ๋ฉ”์‹œ์ง€๊ฐ€ ๋ช…ํ™•ํ•œ์ง€
262
+ - ๋…ผ๋ฆฌ์  ํ๋ฆ„์ด ์ž์—ฐ์Šค๋Ÿฌ์šด์ง€
263
+
264
+ 2. **์‹œ๊ฐ์  ํšจ๊ณผ**
265
+ - ํ…์ŠคํŠธ์™€ ์‹œ๊ฐ ์š”์†Œ์˜ ๊ท ํ˜•
266
+ - ์Šฌ๋ผ์ด๋“œ๋ณ„ ์ผ๊ด€์„ฑ
267
+ - ์ฒญ์ค‘์˜ ์ดํ•ด๋ฅผ ๋•๋Š” ๊ตฌ์„ฑ์ธ์ง€
268
+
269
+ 3. **๋ฐœํ‘œ ์ค€๋น„๋„**
270
+ - ๋ฐœํ‘œ์ž ๋…ธํŠธ์˜ ์ถฉ์‹ค์„ฑ
271
+ - ์˜ˆ์ƒ ์งˆ๋ฌธ์— ๋Œ€ํ•œ ๋Œ€๋น„
272
+ - ์‹œ๊ฐ„ ๋ฐฐ๋ถ„์˜ ์ ์ ˆ์„ฑ
273
+
274
+ 4. **๊ฐœ์„  ํ•„์š”์‚ฌํ•ญ**
275
+ - ๊ตฌ์ฒด์ ์ธ ์ˆ˜์ • ์ง€์‹œ์‚ฌํ•ญ
276
+ - ์ถ”๊ฐ€ํ•ด์•ผ ํ•  ๋‚ด์šฉ
277
+ - ์‚ญ์ œํ•˜๊ฑฐ๋‚˜ ๊ฐ„์†Œํ™”ํ•  ๋ถ€๋ถ„
278
+
279
+ 5. **์ตœ์ข… ์ ๊ฒ€์‚ฌํ•ญ**
280
+ - ์˜คํƒ€๋‚˜ ๋ฌธ๋ฒ• ์˜ค๋ฅ˜
281
+ - ๋ฐ์ดํ„ฐ์˜ ์ •ํ™•์„ฑ
282
+ - ์ „๋ฌธ์„ฑ๊ณผ ์‹ ๋ขฐ์„ฑ"""
283
+
284
+ def create_executor_final_prompt(self, ppt_topic: str, initial_response: str, supervisor_feedback: str, research_summary: str) -> str:
285
+ """์‹คํ–‰์ž AI ์ตœ์ข… PPT ํ”„๋กฌํ”„ํŠธ"""
286
+ return f"""๋‹น์‹ ์€ ์ตœ์ข… PPT๋ฅผ ์™„์„ฑํ•˜๋Š” ์‹คํ–‰์ž AI์ž…๋‹ˆ๋‹ค.
287
+
288
+ PPT ์ฃผ์ œ: {ppt_topic}
289
+
290
+ ์กฐ์‚ฌ์ž AI์˜ ์ฝ˜ํ…์ธ :
291
+ {research_summary}
292
+
293
+ ๋‹น์‹ ์˜ ์ดˆ๊ธฐ PPT ์ดˆ์•ˆ:
294
+ {initial_response}
295
+
296
+ ๊ฐ๋…์ž AI์˜ ํ”ผ๋“œ๋ฐฑ:
297
+ {supervisor_feedback}
298
+
299
+ ์œ„ ํ”ผ๋“œ๋ฐฑ์„ ์™„์ „ํžˆ ๋ฐ˜์˜ํ•˜์—ฌ ์ตœ์ข… PPT๋ฅผ ์ž‘์„ฑํ•˜์„ธ์š”:
300
+
301
+ 1. **๊ฐœ์„ ์‚ฌํ•ญ ๋ฐ˜์˜**
302
+ - ๊ฐ๋…์ž์˜ ๋ชจ๋“  ํ”ผ๋“œ๋ฐฑ ์ ์šฉ
303
+ - ์Šคํ† ๋ฆฌ๋ผ์ธ ๊ฐ•ํ™”
304
+ - ์‹œ๊ฐ์  ์ผ๊ด€์„ฑ ํ™•๋ณด
305
+
306
+ 2. **๋ฐœํ‘œ์ž ๋…ธํŠธ ๊ฐ•ํ™”**
307
+ - ๊ฐ ์Šฌ๋ผ์ด๋“œ๋งˆ๋‹ค ํ’๋ถ€ํ•œ ๊ตฌ์–ด์ฒด ๋ฐœํ‘œ ์Šคํฌ๋ฆฝํŠธ ์ž‘์„ฑ
308
+ - ์ตœ์†Œ 4-5๋ฌธ์žฅ์œผ๋กœ ์ž์„ธํ•˜๊ฒŒ
309
+ - ์‹ค์ œ ๋ฐœํ‘œ ์ƒํ™ฉ์„ ๊ฐ€์ •ํ•œ ์ž์—ฐ์Šค๋Ÿฌ์šด ๋Œ€ํ™”์ฒด
310
+ - ์˜ˆ์‹œ: "์ž, ์ด์ œ ์‹œ์žฅ ํ˜„ํ™ฉ์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ๋ถ„๋„ ์•„์‹œ๋‹ค์‹œํ”ผ ์ตœ๊ทผ ๋””์ง€ํ„ธ ์ „ํ™˜์ด ๊ฐ€์†ํ™”๋˜๋ฉด์„œ..."
311
+
312
+ 3. **์ตœ์ข… ํ’ˆ์งˆ ์ฒดํฌ**
313
+ - ์ „๋ฌธ์„ฑ๊ณผ ์™„์„ฑ๋„ ํ–ฅ์ƒ
314
+ - ์˜คํƒ€ ๋ฐ ๋ฌธ๋ฒ• ๊ฒ€ํ† 
315
+ - ๋…ผ๋ฆฌ์  ํ๋ฆ„ ์žฌํ™•์ธ
316
+
317
+ 4. **ํ”„๋ ˆ์  ํ…Œ์ด์…˜ ์ค€๋น„**
318
+ - ๊ฐ ์Šฌ๋ผ์ด๋“œ๋ณ„ ๋ฐœํ‘œ ์Šคํฌ๋ฆฝํŠธ ์ถ”๊ฐ€
319
+ - ์˜ˆ์ƒ ์งˆ๋ฌธ๊ณผ ๋‹ต๋ณ€ ์ค€๋น„
320
+ - ์‹œ๊ฐ„ ๋ฐฐ๋ถ„ ์ œ์•ˆ (20๋ถ„ ๋ฐœํ‘œ ๊ธฐ์ค€)
321
+
322
+ 5. **์ถ”๊ฐ€ ์ž๋ฃŒ**
323
+ - ๋ฐฑ์—… ์Šฌ๋ผ์ด๋“œ ์ œ์•ˆ
324
+ - ์ฐธ๊ณ  ์ž๋ฃŒ ๋ชฉ๋ก
325
+ - ์ธ์‡„์šฉ ํ•ธ๋“œ์•„์›ƒ ๋ฒ„์ „ ์ œ์•ˆ"""
326
+
327
+ def extract_keywords(self, supervisor_response: str) -> List[str]:
328
+ """๊ฐ๋…์ž ์‘๋‹ต์—์„œ ํ‚ค์›Œ๋“œ ์ถ”์ถœ"""
329
+ keywords = []
330
+
331
+ # [๊ฒ€์ƒ‰ ํ‚ค์›Œ๋“œ]: ํ˜•์‹์œผ๋กœ ํ‚ค์›Œ๋“œ ์ฐพ๊ธฐ
332
+ keyword_match = re.search(r'\[๊ฒ€์ƒ‰ ํ‚ค์›Œ๋“œ\]:\s*(.+)', supervisor_response, re.IGNORECASE)
333
+ if keyword_match:
334
+ keyword_str = keyword_match.group(1)
335
+ keywords = [k.strip() for k in keyword_str.split(',') if k.strip()]
336
+
337
+ # ํ‚ค์›Œ๋“œ๊ฐ€ ์—†์œผ๋ฉด ๊ธฐ๋ณธ ํ‚ค์›Œ๋“œ ์ƒ์„ฑ
338
+ if not keywords:
339
+ keywords = ["industry trends", "market analysis", "case studies", "best practices", "future outlook"]
340
+
341
+ return keywords[:7] # ์ตœ๋Œ€ 7๊ฐœ๋กœ ์ œํ•œ
342
+
343
+ def generate_synonyms(self, keyword: str) -> List[str]:
344
+ """ํ‚ค์›Œ๋“œ์˜ ๋™์˜์–ด/์œ ์‚ฌ์–ด ์ƒ์„ฑ"""
345
+ synonyms = {
346
+ "trend": ["tendency", "direction", "movement", "pattern"],
347
+ "analysis": ["evaluation", "assessment", "study", "research"],
348
+ "strategy": ["approach", "plan", "tactics", "methodology"],
349
+ "market": ["industry", "sector", "business", "commerce"],
350
+ "innovation": ["breakthrough", "advancement", "revolution", "disruption"],
351
+ "growth": ["expansion", "development", "progress", "advancement"],
352
+ "presentation": ["pitch", "proposal", "demonstration", "showcase"],
353
+ "data": ["statistics", "metrics", "analytics", "insights"],
354
+ "technology": ["tech", "digital", "IT", "innovation"],
355
+ "business": ["enterprise", "corporate", "commercial", "company"]
356
+ }
357
+
358
+ # ํ‚ค์›Œ๋“œ ์ •๊ทœํ™”
359
+ keyword_lower = keyword.lower()
360
+
361
+ # ์ง์ ‘ ๋งค์นญ๋˜๋Š” ๋™์˜์–ด๊ฐ€ ์žˆ์œผ๋ฉด ๋ฐ˜ํ™˜
362
+ if keyword_lower in synonyms:
363
+ return synonyms[keyword_lower][:2] # ์ตœ๋Œ€ 2๊ฐœ
364
+
365
+ # ๋ถ€๋ถ„ ๋งค์นญ ํ™•์ธ
366
+ for key, values in synonyms.items():
367
+ if key in keyword_lower or keyword_lower in key:
368
+ return values[:2]
369
+
370
+ # ๋™์˜์–ด๊ฐ€ ์—†์œผ๋ฉด ๋นˆ ๋ฆฌ์ŠคํŠธ
371
+ return []
372
+
373
+ def calculate_credibility_score(self, result: Dict) -> float:
374
+ """๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ์˜ ์‹ ๋ขฐ๋„ ์ ์ˆ˜ ๊ณ„์‚ฐ (0-1)"""
375
+ score = 0.5 # ๊ธฐ๋ณธ ์ ์ˆ˜
376
+
377
+ url = result.get('url', '')
378
+ title = result.get('title', '')
379
+ description = result.get('description', '')
380
+
381
+ # URL ๊ธฐ๋ฐ˜ ์ ์ˆ˜
382
+ trusted_domains = [
383
+ '.edu', '.gov', '.org', 'wikipedia.org', 'harvard.edu',
384
+ 'mckinsey.com', 'deloitte.com', 'pwc.com', 'gartner.com',
385
+ 'forrester.com', 'statista.com', 'bloomberg.com', 'reuters.com'
386
+ ]
387
 
388
+ for domain in trusted_domains:
389
+ if domain in url:
390
+ score += 0.2
391
+ break
392
+
393
+ # HTTPS ์‚ฌ์šฉ ์—ฌ๋ถ€
394
+ if url.startswith('https://'):
395
+ score += 0.1
396
+
397
+ # ์ œ๋ชฉ๊ณผ ์„ค๋ช…์˜ ๊ธธ์ด (๋„ˆ๋ฌด ์งง์œผ๋ฉด ์‹ ๋ขฐ๋„ ๊ฐ์†Œ)
398
+ if len(title) > 20:
399
+ score += 0.05
400
+ if len(description) > 50:
401
+ score += 0.05
402
+
403
+ # ๊ด‘๊ณ /์ŠคํŒธ ํ‚ค์›Œ๋“œ ์ฒดํฌ
404
+ spam_keywords = ['buy now', 'sale', 'discount', 'click here', '100% free']
405
+ if any(spam in (title + description).lower() for spam in spam_keywords):
406
+ score -= 0.3
407
+
408
+ # ๋‚ ์งœ ์ •๋ณด๊ฐ€ ์žˆ์œผ๋ฉด ๊ฐ€์‚ฐ์ 
409
+ if any(year in description for year in ['2024', '2023', '2022']):
410
+ score += 0.1
411
+
412
+ return max(0, min(1, score)) # 0-1 ๋ฒ”์œ„๋กœ ์ œํ•œ
413
+
414
+ def detect_contradictions(self, results: List[Dict]) -> List[Dict]:
415
+ """๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ๊ฐ„ ๋ชจ์ˆœ ๊ฐ์ง€"""
416
+ contradictions = []
417
+
418
+ # ๊ฐ„๋‹จํ•œ ๋ชจ์ˆœ ๊ฐ์ง€ ํŒจํ„ด
419
+ opposite_pairs = [
420
+ ("increase", "decrease"),
421
+ ("improve", "worsen"),
422
+ ("effective", "ineffective"),
423
+ ("success", "failure"),
424
+ ("benefit", "harm"),
425
+ ("positive", "negative"),
426
+ ("growth", "decline")
427
+ ]
428
+
429
+ # ๊ฒฐ๊ณผ๋“ค์„ ๋น„๊ต
430
+ for i in range(len(results)):
431
+ for j in range(i + 1, len(results)):
432
+ desc1 = results[i].get('description', '').lower()
433
+ desc2 = results[j].get('description', '').lower()
434
+
435
+ # ๋ฐ˜๋Œ€ ๊ฐœ๋…์ด ํฌํ•จ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธ
436
+ for word1, word2 in opposite_pairs:
437
+ if (word1 in desc1 and word2 in desc2) or (word2 in desc1 and word1 in desc2):
438
+ # ๊ฐ™์€ ์ฃผ์ œ์— ๋Œ€ํ•ด ๋ฐ˜๋Œ€ ์˜๊ฒฌ์ธ์ง€ ํ™•์ธ
439
+ common_words = set(desc1.split()) & set(desc2.split())
440
+ if len(common_words) > 5: # ๊ณตํ†ต ๋‹จ์–ด๊ฐ€ 5๊ฐœ ์ด์ƒ์ด๋ฉด ๊ฐ™์€ ์ฃผ์ œ๋กœ ๊ฐ„์ฃผ
441
+ contradictions.append({
442
+ 'source1': results[i]['url'],
443
+ 'source2': results[j]['url'],
444
+ 'type': f"{word1} vs {word2}",
445
+ 'desc1': results[i]['description'][:100],
446
+ 'desc2': results[j]['description'][:100]
447
+ })
448
+
449
+ return contradictions
450
+
451
+ def brave_search(self, query: str) -> List[Dict]:
452
+ """Brave Search API ํ˜ธ์ถœ"""
453
+ if self.test_mode or self.bapi_token == "YOUR_BRAVE_API_TOKEN":
454
+ # ํ…Œ์ŠคํŠธ ๋ชจ๋“œ์—์„œ๋Š” ์‹œ๋ฎฌ๋ ˆ์ด์…˜๋œ ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜
455
+ test_results = []
456
+ for i in range(5):
457
+ test_results.append({
458
+ "title": f"{query} - Industry Report {i+1}",
459
+ "description": f"Comprehensive analysis of {query} including market trends, key statistics, and future projections for strategic planning.",
460
+ "url": f"https://report{i+1}.com/{query.replace(' ', '-')}",
461
+ "credibility_score": 0.7 + (i * 0.05)
462
+ })
463
+ return test_results
464
+
465
+ try:
466
+ params = {
467
+ "q": query,
468
+ "count": 20, # 20๊ฐœ๋กœ ์ฆ๊ฐ€
469
+ "safesearch": "moderate",
470
+ "freshness": "pw" # Past week for recent results
471
+ }
472
+
473
+ response = requests.get(
474
+ self.brave_url,
475
+ headers=self.create_brave_headers(),
476
+ params=params,
477
+ timeout=10
478
+ )
479
+
480
+ if response.status_code == 200:
481
+ data = response.json()
482
+ results = []
483
+ for item in data.get("web", {}).get("results", [])[:20]:
484
+ result = {
485
+ "title": item.get("title", ""),
486
+ "description": item.get("description", ""),
487
+ "url": item.get("url", ""),
488
+ "published": item.get("published", "")
489
+ }
490
+ # ์‹ ๋ขฐ๋„ ์ ์ˆ˜ ๊ณ„์‚ฐ
491
+ result["credibility_score"] = self.calculate_credibility_score(result)
492
+ results.append(result)
493
+
494
+ # ์‹ ๋ขฐ๋„ ์ ์ˆ˜ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌ
495
+ results.sort(key=lambda x: x['credibility_score'], reverse=True)
496
+ return results
497
+ else:
498
+ logger.error(f"Brave API ์˜ค๋ฅ˜: {response.status_code}")
499
+ return []
500
+
501
+ except Exception as e:
502
+ logger.error(f"Brave ๊ฒ€์ƒ‰ ์ค‘ ์˜ค๋ฅ˜: {str(e)}")
503
+ return []
504
+
505
+ def simulate_streaming(self, text: str, role: str) -> Generator[str, None, None]:
506
+ """ํ…Œ์ŠคํŠธ ๋ชจ๋“œ์—์„œ ์ŠคํŠธ๋ฆฌ๋ฐ ์‹œ๋ฎฌ๋ ˆ์ด์…˜"""
507
+ words = text.split()
508
+ for i in range(0, len(words), 3):
509
+ chunk = " ".join(words[i:i+3])
510
+ yield chunk + " "
511
+ time.sleep(0.05)
512
+
513
+ def call_llm_streaming(self, messages: List[Dict[str, str]], role: str) -> Generator[str, None, None]:
514
+ """์ŠคํŠธ๋ฆฌ๋ฐ LLM API ํ˜ธ์ถœ"""
515
+
516
+ # ํ…Œ์ŠคํŠธ ๋ชจ๋“œ
517
+ if self.test_mode:
518
+ logger.info(f"ํ…Œ์ŠคํŠธ ๋ชจ๋“œ ์ŠคํŠธ๋ฆฌ๋ฐ - Role: {role}")
519
+ test_responses = {
520
+ "supervisor_initial": """์ „๋ฌธ์ ์ธ PPT ๊ตฌ์กฐ๋ฅผ ์„ค๊ณ„ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.
521
+
522
+ ## 1. PPT ์ „์ฒด ๊ตฌ์กฐ ์„ค๊ณ„
523
+
524
+ **๋ชฉ์ **: ๋””์ง€ํ„ธ ํŠธ๋žœ์Šคํฌ๋ฉ”์ด์…˜์˜ ํ•ต์‹ฌ ์š”์†Œ์™€ ์„ฑ๊ณต ์ „๋žต์„ ๋ช…ํ™•ํ•˜๊ฒŒ ์ „๋‹ฌ
525
+ **ํƒ€๊ฒŸ ์ฒญ์ค‘**: ๊ฒฝ์˜์ง„ ๋ฐ ์˜์‚ฌ๊ฒฐ์ •์ž
526
+ **ํ†ค**: ์ „๋ฌธ์ ์ด๊ณ  ์„ค๋“๋ ฅ ์žˆ๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ์Šคํƒ€์ผ
527
+ **์ „์ฒด ์Šฌ๋ผ์ด๋“œ**: 12์žฅ
528
+
529
+ ## 2. ์„น์…˜๋ณ„ ๊ตฌ์„ฑ
530
+
531
+ ### ๋„์ž…๋ถ€ (3์žฅ)
532
+ - ์Šฌ๋ผ์ด๋“œ 1: ํ‘œ์ง€ - ์ž„ํŒฉํŠธ ์žˆ๋Š” ์ œ๋ชฉ๊ณผ ๋น„์ฃผ์–ผ
533
+ - ์Šฌ๋ผ์ด๋“œ 2: ๋ชฉ์ฐจ - ์ „์ฒด ํ๋ฆ„ ์ œ์‹œ
534
+ - ์Šฌ๋ผ์ด๋“œ 3: ๋””์ง€ํ„ธ ํŠธ๋žœ์Šคํฌ๋ฉ”์ด์…˜์˜ ํ•„์š”์„ฑ
535
+
536
+ ### ๋ณธ๋ก  (7์žฅ)
537
+ **์„น์…˜ 1: ํ˜„ํ™ฉ ๋ถ„์„ (2์žฅ)**
538
+ - ์Šฌ๋ผ์ด๋“œ 4: ์‚ฐ์—…๋ณ„ ๋””์ง€ํ„ธํ™” ํ˜„ํ™ฉ
539
+ - ์Šฌ๋ผ์ด๋“œ 5: ์ฃผ์š” ๋„์ „๊ณผ์ œ
540
+
541
+ **์„น์…˜ 2: ํ•ต์‹ฌ ์ „๋žต (3์žฅ)**
542
+ - ์Šฌ๋ผ์ด๋“œ 6: ๋””์ง€ํ„ธ ํŠธ๋žœ์Šคํฌ๋ฉ”์ด์…˜ ํ”„๋ ˆ์ž„์›Œํฌ
543
+ - ์Šฌ๋ผ์ด๋“œ 7: ๊ธฐ์ˆ  ์Šคํƒ ๋ฐ ์ธํ”„๋ผ
544
+ - ์Šฌ๋ผ์ด๋“œ 8: ๋ณ€ํ™” ๊ด€๋ฆฌ ์ „๋žต
545
+
546
+ **์„น์…˜ 3: ์„ฑ๊ณต ์‚ฌ๋ก€ (2์žฅ)**
547
+ - ์Šฌ๋ผ์ด๋“œ 9: ๊ธ€๋กœ๋ฒŒ ์„ฑ๊ณต ์‚ฌ๋ก€
548
+ - ์Šฌ๋ผ์ด๋“œ 10: ROI ๋ฐ ์„ฑ๊ณผ ์ง€ํ‘œ
549
+
550
+ ### ๊ฒฐ๋ก ๋ถ€ (2์žฅ)
551
+ - ์Šฌ๋ผ์ด๋“œ 11: ํ•ต์‹ฌ ์‹œ์‚ฌ์  ๋ฐ ๊ถŒ๊ณ ์‚ฌํ•ญ
552
+ - ์Šฌ๋ผ์ด๋“œ 12: Q&A
553
+
554
+ ## 3. ๋น„์ฃผ์–ผ ์ „๋žต
555
+ - ์ƒ‰์ƒ: ๊ธฐ์—… ๋ธ”๋ฃจ(#003366) + ์•…์„ผํŠธ ์˜ค๋ Œ์ง€(#FF6B35)
556
+ - ์•„์ด์ฝ˜: ๋ชจ๋˜ํ•˜๊ณ  ํ”Œ๋žซํ•œ ๋””์ž์ธ
557
+ - ์ฐจํŠธ: ๋ฐ์ดํ„ฐ ์‹œ๊ฐํ™” ์ค‘์‹ฌ
558
+
559
+ [๊ฒ€์ƒ‰ ํ‚ค์›Œ๋“œ]: digital transformation trends 2024, DX success cases, digital transformation ROI, change management digital, industry 4.0 statistics""",
560
+
561
+ "researcher": """PPT ์ฝ˜ํ…์ธ ๋ฅผ ์œ„ํ•œ ํ•ต์‹ฌ ์ •๋ณด๋ฅผ ์ •๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.
562
+
563
+ ## 1. ์‹œ๊ฐ์  ์ž๋ฃŒ ๊ฐ€๋Šฅํ•œ ํ†ต๊ณ„/์ˆ˜์น˜ (์‹ ๋ขฐ๋„ ๋†’์Œ)
564
+
565
+ **๋””์ง€ํ„ธ ํŠธ๋žœ์Šคํฌ๋ฉ”์ด์…˜ ํˆฌ์ž ํ˜„ํ™ฉ**
566
+ - 2024๋…„ ๊ธ€๋กœ๋ฒŒ DX ํˆฌ์ž ๊ทœ๋ชจ: $3.4์กฐ (์‹ ๋ขฐ๋„: 0.92)
567
+ - ์—ฐํ‰๊ท  ์„ฑ์žฅ๋ฅ (CAGR): 16.5% (2023-2027)
568
+ - ์ถœ์ฒ˜: IDC Digital Transformation Spending Guide
569
+
570
+ **์‚ฐ์—…๋ณ„ ๋””์ง€ํ„ธํ™” ์ˆ˜์ค€**
571
+ - ๊ธˆ์œต: 78% ๋””์ง€ํ„ธํ™” ์™„๋ฃŒ (์‹ ๋ขฐ๋„: 0.88)
572
+ - ์ œ์กฐ: 52% ์ง„ํ–‰ ์ค‘ (์‹ ๋ขฐ๋„: 0.85)
573
+ - ํ—ฌ์Šค์ผ€์–ด: 61% ๊ฐ€์†ํ™” ๋‹จ๊ณ„
574
+ - ์ถœ์ฒ˜: McKinsey Global Institute
575
+
576
+ ## 2. ํ•ต์‹ฌ ์ธ์‚ฌ์ดํŠธ์™€ ํŠธ๋ Œ๋“œ (์‹ ๋ขฐ๋„ ๋†’์Œ)
577
+
578
+ **2024๋…„ ์ฃผ์š” ํŠธ๋ Œ๋“œ**
579
+ 1. AI/ML ํ†ตํ•ฉ: 87%์˜ ๊ธฐ์—…์ด AI๋ฅผ DX ํ•ต์‹ฌ ์š”์†Œ๋กœ ์ฑ„ํƒ (์‹ ๋ขฐ๋„: 0.90)
580
+ 2. ํด๋ผ์šฐ๋“œ ์šฐ์„ : 94%๊ฐ€ ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ํด๋ผ์šฐ๋“œ ์ „๋žต ์ถ”์ง„
581
+ 3. ๋ฐ์ดํ„ฐ ์ค‘์‹ฌ: ์‹ค์‹œ๊ฐ„ ๋ถ„์„์ด ๊ฒฝ์Ÿ๋ ฅ์˜ ํ•ต์‹ฌ
582
+ - ์ถœ์ฒ˜: Gartner Technology Trends 2024
583
+
584
+ ## 3. ์‚ฌ๋ก€ ์—ฐ๊ตฌ ๋ฐ ์„ฑ๊ณต ์Šคํ† ๋ฆฌ (์‹ ๋ขฐ๋„ ๋†’์Œ)
585
+
586
+ **Amazon ์‚ฌ๋ก€**
587
+ - ๋ฌผ๋ฅ˜ ์ž๋™ํ™”๋กœ ๋ฐฐ์†ก ์‹œ๊ฐ„ 40% ๋‹จ์ถ• (์‹ ๋ขฐ๋„: 0.87)
588
+ - AI ๊ธฐ๋ฐ˜ ์ถ”์ฒœ์œผ๋กœ ๋งค์ถœ 35% ์ฆ๊ฐ€
589
+ - ์ถœ์ฒ˜: Amazon Annual Report 2023
590
+
591
+ **Starbucks ๋””์ง€ํ„ธ ํ˜์‹ **
592
+ - ๋ชจ๋ฐ”์ผ ์ฃผ๋ฌธ ๋น„์ค‘: ์ „์ฒด ๋งค์ถœ์˜ 26% (์‹ ๋ขฐ๋„: 0.85)
593
+ - ๊ฐœ์ธํ™” ๋งˆ์ผ€ํŒ…์œผ๋กœ ๊ณ ๊ฐ ์ถฉ์„ฑ๋„ 23% ํ–ฅ์ƒ
594
+ - ์ถœ์ฒ˜: Starbucks Investor Relations
595
+
596
+ ## 4. ์ „๋ฌธ๊ฐ€ ์˜๊ฒฌ ๋ฐ ์ธ์šฉ๊ตฌ
597
+
598
+ > "๋””์ง€ํ„ธ ํŠธ๋žœ์Šคํฌ๋ฉ”์ด์…˜์€ ๊ธฐ์ˆ ์ด ์•„๋‹Œ ์‚ฌ๋žŒ๊ณผ ๋ฌธํ™”์˜ ๋ณ€ํ™”๋‹ค"
599
+ - Satya Nadella, Microsoft CEO
600
+
601
+ > "2025๋…„๊นŒ์ง€ ๋””์ง€ํ„ธ ๋ฆฌ๋”์™€ ํ›„๋ฐœ์ฃผ์ž์˜ ๊ฒฉ์ฐจ๋Š” 2๋ฐฐ ์ด์ƒ ๋ฒŒ์–ด์งˆ ๊ฒƒ"
602
+ - Michael Porter, Harvard Business School
603
+
604
+ ## 5. ์‹œ๊ฐ ์ž๋ฃŒ ์ถ”์ฒœ
605
+
606
+ **์Šฌ๋ผ์ด๋“œ๋ณ„ ๋น„์ฃผ์–ผ ์ œ์•ˆ**
607
+ - ํ‘œ์ง€: ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ ์ด๋ฏธ์ง€ + ๋™์ ์ธ ๋ฐ์ดํ„ฐ ํ๋ฆ„
608
+ - ํ†ต๊ณ„: ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒํ•œ ๋Œ€์‹œ๋ณด๋“œ ์Šคํƒ€์ผ ์ฐจํŠธ
609
+ - ํ”„๋ ˆ์ž„์›Œํฌ: ๊ณ„์ธต์  ๋‹ค์ด์–ด๊ทธ๋žจ + ์•„์ด์ฝ˜
610
+ - ์‚ฌ๋ก€: ๊ธฐ์—… ๋กœ๊ณ  + ํ•ต์‹ฌ ์ง€ํ‘œ ์ธํฌ๊ทธ๋ž˜ํ”ฝ
611
+ - ํƒ€์ž„๋ผ์ธ: ๋กœ๋“œ๋งต ํ˜•ํƒœ์˜ ๋‹จ๊ณ„๋ณ„ ์ง„ํ–‰๋„
612
+
613
+ **์•„์ด์ฝ˜ ์„ธํŠธ**
614
+ - ๊ธฐ์ˆ : ํด๋ผ์šฐ๋“œ, AI, ๋ฐ์ดํ„ฐ, ๋ณด์•ˆ
615
+ - ๋น„์ฆˆ๋‹ˆ์Šค: ์„ฑ์žฅ, ํ˜์‹ , ํ˜‘์—…, ํšจ์œจ์„ฑ
616
+ - ์‚ฌ๋žŒ: ๋ฆฌ๋”์‹ญ, ํŒ€์›Œํฌ, ์Šคํ‚ฌ, ๋ฌธํ™”""",
617
+
618
+ "supervisor_execution": """์กฐ์‚ฌ ๋‚ด์šฉ์„ ๋ฐ”ํƒ•์œผ๋กœ PPT ์ œ์ž‘์„ ์œ„ํ•œ ๊ตฌ์ฒด์ ์ธ ์ง€์‹œ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค.
619
+
620
+ ## 1. ์Šฌ๋ผ์ด๋“œ๋ณ„ ์ƒ์„ธ ๊ตฌ์„ฑ
621
+
622
+ **์Šฌ๋ผ์ด๋“œ 1: ํ‘œ์ง€**
623
+ - ์ œ๋ชฉ: "๋””์ง€ํ„ธ ํŠธ๋žœ์Šคํฌ๋ฉ”์ด์…˜: ๋ฏธ๋ž˜๋ฅผ ํ–ฅํ•œ ๋„์•ฝ"
624
+ - ๋ถ€์ œ๋ชฉ: "์„ฑ๊ณต์ ์ธ DX ์ „๋žต๊ณผ ์‹คํ–‰ ๋ฐฉ์•ˆ"
625
+ - ๋น„์ฃผ์–ผ: ์—ฐ๊ฒฐ๋œ ๋””์ง€ํ„ธ ๋„คํŠธ์›Œํฌ ๋ฐฐ๊ฒฝ
626
+ - ์กฐ์‚ฌ ์ž๋ฃŒ ํ™œ์šฉ: $3.4์กฐ ์‹œ์žฅ ๊ทœ๋ชจ ๊ฐ•์กฐ
627
+
628
+ **์Šฌ๋ผ์ด๋“œ 4: ์‚ฐ์—…๋ณ„ ํ˜„ํ™ฉ**
629
+ - ์กฐ์‚ฌ๋œ ํ†ต๊ณ„ ํ™œ์šฉ: ๊ธˆ์œต(78%), ์ œ์กฐ(52%), ํ—ฌ์Šค์ผ€์–ด(61%)
630
+ - ์›ํ˜• ์ฐจํŠธ + ์ง„ํ–‰ ๋ฐ” ์กฐํ•ฉ
631
+ - ๊ฐ ์‚ฐ์—…๋ณ„ ๋Œ€ํ‘œ ์•„์ด์ฝ˜ ๋ฐฐ์น˜
632
+
633
+ **์Šฌ๋ผ์ด๋“œ 7: ๊ธฐ์ˆ  ์Šคํƒ**
634
+ - AI/ML(87% ์ฑ„ํƒ๋ฅ ) ์ค‘์‹ฌ์œผ๋กœ ๊ตฌ์„ฑ
635
+ - ํด๋ผ์šฐ๏ฟฝ๏ฟฝ(94%) ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ์ „๋žต ์‹œ๊ฐํ™”
636
+ - ๊ณ„์ธต์  ๋‹ค์ด์–ด๊ทธ๋žจ ์‚ฌ์šฉ
637
+
638
+ **์Šฌ๋ผ์ด๋“œ 9: ์„ฑ๊ณต ์‚ฌ๋ก€**
639
+ - Amazon๊ณผ Starbucks ์‚ฌ๋ก€ ๋Œ€๋น„
640
+ - ํ•ต์‹ฌ ์„ฑ๊ณผ ์ง€ํ‘œ ์ธํฌ๊ทธ๋ž˜ํ”ฝ
641
+ - Before/After ๋น„๊ต ํ˜•์‹
642
+
643
+ ## 2. ๋””์ž์ธ ๊ฐ€์ด๋“œ๋ผ์ธ
644
+
645
+ **์ƒ‰์ƒ ํŒ”๋ ˆํŠธ**
646
+ - ์ฃผ์ƒ‰์ƒ: ๋„ค์ด๋น„ ๋ธ”๋ฃจ (#1E3A8A)
647
+ - ๋ณด์กฐ์ƒ‰์ƒ: ์Šค์นด์ด ๋ธ”๋ฃจ (#3B82F6)
648
+ - ๊ฐ•์กฐ์ƒ‰์ƒ: ์˜ค๋ Œ์ง€ (#F59E0B)
649
+ - ๋ฐฐ๊ฒฝ: ํ™”์ดํŠธ/๋ผ์ดํŠธ ๊ทธ๋ ˆ์ด
650
+
651
+ **ํƒ€์ดํฌ๊ทธ๋ž˜ํ”ผ**
652
+ - ์ œ๋ชฉ: Montserrat Bold (32-40pt)
653
+ - ๋ณธ๋ฌธ: Open Sans Regular (18-24pt)
654
+ - ๊ฐ•์กฐ: Open Sans Semi-Bold
655
+
656
+ **๋ ˆ์ด์•„์›ƒ ์›์น™**
657
+ - ์—ฌ๋ฐฑ ์ถฉ๋ถ„ํžˆ ํ™œ์šฉ (40% ์ด์ƒ)
658
+ - ์ขŒ์šฐ ๋Œ€์นญ ๋˜๋Š” ํ™ฉ๊ธˆ๋น„์œจ
659
+ - ํ•œ ์Šฌ๋ผ์ด๋“œ ํ•œ ๋ฉ”์‹œ์ง€ ์›์น™
660
+
661
+ ## 3. ์Šคํ† ๋ฆฌํ…”๋ง ์ „๋žต
662
+
663
+ **๋„์ž…๋ถ€ ์ „๋žต**
664
+ - ์ถฉ๊ฒฉ์ ์ธ ํ†ต๊ณ„๋กœ ์‹œ์ž‘ ($3.4์กฐ ์‹œ์žฅ)
665
+ - "์™œ ์ง€๊ธˆ์ธ๊ฐ€?" ์งˆ๋ฌธ ์ œ๊ธฐ
666
+ - ์ฒญ์ค‘์˜ pain point ๊ณต๊ฐ
667
+
668
+ **์ „๊ฐœ ๋ฐฉ์‹**
669
+ - ๋ฌธ์ œ โ†’ ํ•ด๊ฒฐ์ฑ… โ†’ ์ฆ๊ฑฐ โ†’ ํ–‰๋™
670
+ - ๊ฐ ์„น์…˜ ๊ฐ„ ์ž์—ฐ์Šค๋Ÿฌ์šด ์ „ํ™˜
671
+ - ์‚ฌ๋ก€๋ฅผ ํ†ตํ•œ ๊ตฌ์ฒดํ™”
672
+
673
+ **ํด๋ผ์ด๋งฅ์Šค**
674
+ - ROI ๋ฐ์ดํ„ฐ๋กœ ์„ค๋“๋ ฅ ๊ทน๋Œ€ํ™”
675
+ - ์„ฑ๊ณต ๊ธฐ์—…๊ณผ์˜ ๊ฒฉ์ฐจ ์‹œ๊ฐํ™”
676
+ - ํ–‰๋™ ์ด‰๊ตฌ ๋ฉ”์‹œ์ง€
677
+
678
+ ## 4. ์‹œ๊ฐํ™” ์ง€์นจ
679
+
680
+ **๋ฐ์ดํ„ฐ ์‹œ๊ฐํ™”**
681
+ - ์‚ฐ์—…๋ณ„ ํ˜„ํ™ฉ: ๋ฐฉ์‚ฌํ˜• ์ฐจํŠธ
682
+ - ์„ฑ์žฅ๋ฅ : ์ƒ์Šน ๊ณก์„  ๊ทธ๋ž˜ํ”„
683
+ - ROI: ๊ณ„์‚ฐ๊ธฐ ์Šคํƒ€์ผ ์ธํฌ๊ทธ๋ž˜ํ”ฝ
684
+ - ํ”„๋กœ์„ธ์Šค: ์ˆœํ™˜ํ˜• ๋‹ค์ด์–ด๊ทธ๋žจ
685
+
686
+ **์• ๋‹ˆ๋ฉ”์ด์…˜ ํšจ๊ณผ**
687
+ - ์Šฌ๋ผ์ด๋“œ ์ „ํ™˜: Morph ํšจ๊ณผ
688
+ - ์ฐจํŠธ ๋“ฑ์žฅ: ์ˆœ์ฐจ์  ๋นŒ๋“œ์—…
689
+ - ๊ฐ•์กฐ ํฌ์ธํŠธ: ์คŒ์ธ/ํ•˜์ด๋ผ์ดํŠธ
690
+ - ๊ณผ๋„ํ•œ ํšจ๊ณผ ์ง€์–‘""",
691
+
692
+ "executor": """PPT ์Šฌ๋ผ์ด๋“œ๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
693
+
694
+ [์Šฌ๋ผ์ด๋“œ 1] ํ‘œ์ง€
695
+ ์ œ๋ชฉ: ๋””์ง€ํ„ธ ํŠธ๋žœ์Šคํฌ๋ฉ”์ด์…˜: ๋ฏธ๋ž˜๋ฅผ ํ–ฅํ•œ ๋„์•ฝ
696
+ ๋ถ€์ œ๋ชฉ: ์„ฑ๊ณต์ ์ธ DX ์ „๋žต๊ณผ ์‹คํ–‰ ๋ฐฉ์•ˆ
697
+ ํ•ต์‹ฌ ๋‚ด์šฉ:
698
+ - ๋ฐœํ‘œ์ž: [์ด๋ฆ„]
699
+ - ๋‚ ์งœ: 2024๋…„ 3์›”
700
+ - ๊ธฐ์—…๋ช…/๋กœ๊ณ 
701
+ ๋ฐœํ‘œ์ž ๋…ธํŠธ: ์ฒญ์ค‘์˜ ์ฃผ๋ชฉ์„ ๋Œ ์ˆ˜ ์žˆ๋„๋ก ์ž์‹ ๊ฐ ์žˆ๊ฒŒ ์‹œ์ž‘. $3.4์กฐ ๊ทœ๋ชจ์˜ ๊ฑฐ๋Œ€ํ•œ ๋ณ€ํ™”์˜ ๋ฌผ๊ฒฐ์ž„์„ ๊ฐ•์กฐ
702
+ ์‹œ๊ฐ ์ž๋ฃŒ: ๋””์ง€ํ„ธ ๋„คํŠธ์›Œํฌ๊ฐ€ ์—ฐ๊ฒฐ๋œ ์ง€๊ตฌ๋ณธ ์ด๋ฏธ์ง€, ๋™์ ์ธ ๋ฐ์ดํ„ฐ ํ๋ฆ„ ํšจ๊ณผ
703
+
704
+ [์Šฌ๋ผ์ด๋“œ 2] ๋ชฉ์ฐจ
705
+ ์ œ๋ชฉ: Agenda
706
+ ํ•ต์‹ฌ ๋‚ด์šฉ:
707
+ - ๋””์ง€ํ„ธ ํŠธ๋žœ์Šคํฌ๋ฉ”์ด์…˜์˜ ํ˜„์žฌ
708
+ - ์‚ฐ์—…๋ณ„ ๋””์ง€ํ„ธํ™” ํ˜„ํ™ฉ๊ณผ ๊ณผ์ œ
709
+ - ์„ฑ๊ณต์„ ์œ„ํ•œ ํ•ต์‹ฌ ์ „๋žต
710
+ - ๊ธ€๋กœ๋ฒŒ ์„ฑ๊ณต ์‚ฌ๋ก€์™€ ๊ตํ›ˆ
711
+ - ๊ฒฐ๋ก  ๋ฐ ๋‹ค์Œ ๋‹จ๊ณ„
712
+ ๋ฐœํ‘œ์ž ๋…ธํŠธ: ์ „์ฒด 20๋ถ„ ๋ฐœํ‘œ ์ค‘ ๊ฐ ์„น์…˜๋ณ„ ์‹œ๊ฐ„ ๋ฐฐ๋ถ„ ์„ค๋ช…
713
+ ์‹œ๊ฐ ์ž๋ฃŒ: ๋ฒˆํ˜ธ๊ฐ€ ๋งค๊ฒจ์ง„ ์•„์ด์ฝ˜๊ณผ ์ง„ํ–‰ ํ‘œ์‹œ ๋ฐ”
714
+
715
+ [์Šฌ๋ผ์ด๋“œ 3] ๋„์ž…
716
+ ์ œ๋ชฉ: ์™œ ์ง€๊ธˆ ๋””์ง€ํ„ธ ํŠธ๋žœ์Šคํฌ๋ฉ”์ด์…˜์ธ๊ฐ€?
717
+ ํ•ต์‹ฌ ๋‚ด์šฉ:
718
+ - 2024๋…„ ๊ธ€๋กœ๋ฒŒ DX ํˆฌ์ž: $3.4์กฐ
719
+ - ๋””์ง€ํ„ธ ๋ฆฌ๋” ๊ธฐ์—…์˜ ์ˆ˜์ต์„ฑ: ํ‰๊ท  ๋Œ€๋น„ 2.5๋ฐฐ
720
+ - ํŒฌ๋ฐ๋ฏน ์ดํ›„ ๋””์ง€ํ„ธ ์ฑ„ํƒ ๊ฐ€์†ํ™”: 10๋…„โ†’2๋…„
721
+ - "๋ณ€ํ™”ํ•˜๊ฑฐ๋‚˜ ๋„ํƒœ๋˜๊ฑฐ๋‚˜" - ์ƒ์กด์˜ ๋ฌธ์ œ
722
+ ๋ฐœํ‘œ์ž ๋…ธํŠธ: ์‹œ์žฅ ๊ทœ๋ชจ์™€ ๊ธด๊ธ‰์„ฑ์„ ๊ฐ•์กฐํ•˜์—ฌ ์ฒญ์ค‘์˜ ๊ด€์‹ฌ ์œ ๋„
723
+ ์‹œ๊ฐ ์ž๋ฃŒ: ๊ธ‰์ƒ์Šนํ•˜๋Š” ๊ทธ๋ž˜ํ”„์™€ ์‹œ๊ณ„ ์•„์ด์ฝ˜์œผ๋กœ ์‹œ๊ธ‰ํ•จ ํ‘œํ˜„
724
+
725
+ [์Šฌ๋ผ์ด๋“œ 4] ์‚ฐ์—…๋ณ„ ํ˜„ํ™ฉ
726
+ ์ œ๋ชฉ: ์‚ฐ์—…๋ณ„ ๋””์ง€ํ„ธ ํŠธ๋žœ์Šคํฌ๋ฉ”์ด์…˜ ํ˜„ํ™ฉ
727
+ ํ•ต์‹ฌ ๋‚ด์šฉ:
728
+ - ๊ธˆ์œต: 78% (์„ ๋„ ๊ทธ๋ฃน)
729
+ - ํ—ฌ์Šค์ผ€์–ด: 61% (๋น ๋ฅธ ์ถ”๊ฒฉ)
730
+ - ์ œ์กฐ: 52% (๊พธ์ค€ํ•œ ์ง„ํ–‰)
731
+ - ์†Œ๋งค: 45% (๊ฐ€์†ํ™” ํ•„์š”)
732
+ ๋ฐœํ‘œ์ž ๋…ธํŠธ: ๊ฐ ์‚ฐ์—…์˜ ํŠน์„ฑ๊ณผ ๋„์ „๊ณผ์ œ ๊ฐ„๋‹จํžˆ ์–ธ๊ธ‰
733
+ ์‹œ๊ฐ ์ž๋ฃŒ: ๋„๋„› ์ฐจํŠธ์™€ ์‚ฐ์—…๋ณ„ ์•„์ด์ฝ˜, ์ง„ํ–‰๋ฅ  ๋ฐ”
734
+
735
+ [์Šฌ๋ผ์ด๋“œ 5] ์ฃผ์š” ๋„์ „๊ณผ์ œ
736
+ ์ œ๋ชฉ: ๋””์ง€ํ„ธ ํŠธ๋žœ์Šคํฌ๋ฉ”์ด์…˜์˜ 5๋Œ€ ์žฅ๋ฒฝ
737
+ ํ•ต์‹ฌ ๋‚ด์šฉ:
738
+ - ๋ ˆ๊ฑฐ์‹œ ์‹œ์Šคํ…œ์˜ ๋ณต์žก์„ฑ (67%)
739
+ - ๋ณ€ํ™” ์ €ํ•ญ๊ณผ ๋ฌธํ™”์  ๊ด€์„ฑ (54%)
740
+ - ๋””์ง€ํ„ธ ์ธ์žฌ ๋ถ€์กฑ (48%)
741
+ - ๋ถˆ๋ช…ํ™•ํ•œ ROI (41%)
742
+ - ์‚ฌ์ด๋ฒ„ ๋ณด์•ˆ ์šฐ๋ ค (38%)
743
+ ๋ฐœํ‘œ์ž ๋…ธํŠธ: ๊ฐ ์žฅ๋ฒฝ์— ๋Œ€ํ•œ ๊ทน๋ณต ๋ฐฉ์•ˆ ๋ฏธ๋ฆฌ ์ค€๋น„
744
+ ์‹œ๊ฐ ์ž๋ฃŒ: ์žฅ๋ฒฝ์„ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฒฝ๋Œ ์•„์ด์ฝ˜๊ณผ ๋ฐฑ๋ถ„์œจ ํ‘œ์‹œ
745
+
746
+ [์Šฌ๋ผ์ด๋“œ 6] DX ํ”„๋ ˆ์ž„์›Œํฌ
747
+ ์ œ๋ชฉ: ๋””์ง€ํ„ธ ํŠธ๋žœ์Šคํฌ๋ฉ”์ด์…˜ ์„ฑ๊ณต ํ”„๋ ˆ์ž„์›Œํฌ
748
+ ํ•ต์‹ฌ ๋‚ด์šฉ:
749
+ - ์ „๋žต: ๋น„์ฆˆ๋‹ˆ์Šค ๋ชฉํ‘œ ์ •๋ ฌ
750
+ - ๊ธฐ์ˆ : AI/ํด๋ผ์šฐ๋“œ/๋ฐ์ดํ„ฐ
751
+ - ํ”„๋กœ์„ธ์Šค: ์• ์ž์ผ ๋ฐฉ๋ฒ•๋ก 
752
+ - ๋ฌธํ™”: ํ˜์‹ ๊ณผ ์‹คํ—˜ ์žฅ๋ ค
753
+ - ๊ฑฐ๋ฒ„๋„Œ์Šค: ์ง€์†์  ๊ฐœ์„ 
754
+ ๋ฐœํ‘œ์ž ๋…ธํŠธ: ๊ฐ ์š”์†Œ๊ฐ€ ์ƒํ˜ธ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์Œ์„ ๊ฐ•์กฐ
755
+ ์‹œ๊ฐ ์ž๋ฃŒ: 5๊ฐํ˜• ๋‹ค์ด์–ด๊ทธ๋žจ, ๊ฐ ๊ผญ์ง€์ ์— ์•„์ด์ฝ˜ ๋ฐฐ์น˜
756
+
757
+ [์Šฌ๋ผ์ด๋“œ 7] ๊ธฐ์ˆ  ์Šคํƒ
758
+ ์ œ๋ชฉ: 2024 ํ•ต์‹ฌ ๊ธฐ์ˆ  ์Šคํƒ
759
+ ํ•ต์‹ฌ ๋‚ด์šฉ:
760
+ - AI/ML ์ฑ„ํƒ๋ฅ : 87%
761
+ - ํด๋ผ์šฐ๋“œ ์ „๋žต: 94% ํ•˜์ด๋ธŒ๋ฆฌ๋“œ
762
+ - ๋ฐ์ดํ„ฐ ๋ถ„์„: ์‹ค์‹œ๊ฐ„ ์ฒ˜๋ฆฌ
763
+ - ๋ณด์•ˆ: Zero Trust ์•„ํ‚คํ…์ฒ˜
764
+ - ํ†ตํ•ฉ: API ์šฐ์„  ์ ‘๊ทผ
765
+ ๋ฐœํ‘œ์ž ๋…ธํŠธ: ๊ฐ ๊ธฐ์ˆ ์˜ ๋น„์ฆˆ๋‹ˆ์Šค ๊ฐ€์น˜ ์—ฐ๊ฒฐ
766
+ ์‹œ๊ฐ ์ž๋ฃŒ: ๊ณ„์ธต์  ๊ธฐ์ˆ  ์Šคํƒ ๋‹ค์ด์–ด๊ทธ๋žจ
767
+
768
+ [์Šฌ๋ผ์ด๋“œ 8] ๋ณ€ํ™” ๊ด€๋ฆฌ
769
+ ์ œ๋ชฉ: ์‚ฌ๋žŒ ์ค‘์‹ฌ์˜ ๋ณ€ํ™” ๊ด€๋ฆฌ
770
+ ํ•ต์‹ฌ ๋‚ด์šฉ:
771
+ - ๋ฆฌ๋”์‹ญ์˜ ๋ช…ํ™•ํ•œ ๋น„์ „ ๊ณต์œ 
772
+ - ๋‹จ๊ณ„๋ณ„ ๊ต์œก ํ”„๋กœ๊ทธ๋žจ
773
+ - ๋น ๋ฅธ ์„ฑ๊ณผ๋กœ ๋ชจ๋ฉ˜ํ…€ ๊ตฌ์ถ•
774
+ - ์ง€์†์  ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜
775
+ - ๋ณด์ƒ ์ฒด๊ณ„ ์—ฐ๊ณ„
776
+ ๋ฐœํ‘œ์ž ๋…ธํŠธ: Satya Nadella ์ธ์šฉ๊ตฌ ํ™œ์šฉ
777
+ ์‹œ๊ฐ ์ž๋ฃŒ: ๋ณ€ํ™” ๊ณก์„ ๊ณผ ์‚ฌ๋žŒ ์•„์ด์ฝ˜
778
+
779
+ [์Šฌ๋ผ์ด๋“œ 9] ์„ฑ๊ณต ์‚ฌ๋ก€
780
+ ์ œ๋ชฉ: ๊ธ€๋กœ๋ฒŒ DX ์„ฑ๊ณต ์Šคํ† ๋ฆฌ
781
+ ํ•ต์‹ฌ ๋‚ด์šฉ:
782
+ - Amazon: ๋ฌผ๋ฅ˜ ์ž๋™ํ™” โ†’ ๋ฐฐ์†ก 40% ๋‹จ์ถ•
783
+ - Starbucks: ๋ชจ๋ฐ”์ผ ์ฃผ๋ฌธ โ†’ ๋งค์ถœ 26%
784
+ - Netflix: AI ์ถ”์ฒœ โ†’ ์‹œ์ฒญ ์‹œ๊ฐ„ 80% ์ฆ๊ฐ€
785
+ - Tesla: OTA ์—…๋ฐ์ดํŠธ โ†’ ์„œ๋น„์Šค ๋น„์šฉ 70% ์ ˆ๊ฐ
786
+ ๋ฐœํ‘œ์ž ๋…ธํŠธ: ๊ฐ ์‚ฌ๋ก€์˜ ํ•ต์‹ฌ ์„ฑ๊ณต ์š”์ธ ๊ฐ•์กฐ
787
+ ์‹œ๊ฐ ์ž๋ฃŒ: ๊ธฐ์—… ๋กœ๊ณ ์™€ ํ•ต์‹ฌ ์ง€ํ‘œ ์ธํฌ๊ทธ๋ž˜ํ”ฝ
788
+
789
+ [์Šฌ๋ผ์ด๋“œ 10] ROI ๋ถ„์„
790
+ ์ œ๋ชฉ: ๋””์ง€ํ„ธ ํŠธ๋žœ์Šคํฌ๋ฉ”์ด์…˜์˜ ๋ช…ํ™•ํ•œ ROI
791
+ ํ•ต์‹ฌ ๋‚ด์šฉ:
792
+ - ์šด์˜ ํšจ์œจ์„ฑ: 30-40% ๊ฐœ์„ 
793
+ - ๊ณ ๊ฐ ๋งŒ์กฑ๋„: NPS 25% ์ƒ์Šน
794
+ - ์‹ ๊ทœ ์ˆ˜์ต์›: ์ „์ฒด ๋งค์ถœ์˜ 15%
795
+ - ํˆฌ์ž ํšŒ์ˆ˜ ๊ธฐ๊ฐ„: ํ‰๊ท  2.5๋…„
796
+ ๋ฐœํ‘œ์ž ๋…ธํŠธ: ๊ตฌ์ฒด์ ์ธ ์ˆ˜์น˜๋กœ ํˆฌ์ž ์ •๋‹น์„ฑ ์ž…์ฆ
797
+ ์‹œ๊ฐ ์ž๋ฃŒ: ROI ๊ณ„์‚ฐ๊ธฐ ์Šคํƒ€์ผ์˜ ์ธํฌ๊ทธ๋ž˜ํ”ฝ
798
+
799
+ [์Šฌ๋ผ์ด๋“œ 11] ํ•ต์‹ฌ ์‹œ์‚ฌ์ 
800
+ ์ œ๋ชฉ: ์„ฑ๊ณต์ ์ธ DX๋ฅผ ์œ„ํ•œ 5๊ฐ€์ง€ ์ œ์–ธ
801
+ ํ•ต์‹ฌ ๋‚ด์šฉ:
802
+ - ์ž‘๊ฒŒ ์‹œ์ž‘ํ•˜๋˜ ํฌ๊ฒŒ ์ƒ๊ฐํ•˜๋ผ
803
+ - ๊ธฐ์ˆ ๋ณด๋‹ค ๋ฌธํ™” ๋ณ€ํ™”์— ํˆฌ์žํ•˜๋ผ
804
+ - ๋ฐ์ดํ„ฐ ๊ธฐ๋ฐ˜ ์˜์‚ฌ๊ฒฐ์ •์„ ์ผ์ƒํ™”ํ•˜๋ผ
805
+ - ์‹คํŒจ๋ฅผ ๋‘๋ ค์›Œํ•˜์ง€ ๋ง๊ณ  ๋น ๋ฅด๊ฒŒ ๋ฐฐ์›Œ๋ผ
806
+ - ๊ณ ๊ฐ ์ค‘์‹ฌ์œผ๋กœ ๋ชจ๋“  ๊ฒƒ์„ ์žฌ์„ค๊ณ„ํ•˜๋ผ
807
+ ๋ฐœํ‘œ์ž ๋…ธํŠธ: ๊ฐ ์ œ์–ธ์— ๋Œ€ํ•œ ์‹ค์ฒœ ๋ฐฉ์•ˆ ์ค€๋น„
808
+ ์‹œ๊ฐ ์ž๋ฃŒ: ์ฒดํฌ๋ฆฌ์ŠคํŠธ ์Šคํƒ€์ผ์˜ ์•„์ด์ฝ˜
809
+
810
+ [์Šฌ๋ผ์ด๋“œ 12] Q&A
811
+ ์ œ๋ชฉ: Questions & Discussion
812
+ ํ•ต์‹ฌ ๋‚ด์šฉ:
813
+ - ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค
814
+ - ์งˆ๋ฌธ๊ณผ ํ† ๋ก  ํ™˜์˜
815
+ - ์—ฐ๋ฝ์ฒ˜: [์ด๋ฉ”์ผ/์ „ํ™”]
816
+ - ์ถ”๊ฐ€ ์ž๋ฃŒ: [์›น์‚ฌ์ดํŠธ/QR์ฝ”๋“œ]
817
+ ๋ฐœํ‘œ์ž ๋…ธํŠธ: ์˜ˆ์ƒ ์งˆ๋ฌธ 3-5๊ฐœ ๋ฏธ๋ฆฌ ์ค€๋น„
818
+ ์‹œ๊ฐ ์ž๋ฃŒ: ๋ฌผ์Œํ‘œ ์•„์ด์ฝ˜๊ณผ ์—ฐ๋ฝ์ฒ˜ ์ •๋ณด""",
819
+
820
+ "supervisor_review": """์‹คํ–‰์ž AI์˜ PPT ์ดˆ์•ˆ์„ ๊ฒ€ํ† ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ „๋ฐ˜์ ์œผ๋กœ ์ž˜ ๊ตฌ์„ฑ๋˜์—ˆ์œผ๋‚˜ ๋‹ค์Œ ๊ฐœ์„ ์‚ฌํ•ญ์„ ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค.
821
+
822
+ ## ๊ฐ•์ 
823
+ - ์กฐ์‚ฌ๋œ ํ†ต๊ณ„์™€ ์ˆ˜์น˜๊ฐ€ ํšจ๊ณผ์ ์œผ๋กœ ํ™œ์šฉ๋จ
824
+ - ์Šคํ† ๋ฆฌ๋ผ์ธ์ด ๋…ผ๋ฆฌ์ ์ด๊ณ  ์„ค๋“๋ ฅ ์žˆ์Œ
825
+ - ๊ฐ ์Šฌ๋ผ์ด๋“œ์˜ ํ•ต์‹ฌ ๋ฉ”์‹œ์ง€๊ฐ€ ๋ช…ํ™•ํ•จ
826
+ - ์‹œ๊ฐ ์ž๋ฃŒ ์ œ์•ˆ์ด ๊ตฌ์ฒด์ ์ž„
827
+
828
+ ## ๊ฐœ์„  ํ•„์š”์‚ฌํ•ญ
829
+
830
+ ### 1. ์ž„ํŒฉํŠธ ๊ฐ•ํ™”
831
+ **์Šฌ๋ผ์ด๋“œ 3 ๊ฐœ์„ **
832
+ - ํ˜„์žฌ: ํ†ต๊ณ„ ๋‚˜์—ด
833
+ - ๊ฐœ์„ : "๊ท€์‚ฌ๋Š” ๋””์ง€ํ„ธ ๋ฆฌ๋”์ž…๋‹ˆ๊นŒ, ํ›„๋ฐœ์ฃผ์ž์ž…๋‹ˆ๊นŒ?"๋ผ๋Š” ๋„๋ฐœ์  ์งˆ๋ฌธ ์ถ”๊ฐ€
834
+ - ์ฒญ์ค‘ ์ฐธ์—ฌ๋ฅผ ์œ„ํ•œ ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ์š”์†Œ ๊ณ ๋ ค
835
+
836
+ **์Šฌ๋ผ์ด๋“œ 5 ๊ฐœ์„ **
837
+ - ํ˜„์žฌ: ์žฅ๋ฒฝ๋งŒ ์ œ์‹œ
838
+ - ๊ฐœ์„ : ๊ฐ ์žฅ๋ฒฝ๋ณ„ "Quick Win" ์†”๋ฃจ์…˜ ํ•œ ์ค„ ์ถ”๊ฐ€
839
+ - ํฌ๋ง์  ๋ฉ”์‹œ์ง€๋กœ ๊ท ํ˜• ๋งž์ถ”๊ธฐ
840
+
841
+ ### 2. ์Šคํ† ๋ฆฌํ…”๋ง ๊ฐ•ํ™”
842
+ **์ „ํ™˜ ๋ฌธ๊ตฌ ์ถ”๊ฐ€**
843
+ - ์Šฌ๋ผ์ด๋“œ ๊ฐ„ ์—ฐ๊ฒฐ ๋ฌธ๊ตฌ ํ•„์š”
844
+ - ์˜ˆ: "์ด์ œ ์ด๋Ÿฌํ•œ ํ˜„ํ™ฉ์„ ์–ด๋–ป๊ฒŒ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ์„๊นŒ์š”?"
845
+
846
+ **๊ฐ์ •์  ์—ฐ๊ฒฐ**
847
+ - ์ˆซ์ž์™€ ํ†ต๊ณ„ ์™ธ์— ์ธ๊ฐ„์  ์Šคํ† ๋ฆฌ ์ถ”๊ฐ€
848
+ - ๋ณ€ํ™”๋ฅผ ๊ฒช์€ ์ง์›/๊ณ ๊ฐ์˜ ์‹ค์ œ ๊ฒฝํ—˜๋‹ด
849
+
850
+ ### 3. ๋น„์ฃผ์–ผ ์ผ๊ด€์„ฑ
851
+ **์ƒ‰์ƒ ์‚ฌ์šฉ ์ •์ œ**
852
+ - ๊ฐ•์กฐ์ƒ‰(์˜ค๋ Œ์ง€) ๊ณผ๋„ ์‚ฌ์šฉ ์ž์ œ
853
+ - ๊ฐ ์„น์…˜๋ณ„ ์ƒ‰์ƒ ํ†ค ๊ตฌ๋ถ„
854
+ - ๋ฐ์ดํ„ฐ ์‹œ๊ฐํ™” ์ƒ‰์ƒ ํŒ”๋ ˆํŠธ ํ†ต์ผ
855
+
856
+ **์•„์ด์ฝ˜ ์Šคํƒ€์ผ**
857
+ - ๋ชจ๋“  ์•„์ด์ฝ˜ ๋™์ผ ์Šคํƒ€์ผ๋กœ ํ†ต์ผ
858
+ - ๋ผ์ธ ๋‘๊ป˜, ๋ชจ์„œ๋ฆฌ ์ฒ˜๋ฆฌ ์ผ๊ด€์„ฑ
859
+
860
+ ### 4. ๋ฐœํ‘œ ์ค€๋น„ ๊ฐ•ํ™”
861
+ **์‹œ๊ฐ„ ๋ฐฐ๋ถ„ ๋ช…์‹œ**
862
+ - ๊ฐ ์Šฌ๋ผ์ด๋“œ๋ณ„ ์˜ˆ์ƒ ์†Œ์š” ์‹œ๊ฐ„ ์ถ”๊ฐ€
863
+ - ์ „์ฒด 20๋ถ„ ๊ธฐ์ค€ ์ƒ์„ธ ๋ฐฐ๋ถ„
864
+
865
+ **์ „ํ™˜ ์Šคํฌ๋ฆฝํŠธ**
866
+ - ์Šฌ๋ผ์ด๋“œ ๊ฐ„ ์ž์—ฐ์Šค๋Ÿฌ์šด ์ „ํ™˜ ๋ฉ˜ํŠธ ์ค€๋น„
867
+ - ์ฒญ์ค‘ ๋ฐ˜์‘ ์ฒดํฌ ํฌ์ธํŠธ ์„ค์ •
868
+
869
+ ### 5. ์ถ”๊ฐ€ ๊ถŒ์žฅ์‚ฌํ•ญ
870
+ **๋ฐฑ์—… ์Šฌ๋ผ์ด๋“œ ์ค€๋น„**
871
+ - ์ƒ์„ธ ๊ธฐ์ˆ  ์ŠคํŽ™
872
+ - ์ถ”๊ฐ€ ์‚ฌ๋ก€ ์—ฐ๊ตฌ
873
+ - ์—…์ข…๋ณ„ ๋งž์ถค ์ „๋žต
874
+ - ์ƒ์„ธ ROI ๊ณ„์‚ฐ ๋ฐฉ๋ฒ•
875
+
876
+ **์ธ์‡„ ์ž๋ฃŒ**
877
+ - 3์Šฌ๋ผ์ด๋“œ/ํŽ˜์ด์ง€ ํ˜•์‹
878
+ - ๋ฉ”๋ชจ ๊ณต๊ฐ„ ํฌํ•จ
879
+ - ํ•ต์‹ฌ ์ˆ˜์น˜ ์š”์•ฝ ํŽ˜์ด์ง€
880
+
881
+ ์ด๋Ÿฌํ•œ ๊ฐœ์„ ์‚ฌํ•ญ์„ ๋ฐ˜์˜ํ•˜๋ฉด ๋”์šฑ ์™„์„ฑ๋„ ๋†’๊ณ  ์„ค๋“๋ ฅ ์žˆ๋Š” PPT๊ฐ€ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.""",
882
+
883
+ "executor_final": """๊ฐ๋…์ž AI์˜ ํ”ผ๋“œ๋ฐฑ์„ ์™„์ „ํžˆ ๋ฐ˜์˜ํ•œ ์ตœ์ข… PPT๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
884
+
885
+ # ๐ŸŽฏ ๋””์ง€ํ„ธ ํŠธ๋žœ์Šคํฌ๋ฉ”์ด์…˜: ๋ฏธ๋ž˜๋ฅผ ํ–ฅํ•œ ๋„์•ฝ
886
+ ## ์ตœ์ข… ์™„์„ฑ PPT (๋ฐœํ‘œ ์‹œ๊ฐ„: 20๋ถ„)
887
+
888
+ ---
889
+
890
+ [์Šฌ๋ผ์ด๋“œ 1] ํ‘œ์ง€ (30์ดˆ)
891
+ **์ œ๋ชฉ**: ๋””์ง€ํ„ธ ํŠธ๋žœ์Šคํฌ๋ฉ”์ด์…˜: ๋ฏธ๋ž˜๋ฅผ ํ–ฅํ•œ ๋„์•ฝ
892
+ **๋ถ€์ œ๋ชฉ**: ์„ฑ๊ณต์ ์ธ DX ์ „๋žต๊ณผ ์‹คํ–‰ ๋ฐฉ์•ˆ
893
+ **๋น„์ฃผ์–ผ**:
894
+ - ๋ฐฐ๊ฒฝ: ์—ฐ๊ฒฐ๋œ ๋””์ง€ํ„ธ ๋„คํŠธ์›Œํฌ์™€ ๋ฐ์ดํ„ฐ ํ๋ฆ„
895
+ - ์ค‘์•™: ํšŒ์‚ฌ ๋กœ๊ณ 
896
+ - ํ•˜๋‹จ: ๋ฐœํ‘œ์ž ์ •๋ณด ๋ฐ ๋‚ ์งœ
897
+ **๋ฐœํ‘œ์ž ๋…ธํŠธ**:
898
+ "์•ˆ๋…•ํ•˜์‹ญ๋‹ˆ๊นŒ. ์˜ค๋Š˜ ์—ฌ๋Ÿฌ๋ถ„๊ณผ ํ•จ๊ป˜ $3.4์กฐ ๊ทœ๋ชจ์˜ ๋””์ง€ํ„ธ ํ˜๋ช…, ๊ทธ ์ค‘์‹ฌ์—์„œ ์šฐ๋ฆฌ๊ฐ€ ์–ด๋–ป๊ฒŒ ์„ฑ๊ณตํ•  ์ˆ˜ ์žˆ์„์ง€ ๋…ผ์˜ํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค."
899
+
900
+ ---
901
+
902
+ [์Šฌ๋ผ์ด๋“œ 2] ๋ชฉ์ฐจ (30์ดˆ)
903
+ **์ œ๋ชฉ**: ์˜ค๋Š˜์˜ ์—ฌ์ •
904
+ **ํ•ต์‹ฌ ๋‚ด์šฉ**:
905
+ 1. ๐Ÿ“Š ๋””์ง€ํ„ธ ํŠธ๋žœ์Šคํฌ๋ฉ”์ด์…˜์˜ ํ˜„์žฌ (3๋ถ„)
906
+ 2. ๐Ÿญ ์‚ฐ์—…๋ณ„ ํ˜„ํ™ฉ๊ณผ ๋„์ „๊ณผ์ œ (3๋ถ„)
907
+ 3. ๐ŸŽฏ ์„ฑ๊ณต ์ „๋žต๊ณผ ํ”„๋ ˆ์ž„์›Œํฌ (5๋ถ„)
908
+ 4. ๐ŸŒŸ ๊ธ€๋กœ๋ฒŒ ์„ฑ๊ณต ์‚ฌ๋ก€ (4๋ถ„)
909
+ 5. ๐Ÿ’ก ํ•ต์‹ฌ ์‹œ์‚ฌ์ ๊ณผ ์‹คํ–‰ ๋ฐฉ์•ˆ (4๋ถ„)
910
+ 6. ๐Ÿค Q&A (1๋ถ„)
911
+ **๋ฐœํ‘œ์ž ๋…ธํŠธ**:
912
+ "20๋ถ„๊ฐ„์˜ ์—ฌ์ •์„ ํ†ตํ•ด ๋””์ง€ํ„ธ ํŠธ๋žœ์Šคํฌ๋ฉ”์ด์…˜์˜ ํ˜„์žฌ์™€ ๋ฏธ๋ž˜, ๊ทธ๋ฆฌ๊ณ  ์‹คํ–‰ ๋ฐฉ์•ˆ์„ ํ•จ๊ป˜ ํƒ์ƒ‰ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค."
913
+ **์‹œ๊ฐ ์ž๋ฃŒ**: ์ง„ํ–‰ ๋‹จ๊ณ„๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๋กœ๋“œ๋งต ์Šคํƒ€์ผ ๋””์ž์ธ
914
+
915
+ ---
916
+
917
+ [์Šฌ๋ผ์ด๋“œ 3] ๋„์ „์  ์งˆ๋ฌธ (1๋ถ„ 30์ดˆ)
918
+ **์ œ๋ชฉ**: ๊ท€์‚ฌ๋Š” ๋””์ง€ํ„ธ ๋ฆฌ๋”์ž…๋‹ˆ๊นŒ, ํ›„๋ฐœ์ฃผ์ž์ž…๋‹ˆ๊นŒ?
919
+ **ํ•ต์‹ฌ ๋‚ด์šฉ**:
920
+ - ๐ŸŒ 2024๋…„ ๊ธ€๋กœ๋ฒŒ DX ์‹œ์žฅ: **$3.4์กฐ**
921
+ - ๐Ÿ“ˆ ๋””์ง€ํ„ธ ๋ฆฌ๋”์˜ ์ˆ˜์ต์„ฑ: ํ‰๊ท  ๋Œ€๋น„ **2.5๋ฐฐ**
922
+ - โฐ ๋ณ€ํ™”์˜ ์†๋„: 10๋…„ โ†’ **2๋…„** (ํŒฌ๋ฐ๋ฏน ๊ฐ€์†ํ™”)
923
+ - โšก ํ•ต์‹ฌ ์งˆ๋ฌธ: "์šฐ๋ฆฌ๋Š” ๋ณ€ํ™”๋ฅผ ์ฃผ๋„ํ•˜๊ณ  ์žˆ๋Š”๊ฐ€?"
924
+ **๋ฐœํ‘œ์ž ๋…ธํŠธ**:
925
+ "์ž ์‹œ ์ƒ๊ฐํ•ด๋ณด์‹ญ์‹œ์˜ค. ๊ท€์‚ฌ๋Š” ์ด ๊ฑฐ๋Œ€ํ•œ ๋ณ€ํ™”์˜ ๋ฌผ๊ฒฐ์„ ํƒ€๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ, ์•„๋‹ˆ๋ฉด ๋’ค์ฒ˜์ ธ ์žˆ์Šต๋‹ˆ๊นŒ?"
926
+ **์‹œ๊ฐ ์ž๋ฃŒ**:
927
+ - ์ƒ๋‹จ: ๋„๋ฐœ์  ์งˆ๋ฌธ ํฌ๊ฒŒ ํ‘œ์‹œ
928
+ - ์ค‘์•™: ๋ฆฌ๋” vs ํ›„๋ฐœ์ฃผ์ž ๋Œ€๋น„ ์ธํฌ๊ทธ๋ž˜ํ”ฝ
929
+ - ์ „ํ™˜: ์ฒญ์ค‘ ์ฐธ์—ฌ๋ฅผ ์œ„ํ•œ 3์ดˆ pause
930
+
931
+ ---
932
+
933
+ [์Šฌ๋ผ์ด๋“œ 4] ์‚ฐ์—…๋ณ„ ๋””์ง€ํ„ธํ™” ํ˜„ํ™ฉ (1๋ถ„ 30์ดˆ)
934
+ **์ œ๋ชฉ**: ๋‹น์‹ ์˜ ์‚ฐ์—…์€ ์–ด๋””์— ์œ„์น˜ํ•ฉ๋‹ˆ๊นŒ?
935
+ **ํ•ต์‹ฌ ๋‚ด์šฉ**:
936
+ - ๐Ÿฆ ๊ธˆ์œต: 78% - "๋””์ง€ํ„ธ์ด ์ƒˆ๋กœ์šด ํ‘œ์ค€"
937
+ - ๐Ÿฅ ํ—ฌ์Šค์ผ€์–ด: 61% - "์›๊ฒฉ์˜๋ฃŒ๊ฐ€ ์ผ์ƒ์œผ๋กœ"
938
+ - ๐Ÿญ ์ œ์กฐ: 52% - "์Šค๋งˆํŠธ ํŒฉํ† ๋ฆฌ๋กœ ์ง„ํ™”"
939
+ - ๐Ÿ›๏ธ ์†Œ๋งค: 45% - "์˜ด๋‹ˆ์ฑ„๋„์ด ์ƒ์กด ์กฐ๊ฑด"
940
+ **๋ฐœํ‘œ์ž ๋…ธํŠธ**:
941
+ "๊ธˆ์œต์—…์€ ์ด๋ฏธ 78%๊ฐ€ ๋””์ง€ํ„ธํ™”๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ท€์‚ฌ์˜ ์‚ฐ์—…์€ ์–ด๋–ป์Šต๋‹ˆ๊นŒ? ์ด์ œ ๊ฐ ์‚ฐ์—…์˜ ์„ฑ๊ณต ๋น„๊ฒฐ์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค."
942
+ **์‹œ๊ฐ ์ž๋ฃŒ**:
943
+ - ๋ ˆ์ด์Šค ํŠธ๋ž™ ํ˜•ํƒœ์˜ ์ง„ํ–‰๋„ ํ‘œ์‹œ
944
+ - ๊ฐ ์‚ฐ์—…๋ณ„ ๋Œ€ํ‘œ ์•„์ด์ฝ˜๊ณผ ์ง„ํ–‰๋ฅ 
945
+ - ์—…์ข…๋ณ„ ๋Œ€ํ‘œ ๊ธฐ์—… ๋กœ๊ณ  ์ž‘๊ฒŒ ํ‘œ์‹œ
946
+
947
+ ---
948
+
949
+ [์Šฌ๋ผ์ด๋“œ 5] 5๋Œ€ ์žฅ๋ฒฝ๊ณผ ํ•ด๊ฒฐ์ฑ… (2๋ถ„)
950
+ **์ œ๋ชฉ**: ์žฅ๋ฒฝ์„ ๊ธฐํšŒ๋กœ: 5๋Œ€ ๋„์ „๊ณผ์ œ์™€ Quick Win
951
+ **ํ•ต์‹ฌ ๋‚ด์šฉ**:
952
+ - ๐Ÿ”ง ๋ ˆ๊ฑฐ์‹œ ์‹œ์Šคํ…œ (67%) โ†’ "๋‹จ๊ณ„์  ํ˜„๋Œ€ํ™” ์ „๋žต"
953
+ - ๐Ÿšซ ๋ณ€ํ™” ์ €ํ•ญ (54%) โ†’ "์ž‘์€ ์„ฑ๊ณต ์Šคํ† ๋ฆฌ ํ™•์‚ฐ"
954
+ - ๐Ÿ‘ฅ ์ธ์žฌ ๋ถ€์กฑ (48%) โ†’ "์—…์Šคํ‚ฌ๋ง + ์™ธ๋ถ€ ํŒŒํŠธ๋„ˆ์‹ญ"
955
+ - ๐Ÿ’ฐ ๋ถˆ๋ช…ํ™•ํ•œ ROI (41%) โ†’ "ํŒŒ์ผ๋Ÿฟ ํ”„๋กœ์ ํŠธ๋กœ ์ฆ๋ช…"
956
+ - ๐Ÿ”’ ๋ณด์•ˆ ์šฐ๋ ค (38%) โ†’ "Security by Design ์›์น™"
957
+ **๋ฐœํ‘œ์ž ๋…ธํŠธ**:
958
+ "๋ชจ๋“  ์žฅ๋ฒฝ์—๋Š” ํ•ด๊ฒฐ์ฑ…์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ค‘์š”ํ•œ ๊ฒƒ์€ ์–ด๋””์„œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•  ๊ฒƒ์ธ๊ฐ€์ž…๋‹ˆ๋‹ค."
959
+ **์ „ํ™˜ ๋ฉ˜ํŠธ**: "๊ทธ๋ ‡๋‹ค๋ฉด ์ด๋Ÿฌํ•œ ์žฅ๋ฒฝ์„ ๋„˜์–ด ์„ฑ๊ณตํ•˜๊ธฐ ์œ„ํ•œ ๊ฒ€์ฆ๋œ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์†Œ๊ฐœํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค."
960
+ **์‹œ๊ฐ ์ž๋ฃŒ**:
961
+ - ์žฅ๋ฒฝโ†’ํ•ด๊ฒฐ์ฑ… ํ™”์‚ดํ‘œ ์• ๋‹ˆ๋ฉ”์ด์…˜
962
+ - ๊ฐ ํ•ญ๋ชฉ๋ณ„ ์ˆœ์ฐจ์  ๋“ฑ์žฅ ํšจ๊ณผ
963
+
964
+ ---
965
+
966
+ [์Šฌ๋ผ์ด๋“œ 6] DX ์„ฑ๊ณต ํ”„๋ ˆ์ž„์›Œํฌ (2๋ถ„)
967
+ **์ œ๋ชฉ**: ๊ฒ€์ฆ๋œ ๋””์ง€ํ„ธ ํŠธ๋žœ์Šคํฌ๋ฉ”์ด์…˜ ํ”„๋ ˆ์ž„์›Œํฌ
968
+ **ํ•ต์‹ฌ ๋‚ด์šฉ**:
969
+ ๐ŸŽฏ **์ „๋žต**: ๋น„์ฆˆ๋‹ˆ์Šค ๋ชฉํ‘œ์™€ 100% ์ •๋ ฌ
970
+ ๐Ÿ”ง **๊ธฐ์ˆ **: AI(87%) + ํด๋ผ์šฐ๋“œ(94%) + ๋ฐ์ดํ„ฐ
971
+ ๐Ÿ‘ฅ **๋ฌธํ™”**: ํ˜์‹  DNA ์ฃผ์ž…
972
+ โš™๏ธ **ํ”„๋กœ์„ธ์Šค**: ์• ์ž์ผ + DevOps
973
+ ๐Ÿ“Š **๊ฑฐ๋ฒ„๋„Œ์Šค**: ์ธก์ • ๊ฐ€๋Šฅํ•œ KPI
974
+ **๋ฐœํ‘œ์ž ๋…ธํŠธ**:
975
+ "์ด 5๊ฐ€์ง€ ์š”์†Œ๋Š” ํ†ฑ๋‹ˆ๋ฐ”ํ€ด์ฒ˜๋Ÿผ ๋งž๋ฌผ๋ ค ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜๋‚˜๋ผ๋„ ๋น ์ง€๋ฉด ์ „์ฒด๊ฐ€ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."
976
+ **์‹œ๊ฐ ์ž๋ฃŒ**:
977
+ - ์ค‘์•™: 5๊ฐํ˜• ๋‹ค์ด์–ด๊ทธ๋žจ
978
+ - ๊ฐ ์š”์†Œ ๊ฐ„ ์—ฐ๊ฒฐ์„ ์œผ๋กœ ์ƒํ˜ธ์˜์กด์„ฑ ํ‘œํ˜„
979
+ - ํ˜ธ๋ฒ„ ํšจ๊ณผ๋กœ ๊ฐ ์š”์†Œ ์ƒ์„ธ ์„ค๋ช…
980
+
981
+ ---
982
+
983
+ [์Šฌ๋ผ์ด๋“œ 7] 2024 ๊ธฐ์ˆ  ์Šคํƒ (1๋ถ„ 30์ดˆ)
984
+ **์ œ๋ชฉ**: ๋ฏธ๋ž˜๋ฅผ ๋งŒ๋“œ๋Š” ๊ธฐ์ˆ  ์Šคํƒ
985
+ **ํ•ต์‹ฌ ๋‚ด์šฉ**:
986
+ **Layer 1 - ์ธํ”„๋ผ**
987
+ - โ˜๏ธ ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ํด๋ผ์šฐ๋“œ (94% ์ฑ„ํƒ)
988
+ **Layer 2 - ๋ฐ์ดํ„ฐ**
989
+ - ๐Ÿ“Š ์‹ค์‹œ๊ฐ„ ๋ถ„์„ ํ”Œ๋žซํผ
990
+ **Layer 3 - ์ธํ…”๋ฆฌ์ „์Šค**
991
+ - ๐Ÿค– AI/ML (87% ํ†ตํ•ฉ)
992
+ **Layer 4 - ๊ฒฝํ—˜**
993
+ - ๐Ÿ“ฑ ์˜ด๋‹ˆ์ฑ„๋„ ์ธํ„ฐํŽ˜์ด์Šค
994
+ **Layer 5 - ๋ณด์•ˆ**
995
+ - ๐Ÿ” Zero Trust ์•„ํ‚คํ…์ฒ˜
996
+ **๋ฐœํ‘œ์ž ๋…ธํŠธ**:
997
+ "๊ฐ ๋ ˆ์ด์–ด๋Š” ๊ทธ ์œ„์˜ ๋ ˆ์ด์–ด๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ํƒ„ํƒ„ํ•œ ๊ธฐ์ดˆ ์—†์ด๋Š” ํ˜์‹ ๋„ ์—†์Šต๋‹ˆ๋‹ค."
998
+ **์‹œ๊ฐ ์ž๋ฃŒ**:
999
+ - ํ”ผ๋ผ๋ฏธ๋“œ ํ˜•ํƒœ์˜ ๊ธฐ์ˆ  ์Šคํƒ
1000
+ - ๊ฐ ๋ ˆ์ด์–ด๋ณ„ ๋Œ€ํ‘œ ๊ธฐ์ˆ  ๋กœ๊ณ 
1001
+
1002
+ ---
1003
+
1004
+ [์Šฌ๋ผ์ด๋“œ 8] ์ธ๊ฐ„ ์ค‘์‹ฌ ๋ณ€ํ™” ๊ด€๋ฆฌ (1๋ถ„ 30์ดˆ)
1005
+ **์ œ๋ชฉ**: ๊ธฐ์ˆ ์ด ์•„๋‹Œ ์‚ฌ๋žŒ์ด ๋งŒ๋“œ๋Š” ๋ณ€ํ™”
1006
+ **ํ•ต์‹ฌ ๋‚ด์šฉ**:
1007
+ > "๋””์ง€ํ„ธ ํŠธ๋žœ์Šคํฌ๋ฉ”์ด์…˜์€ ๊ธฐ์ˆ ์ด ์•„๋‹Œ ์‚ฌ๋žŒ๊ณผ ๋ฌธํ™”์˜ ๋ณ€ํ™”๋‹ค"
1008
+ > - Satya Nadella, Microsoft CEO
1009
+
1010
+ - ๐ŸŽฏ **๋น„์ „**: ๋ช…ํ™•ํ•˜๊ณ  ๊ณ ๋ฌด์ ์ธ ๋ฏธ๋ž˜์ƒ
1011
+ - ๐Ÿ“š **๊ต์œก**: ์ง€์†์  ํ•™์Šต ๋ฌธํ™”
1012
+ - ๐Ÿ† **์„ฑ๊ณผ**: ์ž‘์€ ์Šน๋ฆฌ์˜ ์ถ•์ 
1013
+ - ๐Ÿ’ฌ **์†Œํ†ต**: ์–‘๋ฐฉํ–ฅ ํ”ผ๋“œ๋ฐฑ ๋ฃจํ”„
1014
+ - ๐ŸŽ **๋ณด์ƒ**: ํ˜์‹ ์— ๋Œ€ํ•œ ์ธ์„ผํ‹ฐ๋ธŒ
1015
+ **๋ฐœํ‘œ์ž ๋…ธํŠธ**:
1016
+ "๊ฐ€์žฅ ์•ž์„  ๊ธฐ์ˆ ๋„ ์‚ฌ๋žŒ์ด ๋ฐ›์•„๋“ค์ด์ง€ ์•Š์œผ๋ฉด ๋ฌด์šฉ์ง€๋ฌผ์ž…๋‹ˆ๋‹ค."
1017
+ **์ „ํ™˜ ๋ฉ˜ํŠธ**: "์ด์ œ ์ด๋Ÿฌํ•œ ์›์น™๋“ค์ด ์‹ค์ œ๋กœ ์–ด๋–ค ์„ฑ๊ณผ๋ฅผ ๋งŒ๋“ค์–ด๋ƒˆ๋Š”์ง€ ๋ณด์‹œ๊ฒ ์Šต๋‹ˆ๋‹ค."
1018
+ **์‹œ๊ฐ ์ž๋ฃŒ**: ์‚ฌ๋žŒ ์ค‘์‹ฌ์˜ ์›ํ˜• ๋‹ค์ด์–ด๊ทธ๋žจ
1019
+
1020
+ ---
1021
+
1022
+ [์Šฌ๋ผ์ด๋“œ 9] ๊ธ€๋กœ๋ฒŒ ์„ฑ๊ณต ์Šคํ† ๋ฆฌ (2๋ถ„)
1023
+ **์ œ๋ชฉ**: ์ˆซ์ž๋กœ ์ฆ๋ช…๋œ DX ์„ฑ๊ณต ์‚ฌ๋ก€
1024
+ **ํ•ต์‹ฌ ๋‚ด์šฉ**:
1025
+ ๐Ÿ“ฆ **Amazon**: ๋ฌผ๋ฅ˜ ์ž๋™ํ™” โ†’ ๋ฐฐ์†ก ์‹œ๊ฐ„ **40% ๋‹จ์ถ•**
1026
+ โ˜• **Starbucks**: ๋ชจ๋ฐ”์ผ ์ฃผ๋ฌธ โ†’ ๋งค์ถœ์˜ **26% ์ฐจ์ง€**
1027
+ ๐ŸŽฌ **Netflix**: AI ์ถ”์ฒœ โ†’ ์‹œ์ฒญ ์‹œ๊ฐ„ **80% ์ฆ๊ฐ€**
1028
+ ๐Ÿš— **Tesla**: OTA ์—…๋ฐ์ดํŠธ โ†’ ์„œ๋น„์Šค ๋น„์šฉ **70% ์ ˆ๊ฐ**
1029
+
1030
+ **๊ณตํ†ต ์„ฑ๊ณต ์š”์ธ**:
1031
+ - ๊ณ ๊ฐ ๊ฒฝํ—˜ ์ตœ์šฐ์„ 
1032
+ - ๋ฐ์ดํ„ฐ ๊ธฐ๋ฐ˜ ์˜์‚ฌ๊ฒฐ์ •
1033
+ - ์ง€์†์  ํ˜์‹  ๋ฌธํ™”
1034
+ **๋ฐœํ‘œ์ž ๋…ธํŠธ**:
1035
+ "์ด๋“ค์˜ ๊ณตํ†ต์ ์€ ๋ฌด์—‡์ผ๊นŒ์š”? ๊ธฐ์ˆ ์„ ๋ชฉ์ ์ด ์•„๋‹Œ ์ˆ˜๋‹จ์œผ๋กœ ํ™œ์šฉํ–ˆ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค."
1036
+ **์‹œ๊ฐ ์ž๋ฃŒ**:
1037
+ - ๊ฐ ๊ธฐ์—…๋ณ„ Before/After ๋Œ€๋น„
1038
+ - ํ•ต์‹ฌ ์ง€ํ‘œ ํฌ๊ฒŒ ๊ฐ•์กฐ
1039
+
1040
+ ---
1041
+
1042
+ [์Šฌ๋ผ์ด๋“œ 10] ROI์˜ ์ง„์‹ค (2๋ถ„)
1043
+ **์ œ๋ชฉ**: ํˆฌ์ž ๋Œ€๋น„ ์ˆ˜์ต, ์ˆจ๊ฒจ์ง„ ๊ฐ€์น˜๊นŒ์ง€
1044
+ **์ •๋Ÿ‰์  ํšจ๊ณผ**:
1045
+ - ๐Ÿ’ฐ ์šด์˜ ํšจ์œจ์„ฑ: **30-40% ๊ฐœ์„ **
1046
+ - ๐Ÿ˜Š ๊ณ ๊ฐ ๋งŒ์กฑ๋„: NPS **25ํฌ์ธํŠธ ์ƒ์Šน**
1047
+ - ๐Ÿš€ ์‹ ๊ทœ ์ˆ˜์ต: ์ „์ฒด ๋งค์ถœ์˜ **15% ์ฐฝ์ถœ**
1048
+ - โฑ๏ธ ํˆฌ์ž ํšŒ์ˆ˜: ํ‰๊ท  **2.5๋…„**
1049
+
1050
+ **์ •์„ฑ์  ํšจ๊ณผ**:
1051
+ - ์ง์› ๋งŒ์กฑ๋„ ํ–ฅ์ƒ
1052
+ - ๋ธŒ๋žœ๋“œ ์ด๋ฏธ์ง€ ์ œ๊ณ 
1053
+ - ๋ฏธ๋ž˜ ๋Œ€์‘๋ ฅ ํ™•๋ณด
1054
+ **๋ฐœํ‘œ์ž ๋…ธํŠธ**:
1055
+ "ROI๋Š” ๋‹จ์ˆœํžˆ ์ˆซ์ž๋กœ๋งŒ ์ธก์ •๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์กฐ์ง์˜ ๋ฏธ๋ž˜ ๊ฒฝ์Ÿ๋ ฅ์ด ์ง„์ •ํ•œ ๊ฐ€์น˜์ž…๋‹ˆ๋‹ค."
1056
+ **์‹œ๊ฐ ์ž๋ฃŒ**:
1057
+ - ROI ๊ณ„์‚ฐ๊ธฐ ์ธํ„ฐํŽ˜์ด์Šค
1058
+ - ์ •๋Ÿ‰/์ •์„ฑ ํšจ๊ณผ ๊ท ํ˜• ํ‘œ์‹œ
1059
+
1060
+ ---
1061
+
1062
+ [์Šฌ๋ผ์ด๋“œ 11] ์‹คํ–‰์„ ์œ„ํ•œ 5๊ฐ€์ง€ ์ œ์–ธ (2๋ถ„)
1063
+ **์ œ๋ชฉ**: ๋‚ด์ผ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋Š” 5๊ฐ€์ง€ ํ–‰๋™
1064
+ **ํ•ต์‹ฌ ์ œ์–ธ**:
1065
+ 1. ๐ŸŒฑ **Start Small, Think Big**
1066
+ - "ํŒŒ์ผ๋Ÿฟ ํ”„๋กœ์ ํŠธ๋กœ ์‹œ์ž‘ํ•˜๋˜ ์ „์‚ฌ ํ™•์‚ฐ ๊ณ„ํš ์ˆ˜๋ฆฝ"
1067
+ 2. ๐Ÿ‘ฅ **Culture First, Technology Second**
1068
+ - "์ตœ๊ณ ์˜ ๊ธฐ์ˆ ๋„ ๋ฌธํ™”๊ฐ€ ๋’ท๋ฐ›์นจ๋˜์ง€ ์•Š์œผ๋ฉด ์‹คํŒจ"
1069
+ 3. ๐Ÿ“Š **Data-Driven Everything**
1070
+ - "์ถ”์ธก์ด ์•„๋‹Œ ๋ฐ์ดํ„ฐ๋กœ ์˜์‚ฌ๊ฒฐ์ •"
1071
+ 4. ๐Ÿ”„ **Fail Fast, Learn Faster**
1072
+ - "์‹คํŒจ๋ฅผ ๋‘๋ ค์›Œํ•˜์ง€ ๋ง๊ณ  ๋น ๋ฅด๊ฒŒ ํ”ผ๋ฒ—"
1073
+ 5. ๐ŸŽฏ **Customer at the Center**
1074
+ - "๋ชจ๋“  ๋ณ€ํ™”์˜ ์ค‘์‹ฌ์— ๊ณ ๊ฐ ๊ฐ€์น˜"
1075
+ **๋ฐœํ‘œ์ž ๋…ธํŠธ**:
1076
+ "์ด ์ค‘ ๋‹จ ํ•˜๋‚˜๋งŒ์ด๋ผ๋„ ๋‚ด์ผ๋ถ€ํ„ฐ ์‹ค์ฒœํ•œ๋‹ค๋ฉด, 1๋…„ ํ›„ ์กฐ์ง์€ ์™„์ „ํžˆ ๋‹ฌ๋ผ์ ธ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค."
1077
+ **์‹œ๊ฐ ์ž๋ฃŒ**: ์ฒดํฌ๋ฐ•์Šค ์Šคํƒ€์ผ, ํ•˜๋‚˜์”ฉ ์ฒดํฌ๋˜๋Š” ์• ๋‹ˆ๋ฉ”์ด์…˜
1078
+
1079
+ ---
1080
+
1081
+ [์Šฌ๋ผ์ด๋“œ 12] ๋งˆ๋ฌด๋ฆฌ ๋ฐ Q&A (1๋ถ„)
1082
+ **์ œ๋ชฉ**: ํ•จ๊ป˜ ๋งŒ๋“œ๋Š” ๋””์ง€ํ„ธ ๋ฏธ๋ž˜
1083
+ **ํ•ต์‹ฌ ๋‚ด์šฉ**:
1084
+ ๐Ÿ™ **๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค**
1085
+
1086
+ ๐Ÿ’ญ **์ƒ๊ฐํ•ด๋ณผ ์งˆ๋ฌธ๋“ค**:
1087
+ - ์šฐ๋ฆฌ ์กฐ์ง์˜ ๋””์ง€ํ„ธ ์„ฑ์ˆ™๋„๋Š”?
1088
+ - ๊ฐ€์žฅ ๋จผ์ € ํ•ด๊ฒฐํ•ด์•ผ ํ•  ๊ณผ์ œ๋Š”?
1089
+ - ์ฒซ ๋ฒˆ์งธ ํŒŒ์ผ๋Ÿฟ ํ”„๋กœ์ ํŠธ๋Š”?
1090
+
1091
+ ๐Ÿ“ง ์—ฐ๋ฝ์ฒ˜: [์ด๋ฉ”์ผ]
1092
+ ๐Ÿ“ฑ LinkedIn: [ํ”„๋กœํ•„]
1093
+ ๐Ÿ”— ์ถ”๊ฐ€ ์ž๋ฃŒ: [QR ์ฝ”๋“œ]
1094
+ **๋ฐœํ‘œ์ž ๋…ธํŠธ**:
1095
+ "๋””์ง€ํ„ธ ํŠธ๋žœ์Šคํฌ๋ฉ”์ด์…˜์€ ๋ชฉ์ ์ง€๊ฐ€ ์•„๋‹Œ ์—ฌ์ •์ž…๋‹ˆ๋‹ค. ๊ทธ ์—ฌ์ •์„ ํ•จ๊ป˜ํ•˜๊ฒŒ ๋˜์–ด ์˜๊ด‘์ž…๋‹ˆ๋‹ค."
1096
+ **์‹œ๊ฐ ์ž๋ฃŒ**: QR ์ฝ”๋“œ์™€ ์—ฐ๋ฝ์ฒ˜ ์ •๋ณด
1097
+
1098
+ ---
1099
+
1100
+ ## ๐Ÿ“Ž ๋ฐฑ์—… ์Šฌ๋ผ์ด๋“œ (ํ•„์š”์‹œ ํ™œ์šฉ)
1101
+
1102
+ [๋ฐฑ์—… 1] ์‚ฐ์—…๋ณ„ ์ƒ์„ธ ์ „๋žต
1103
+ [๋ฐฑ์—… 2] ๊ธฐ์ˆ  ์Šคํƒ ์ƒ์„ธ ์ŠคํŽ™
1104
+ [๋ฐฑ์—… 3] ์ถ”๊ฐ€ ์„ฑ๊ณต ์‚ฌ๋ก€ (๊ตญ๋‚ด ๊ธฐ์—…)
1105
+ [๋ฐฑ์—… 4] ROI ๊ณ„์‚ฐ ๋ฐฉ๋ฒ•๋ก 
1106
+ [๋ฐฑ์—… 5] ๋‹จ๊ณ„๋ณ„ ์‹คํ–‰ ๋กœ๋“œ๋งต
1107
+
1108
+ ## ๐ŸŽค ์˜ˆ์ƒ Q&A ๋ฐ ๋‹ต๋ณ€ ์ค€๋น„
1109
+
1110
+ **Q1: ์šฐ๋ฆฌ ๊ฐ™์€ ์ค‘๊ฒฌ๊ธฐ์—…๋„ ๊ฐ€๋Šฅํ•œ๊ฐ€์š”?**
1111
+ A: ์˜คํžˆ๋ ค ์ค‘๊ฒฌ๊ธฐ์—…์ด ๋” ๋น ๋ฅด๊ฒŒ ๋ณ€ํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž‘์€ ํŒŒ์ผ๋Ÿฟ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์„ธ์š”.
1112
+
1113
+ **Q2: ์˜ˆ์‚ฐ์ด ์ œํ•œ์ ์ธ๋ฐ ์–ด๋–ป๊ฒŒ ์‹œ์ž‘ํ•˜๋‚˜์š”?**
1114
+ A: ํด๋ผ์šฐ๋“œ ๊ธฐ๋ฐ˜ SaaS๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์ดˆ๊ธฐ ํˆฌ์ž๋ฅผ ์ตœ์†Œํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
1115
+
1116
+ **Q3: ์ง์›๋“ค์˜ ์ €ํ•ญ์ด ์‹ฌํ•œ๋ฐ ์–ด๋–ป๊ฒŒ ๊ทน๋ณตํ•˜๋‚˜์š”?**
1117
+ A: ๋ณ€ํ™”์˜ ์ˆ˜ํ˜œ์ž๋ฅผ ๋จผ์ € ๋งŒ๋“ค๊ณ , ๊ทธ๋“ค์ด ์ „๋„์‚ฌ๊ฐ€ ๋˜๊ฒŒ ํ•˜์„ธ์š”.
1118
+
1119
+ ---
1120
+ *์ด PPT๋Š” 20๋ถ„ ๋ฐœํ‘œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ž‘์„ฑ๋˜์—ˆ์œผ๋ฉฐ, ์ฒญ์ค‘๊ณผ์˜ ์ƒํ˜ธ์ž‘์šฉ์„ ๊ทน๋Œ€ํ™”ํ•˜๋„๋ก ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.*"""
1121
+ }
1122
+
1123
+ # ํ”„๋กฌํ”„ํŠธ ๋‚ด์šฉ์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ์‘๋‹ต ์„ ํƒ
1124
+ if role == "supervisor" and "์กฐ์‚ฌ์ž AI๊ฐ€ ์ •๋ฆฌํ•œ" in messages[0]["content"]:
1125
+ response = test_responses["supervisor_execution"]
1126
+ elif role == "supervisor" and messages[0]["content"].find("์‹คํ–‰์ž AI์˜ PPT ์ดˆ์•ˆ") > -1:
1127
+ response = test_responses["supervisor_review"]
1128
+ elif role == "supervisor":
1129
+ response = test_responses["supervisor_initial"]
1130
+ elif role == "researcher":
1131
+ response = test_responses["researcher"]
1132
+ elif role == "executor" and "์ตœ์ข… PPT" in messages[0]["content"]:
1133
+ response = test_responses["executor_final"]
1134
+ else:
1135
+ response = test_responses["executor"]
1136
+
1137
+ yield from self.simulate_streaming(response, role)
1138
  return
1139
 
1140
+ # ์‹ค์ œ API ํ˜ธ์ถœ
1141
+ try:
1142
+ system_prompts = {
1143
+ "supervisor": "๋‹น์‹ ์€ ์ „๋ฌธ์ ์ธ PPT ๊ตฌ์กฐ๋ฅผ ์„ค๊ณ„ํ•˜๊ณ  ์ง€๋„ํ•˜๋Š” ๊ฐ๋…์ž AI์ž…๋‹ˆ๋‹ค.",
1144
+ "researcher": "๋‹น์‹ ์€ PPT ์ฝ˜ํ…์ธ ๋ฅผ ์œ„ํ•œ ์ •๋ณด๋ฅผ ์กฐ์‚ฌํ•˜๊ณ  ์ •๋ฆฌํ•˜๋Š” ์กฐ์‚ฌ์ž AI์ž…๋‹ˆ๋‹ค.",
1145
+ "executor": "๋‹น์‹ ์€ ์‹ค์ œ PPT ์Šฌ๋ผ์ด๋“œ ๋‚ด์šฉ์„ ์ž‘์„ฑํ•˜๋Š” ์‹คํ–‰์ž AI์ž…๋‹ˆ๋‹ค."
1146
+ }
1147
+
1148
+ full_messages = [
1149
+ {"role": "system", "content": system_prompts.get(role, "")},
1150
+ *messages
1151
+ ]
1152
+
1153
+ payload = {
1154
+ "model": self.model_id,
1155
+ "messages": full_messages,
1156
+ "max_tokens": 4096,
1157
+ "temperature": 0.7,
1158
+ "top_p": 0.8,
1159
+ "stream": True,
1160
+ "stream_options": {"include_usage": True}
1161
+ }
1162
+
1163
+ logger.info(f"API ์ŠคํŠธ๋ฆฌ๋ฐ ํ˜ธ์ถœ ์‹œ์ž‘ - Role: {role}")
1164
+
1165
+ response = requests.post(
1166
+ self.api_url,
1167
+ headers=self.create_headers(),
1168
+ json=payload,
1169
+ stream=True,
1170
+ timeout=10
1171
+ )
1172
+
1173
+ if response.status_code != 200:
1174
+ logger.error(f"API ์˜ค๋ฅ˜: {response.status_code}")
1175
+ yield f"โŒ API ์˜ค๋ฅ˜ ({response.status_code}): {response.text[:200]}"
1176
+ return
1177
+
1178
+ for line in response.iter_lines():
1179
+ if line:
1180
+ line = line.decode('utf-8')
1181
+ if line.startswith("data: "):
1182
+ data = line[6:]
1183
+ if data == "[DONE]":
1184
+ break
1185
+ try:
1186
+ chunk = json.loads(data)
1187
+ if "choices" in chunk and chunk["choices"]:
1188
+ content = chunk["choices"][0].get("delta", {}).get("content", "")
1189
+ if content:
1190
+ yield content
1191
+ except json.JSONDecodeError:
1192
+ continue
1193
+
1194
+ except requests.exceptions.Timeout:
1195
+ yield "โฑ๏ธ API ํ˜ธ์ถœ ์‹œ๊ฐ„์ด ์ดˆ๊ณผ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”."
1196
+ except requests.exceptions.ConnectionError:
1197
+ yield "๐Ÿ”Œ API ์„œ๋ฒ„์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ธํ„ฐ๋„ท ์—ฐ๊ฒฐ์„ ํ™•์ธํ•ด์ฃผ์„ธ์š”."
1198
+ except Exception as e:
1199
+ logger.error(f"์ŠคํŠธ๋ฆฌ๋ฐ ์ค‘ ์˜ค๋ฅ˜: {str(e)}")
1200
+ yield f"โŒ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {str(e)}"
1201
+
1202
+ # ์‹œ์Šคํ…œ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
1203
+ ppt_system = PPTCreationSystem()
1204
+
1205
+ # ===== ๋ฉ”์ธ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜ =====
1206
+ def process_ppt_streaming(ppt_topic: str, template_name: str, audience_type: str, language: str,
1207
+ custom_slides: List[Dict], slide_count: int, seed: int, uploaded_file,
1208
+ use_web_search: bool, theme_name: str = "Minimal Light",
1209
+ progress=gr.Progress()):
1210
+ """ํ†ตํ•ฉ๋œ PPT ์ƒ์„ฑ ์ฒ˜๋ฆฌ - 3์ž ํ˜‘์˜ ์‹œ์Šคํ…œ ์‚ฌ์šฉ"""
1211
+ # Update global variables
1212
+ global current_topic, uploaded_content, current_language
1213
+ current_topic = ppt_topic
1214
+ current_language = language
1215
+
1216
+ # Read uploaded file content
1217
+ uploaded_content = ""
1218
+ if uploaded_file is not None:
1219
+ try:
1220
+ uploaded_content = read_uploaded_file(uploaded_file.name)
1221
+ print(f"[File Upload] Content length: {len(uploaded_content)} characters")
1222
+ except Exception as e:
1223
+ print(f"[File Upload] Error: {str(e)}")
1224
+ uploaded_content = ""
1225
+
1226
+ # Template selection and slide configuration
1227
+ try:
1228
+ if template_name == "Custom" and custom_slides:
1229
+ slides = [{"title": "Cover", "style": "Title Slide (Hero)", "prompt_hint": "Presentation cover"}]
1230
+ slides.extend(custom_slides)
1231
+ slides.append({"title": "Thank You", "style": "Thank You Slide", "prompt_hint": "Presentation closing and key message"})
1232
+ else:
1233
+ template = PPT_TEMPLATES.get(template_name)
1234
+ if not template:
1235
+ yield "", "", "", None, f"โŒ Template '{template_name}' not found."
1236
+ return
1237
+ slides = generate_dynamic_slides(ppt_topic, template, slide_count)
1238
+ except Exception as e:
1239
+ print(f"[Slide Configuration] Error: {str(e)}")
1240
+ yield "", "", "", None, f"โŒ Error configuring slides: {str(e)}"
1241
+ return
1242
+
1243
+ if not slides:
1244
+ yield "", "", "", None, "No slides defined."
1245
+ return
1246
+
1247
+ total_slides = len(slides)
1248
+ print(f"\n[PPT Generation] Starting - Total {total_slides} slides (Cover + {slide_count} content + Thank You)")
1249
+ print(f"[PPT Generation] Topic: {ppt_topic}")
1250
+ print(f"[PPT Generation] Template: {template_name}")
1251
+ print(f"[PPT Generation] Audience: {audience_type}")
1252
+ print(f"[PPT Generation] Language: {language}")
1253
+ print(f"[PPT Generation] Design Theme: {theme_name}")
1254
+ print(f"[PPT Generation] Web Search: {'Enabled' if use_web_search else 'Disabled'}")
1255
+
1256
+ conversation_log = []
1257
+ all_responses = {"supervisor": [], "researcher": [], "executor": []}
1258
+
1259
+ try:
1260
+ # 1๋‹จ๊ณ„: ๊ฐ๋…์ž AI ์ดˆ๊ธฐ ๋ถ„์„ ๋ฐ ํ‚ค์›Œ๋“œ ์ถ”์ถœ
1261
+ progress(0.1, "๐Ÿง  ๊ฐ๋…์ž AI๊ฐ€ PPT ๊ตฌ์กฐ๋ฅผ ์„ค๊ณ„ ์ค‘...")
1262
+ supervisor_prompt = ppt_system.create_supervisor_initial_prompt(ppt_topic)
1263
+ supervisor_initial_response = ""
1264
+
1265
+ supervisor_text = "[PPT ๊ตฌ์กฐ ์„ค๊ณ„] ๐Ÿ”„ ์ƒ์„ฑ ์ค‘...\n"
1266
+ for chunk in ppt_system.call_llm_streaming(
1267
+ [{"role": "user", "content": supervisor_prompt}],
1268
+ "supervisor"
1269
+ ):
1270
+ supervisor_initial_response += chunk
1271
+ supervisor_text = f"[PPT ๊ตฌ์กฐ ์„ค๊ณ„] - {datetime.now().strftime('%H:%M:%S')}\n{supervisor_initial_response}"
1272
+ yield supervisor_text, "", "", None, "๐Ÿ”„ ๊ฐ๋…์ž AI๊ฐ€ PPT ๊ตฌ์กฐ๋ฅผ ์„ค๊ณ„ ์ค‘..."
1273
+
1274
+ all_responses["supervisor"].append(supervisor_initial_response)
1275
+
1276
+ # 2๋‹จ๊ณ„: ์›น ๊ฒ€์ƒ‰ ์ˆ˜ํ–‰ (์„ ํƒ๋œ ๊ฒฝ์šฐ)
1277
+ search_results = {}
1278
+ if use_web_search and BRAVE_API_TOKEN:
1279
+ progress(0.2, "๐Ÿ” PPT ์ฝ˜ํ…์ธ  ๊ฒ€์ƒ‰ ์ค‘...")
1280
+ keywords = ppt_system.extract_keywords(supervisor_initial_response)
1281
+ logger.info(f"์ถ”์ถœ๋œ ํ‚ค์›Œ๋“œ: {keywords}")
1282
+
1283
+ researcher_text = "[์ฝ˜ํ…์ธ  ๊ฒ€์ƒ‰] ๐Ÿ” ๊ฒ€์ƒ‰ ์ค‘...\n"
1284
+ yield supervisor_text, researcher_text, "", None, "๐Ÿ” PPT ์ฝ˜ํ…์ธ  ๊ฒ€์ƒ‰ ์ค‘..."
1285
+
1286
+ total_search_count = 0
1287
+
1288
+ # ์›๋ž˜ ํ‚ค์›Œ๋“œ๋กœ ๊ฒ€์ƒ‰
1289
+ for keyword in keywords:
1290
+ try:
1291
+ results = ppt_system.brave_search(keyword)
1292
+ if results:
1293
+ search_results[keyword] = results
1294
+ total_search_count += len(results)
1295
+ researcher_text += f"โœ“ '{keyword}' ๊ฒ€์ƒ‰ ์™„๋ฃŒ ({len(results)}๊ฐœ ๊ฒฐ๊ณผ)\n"
1296
+ yield supervisor_text, researcher_text, "", None, f"๐Ÿ” '{keyword}' ๊ฒ€์ƒ‰ ์ค‘..."
1297
+ except Exception as e:
1298
+ print(f"[Search] Error searching for '{keyword}': {str(e)}")
1299
+
1300
+ researcher_text += f"\n๐Ÿ“Š ์ด {total_search_count}๊ฐœ์˜ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์ˆ˜์ง‘ ์™„๋ฃŒ\n"
1301
+
1302
+ # 3๋‹จ๊ณ„: ์กฐ์‚ฌ์ž AI๊ฐ€ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์ •๋ฆฌ
1303
+ progress(0.3, "๐Ÿ“ ์กฐ์‚ฌ์ž AI๊ฐ€ ์ฝ˜ํ…์ธ  ์ •๋ฆฌ ์ค‘...")
1304
+ researcher_prompt = ppt_system.create_researcher_prompt(ppt_topic, supervisor_initial_response, search_results)
1305
+ researcher_response = ""
1306
+
1307
+ researcher_text = "[PPT ์ฝ˜ํ…์ธ  ์ •๋ฆฌ] ๐Ÿ”„ ์ƒ์„ฑ ์ค‘...\n"
1308
+ for chunk in ppt_system.call_llm_streaming(
1309
+ [{"role": "user", "content": researcher_prompt}],
1310
+ "researcher"
1311
+ ):
1312
+ researcher_response += chunk
1313
+ researcher_text = f"[PPT ์ฝ˜ํ…์ธ  ์ •๋ฆฌ] - {datetime.now().strftime('%H:%M:%S')}\n{researcher_response}"
1314
+ yield supervisor_text, researcher_text, "", None, "๐Ÿ“ ์กฐ์‚ฌ์ž AI๊ฐ€ ์ฝ˜ํ…์ธ  ์ •๋ฆฌ ์ค‘..."
1315
+
1316
+ all_responses["researcher"].append(researcher_response)
1317
+
1318
+ # 4๋‹จ๊ณ„: ๊ฐ๋…์ž AI๊ฐ€ ์กฐ์‚ฌ ๋‚ด์šฉ ๊ธฐ๋ฐ˜์œผ๋กœ ์‹คํ–‰ ์ง€์‹œ
1319
+ progress(0.4, "๐ŸŽฏ ๊ฐ๋…์ž AI๊ฐ€ ์ œ์ž‘ ์ง€์‹œ ์ค‘...")
1320
+ supervisor_execution_prompt = ppt_system.create_supervisor_execution_prompt(ppt_topic, researcher_response)
1321
+ supervisor_execution_response = ""
1322
+
1323
+ supervisor_text += "\n\n---\n\n[PPT ์ œ์ž‘ ์ง€์‹œ] ๐Ÿ”„ ์ƒ์„ฑ ์ค‘...\n"
1324
+ for chunk in ppt_system.call_llm_streaming(
1325
+ [{"role": "user", "content": supervisor_execution_prompt}],
1326
+ "supervisor"
1327
+ ):
1328
+ supervisor_execution_response += chunk
1329
+ temp_text = f"{all_responses['supervisor'][0]}\n\n---\n\n[PPT ์ œ์ž‘ ์ง€์‹œ] - {datetime.now().strftime('%H:%M:%S')}\n{supervisor_execution_response}"
1330
+ supervisor_text = f"[PPT ๊ตฌ์กฐ ์„ค๊ณ„] - {datetime.now().strftime('%H:%M:%S')}\n{temp_text}"
1331
+ yield supervisor_text, researcher_text, "", None, "๐ŸŽฏ ๊ฐ๋…์ž AI๊ฐ€ ์ œ์ž‘ ์ง€์‹œ ์ค‘..."
1332
+
1333
+ all_responses["supervisor"].append(supervisor_execution_response)
1334
+
1335
+ # 5๋‹จ๊ณ„: ์‹คํ–‰์ž AI๊ฐ€ ์กฐ์‚ฌ ๋‚ด์šฉ๊ณผ ์ง€์‹œ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ดˆ๊ธฐ PPT ์ž‘์„ฑ
1336
+ progress(0.5, "๐Ÿ“Š ์‹คํ–‰์ž AI๊ฐ€ PPT ์ž‘์„ฑ ์ค‘...")
1337
+ executor_prompt = ppt_system.create_executor_prompt(ppt_topic, supervisor_execution_response, researcher_response)
1338
+ executor_response = ""
1339
+
1340
+ executor_text = "[์ดˆ๊ธฐ PPT ์ž‘์„ฑ] ๐Ÿ”„ ์ƒ์„ฑ ์ค‘...\n"
1341
+ for chunk in ppt_system.call_llm_streaming(
1342
+ [{"role": "user", "content": executor_prompt}],
1343
+ "executor"
1344
+ ):
1345
+ executor_response += chunk
1346
+ executor_text = f"[์ดˆ๊ธฐ PPT ์ž‘์„ฑ] - {datetime.now().strftime('%H:%M:%S')}\n{executor_response}"
1347
+ yield supervisor_text, researcher_text, executor_text, None, "๐Ÿ“Š ์‹คํ–‰์ž AI๊ฐ€ PPT ์ž‘์„ฑ ์ค‘..."
1348
+
1349
+ all_responses["executor"].append(executor_response)
1350
+
1351
+ # 5.5๋‹จ๊ณ„: ์‹คํ–‰์ž AI ์‘๋‹ต ํŒŒ์‹ฑ (๊ฐœ์„ ๋œ ํŒŒ์„œ ์‚ฌ์šฉ)
1352
+ progress(0.55, "๐Ÿ“ ์‹คํ–‰์ž AI ์‘๋‹ต์„ ์Šฌ๋ผ์ด๋“œ๋กœ ๋ณ€ํ™˜ ์ค‘...")
1353
+
1354
+ # ๊ฐœ์„ ๋œ ํŒŒ์„œ ์‚ฌ์šฉ
1355
+ parsed_slides = parse_executor_response(executor_response, slides, language)
1356
+ logger.info(f"ํŒŒ์‹ฑ๋œ ์Šฌ๋ผ์ด๋“œ ์ˆ˜: {len(parsed_slides)}")
1357
+
1358
+ # ํŒŒ์‹ฑ ์„ฑ๊ณต ์—ฌ๋ถ€ ํ™•์ธ
1359
+ parsing_success = len(parsed_slides) > 0
1360
+
1361
+ # ํŒŒ์‹ฑ ๊ฒฐ๊ณผ ๋กœ๊ทธ
1362
+ for slide_idx, slide_data in parsed_slides.items():
1363
+ logger.info(f"[ํŒŒ์‹ฑ ๊ฒฐ๊ณผ] ์Šฌ๋ผ์ด๋“œ {slide_idx + 1}:")
1364
+ logger.info(f" - ์ œ๋ชฉ: {slide_data.get('title', 'N/A')}")
1365
+ logger.info(f" - ๋ถ€์ œ๋ชฉ: {slide_data.get('subtitle', 'N/A')}")
1366
+ logger.info(f" - ๋ถˆ๋ฆฟ ํฌ์ธํŠธ ์ˆ˜: {len(slide_data.get('bullet_points', []))}")
1367
+ if slide_data.get('bullet_points'):
1368
+ logger.info(f" - ์ฒซ ๋ฒˆ์งธ ๋ถˆ๋ฆฟ: {slide_data['bullet_points'][0]}")
1369
+
1370
+ # ํŒŒ์‹ฑ ์‹คํŒจ ์‹œ ๊ฒฝ๊ณ  ๋ฐ ๋Œ€์ฒด ๋ฐฉ์•ˆ
1371
+ if not parsing_success:
1372
+ logger.warning("[ํŒŒ์‹ฑ] ์‹คํ–‰์ž ์‘๋‹ต ํŒŒ์‹ฑ ์‹คํŒจ - ์‹คํ–‰์ž ์‘๋‹ต ์›๋ฌธ์„ ์ง์ ‘ ์‚ฌ์šฉ ์‹œ๋„")
1373
+
1374
+ # ์‹คํ–‰์ž ์‘๋‹ต์„ ์ง์ ‘ ๋ณด์—ฌ์ฃผ๊ธฐ (๋””๋ฒ„๊น…์šฉ)
1375
+ yield supervisor_text, researcher_text, executor_text + "\n\nโš ๏ธ ํŒŒ์‹ฑ ์‹คํŒจ - ๋Œ€์ฒด ๋ฐฉ๋ฒ• ์‚ฌ์šฉ ์ค‘...", None, "โš ๏ธ ์Šฌ๋ผ์ด๋“œ ํŒŒ์‹ฑ ์ค‘ ๋ฌธ์ œ ๋ฐœ๊ฒฌ, ๋Œ€์ฒด ๋ฐฉ๋ฒ• ์‚ฌ์šฉ..."
1376
+
1377
+ # 6๋‹จ๊ณ„: ์‹ค์ œ ์Šฌ๋ผ์ด๋“œ ์ƒ์„ฑ (๊ฐœ์„ ๋œ ๋กœ์ง)
1378
+ progress(0.6, "๐ŸŽจ ์Šฌ๋ผ์ด๋“œ ์ด๋ฏธ์ง€ ์ƒ์„ฑ ์ค‘...")
1379
+ results = []
1380
+ preview_html = """
1381
+ <style>
1382
+ .slides-container {
1383
+ width: 100%;
1384
+ max-width: 1400px;
1385
+ margin: 0 auto;
1386
+ }
1387
+ </style>
1388
+ <div class="slides-container">
1389
+ """
1390
+
1391
+ # Process each slide with improved logic
1392
+ for i, slide in enumerate(slides):
1393
+ try:
1394
+ progress((0.6 + (0.3 * i / total_slides)), f"์Šฌ๋ผ์ด๋“œ {i+1}/{total_slides} ์ฒ˜๋ฆฌ ์ค‘...")
1395
 
1396
+ # Translate slide title if Korean
1397
+ display_title = slide.get('title', '')
1398
+ if language == "Korean" and slide.get('title', '') in SLIDE_TITLE_TRANSLATIONS:
1399
+ display_title = SLIDE_TITLE_TRANSLATIONS[slide.get('title', '')]
1400
 
1401
+ slide_info = f"Slide {i+1}: {display_title}"
1402
+ slide_context = f"{slide.get('title', '')} - {slide.get('prompt_hint', '')}"
1403
+
1404
+ # ํŒŒ์‹ฑ๋œ ๋ฐ์ดํ„ฐ ํ™•์ธ ๋ฐ ์‚ฌ์šฉ
1405
+ content = None
1406
+ speaker_notes = ""
1407
+
1408
+ if i in parsed_slides and parsing_success:
1409
+ # ํŒŒ์‹ฑ๋œ ๋ฐ์ดํ„ฐ ์‚ฌ์šฉ
1410
+ parsed_data = parsed_slides[i]
1411
+ logger.info(f"[์Šฌ๋ผ์ด๋“œ {i+1}] ์‹คํ–‰์ž AI์˜ ํŒŒ์‹ฑ๋œ ์ฝ˜ํ…์ธ  ์‚ฌ์šฉ")
1412
+
1413
+ # ๋ถˆ๋ฆฟ ํฌ์ธํŠธ ๊ฒ€์ฆ
1414
+ valid_bullets = []
1415
+ for bp in parsed_data.get("bullet_points", []):
1416
+ # ์˜๋ฏธ์—†๋Š” placeholder ์ œ๊ฑฐ
1417
+ if bp and not any(skip in bp for skip in ["Point 1", "Point 2", "Point 3", "Point 4", "Point 5", "๐Ÿ“Œ Point"]):
1418
+ valid_bullets.append(bp)
1419
+
1420
+ # ์œ ํšจํ•œ ๋ถˆ๋ฆฟ ํฌ์ธํŠธ๊ฐ€ ์žˆ์œผ๋ฉด ์‚ฌ์šฉ
1421
+ if len(valid_bullets) >= 3: # ์ตœ์†Œ 3๊ฐœ ์ด์ƒ์ผ ๋•Œ๋งŒ ์‚ฌ์šฉ
1422
+ content = {
1423
+ "subtitle": parsed_data.get("subtitle") or display_title,
1424
+ "bullet_points": valid_bullets[:5] # ์ตœ๋Œ€ 5๊ฐœ
1425
+ }
1426
+ speaker_notes = parsed_data.get("speaker_notes", "")
1427
+ logger.info(f"[์Šฌ๋ผ์ด๋“œ {i+1}] ํŒŒ์‹ฑ๋œ ์ฝ˜ํ…์ธ  ์‚ฌ์šฉ ์™„๋ฃŒ - ๋ถˆ๋ฆฟ {len(valid_bullets)}๊ฐœ")
1428
+ else:
1429
+ logger.warning(f"[์Šฌ๋ผ์ด๋“œ {i+1}] ๋ถˆ๋ฆฟ ํฌ์ธํŠธ ๋ถ€์กฑ ({len(valid_bullets)}๊ฐœ) - ์‹คํ–‰์ž ์‘๋‹ต์—์„œ ์žฌ์ถ”์ถœ ์‹œ๋„")
1430
+
1431
+ # ์‹คํ–‰์ž ์‘๋‹ต์—์„œ ํ•ด๋‹น ์Šฌ๋ผ์ด๋“œ ๊ด€๋ จ ๋‚ด์šฉ ์žฌ์ถ”์ถœ
1432
+ slide_keywords = [display_title, slide.get('title', ''), slide.get('prompt_hint', '')]
1433
+ extracted_content = extract_relevant_content_from_executor(
1434
+ executor_response, slide_keywords, i+1, slide.get('title', '')
1435
+ )
1436
+
1437
+ if extracted_content and len(extracted_content.get("bullet_points", [])) >= 3:
1438
+ content = extracted_content
1439
+ speaker_notes = extracted_content.get("speaker_notes", "")
1440
+ logger.info(f"[์Šฌ๋ผ์ด๋“œ {i+1}] ์‹คํ–‰์ž ์‘๋‹ต์—์„œ ์žฌ์ถ”์ถœ ์„ฑ๊ณต")
1441
+
1442
+ # ํŒŒ์‹ฑ ์‹คํŒจํ•˜๊ฑฐ๋‚˜ ์ฝ˜ํ…์ธ ๊ฐ€ ์—†์œผ๋ฉด ์‹คํ–‰์ž ์‘๋‹ต์—์„œ ์ง์ ‘ ์ถ”์ถœ
1443
+ if not content:
1444
+ logger.warning(f"[์Šฌ๋ผ์ด๋“œ {i+1}] ํŒŒ์‹ฑ ์‹คํŒจ - ์‹คํ–‰์ž ์‘๋‹ต์—์„œ ์ง์ ‘ ์ถ”์ถœ ์‹œ๋„")
1445
+
1446
+ # ์Šฌ๋ผ์ด๋“œ ๋ฒˆํ˜ธ๋กœ ์‹คํ–‰์ž ์‘๋‹ต์—์„œ ํ•ด๋‹น ๋ถ€๋ถ„ ์ฐพ๊ธฐ
1447
+ slide_section = extract_slide_section_from_executor(executor_response, i+1)
1448
+
1449
+ if slide_section:
1450
+ content = parse_slide_section(slide_section, display_title)
1451
+ speaker_notes = extract_speaker_notes_from_section(slide_section)
1452
+ logger.info(f"[์Šฌ๋ผ์ด๋“œ {i+1}] ์‹คํ–‰์ž ์‘๋‹ต์—์„œ ์ง์ ‘ ์ถ”์ถœ ์„ฑ๊ณต")
1453
+
1454
+ # ๊ทธ๋ž˜๋„ ์ฝ˜ํ…์ธ ๊ฐ€ ์—†์œผ๋ฉด ์ตœ์ข… ํด๋ฐฑ
1455
+ if not content or len(content.get("bullet_points", [])) < 3:
1456
+ logger.warning(f"[์Šฌ๋ผ์ด๋“œ {i+1}] ๋ชจ๋“  ๋ฐฉ๋ฒ• ์‹คํŒจ - generate_slide_content ํด๋ฐฑ ์‚ฌ์šฉ")
1457
+
1458
+ # Thank You slide ํŠน๋ณ„ ์ฒ˜๋ฆฌ
1459
+ if slide.get('title') == 'Thank You':
1460
+ conclusion_phrase = generate_conclusion_phrase(
1461
+ ppt_topic, audience_type, language,
1462
+ FRIENDLI_TOKEN, API_URL, MODEL_ID, AUDIENCE_TYPES
1463
+ )
1464
+ content = {
1465
+ "subtitle": conclusion_phrase,
1466
+ "bullet_points": []
1467
+ }
1468
+ speaker_notes = generate_closing_notes(
1469
+ ppt_topic, conclusion_phrase, audience_type, language,
1470
+ FRIENDLI_TOKEN, API_URL, MODEL_ID, AUDIENCE_TYPES
1471
+ )
1472
+ else:
1473
+ # ์ผ๋ฐ˜ ์Šฌ๋ผ์ด๋“œ ํด๋ฐฑ ์ƒ์„ฑ
1474
+ content = generate_slide_content(
1475
+ ppt_topic, slide.get('title', ''), slide_context, audience_type, language,
1476
+ uploaded_content, list(search_results.values()) if use_web_search else [],
1477
+ FRIENDLI_TOKEN, API_URL, MODEL_ID, AUDIENCE_TYPES
1478
+ )
1479
+ speaker_notes = generate_presentation_notes(
1480
+ ppt_topic, slide.get('title', ''), content, audience_type, language,
1481
+ FRIENDLI_TOKEN, API_URL, MODEL_ID, AUDIENCE_TYPES
1482
+ )
1483
+
1484
+ # ๋ฐœํ‘œ์ž ๋…ธํŠธ๊ฐ€ ์—†์œผ๋ฉด ์ƒ์„ฑ
1485
+ if not speaker_notes:
1486
+ speaker_notes = generate_presentation_notes(
1487
+ ppt_topic, slide.get('title', ''), content, audience_type, language,
1488
+ FRIENDLI_TOKEN, API_URL, MODEL_ID, AUDIENCE_TYPES
1489
+ )
1490
+
1491
+ # Generate prompt and image
1492
+ style_key = slide.get("style", "Colorful Mind Map")
1493
+ if style_key in STYLE_TEMPLATES:
1494
+ style_info = STYLE_TEMPLATES[style_key]
1495
+ prompt = generate_prompt_with_llm(
1496
+ ppt_topic, style_info["example"],
1497
+ slide_context, uploaded_content,
1498
+ FRIENDLI_TOKEN, API_URL, MODEL_ID
1499
+ )
1500
+
1501
+ # Generate image
1502
+ slide_seed = seed + i
1503
+ img, used_prompt = generate_image(
1504
+ prompt, slide_seed, slide_info,
1505
+ REPLICATE_API_TOKEN, current_topic, current_language,
1506
+ FRIENDLI_TOKEN, API_URL, MODEL_ID
1507
+ )
1508
+
1509
+ # Prepare slide data
1510
+ slide_data = {
1511
+ "slide_number": i + 1,
1512
+ "title": display_title,
1513
+ "subtitle": content["subtitle"],
1514
+ "bullet_points": content["bullet_points"][:5],
1515
+ "image": img,
1516
+ "style": style_info["name"],
1517
+ "speaker_notes": speaker_notes,
1518
+ "topic": ppt_topic
1519
+ }
1520
+
1521
+ # ๋””๋ฒ„๊น…: ์‹ค์ œ ์‚ฌ์šฉ๋œ ์ฝ˜ํ…์ธ  ๋กœ๊ทธ
1522
+ logger.info(f"[์Šฌ๋ผ์ด๋“œ {i+1}] ์ตœ์ข… ์ฝ˜ํ…์ธ :")
1523
+ logger.info(f" - ๋ถ€์ œ๋ชฉ: {slide_data['subtitle']}")
1524
+ logger.info(f" - ๋ถˆ๋ฆฟ ํฌ์ธํŠธ: {len(slide_data['bullet_points'])}๊ฐœ")
1525
+ if slide_data['bullet_points']:
1526
+ logger.info(f" - ์ฒซ ๋ฒˆ์งธ ๋ถˆ๋ฆฟ: {slide_data['bullet_points'][0]}")
1527
+
1528
+ # Generate preview HTML
1529
+ preview_html += create_slide_preview_html(slide_data)
1530
+
1531
+ # Update current state
1532
+ yield supervisor_text, researcher_text, executor_text, None, f"### ๐Ÿ”„ {slide_info} ์ƒ์„ฑ ์ค‘..."
1533
+
1534
+ results.append({
1535
+ "slide_data": slide_data,
1536
+ "success": img is not None
1537
+ })
1538
+ else:
1539
+ logger.error(f"[์Šฌ๋ผ์ด๋“œ {i+1}] ์•Œ ์ˆ˜ ์—†๋Š” ์Šคํƒ€์ผ: {style_key}")
1540
+
1541
+ except Exception as e:
1542
+ logger.error(f"[์Šฌ๋ผ์ด๋“œ {i+1}] ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜: {str(e)}")
1543
+ import traceback
1544
+ traceback.print_exc()
1545
+
1546
+ # ์˜ค๋ฅ˜ ์‹œ ๊ธฐ๋ณธ๊ฐ’
1547
+ results.append({
1548
+ "slide_data": {
1549
+ "slide_number": i + 1,
1550
+ "title": display_title,
1551
+ "subtitle": "์ฝ˜ํ…์ธ  ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ",
1552
+ "bullet_points": ["โ€ข ์˜ค๋ฅ˜๋กœ ์ธํ•ด ์ฝ˜ํ…์ธ ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค"],
1553
+ "image": None,
1554
+ "style": "Error",
1555
+ "speaker_notes": "์˜ค๋ฅ˜๋กœ ์ธํ•ด ๋ฐœํ‘œ์ž ๋…ธํŠธ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.",
1556
+ "topic": ppt_topic
1557
+ },
1558
+ "success": False
1559
+ })
1560
+
1561
+ # Create PPTX file
1562
+ progress(0.95, "Creating PPTX file...")
1563
+ pptx_path = None
1564
  try:
1565
+ pptx_path = create_pptx_file(results, ppt_topic, template_name, theme_name, DESIGN_THEMES)
1566
+ except Exception as e:
1567
+ print(f"[PPTX] File creation error: {str(e)}")
1568
+ import traceback
1569
+ traceback.print_exc()
1570
+
1571
+ preview_html += "</div>"
1572
+ progress(1.0, "Complete!")
1573
+ successful = sum(1 for r in results if r["success"])
1574
+ final_status = f"### ๐ŸŽ‰ Generation complete! {successful} out of {total_slides} slides succeeded"
1575
+
1576
+ # Save global variables
1577
+ global current_slides_data, current_template, current_theme
1578
+ current_slides_data = results
1579
+ current_template = template_name
1580
+ current_theme = theme_name
1581
+
1582
+ if pptx_path:
1583
+ final_status += f"\n\n### ๐Ÿ“ฅ PPTX file is ready!"
1584
+ final_status += f"\n\n๐ŸŽค **Speaker notes for {audience_type} included in each slide!**"
1585
+ if PROCESS_FLOW_AVAILABLE:
1586
+ final_status += f"\n\n๐Ÿ”ง **Process flow diagrams are automatically generated ({language} support)**"
1587
+
1588
+ yield supervisor_text, researcher_text, executor_text, pptx_path, final_status
1589
+
1590
+ except Exception as e:
1591
+ error_msg = f"โŒ ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜: {str(e)}"
1592
+ print(f"[PPT Generation] Critical error: {str(e)}")
1593
+ import traceback
1594
+ traceback.print_exc()
1595
+ yield "", "", "", None, error_msg
1596
+
1597
+ def generate_ppt_handler(topic, template_name, audience_type, language, theme_name, slide_count,
1598
+ seed, file_upload, use_web_search, custom_slide_count,
1599
+ progress=gr.Progress(), *custom_inputs):
1600
+ if not topic.strip():
1601
+ yield "", "", "", None, "โŒ Please enter a topic."
1602
+ return
1603
+
1604
+ # Process custom slides
1605
+ custom_slides = []
1606
+ if template_name == "Custom" and custom_inputs:
1607
+ try:
1608
+ # Convert custom_inputs to list to avoid tuple slicing issues
1609
+ custom_inputs_list = list(custom_inputs)
1610
 
1611
+ for i in range(0, min(custom_slide_count * 3, len(custom_inputs_list)), 3):
1612
+ title = custom_inputs_list[i] if i < len(custom_inputs_list) else ""
1613
+ style = custom_inputs_list[i+1] if i+1 < len(custom_inputs_list) else "Colorful Mind Map"
1614
+ hint = custom_inputs_list[i+2] if i+2 < len(custom_inputs_list) else ""
1615
+
1616
+ if title and style:
1617
+ custom_slides.append({
1618
+ "title": title,
1619
+ "style": style,
1620
+ "prompt_hint": hint
1621
+ })
1622
+ except Exception as e:
1623
+ print(f"[Custom Slides] Error processing custom inputs: {str(e)}")
1624
+ yield "", "", "", None, f"โŒ Error processing custom slides: {str(e)}"
1625
+ return
1626
+
1627
+ # Generate PPT
1628
+ try:
1629
+ for supervisor, researcher, executor, pptx_file, status in process_ppt_streaming(
1630
+ topic, template_name, audience_type, language, custom_slides, slide_count,
1631
+ seed, file_upload, use_web_search, theme_name, progress
1632
+ ):
1633
+ yield supervisor, researcher, executor, pptx_file, status
1634
  except Exception as e:
1635
+ print(f"[PPT Generation] Error: {str(e)}")
1636
  import traceback
1637
+ traceback.print_exc()
1638
+ yield "", "", "", None, f"โŒ Error during PPT generation: {str(e)}"
1639
+
1640
+ # ===== Gradio UI =====
1641
+ with gr.Blocks(title="PPT Generator", theme=gr.themes.Soft(), css=get_css()) as demo:
1642
+ gr.Markdown("""
1643
+ # ๐ŸŽฏ Open GAMMA 'GAMJA' - AI Presentation Generator with 3-AI Collaboration
1644
+
1645
+ ### Create professional presentations with AI-powered collaboration system!
1646
+
1647
+ ** Community: https://discord.gg/openfreeai
1648
+ """)
1649
+
1650
+ # API token status check
1651
+ token_status = []
1652
+ if not REPLICATE_API_TOKEN:
1653
+ token_status.append("โš ๏ธ RAPI_TOKEN environment variable not set.")
1654
+ if not FRIENDLI_TOKEN:
1655
+ token_status.append("โš ๏ธ FRIENDLI_TOKEN environment variable not set.")
1656
+ if not BRAVE_API_TOKEN:
1657
+ token_status.append("โ„น๏ธ BAPI_TOKEN not available. Web search disabled.")
1658
+ if not PROCESS_FLOW_AVAILABLE:
1659
+ token_status.append("โ„น๏ธ process_flow_generator not available. Process flow diagrams disabled.")
1660
+
1661
+ if token_status:
1662
+ gr.Markdown("\n".join(token_status))
1663
+
1664
+ with gr.Row():
1665
+ with gr.Column(scale=1):
1666
+ # Language selection (at the top)
1667
+ language_select = gr.Radio(
1668
+ choices=["English", "Korean"],
1669
+ label="๐ŸŒ Content Language",
1670
+ value="English",
1671
+ info="Select the language for your presentation content"
1672
+ )
1673
+
1674
+ # Example selection
1675
+ with gr.Row():
1676
+ example_btn = gr.Button("๐Ÿ“‹ Load Example", size="sm", variant="secondary")
1677
+
1678
+ # Basic inputs
1679
+ topic_input = gr.Textbox(
1680
+ label="Presentation Topic",
1681
+ placeholder="e.g., AI Startup Investment Pitch, New Product Launch, Digital Transformation Strategy",
1682
+ lines=2
1683
+ )
1684
+
1685
+ # Audience selection
1686
+ audience_select = gr.Dropdown(
1687
+ choices=list(AUDIENCE_TYPES.keys()),
1688
+ label="๐ŸŽญ Target Audience",
1689
+ value="General Staff",
1690
+ info="Content and tone will be automatically optimized for your audience"
1691
+ )
1692
+
1693
+ # Audience description display
1694
+ audience_info = gr.Markdown()
1695
+
1696
+ # PPT template selection
1697
+ template_select = gr.Dropdown(
1698
+ choices=list(PPT_TEMPLATES.keys()),
1699
+ label="PPT Template",
1700
+ value="Business Proposal",
1701
+ info="Select a template that matches your purpose"
1702
+ )
1703
+
1704
+ # Design theme selection
1705
+ theme_select = gr.Dropdown(
1706
+ choices=list(DESIGN_THEMES.keys()),
1707
+ label="Design Theme",
1708
+ value="Minimal Light",
1709
+ info="Overall design style for your presentation"
1710
+ )
1711
+
1712
+ # Theme preview
1713
+ theme_preview = gr.HTML()
1714
+
1715
+ # Slide count selection
1716
+ slide_count = gr.Slider(
1717
+ minimum=6,
1718
+ maximum=20,
1719
+ value=8,
1720
+ step=1,
1721
+ label="Number of Content Slides (excluding Cover and Thank You)",
1722
+ info="Select the number of content slides to generate (not used in Custom template)"
1723
+ )
1724
+
1725
+ # File upload
1726
+ file_upload = gr.File(
1727
+ label="Reference Material Upload (Optional)",
1728
+ file_types=[".pdf", ".csv", ".txt"],
1729
+ type="filepath",
1730
+ value=None
1731
+ )
1732
+
1733
+ # Web search option
1734
+ use_web_search = gr.Checkbox(
1735
+ label="Use Web Search",
1736
+ value=True,
1737
+ info="Use Brave Search to include latest information"
1738
+ )
1739
+
1740
+ # Template description
1741
+ template_info = gr.Markdown()
1742
+
1743
+ # Seed value
1744
+ seed_input = gr.Slider(
1745
+ minimum=1,
1746
+ maximum=100,
1747
+ value=10,
1748
+ step=1,
1749
+ label="Seed Value"
1750
+ )
1751
+
1752
+ generate_btn = gr.Button("๐Ÿš€ Generate PPT (AI creates all content automatically)", variant="primary", size="lg")
1753
+
1754
+ # Usage instructions
1755
+ with gr.Accordion("๐Ÿ“– How to Use", open=False):
1756
+ gr.Markdown(get_usage_instructions())
1757
+
1758
+ # Status display
1759
+ with gr.Row():
1760
+ with gr.Column():
1761
+ status_output = gr.Markdown(
1762
+ value="### ๐Ÿ‘† Select a template and click the generate button!"
1763
+ )
1764
+
1765
+ # PPTX download area
1766
+ download_file = gr.File(
1767
+ label="๐Ÿ“ฅ Download Generated PPTX File",
1768
+ visible=True,
1769
+ elem_id="download-file"
1770
+ )
1771
+
1772
+ # AI outputs in tabs
1773
+ with gr.Tabs():
1774
+ with gr.TabItem("๐Ÿค– 3-AI Collaboration Process"):
1775
+ with gr.Row():
1776
+ # ๊ฐ๋…์ž AI ์ถœ๋ ฅ
1777
+ with gr.Column():
1778
+ gr.Markdown("### ๐Ÿง  Supervisor AI (Structure Design)")
1779
+ supervisor_output = gr.Textbox(
1780
+ label="",
1781
+ lines=20,
1782
+ max_lines=25,
1783
+ interactive=False,
1784
+ elem_classes=["supervisor-box"]
1785
+ )
1786
+
1787
+ # ์กฐ์‚ฌ์ž AI ์ถœ๋ ฅ
1788
+ with gr.Column():
1789
+ gr.Markdown("### ๐Ÿ” Researcher AI (Content Collection)")
1790
+ researcher_output = gr.Textbox(
1791
+ label="",
1792
+ lines=20,
1793
+ max_lines=25,
1794
+ interactive=False,
1795
+ elem_classes=["researcher-box"]
1796
+ )
1797
+
1798
+ # ์‹คํ–‰์ž AI ์ถœ๋ ฅ
1799
+ with gr.Column():
1800
+ gr.Markdown("### ๐Ÿ“ Executor AI (Slide Creation)")
1801
+ executor_output = gr.Textbox(
1802
+ label="",
1803
+ lines=20,
1804
+ max_lines=25,
1805
+ interactive=False,
1806
+ elem_classes=["executor-box"]
1807
+ )
1808
+
1809
+ with gr.TabItem("๐Ÿ“Š PPT Preview"):
1810
+ # Preview area
1811
+ preview_output = gr.HTML(
1812
+ label="PPT Preview (16:9)",
1813
+ elem_classes="preview-container"
1814
+ )
1815
+
1816
+ # Custom slides section
1817
+ with gr.Accordion("๐Ÿ“ Custom Slide Configuration", open=False, elem_id="custom_accordion") as custom_accordion:
1818
+ gr.Markdown("Build your presentation without using templates. (3-20 slides)")
1819
+
1820
+ # Custom slide count selection
1821
+ custom_slide_count = gr.Slider(
1822
+ minimum=3,
1823
+ maximum=20,
1824
+ value=5,
1825
+ step=1,
1826
+ label="Number of Custom Slides",
1827
+ info="Select the number of custom slides to create"
1828
+ )
1829
+
1830
+ custom_slides_components = create_custom_slides_ui(initial_count=5)
1831
+
1832
+ # Connect events
1833
+ example_btn.click(
1834
+ fn=load_example,
1835
+ inputs=[template_select, language_select],
1836
+ outputs=[topic_input]
1837
+ )
1838
+
1839
+ audience_select.change(
1840
+ fn=update_audience_info,
1841
+ inputs=[audience_select],
1842
+ outputs=[audience_info]
1843
+ )
1844
+
1845
+ theme_select.change(
1846
+ fn=update_theme_preview,
1847
+ inputs=[theme_select],
1848
+ outputs=[theme_preview]
1849
+ )
1850
+
1851
+ template_select.change(
1852
+ fn=update_template_info,
1853
+ inputs=[template_select, slide_count],
1854
+ outputs=[template_info, slide_count, custom_accordion]
1855
+ )
1856
+
1857
+ slide_count.change(
1858
+ fn=lambda t, s: update_template_info(t, s)[0],
1859
+ inputs=[template_select, slide_count],
1860
+ outputs=[template_info]
1861
+ )
1862
+
1863
+ custom_slide_count.change(
1864
+ fn=update_custom_slides_visibility,
1865
+ inputs=[custom_slide_count],
1866
+ outputs=[slide["row"] for slide in custom_slides_components]
1867
+ )
1868
+
1869
+ # Flatten custom slide input components
1870
+ all_custom_inputs = []
1871
+ for slide in custom_slides_components:
1872
+ all_custom_inputs.extend([slide["title"], slide["style"], slide["hint"]])
1873
+
1874
+ generate_btn.click(
1875
+ fn=generate_ppt_handler,
1876
+ inputs=[
1877
+ topic_input, template_select, audience_select, language_select, theme_select,
1878
+ slide_count, seed_input, file_upload, use_web_search, custom_slide_count
1879
+ ] + all_custom_inputs,
1880
+ outputs=[supervisor_output, researcher_output, executor_output, download_file, status_output]
1881
+ )
1882
+
1883
+ # Load initial info on startup
1884
+ demo.load(
1885
+ fn=lambda: (update_template_info(template_select.value, slide_count.value)[0],
1886
+ update_theme_preview(theme_select.value),
1887
+ update_audience_info(audience_select.value)),
1888
+ inputs=[],
1889
+ outputs=[template_info, theme_preview, audience_info]
1890
+ )
1891
 
1892
+ # Run app
1893
  if __name__ == "__main__":
1894
+ demo.queue() # Enable queue for streaming
1895
+ demo.launch(ssr_mode=False)