aiqtech commited on
Commit
b98b58f
·
verified ·
1 Parent(s): 505cfe8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +211 -128
app.py CHANGED
@@ -3,9 +3,8 @@ import os
3
  import json
4
  import requests
5
  from datetime import datetime
6
- import asyncio
7
- import aiohttp
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 call_llm_sync(self, messages: List[Dict[str, str]], role: str) -> str:
66
- """동기식 LLM API 호출"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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": False
 
87
  }
88
 
 
 
89
  response = requests.post(
90
  self.api_url,
91
  headers=self.create_headers(),
92
  json=payload,
93
- timeout=60
 
94
  )
95
 
96
- if response.status_code == 200:
97
- data = response.json()
98
- return data["choices"][0]["message"]["content"]
99
- else:
100
  logger.error(f"API 오류: {response.status_code}")
101
- return f"API 호출 오류: {response.status_code}"
102
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  except Exception as e:
104
- logger.error(f"LLM 호출 중 오류: {str(e)}")
105
- return f"오류 발생: {str(e)}"
 
 
 
 
 
 
 
 
106
 
107
- def process_collaborative(self, user_query: str) -> Dict[str, Any]:
108
- """협력적 처리 프로세스"""
109
- conversation_log = []
 
 
 
 
110
 
111
- try:
112
- # 1단계: 감독자 AI의 초기 분석
113
- supervisor_prompt = self.create_supervisor_prompt(user_query)
114
- supervisor_response = self.call_llm_sync(
115
- [{"role": "user", "content": supervisor_prompt}],
116
- "supervisor"
117
- )
118
-
119
- conversation_log.append({
120
- "role": "supervisor",
121
- "stage": "초기 분석",
122
- "content": supervisor_response,
123
- "timestamp": datetime.now().strftime("%H:%M:%S")
124
- })
125
-
126
- # 2단계: 실행자 AI의 세부 구현
127
- executor_prompt = self.create_executor_prompt(user_query, supervisor_response)
128
- executor_response = self.call_llm_sync(
129
- [{"role": "user", "content": executor_prompt}],
130
- "executor"
131
- )
132
-
133
- conversation_log.append({
134
- "role": "executor",
135
- "stage": "세부 구현",
136
- "content": executor_response,
137
- "timestamp": datetime.now().strftime("%H:%M:%S")
138
- })
139
-
140
- # 3단계: 감독자 AI의 검토 및 피드백
141
- review_prompt = self.create_supervisor_prompt(user_query, executor_response)
142
- review_response = self.call_llm_sync(
143
- [{"role": "user", "content": review_prompt}],
144
- "supervisor"
145
- )
146
-
147
- conversation_log.append({
148
- "role": "supervisor",
149
- "stage": "검토 및 피드백",
150
- "content": review_response,
151
- "timestamp": datetime.now().strftime("%H:%M:%S")
152
- })
153
-
154
- # 4단계: 최종 종합
155
- final_summary = f"""## 🤝 협력적 AI 시스템 종합 답변
 
 
 
 
 
 
 
 
 
 
156
 
157
  ### 📌 사용자 질문
158
  {user_query}
159
 
160
  ### 🔍 거시적 분석 (감독자 AI)
161
- {supervisor_response}
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, result["final_result"])]
216
 
217
- return (
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
- return history, "", "", error_msg, error_msg
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=process_query,
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=process_query,
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
- - `FRIENDLI_TOKEN` 환경 변수를 설정하세요: `export FRIENDLI_TOKEN="your_token"`
367
- - 또는 코드의 `FRIENDLI_TOKEN` 변수를 직접 수정하세요.
 
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,