Update app.py
Browse files
app.py
CHANGED
@@ -3,9 +3,8 @@ import os
|
|
3 |
import json
|
4 |
import requests
|
5 |
from datetime import datetime
|
6 |
-
import
|
7 |
-
import
|
8 |
-
from typing import List, Dict, Any
|
9 |
import logging
|
10 |
|
11 |
# 로깅 설정
|
@@ -16,6 +15,7 @@ logger = logging.getLogger(__name__)
|
|
16 |
FRIENDLI_TOKEN = os.getenv("FRIENDLI_TOKEN", "YOUR_FRIENDLI_TOKEN")
|
17 |
API_URL = "https://api.friendli.ai/dedicated/v1/chat/completions"
|
18 |
MODEL_ID = "dep89a2fld32mcm"
|
|
|
19 |
|
20 |
# 전역 변수
|
21 |
conversation_history = []
|
@@ -25,6 +25,10 @@ class LLMCollaborativeSystem:
|
|
25 |
self.token = FRIENDLI_TOKEN
|
26 |
self.api_url = API_URL
|
27 |
self.model_id = MODEL_ID
|
|
|
|
|
|
|
|
|
28 |
|
29 |
def create_headers(self):
|
30 |
"""API 헤더 생성"""
|
@@ -62,16 +66,95 @@ class LLMCollaborativeSystem:
|
|
62 |
|
63 |
위 지침을 바탕으로 구체적이고 실행 가능한 세부 내용을 작성해주세요. 실용적이고 구현 가능한 해결책에 집중하세요."""
|
64 |
|
65 |
-
def
|
66 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
try:
|
68 |
-
# 역할에 따른 시스템 프롬프트
|
69 |
system_prompts = {
|
70 |
"supervisor": "당신은 거시적 관점에서 분석하고 지도하는 감독자 AI입니다.",
|
71 |
"executor": "당신은 세부적인 내용을 구현하는 실행자 AI입니다."
|
72 |
}
|
73 |
|
74 |
-
# 메시지 구성
|
75 |
full_messages = [
|
76 |
{"role": "system", "content": system_prompts.get(role, "")},
|
77 |
*messages
|
@@ -83,82 +166,126 @@ class LLMCollaborativeSystem:
|
|
83 |
"max_tokens": 2048,
|
84 |
"temperature": 0.7,
|
85 |
"top_p": 0.8,
|
86 |
-
"stream":
|
|
|
87 |
}
|
88 |
|
|
|
|
|
89 |
response = requests.post(
|
90 |
self.api_url,
|
91 |
headers=self.create_headers(),
|
92 |
json=payload,
|
93 |
-
|
|
|
94 |
)
|
95 |
|
96 |
-
if response.status_code
|
97 |
-
data = response.json()
|
98 |
-
return data["choices"][0]["message"]["content"]
|
99 |
-
else:
|
100 |
logger.error(f"API 오류: {response.status_code}")
|
101 |
-
|
102 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
except Exception as e:
|
104 |
-
logger.error(f"
|
105 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
106 |
|
107 |
-
|
108 |
-
|
109 |
-
|
|
|
|
|
|
|
|
|
110 |
|
111 |
-
|
112 |
-
|
113 |
-
supervisor_prompt
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
)
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
}
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
156 |
|
157 |
### 📌 사용자 질문
|
158 |
{user_query}
|
159 |
|
160 |
### 🔍 거시적 분석 (감독자 AI)
|
161 |
-
{
|
162 |
|
163 |
### 💡 세부 구현 (실행자 AI)
|
164 |
{executor_response}
|
@@ -168,63 +295,15 @@ class LLMCollaborativeSystem:
|
|
168 |
|
169 |
---
|
170 |
*이 답변은 거시적 관점과 미시적 세부사항을 종합하여 작성되었습니다.*"""
|
171 |
-
|
172 |
-
return {
|
173 |
-
"final_result": final_summary,
|
174 |
-
"conversation_log": conversation_log,
|
175 |
-
"supervisor_texts": [log["content"] for log in conversation_log if log["role"] == "supervisor"],
|
176 |
-
"executor_texts": [log["content"] for log in conversation_log if log["role"] == "executor"]
|
177 |
-
}
|
178 |
-
|
179 |
-
except Exception as e:
|
180 |
-
logger.error(f"협력 처리 오류: {str(e)}")
|
181 |
-
return {
|
182 |
-
"final_result": f"처리 중 오류가 발생했습니다: {str(e)}",
|
183 |
-
"conversation_log": [],
|
184 |
-
"supervisor_texts": [],
|
185 |
-
"executor_texts": []
|
186 |
-
}
|
187 |
-
|
188 |
-
# 시스템 인스턴스 생성
|
189 |
-
llm_system = LLMCollaborativeSystem()
|
190 |
-
|
191 |
-
def process_query(user_query, history):
|
192 |
-
"""Gradio 인터페이스를 위한 쿼리 처리 함수"""
|
193 |
-
if not user_query:
|
194 |
-
return history, "", "", "", "❌ 질문을 입력해주세요."
|
195 |
-
|
196 |
-
# 처리 시작
|
197 |
-
status = "🔄 AI들이 협력하여 답변을 생성하고 있습니다..."
|
198 |
-
|
199 |
-
try:
|
200 |
-
# 협력적 처리
|
201 |
-
result = llm_system.process_collaborative(user_query)
|
202 |
-
|
203 |
-
# 감독자와 실행자 텍스트 포맷팅
|
204 |
-
supervisor_text = "\n\n---\n\n".join([
|
205 |
-
f"[{log['stage']}] - {log['timestamp']}\n{log['content']}"
|
206 |
-
for log in result["conversation_log"] if log["role"] == "supervisor"
|
207 |
-
])
|
208 |
-
|
209 |
-
executor_text = "\n\n---\n\n".join([
|
210 |
-
f"[{log['stage']}] - {log['timestamp']}\n{log['content']}"
|
211 |
-
for log in result["conversation_log"] if log["role"] == "executor"
|
212 |
-
])
|
213 |
|
214 |
# 히스토리 업데이트
|
215 |
-
new_history = history + [(user_query,
|
216 |
|
217 |
-
|
218 |
-
new_history,
|
219 |
-
supervisor_text,
|
220 |
-
executor_text,
|
221 |
-
result["final_result"],
|
222 |
-
"✅ 분석 완료!"
|
223 |
-
)
|
224 |
|
225 |
except Exception as e:
|
226 |
error_msg = f"❌ 처리 중 오류: {str(e)}"
|
227 |
-
|
228 |
|
229 |
def clear_all():
|
230 |
"""모든 내용 초기화"""
|
@@ -235,23 +314,25 @@ css = """
|
|
235 |
.gradio-container {
|
236 |
font-family: 'Arial', sans-serif;
|
237 |
}
|
238 |
-
.supervisor-box {
|
239 |
-
border-left: 4px solid #667eea;
|
240 |
-
padding-left: 10px;
|
241 |
}
|
242 |
-
.executor-box {
|
243 |
-
border-left: 4px solid #764ba2;
|
244 |
-
padding-left: 10px;
|
245 |
}
|
246 |
"""
|
247 |
|
248 |
with gr.Blocks(title="협력적 LLM 시스템", theme=gr.themes.Soft(), css=css) as app:
|
249 |
gr.Markdown(
|
250 |
-
"""
|
251 |
# 🤝 협력적 LLM 시스템
|
252 |
|
253 |
> 거시적 감독자 AI와 미시적 실행자 AI가 협력하여 최상의 답변을 만들어냅니다.
|
254 |
|
|
|
|
|
255 |
**시스템 구조:**
|
256 |
- 🧠 **감독자 AI**: 전체적인 방향과 프레임워크를 제시
|
257 |
- 👁️ **실행자 AI**: 구체적이고 실행 가능한 세부사항을 작성
|
@@ -332,7 +413,7 @@ with gr.Blocks(title="협력적 LLM 시스템", theme=gr.themes.Soft(), css=css)
|
|
332 |
|
333 |
# 이벤트 핸들러
|
334 |
submit_btn.click(
|
335 |
-
fn=
|
336 |
inputs=[user_input, chatbot],
|
337 |
outputs=[chatbot, supervisor_output, executor_output, final_output, status_text]
|
338 |
).then(
|
@@ -341,7 +422,7 @@ with gr.Blocks(title="협력적 LLM 시스템", theme=gr.themes.Soft(), css=css)
|
|
341 |
)
|
342 |
|
343 |
user_input.submit(
|
344 |
-
fn=
|
345 |
inputs=[user_input, chatbot],
|
346 |
outputs=[chatbot, supervisor_output, executor_output, final_output, status_text]
|
347 |
).then(
|
@@ -363,12 +444,14 @@ with gr.Blocks(title="협력적 LLM 시스템", theme=gr.themes.Soft(), css=css)
|
|
363 |
3. 최종 종합 결과는 상단에 표시됩니다.
|
364 |
|
365 |
### ⚙️ 환경 설정
|
366 |
-
-
|
367 |
-
-
|
|
|
368 |
"""
|
369 |
)
|
370 |
|
371 |
if __name__ == "__main__":
|
|
|
372 |
app.launch(
|
373 |
server_name="0.0.0.0",
|
374 |
server_port=7860,
|
|
|
3 |
import json
|
4 |
import requests
|
5 |
from datetime import datetime
|
6 |
+
import time
|
7 |
+
from typing import List, Dict, Any, Generator
|
|
|
8 |
import logging
|
9 |
|
10 |
# 로깅 설정
|
|
|
15 |
FRIENDLI_TOKEN = os.getenv("FRIENDLI_TOKEN", "YOUR_FRIENDLI_TOKEN")
|
16 |
API_URL = "https://api.friendli.ai/dedicated/v1/chat/completions"
|
17 |
MODEL_ID = "dep89a2fld32mcm"
|
18 |
+
TEST_MODE = os.getenv("TEST_MODE", "false").lower() == "true"
|
19 |
|
20 |
# 전역 변수
|
21 |
conversation_history = []
|
|
|
25 |
self.token = FRIENDLI_TOKEN
|
26 |
self.api_url = API_URL
|
27 |
self.model_id = MODEL_ID
|
28 |
+
self.test_mode = TEST_MODE or (self.token == "YOUR_FRIENDLI_TOKEN")
|
29 |
+
|
30 |
+
if self.test_mode:
|
31 |
+
logger.warning("테스트 모드로 실행됩니다.")
|
32 |
|
33 |
def create_headers(self):
|
34 |
"""API 헤더 생성"""
|
|
|
66 |
|
67 |
위 지침을 바탕으로 구체적이고 실행 가능한 세부 내용을 작성해주세요. 실용적이고 구현 가능한 해결책에 집중하세요."""
|
68 |
|
69 |
+
def simulate_streaming(self, text: str, role: str) -> Generator[str, None, None]:
|
70 |
+
"""테스트 모드에서 스트리밍 시뮬레이션"""
|
71 |
+
words = text.split()
|
72 |
+
for i in range(0, len(words), 3):
|
73 |
+
chunk = " ".join(words[i:i+3])
|
74 |
+
yield chunk + " "
|
75 |
+
time.sleep(0.1)
|
76 |
+
|
77 |
+
def call_llm_streaming(self, messages: List[Dict[str, str]], role: str) -> Generator[str, None, None]:
|
78 |
+
"""스트리밍 LLM API 호출"""
|
79 |
+
|
80 |
+
# 테스트 모드
|
81 |
+
if self.test_mode:
|
82 |
+
logger.info(f"테스트 모드 스트리밍 - Role: {role}")
|
83 |
+
test_responses = {
|
84 |
+
"supervisor_initial": """이 질문에 대한 거시적 분석을 제시하겠습니다.
|
85 |
+
|
86 |
+
1. **핵심 개념 파악**
|
87 |
+
- 질문의 본질적 요소를 심층 분석합니다
|
88 |
+
- 관련된 주요 이론과 원칙을 검토합니다
|
89 |
+
- 다양한 관점에서의 접근 방법을 고려합니다
|
90 |
+
|
91 |
+
2. **전략적 접근 방향**
|
92 |
+
- 체계적이고 단계별 해결 방안을 수립합니다
|
93 |
+
- 장단기 목표를 명확히 설정합니다
|
94 |
+
- 리스크 요인과 대응 방안을 마련합니다
|
95 |
+
|
96 |
+
3. **기대 효과와 과제**
|
97 |
+
- 예상되는 긍정적 성과를 분석합니다
|
98 |
+
- 잠재적 도전 과제를 식별합니다
|
99 |
+
- 지속가능한 발전 방향을 제시합니다""",
|
100 |
+
|
101 |
+
"executor": """감독자 AI의 지침에 따라 구체적인 실행 계획을 수립하겠습니다.
|
102 |
+
|
103 |
+
**단계 1: 현황 분석 및 준비** (1-2주)
|
104 |
+
- 현재 상황에 대한 정밀 진단 실시
|
105 |
+
- 필요한 자원과 인력 확보
|
106 |
+
- 이해관계자들과의 소통 채널 구축
|
107 |
+
|
108 |
+
**단계 2: 파일럿 프로젝트 실행** (3-4주)
|
109 |
+
- 소규모 테스트 프로젝트 진행
|
110 |
+
- 초기 결과 데이터 수집 및 분석
|
111 |
+
- 피드백을 통한 개선점 도출
|
112 |
+
|
113 |
+
**단계 3: 본격 구현** (2-3개월)
|
114 |
+
- 검증된 방법론을 전체에 적용
|
115 |
+
- 주기적인 모니터링과 조정
|
116 |
+
- 성과 지표 측정 및 보고
|
117 |
+
|
118 |
+
**단계 4: 평가 및 확산** (지속)
|
119 |
+
- 종합적인 성과 평가
|
120 |
+
- 베스트 프랙티스 문서화
|
121 |
+
- 다른 영역으로의 확대 적용""",
|
122 |
+
|
123 |
+
"supervisor_review": """실행자 AI의 계획을 검토한 결과, 다음과 같은 개선사항을 제안합니다.
|
124 |
+
|
125 |
+
**강점**
|
126 |
+
- 단계별 접근이 체계적이고 현실적입니다
|
127 |
+
- 파일럿 프로젝트를 통한 위험 최소화 전략이 우수합니다
|
128 |
+
- 지속적인 모니터링 체계가 잘 구축되어 있습니다
|
129 |
+
|
130 |
+
**개선 필요사항**
|
131 |
+
1. 각 단계별 구체적인 성과 지표(KPI) 설정이 필요합니다
|
132 |
+
2. 예상치 못한 상황에 대한 대안(Plan B) 준비가 보완되어야 합니다
|
133 |
+
3. 이해관계자별 맞춤형 커뮤니케이션 전략이 추가되면 좋겠습니다
|
134 |
+
|
135 |
+
**추가 권장사항**
|
136 |
+
- 변화 관리(Change Management) 측면 강화
|
137 |
+
- 디지털 도구 활용 방안 구체화
|
138 |
+
- 장기적 지속가능성 확보 방안 마련"""
|
139 |
+
}
|
140 |
+
|
141 |
+
if role == "supervisor" and not messages[0]["content"].find("실행자 AI의 답변") > -1:
|
142 |
+
response = test_responses["supervisor_initial"]
|
143 |
+
elif role == "executor":
|
144 |
+
response = test_responses["executor"]
|
145 |
+
else:
|
146 |
+
response = test_responses["supervisor_review"]
|
147 |
+
|
148 |
+
yield from self.simulate_streaming(response, role)
|
149 |
+
return
|
150 |
+
|
151 |
+
# 실제 API 호출
|
152 |
try:
|
|
|
153 |
system_prompts = {
|
154 |
"supervisor": "당신은 거시적 관점에서 분석하고 지도하는 감독자 AI입니다.",
|
155 |
"executor": "당신은 세부적인 내용을 구현하는 실행자 AI입니다."
|
156 |
}
|
157 |
|
|
|
158 |
full_messages = [
|
159 |
{"role": "system", "content": system_prompts.get(role, "")},
|
160 |
*messages
|
|
|
166 |
"max_tokens": 2048,
|
167 |
"temperature": 0.7,
|
168 |
"top_p": 0.8,
|
169 |
+
"stream": True,
|
170 |
+
"stream_options": {"include_usage": True}
|
171 |
}
|
172 |
|
173 |
+
logger.info(f"API 스트리밍 호출 시작 - Role: {role}")
|
174 |
+
|
175 |
response = requests.post(
|
176 |
self.api_url,
|
177 |
headers=self.create_headers(),
|
178 |
json=payload,
|
179 |
+
stream=True,
|
180 |
+
timeout=10
|
181 |
)
|
182 |
|
183 |
+
if response.status_code != 200:
|
|
|
|
|
|
|
184 |
logger.error(f"API 오류: {response.status_code}")
|
185 |
+
yield f"❌ API 오류 ({response.status_code}): {response.text[:200]}"
|
186 |
+
return
|
187 |
+
|
188 |
+
for line in response.iter_lines():
|
189 |
+
if line:
|
190 |
+
line = line.decode('utf-8')
|
191 |
+
if line.startswith("data: "):
|
192 |
+
data = line[6:]
|
193 |
+
if data == "[DONE]":
|
194 |
+
break
|
195 |
+
try:
|
196 |
+
chunk = json.loads(data)
|
197 |
+
if "choices" in chunk and chunk["choices"]:
|
198 |
+
content = chunk["choices"][0].get("delta", {}).get("content", "")
|
199 |
+
if content:
|
200 |
+
yield content
|
201 |
+
except json.JSONDecodeError:
|
202 |
+
continue
|
203 |
+
|
204 |
+
except requests.exceptions.Timeout:
|
205 |
+
yield "⏱️ API 호출 시간이 초과되었습니다. 다시 시도해주세요."
|
206 |
+
except requests.exceptions.ConnectionError:
|
207 |
+
yield "🔌 API 서버에 연결할 수 없습니다. 인터넷 연결을 확인해주세요."
|
208 |
except Exception as e:
|
209 |
+
logger.error(f"스트리밍 중 오류: {str(e)}")
|
210 |
+
yield f"❌ 오류 발생: {str(e)}"
|
211 |
+
|
212 |
+
# 시스템 인스턴스 생성
|
213 |
+
llm_system = LLMCollaborativeSystem()
|
214 |
+
|
215 |
+
def process_query_streaming(user_query: str, history: List):
|
216 |
+
"""스트리밍을 지원하는 쿼리 처리"""
|
217 |
+
if not user_query:
|
218 |
+
return history, "", "", "", "❌ 질문을 입력해주세요."
|
219 |
|
220 |
+
conversation_log = []
|
221 |
+
all_responses = {"supervisor": [], "executor": []}
|
222 |
+
|
223 |
+
try:
|
224 |
+
# 1단계: 감독자 AI 초기 분석 (스트리밍)
|
225 |
+
supervisor_prompt = llm_system.create_supervisor_prompt(user_query)
|
226 |
+
supervisor_response = ""
|
227 |
|
228 |
+
supervisor_text = "[초기 분석] 🔄 생성 중...\n"
|
229 |
+
for chunk in llm_system.call_llm_streaming(
|
230 |
+
[{"role": "user", "content": supervisor_prompt}],
|
231 |
+
"supervisor"
|
232 |
+
):
|
233 |
+
supervisor_response += chunk
|
234 |
+
supervisor_text = f"[초기 분석] - {datetime.now().strftime('%H:%M:%S')}\n{supervisor_response}"
|
235 |
+
yield history, supervisor_text, "", "", "🔄 감독자 AI가 분석 중..."
|
236 |
+
|
237 |
+
all_responses["supervisor"].append(supervisor_response)
|
238 |
+
conversation_log.append({
|
239 |
+
"role": "supervisor",
|
240 |
+
"stage": "초기 분석",
|
241 |
+
"content": supervisor_response,
|
242 |
+
"timestamp": datetime.now().strftime("%H:%M:%S")
|
243 |
+
})
|
244 |
+
|
245 |
+
# 2단계: 실행자 AI 세부 구현 (스트리밍)
|
246 |
+
executor_prompt = llm_system.create_executor_prompt(user_query, supervisor_response)
|
247 |
+
executor_response = ""
|
248 |
+
|
249 |
+
executor_text = "[세부 구현] 🔄 생성 중...\n"
|
250 |
+
for chunk in llm_system.call_llm_streaming(
|
251 |
+
[{"role": "user", "content": executor_prompt}],
|
252 |
+
"executor"
|
253 |
+
):
|
254 |
+
executor_response += chunk
|
255 |
+
executor_text = f"[세부 구현] - {datetime.now().strftime('%H:%M:%S')}\n{executor_response}"
|
256 |
+
yield history, supervisor_text, executor_text, "", "🔄 실행자 AI가 구현 중..."
|
257 |
+
|
258 |
+
all_responses["executor"].append(executor_response)
|
259 |
+
conversation_log.append({
|
260 |
+
"role": "executor",
|
261 |
+
"stage": "세부 구현",
|
262 |
+
"content": executor_response,
|
263 |
+
"timestamp": datetime.now().strftime("%H:%M:%S")
|
264 |
+
})
|
265 |
+
|
266 |
+
# 3단계: 감독자 AI 검토 (스트리밍)
|
267 |
+
review_prompt = llm_system.create_supervisor_prompt(user_query, executor_response)
|
268 |
+
review_response = ""
|
269 |
+
|
270 |
+
supervisor_text += "\n\n---\n\n[검토 및 피드백] 🔄 생성 중...\n"
|
271 |
+
for chunk in llm_system.call_llm_streaming(
|
272 |
+
[{"role": "user", "content": review_prompt}],
|
273 |
+
"supervisor"
|
274 |
+
):
|
275 |
+
review_response += chunk
|
276 |
+
supervisor_text = f"[초기 분석] - {conversation_log[0]['timestamp']}\n{all_responses['supervisor'][0]}\n\n---\n\n[검토 및 피드백] - {datetime.now().strftime('%H:%M:%S')}\n{review_response}"
|
277 |
+
yield history, supervisor_text, executor_text, "", "🔄 감독자 AI가 검토 중..."
|
278 |
+
|
279 |
+
all_responses["supervisor"].append(review_response)
|
280 |
+
|
281 |
+
# 최종 결과 생성
|
282 |
+
final_summary = f"""## 🤝 협력적 AI 시스템 종합 답변
|
283 |
|
284 |
### 📌 사용자 질문
|
285 |
{user_query}
|
286 |
|
287 |
### 🔍 거시적 분석 (감독자 AI)
|
288 |
+
{all_responses['supervisor'][0]}
|
289 |
|
290 |
### 💡 세부 구현 (실행자 AI)
|
291 |
{executor_response}
|
|
|
295 |
|
296 |
---
|
297 |
*이 답변은 거시적 관점과 미시적 세부사항을 종합하여 작성되었습니다.*"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
298 |
|
299 |
# 히스토리 업데이트
|
300 |
+
new_history = history + [(user_query, final_summary)]
|
301 |
|
302 |
+
yield new_history, supervisor_text, executor_text, final_summary, "✅ 분석 완료!"
|
|
|
|
|
|
|
|
|
|
|
|
|
303 |
|
304 |
except Exception as e:
|
305 |
error_msg = f"❌ 처리 중 오류: {str(e)}"
|
306 |
+
yield history, "", "", error_msg, error_msg
|
307 |
|
308 |
def clear_all():
|
309 |
"""모든 내용 초기화"""
|
|
|
314 |
.gradio-container {
|
315 |
font-family: 'Arial', sans-serif;
|
316 |
}
|
317 |
+
.supervisor-box textarea {
|
318 |
+
border-left: 4px solid #667eea !important;
|
319 |
+
padding-left: 10px !important;
|
320 |
}
|
321 |
+
.executor-box textarea {
|
322 |
+
border-left: 4px solid #764ba2 !important;
|
323 |
+
padding-left: 10px !important;
|
324 |
}
|
325 |
"""
|
326 |
|
327 |
with gr.Blocks(title="협력적 LLM 시스템", theme=gr.themes.Soft(), css=css) as app:
|
328 |
gr.Markdown(
|
329 |
+
f"""
|
330 |
# 🤝 협력적 LLM 시스템
|
331 |
|
332 |
> 거시적 감독자 AI와 미시적 실행자 AI가 협력하여 최상의 답변을 만들어냅니다.
|
333 |
|
334 |
+
**상태**: {'🟢 실제 모드' if not llm_system.test_mode else '🟡 테스트 모드'}
|
335 |
+
|
336 |
**시스템 구조:**
|
337 |
- 🧠 **감독자 AI**: 전체적인 방향과 프레임워크를 제시
|
338 |
- 👁️ **실행자 AI**: 구체적이고 실행 가능한 세부사항을 작성
|
|
|
413 |
|
414 |
# 이벤트 핸들러
|
415 |
submit_btn.click(
|
416 |
+
fn=process_query_streaming,
|
417 |
inputs=[user_input, chatbot],
|
418 |
outputs=[chatbot, supervisor_output, executor_output, final_output, status_text]
|
419 |
).then(
|
|
|
422 |
)
|
423 |
|
424 |
user_input.submit(
|
425 |
+
fn=process_query_streaming,
|
426 |
inputs=[user_input, chatbot],
|
427 |
outputs=[chatbot, supervisor_output, executor_output, final_output, status_text]
|
428 |
).then(
|
|
|
444 |
3. 최종 종합 결과는 상단에 표시됩니다.
|
445 |
|
446 |
### ⚙️ 환경 설정
|
447 |
+
- **실제 모드**: `export FRIENDLI_TOKEN="your_token"`
|
448 |
+
- **테스트 모드**: `export TEST_MODE=true` (API 없이 작동)
|
449 |
+
- 현재 토큰이 설정되지 않으면 자동으로 테스트 모드로 실행됩니다.
|
450 |
"""
|
451 |
)
|
452 |
|
453 |
if __name__ == "__main__":
|
454 |
+
app.queue() # 스트리밍을 위한 큐 활성화
|
455 |
app.launch(
|
456 |
server_name="0.0.0.0",
|
457 |
server_port=7860,
|