ginipick commited on
Commit
3b6b6aa
·
verified ·
1 Parent(s): 2d72c19

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +212 -158
app.py CHANGED
@@ -1,20 +1,26 @@
1
  # -*- coding: utf-8 -*-
2
  """
3
- AI 뉴스 & 허깅페이스 트렌딩 LLM 분석 웹앱 (Fireworks AI 완전판 v3.1)
4
- 파일명: app_fireworks.py
5
 
6
  주요 기능:
7
- 1. Fireworks AI API로 실제 LLM 분석 (Qwen3-235B 모델)
8
- 2. SQLite DB 영구 스토리지
9
- 3. 실제 Hugging Face Trending API 연동 (모델/스페이스 30위)
10
- 4. 초등학생 수준 분석 (요약/의미/영향/행동지침)
 
 
11
  5. 탭 UI (뉴스/모델/스페이스)
12
 
13
  실행 방법:
14
  1. pip install Flask requests beautifulsoup4 huggingface_hub
15
- 2. export FIREWORKS_API_KEY="your-api-key-here"
16
- 3. python app_fireworks.py
17
  4. 브라우저에서 http://localhost:7860 접속
 
 
 
 
18
  """
19
 
20
  from flask import Flask, render_template_string, jsonify, request
@@ -35,10 +41,6 @@ app.config['JSON_AS_ASCII'] = False
35
  # 데이터베이스 파일 경로
36
  DB_PATH = 'ai_news_analysis.db'
37
 
38
- # Fireworks AI API 설정
39
- FIREWORKS_API_KEY = os.environ.get('FIREWORKS_API_KEY', '')
40
- FIREWORKS_API_URL = "https://api.fireworks.ai/inference/v1/chat/completions"
41
-
42
 
43
  # ============================================
44
  # HTML 템플릿 (탭 UI 포함)
@@ -540,7 +542,7 @@ HTML_TEMPLATE = """
540
  <body>
541
  <div class="container">
542
  <h1>🤖 AI 뉴스 & 허깅페이스 LLM 분석</h1>
543
- <p class="subtitle">초등학생도 이해하는 AI 트렌드 분석 시스템 🎓 (Powered by Fireworks AI)</p>
544
 
545
  <!-- 통계 카드 -->
546
  <div class="stats">
@@ -717,12 +719,12 @@ HTML_TEMPLATE = """
717
 
718
  <!-- 푸터 -->
719
  <div class="footer">
720
- <p>🤖 AI 뉴스 LLM 분석 시스템 v3.1 (Fireworks AI Edition)</p>
721
  <p style="margin-top: 10px; font-size: 0.9em;">
722
- 💾 SQLite DB 영구 저장 | 🤗 Hugging Face Trending API | 🔥 Powered by Fireworks AI (Qwen3-235B)
723
  </p>
724
  <p style="margin-top: 10px; font-size: 0.85em; color: #999;">
725
- 데이터 출처: AI Times, Hugging Face | 분석: Fireworks AI LLM
726
  </p>
727
  </div>
728
  </div>
@@ -742,7 +744,7 @@ HTML_TEMPLATE = """
742
  document.getElementById(tabName + '-content').classList.add('active');
743
  }
744
 
745
- console.log('✅ AI 뉴스 LLM 분석 시스템 로드 완료 (Fireworks AI)');
746
  </script>
747
  </body>
748
  </html>
@@ -845,7 +847,7 @@ def save_news_to_db(news_list: List[Dict]):
845
  ))
846
  saved_count += 1
847
  except sqlite3.IntegrityError:
848
- pass
849
 
850
  conn.commit()
851
  conn.close()
@@ -999,7 +1001,7 @@ def load_spaces_from_db() -> List[Dict]:
999
  'simple_explanation': row[7],
1000
  'tech_stack': json.loads(row[8]) if row[8] else [],
1001
  'rank': row[9],
1002
- 'description': row[3]
1003
  })
1004
 
1005
  conn.close()
@@ -1007,44 +1009,35 @@ def load_spaces_from_db() -> List[Dict]:
1007
 
1008
 
1009
  # ============================================
1010
- # Fireworks AI LLM 분석기 클래스
1011
  # ============================================
1012
 
1013
- class FireworksLLMAnalyzer:
1014
- """Fireworks AI API를 사용한 LLM 분석기"""
1015
 
1016
- def __init__(self, api_key: str = None):
1017
- self.api_key = api_key or FIREWORKS_API_KEY
1018
- self.api_url = FIREWORKS_API_URL
1019
- self.model = "accounts/fireworks/models/qwen3-235b-a22b-instruct-2507"
1020
-
1021
- if not self.api_key:
1022
- print("⚠️ FIREWORKS_API_KEY 설정되지 않았습니다. 샘플 분석을 사용합니다.")
1023
- self.api_available = False
1024
- else:
1025
- self.api_available = True
1026
- print("✅ Fireworks AI API 연결 준비 완료")
1027
 
1028
- def call_llm(self, prompt: str, max_tokens: int = 2000) -> str:
1029
- """Fireworks AI LLM 호출"""
1030
  if not self.api_available:
1031
- return ""
1032
 
1033
  try:
1034
  payload = {
1035
- "model": self.model,
1036
  "max_tokens": max_tokens,
1037
  "top_p": 1,
1038
  "top_k": 40,
1039
  "presence_penalty": 0,
1040
  "frequency_penalty": 0,
1041
  "temperature": 0.6,
1042
- "messages": [
1043
- {
1044
- "role": "user",
1045
- "content": prompt
1046
- }
1047
- ]
1048
  }
1049
 
1050
  headers = {
@@ -1053,66 +1046,55 @@ class FireworksLLMAnalyzer:
1053
  "Authorization": f"Bearer {self.api_key}"
1054
  }
1055
 
1056
- response = requests.post(
1057
- self.api_url,
1058
- headers=headers,
1059
- data=json.dumps(payload),
1060
- timeout=30
1061
- )
 
 
 
 
 
 
 
 
 
1062
 
1063
  if response.status_code == 200:
1064
- result = response.json()
1065
- return result['choices'][0]['message']['content'].strip()
 
 
 
1066
  else:
1067
- print(f"⚠️ LLM API 오류: {response.status_code}")
1068
- return ""
1069
-
1070
  except Exception as e:
1071
- print(f"⚠️ LLM 호출 오류: {e}")
1072
- return ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1073
 
1074
  def analyze_news_simple(self, title: str, content: str = "") -> Dict:
1075
  """뉴스 기사를 초등학생 수준으로 분석"""
1076
 
1077
- prompt = f"""다음 AI 뉴스를 초등학생(10살)도 이해할 수 있게 분석해주세요.
1078
-
1079
- 뉴스 제목: {title}
1080
-
1081
- 다음 형식으로 JSON 응답해주세요:
1082
- {{
1083
- "summary": "초등학생이 이해할 수 있는 쉬운 요약 (2-3문장)",
1084
- "significance": "이 뉴스가 왜 중요한지 쉽게 설명 (2문장)",
1085
- "impact_level": "high 또는 medium 또는 low",
1086
- "impact_text": "높음 또는 중간 또는 낮음",
1087
- "impact_description": "영향도에 대한 설명 (1-2문장)",
1088
- "action": "우리가 할 수 있는 것 (1-2문장)"
1089
- }}
1090
-
1091
- JSON만 출력하고 다른 설명은 하지 마세요."""
1092
-
1093
- response = self.call_llm(prompt, max_tokens=1500)
1094
-
1095
- if response:
1096
- try:
1097
- # JSON 파싱
1098
- response = response.strip()
1099
- if response.startswith("```json"):
1100
- response = response[7:]
1101
- if response.endswith("```"):
1102
- response = response[:-3]
1103
- response = response.strip()
1104
-
1105
- analysis = json.loads(response)
1106
- return analysis
1107
- except json.JSONDecodeError as e:
1108
- print(f"⚠️ JSON 파싱 오류: {e}")
1109
- print(f"응답: {response[:200]}")
1110
-
1111
- # 기본 분석 (API 실패 시)
1112
- return self._get_fallback_news_analysis(title)
1113
-
1114
- def _get_fallback_news_analysis(self, title: str) -> Dict:
1115
- """API 실패 시 기본 분석"""
1116
  analysis_templates = {
1117
  "챗GPT": {
1118
  "summary": "마이크로소프트(MS)라는 큰 회사가 챗GPT라는 AI를 너무 많은 사람들이 사용해서, 컴퓨터를 보관하는 큰 건물(데이터센터)이 부족하다고 말했어요.",
@@ -1140,10 +1122,12 @@ JSON만 출력하고 다른 설명은 하지 마세요."""
1140
  }
1141
  }
1142
 
 
1143
  for keyword, template in analysis_templates.items():
1144
  if keyword.lower() in title.lower():
1145
  return template
1146
 
 
1147
  return {
1148
  "summary": f"'{title}'라는 AI 관련 뉴스가 나왔어요. AI 기술이 계속 발전하고 있다는 소식이에요.",
1149
  "significance": "AI는 우리 생활을 더 편리하게 만들어주는 기술이에요.",
@@ -1154,23 +1138,43 @@ JSON만 출력하고 다른 설명은 하지 마세요."""
1154
  }
1155
 
1156
  def analyze_model(self, model_name: str, task: str, downloads: int) -> str:
1157
- """허깅페이스 모델 분석"""
 
 
 
1158
 
1159
- prompt = f"""다음 허깅페이스 AI 모델을 초등학생(10살)이 이해할 수 있게 설명해주세요.
 
 
 
 
 
 
 
 
 
 
1160
 
1161
- 모델명: {model_name}
1162
- 태스크: {task}
1163
- 다운로드 수: {downloads:,}
1164
 
1165
- 2-3문장으로 모델이 무엇을 하는지, 인기가 많은지 쉽게 설명해주세요.
1166
- 설명만 작성하고 다른 내용은 쓰지 마세요."""
 
 
1167
 
1168
- response = self.call_llm(prompt, max_tokens=300)
1169
-
1170
- if response:
1171
- return response
 
 
 
 
 
 
 
1172
 
1173
- # 기본 분석
1174
  task_explanations = {
1175
  "text-generation": "글을 자동으로 만들어주는",
1176
  "image-to-text": "사진을 보고 설명을 써주는",
@@ -1196,39 +1200,65 @@ JSON만 출력하고 다른 설명은 하지 마세요."""
1196
 
1197
  return f"이 모델은 {task_desc} AI예요. {popularity} 사람들이 다운로드해서 사용하고 있어요. {model_name.split('/')[-1]}라는 이름으로 유명해요!"
1198
 
1199
- def analyze_space(self, space_name: str, description: str) -> Dict:
1200
- """허깅페이스 스페이스 분석"""
1201
 
1202
- prompt = f"""다음 허깅페이스 스페이스를 초등학생(10살)이 이해할 수 있게 설명해주세요.
1203
-
1204
- 스페이스명: {space_name}
1205
- 설명: {description}
 
 
 
 
 
 
 
 
 
 
1206
 
1207
- 다음 형식으로 JSON 응답해주세요:
1208
- {{
1209
- "simple_explanation": "이 스페이스가 무엇을 하는지 쉽게 설명 (2-3문장)",
1210
- "tech_stack": ["기술1", "기술2", "기술3"]
1211
- }}
1212
 
1213
- JSON만 출력하고 다른 설명은 하지 마세요."""
 
 
 
1214
 
1215
- response = self.call_llm(prompt, max_tokens=500)
1216
-
1217
- if response:
1218
- try:
1219
- response = response.strip()
1220
- if response.startswith("```json"):
1221
- response = response[7:]
1222
- if response.endswith("```"):
1223
- response = response[:-3]
1224
- response = response.strip()
1225
 
1226
- analysis = json.loads(response)
1227
- return analysis
1228
- except json.JSONDecodeError:
1229
- pass
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1230
 
1231
- # 기본 분석
1232
  return {
1233
  "simple_explanation": f"{space_name}는 웹브라우저에서 바로 AI를 체험해볼 수 있는 곳이에요. 설치 없이도 사용할 수 있어서 편리해요! 마치 온라인 게임처럼 바로 접속해서 AI를 사용할 수 있답니다.",
1234
  "tech_stack": ["Python", "Gradio", "Transformers", "PyTorch"]
@@ -1240,10 +1270,10 @@ JSON만 출력하고 다른 설명은 하지 마세요."""
1240
  # ============================================
1241
 
1242
  class AdvancedAIAnalyzer:
1243
- """LLM 기반 고급 AI 뉴스 분석기 (Fireworks AI)"""
1244
 
1245
  def __init__(self):
1246
- self.llm_analyzer = FireworksLLMAnalyzer()
1247
  self.huggingface_data = {
1248
  "models": [],
1249
  "spaces": []
@@ -1257,9 +1287,12 @@ class AdvancedAIAnalyzer:
1257
  models_list = []
1258
 
1259
  try:
 
1260
  api = HfApi()
 
 
1261
  models = list(api.list_models(
1262
- sort="trending",
1263
  direction=-1,
1264
  limit=limit
1265
  ))
@@ -1277,8 +1310,8 @@ class AdvancedAIAnalyzer:
1277
  'rank': idx
1278
  }
1279
 
1280
- # LLM 분석 추가
1281
- print(f" 🧠 모델 {idx} LLM 분석 중...")
1282
  model_info['analysis'] = self.llm_analyzer.analyze_model(
1283
  model_info['name'],
1284
  model_info['task'],
@@ -1287,9 +1320,12 @@ class AdvancedAIAnalyzer:
1287
 
1288
  models_list.append(model_info)
1289
 
 
 
 
 
1290
  if idx % 5 == 0:
1291
  print(f" ✓ {idx}개 모델 처리 완료...")
1292
- time.sleep(0.5) # Rate limit 방지
1293
 
1294
  except Exception as e:
1295
  print(f" ⚠️ 모델 {idx} 처리 오류: {e}")
@@ -1297,6 +1333,7 @@ class AdvancedAIAnalyzer:
1297
 
1298
  print(f"✅ {len(models_list)}개 트렌딩 모델 수집 완료")
1299
 
 
1300
  if models_list:
1301
  save_models_to_db(models_list)
1302
 
@@ -1314,9 +1351,12 @@ class AdvancedAIAnalyzer:
1314
  spaces_list = []
1315
 
1316
  try:
 
1317
  api = HfApi()
 
 
1318
  spaces = list(api.list_spaces(
1319
- sort="trending",
1320
  direction=-1,
1321
  limit=limit
1322
  ))
@@ -1336,10 +1376,11 @@ class AdvancedAIAnalyzer:
1336
  'rank': idx
1337
  }
1338
 
1339
- # LLM 분석 추가
1340
- print(f" 🧠 스페이스 {idx} LLM 분석 중...")
1341
  space_analysis = self.llm_analyzer.analyze_space(
1342
  space_info['name'],
 
1343
  space_info['title']
1344
  )
1345
 
@@ -1349,9 +1390,12 @@ class AdvancedAIAnalyzer:
1349
 
1350
  spaces_list.append(space_info)
1351
 
 
 
 
 
1352
  if idx % 5 == 0:
1353
  print(f" ✓ {idx}개 스페이스 처리 완료...")
1354
- time.sleep(0.5) # Rate limit 방지
1355
 
1356
  except Exception as e:
1357
  print(f" ⚠️ 스페이스 {idx} 처리 오류: {e}")
@@ -1359,6 +1403,7 @@ class AdvancedAIAnalyzer:
1359
 
1360
  print(f"✅ {len(spaces_list)}개 트렌딩 스페이스 수집 완료")
1361
 
 
1362
  if spaces_list:
1363
  save_spaces_to_db(spaces_list)
1364
 
@@ -1401,9 +1446,7 @@ class AdvancedAIAnalyzer:
1401
  news = self.create_sample_news()
1402
  analyzed_news = []
1403
 
1404
- for idx, article in enumerate(news, 1):
1405
- print(f" 🧠 뉴스 {idx}/{len(news)} LLM 분석 중...")
1406
-
1407
  analysis = self.llm_analyzer.analyze_news_simple(
1408
  article['title'],
1409
  ""
@@ -1411,19 +1454,22 @@ class AdvancedAIAnalyzer:
1411
 
1412
  article['analysis'] = analysis
1413
  analyzed_news.append(article)
1414
-
1415
- time.sleep(0.5) # Rate limit 방지
1416
 
1417
  print(f"✅ {len(analyzed_news)}개 뉴스 분석 완료")
1418
 
 
1419
  save_news_to_db(analyzed_news)
1420
 
1421
  return analyzed_news
1422
 
1423
  def get_all_data(self, force_refresh: bool = False) -> Dict:
1424
- """모든 데이터 수집 및 분석"""
 
 
 
 
1425
  print("\n" + "="*60)
1426
- print("🚀 AI 뉴스 & 허깅페이스 LLM 분석 시작 (Fireworks AI)")
1427
  print("="*60 + "\n")
1428
 
1429
  if force_refresh:
@@ -1434,6 +1480,7 @@ class AdvancedAIAnalyzer:
1434
  else:
1435
  print("💾 DB 우선 로드 모드")
1436
 
 
1437
  analyzed_news = load_news_from_db()
1438
  if not analyzed_news:
1439
  print("📰 DB에 뉴스 없음 → 새로 수집")
@@ -1455,6 +1502,7 @@ class AdvancedAIAnalyzer:
1455
  else:
1456
  print(f"✅ DB에서 {len(analyzed_spaces)}개 스페이스 로드")
1457
 
 
1458
  stats = {
1459
  'total_news': len(analyzed_news),
1460
  'hf_models': len(analyzed_models),
@@ -1484,6 +1532,7 @@ class AdvancedAIAnalyzer:
1484
  def index():
1485
  """메인 페이지"""
1486
  try:
 
1487
  force_refresh = request.args.get('refresh', 'false').lower() == 'true'
1488
 
1489
  analyzer = AdvancedAIAnalyzer()
@@ -1551,6 +1600,7 @@ def api_refresh():
1551
  def health():
1552
  """헬스 체크"""
1553
  try:
 
1554
  conn = sqlite3.connect(DB_PATH)
1555
  cursor = conn.cursor()
1556
  cursor.execute("SELECT COUNT(*) FROM news")
@@ -1563,15 +1613,17 @@ def health():
1563
 
1564
  return jsonify({
1565
  "status": "healthy",
1566
- "service": "AI News LLM Analyzer (Fireworks AI)",
1567
  "version": "3.1.0",
1568
- "llm_provider": "Fireworks AI (Qwen3-235B)",
1569
  "database": {
1570
  "connected": True,
1571
  "news_count": news_count,
1572
  "models_count": models_count,
1573
  "spaces_count": spaces_count
1574
  },
 
 
 
1575
  "timestamp": datetime.now().isoformat()
1576
  })
1577
  except Exception as e:
@@ -1592,18 +1644,20 @@ if __name__ == '__main__':
1592
  ╔════════════════════════════════════════════════════════════╗
1593
  ║ ║
1594
  ║ 🤖 AI 뉴스 & 허깅페이스 LLM 분석 웹앱 v3.1 ║
1595
- ║ 🔥 Powered by Fireworks AI (Qwen3-235B) ║
1596
  ║ ║
1597
  ╚════════════════════════════════════════════════════════════╝
1598
 
1599
  ✨ 주요 기능:
1600
- • 🔥 Fireworks AI LLM으로 실제 분석
1601
  • 💾 SQLite DB 영구 스토리지
1602
  • 📰 뉴스 초등학생 수준 분석
1603
- • 🤗 허깅페이스 트렌딩 모델 TOP 30
1604
- • 🚀 허깅페이스 트렌딩 스페이스 TOP 30
 
1605
  • 🎨 탭 UI (뉴스/모델/스페이스)
1606
 
 
 
 
1607
  🚀 서버 정보:
1608
  📍 메인: http://localhost:{port}
1609
  🔄 강제갱신: http://localhost:{port}/?refresh=true
@@ -1612,11 +1666,11 @@ if __name__ == '__main__':
1612
  💚 Health: http://localhost:{port}/health
1613
 
1614
  💾 데이터베이스: {DB_PATH}
1615
- 🔑 API 키 상태: {'✅ 설정됨' if FIREWORKS_API_KEY else '⚠️ 미설정 (샘플 분석 사용)'}
1616
 
1617
  초기화 중...
1618
  """)
1619
 
 
1620
  try:
1621
  init_database()
1622
  except Exception as e:
 
1
  # -*- coding: utf-8 -*-
2
  """
3
+ AI 뉴스 & 허깅페이스 트렌딩 LLM 분석 웹앱 (완전판 v3.1)
4
+ 파일명: app_advanced.py
5
 
6
  주요 기능:
7
+ 1. SQLite DB 영구 스토리지
8
+ 2. 실제 Hugging Face Trending API 연동 (모델/스페이스 30위)
9
+ 3. Fireworks AI (Qwen3-235B) 실시간 LLM 분석
10
+ - 모델 카드 자동 분석 (README.md)
11
+ - 스페이스 코드 자동 분석 (app.py)
12
+ 4. 초등학생도 이해 가능한 쉬운 설명
13
  5. 탭 UI (뉴스/모델/스페이스)
14
 
15
  실행 방법:
16
  1. pip install Flask requests beautifulsoup4 huggingface_hub
17
+ 2. export FIREWORKS_API_KEY="your-api-key-here" # 필수!
18
+ 3. python app_advanced.py
19
  4. 브라우저에서 http://localhost:7860 접속
20
+
21
+ 환경변수:
22
+ - FIREWORKS_API_KEY: Fireworks AI API 키 (필수)
23
+ - PORT: 서버 포트 (기본값: 7860)
24
  """
25
 
26
  from flask import Flask, render_template_string, jsonify, request
 
41
  # 데이터베이스 파일 경로
42
  DB_PATH = 'ai_news_analysis.db'
43
 
 
 
 
 
44
 
45
  # ============================================
46
  # HTML 템플릿 (탭 UI 포함)
 
542
  <body>
543
  <div class="container">
544
  <h1>🤖 AI 뉴스 & 허깅페이스 LLM 분석</h1>
545
+ <p class="subtitle">초등학생도 이해하는 AI 트렌드 분석 시스템 🎓</p>
546
 
547
  <!-- 통계 카드 -->
548
  <div class="stats">
 
719
 
720
  <!-- 푸터 -->
721
  <div class="footer">
722
+ <p>🤖 AI 뉴스 LLM 분석 시스템 v3.1</p>
723
  <p style="margin-top: 10px; font-size: 0.9em;">
724
+ 💾 SQLite DB 영구 저장 | 🤗 Hugging Face Trending API | 🧠 Powered by Fireworks AI (Qwen3-235B)
725
  </p>
726
  <p style="margin-top: 10px; font-size: 0.85em; color: #999;">
727
+ 데이터 출처: AI Times, Hugging Face | 실시간 분석: Fireworks AI
728
  </p>
729
  </div>
730
  </div>
 
744
  document.getElementById(tabName + '-content').classList.add('active');
745
  }
746
 
747
+ console.log('✅ AI 뉴스 LLM 분석 시스템 로드 완료');
748
  </script>
749
  </body>
750
  </html>
 
847
  ))
848
  saved_count += 1
849
  except sqlite3.IntegrityError:
850
+ pass # 이미 존재하는 뉴스
851
 
852
  conn.commit()
853
  conn.close()
 
1001
  'simple_explanation': row[7],
1002
  'tech_stack': json.loads(row[8]) if row[8] else [],
1003
  'rank': row[9],
1004
+ 'description': row[3] # title을 description으로 사용
1005
  })
1006
 
1007
  conn.close()
 
1009
 
1010
 
1011
  # ============================================
1012
+ # LLM 분석기 클래스
1013
  # ============================================
1014
 
1015
+ class LLMAnalyzer:
1016
+ """Fireworks AI (Qwen3) 기반 LLM 분석기"""
1017
 
1018
+ def __init__(self):
1019
+ self.api_key = os.environ.get('FIREWORKS_API_KEY', '')
1020
+ self.api_url = "https://api.fireworks.ai/inference/v1/chat/completions"
1021
+ self.api_available = bool(self.api_key)
1022
+
1023
+ if not self.api_available:
1024
+ print("⚠️ FIREWORKS_API_KEY 환경변수가 설정되지 않았습니다. 템플릿 모드로 동작합니다.")
 
 
 
 
1025
 
1026
+ def call_llm(self, messages: List[Dict], max_tokens: int = 2000) -> str:
1027
+ """Fireworks AI API 호출"""
1028
  if not self.api_available:
1029
+ return None
1030
 
1031
  try:
1032
  payload = {
1033
+ "model": "accounts/fireworks/models/qwen3-235b-a22b-instruct-2507",
1034
  "max_tokens": max_tokens,
1035
  "top_p": 1,
1036
  "top_k": 40,
1037
  "presence_penalty": 0,
1038
  "frequency_penalty": 0,
1039
  "temperature": 0.6,
1040
+ "messages": messages
 
 
 
 
 
1041
  }
1042
 
1043
  headers = {
 
1046
  "Authorization": f"Bearer {self.api_key}"
1047
  }
1048
 
1049
+ response = requests.post(self.api_url, headers=headers, json=payload, timeout=30)
1050
+ response.raise_for_status()
1051
+
1052
+ result = response.json()
1053
+ return result['choices'][0]['message']['content']
1054
+
1055
+ except Exception as e:
1056
+ print(f" ⚠️ LLM API 호출 오류: {e}")
1057
+ return None
1058
+
1059
+ def fetch_model_card(self, model_id: str) -> str:
1060
+ """허깅페이스 모델 카드(README.md) 가져오기"""
1061
+ try:
1062
+ url = f"https://huggingface.co/{model_id}/raw/main/README.md"
1063
+ response = requests.get(url, timeout=10)
1064
 
1065
  if response.status_code == 200:
1066
+ content = response.text
1067
+ # 너무 긴 경우 앞부분만 (약 3000자)
1068
+ if len(content) > 3000:
1069
+ content = content[:3000] + "\n...(후략)"
1070
+ return content
1071
  else:
1072
+ return None
 
 
1073
  except Exception as e:
1074
+ print(f" ⚠️ 모델 카드 가져오기 오류: {e}")
1075
+ return None
1076
+
1077
+ def fetch_space_code(self, space_id: str) -> str:
1078
+ """허깅페이스 스페이스 app.py 가져오기"""
1079
+ try:
1080
+ url = f"https://huggingface.co/spaces/{space_id}/raw/main/app.py"
1081
+ response = requests.get(url, timeout=10)
1082
+
1083
+ if response.status_code == 200:
1084
+ content = response.text
1085
+ # 너무 긴 경우 앞부분만 (약 2000자)
1086
+ if len(content) > 2000:
1087
+ content = content[:2000] + "\n...(후략)"
1088
+ return content
1089
+ else:
1090
+ return None
1091
+ except Exception as e:
1092
+ print(f" ⚠️ 스페이스 코드 가져오기 오류: {e}")
1093
+ return None
1094
 
1095
  def analyze_news_simple(self, title: str, content: str = "") -> Dict:
1096
  """뉴스 기사를 초등학생 수준으로 분석"""
1097
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1098
  analysis_templates = {
1099
  "챗GPT": {
1100
  "summary": "마이크로소프트(MS)라는 큰 회사가 챗GPT라는 AI를 너무 많은 사람들이 사용해서, 컴퓨터를 보관하는 큰 건물(데이터센터)이 부족하다고 말했어요.",
 
1122
  }
1123
  }
1124
 
1125
+ # 키워드 매칭으로 템플릿 선택
1126
  for keyword, template in analysis_templates.items():
1127
  if keyword.lower() in title.lower():
1128
  return template
1129
 
1130
+ # 기본 분석
1131
  return {
1132
  "summary": f"'{title}'라는 AI 관련 뉴스가 나왔어요. AI 기술이 계속 발전하고 있다는 소식이에요.",
1133
  "significance": "AI는 우리 생활을 더 편리하게 만들어주는 기술이에요.",
 
1138
  }
1139
 
1140
  def analyze_model(self, model_name: str, task: str, downloads: int) -> str:
1141
+ """허깅페이스 모델 분석 - 모델 카드를 LLM으로 분석"""
1142
+
1143
+ # 1. 모델 카드 가져오기
1144
+ model_card = self.fetch_model_card(model_name)
1145
 
1146
+ # 2. LLM으로 분석
1147
+ if model_card and self.api_available:
1148
+ try:
1149
+ messages = [
1150
+ {
1151
+ "role": "system",
1152
+ "content": "당신은 초등학생도 이해할 수 있게 AI 모델을 쉽게 설명하는 전문가입니다. 한국어로 답변하세요."
1153
+ },
1154
+ {
1155
+ "role": "user",
1156
+ "content": f"""다음은 허깅페이스 모델 '{model_name}'의 모델 카드입니다:
1157
 
1158
+ {model_card}
 
 
1159
 
1160
+ 모델을 초등학생이 이해할 있도록 3-4문장으로 쉽게 설명해주세요. 다음 내용을 포함하세요:
1161
+ 1. 모델이 무엇을 하는지
1162
+ 2. 어떤 특징이 있는지
1163
+ 3. 누가 사용하면 좋은지
1164
 
1165
+ 답변은 반드시 3-4문장의 한국어로만 작성하세요."""
1166
+ }
1167
+ ]
1168
+
1169
+ result = self.call_llm(messages, max_tokens=500)
1170
+
1171
+ if result:
1172
+ return result.strip()
1173
+
1174
+ except Exception as e:
1175
+ print(f" ⚠️ 모델 분석 LLM 오류: {e}")
1176
 
1177
+ # 3. Fallback: 템플릿 기반 설명
1178
  task_explanations = {
1179
  "text-generation": "글을 자동으로 만들어주는",
1180
  "image-to-text": "사진을 보고 설명을 써주는",
 
1200
 
1201
  return f"이 모델은 {task_desc} AI예요. {popularity} 사람들이 다운로드해서 사용하고 있어요. {model_name.split('/')[-1]}라는 이름으로 유명해요!"
1202
 
1203
+ def analyze_space(self, space_name: str, space_id: str, description: str) -> Dict:
1204
+ """허깅페이스 스페이스 분석 - app.py를 LLM으로 분석"""
1205
 
1206
+ # 1. app.py 코드 가져오기
1207
+ app_code = self.fetch_space_code(space_id)
1208
+
1209
+ # 2. LLM으로 분석
1210
+ if app_code and self.api_available:
1211
+ try:
1212
+ messages = [
1213
+ {
1214
+ "role": "system",
1215
+ "content": "당신은 초등학생도 이해할 수 있게 AI 애플리케이션을 쉽게 설명하는 전문가입니다. 한국어로 답변하세요."
1216
+ },
1217
+ {
1218
+ "role": "user",
1219
+ "content": f"""다음은 허깅페이스 스페이스 '{space_name}'의 app.py 코드입니다:
1220
 
1221
+ {app_code}
 
 
 
 
1222
 
1223
+ 앱을 초등학생이 이해할 있도록 3-4문장으로 쉽게 설명해주세요. 다음 내용을 포함하세요:
1224
+ 1. 이 앱이 무엇을 하는지
1225
+ 2. 어떤 기술을 사용하는지
1226
+ 3. 어떻게 활용할 수 있는지
1227
 
1228
+ 답변은 반드시 3-4문장의 한국어로만 작성하세요."""
1229
+ }
1230
+ ]
1231
+
1232
+ result = self.call_llm(messages, max_tokens=500)
 
 
 
 
 
1233
 
1234
+ if result:
1235
+ # 기술 스택 추출 시도
1236
+ tech_stack = []
1237
+ if 'gradio' in app_code.lower():
1238
+ tech_stack.append('Gradio')
1239
+ if 'streamlit' in app_code.lower():
1240
+ tech_stack.append('Streamlit')
1241
+ if 'transformers' in app_code.lower():
1242
+ tech_stack.append('Transformers')
1243
+ if 'torch' in app_code.lower() or 'pytorch' in app_code.lower():
1244
+ tech_stack.append('PyTorch')
1245
+ if 'tensorflow' in app_code.lower():
1246
+ tech_stack.append('TensorFlow')
1247
+ if 'diffusers' in app_code.lower():
1248
+ tech_stack.append('Diffusers')
1249
+
1250
+ if not tech_stack:
1251
+ tech_stack = ['Python', 'AI']
1252
+
1253
+ return {
1254
+ "simple_explanation": result.strip(),
1255
+ "tech_stack": tech_stack
1256
+ }
1257
+
1258
+ except Exception as e:
1259
+ print(f" ⚠️ 스페이스 분석 LLM 오류: {e}")
1260
 
1261
+ # 3. Fallback: 템플릿 기반 설명
1262
  return {
1263
  "simple_explanation": f"{space_name}는 웹브라우저에서 바로 AI를 체험해볼 수 있는 곳이에요. 설치 없이도 사용할 수 있어서 편리해요! 마치 온라인 게임처럼 바로 접속해서 AI를 사용할 수 있답니다.",
1264
  "tech_stack": ["Python", "Gradio", "Transformers", "PyTorch"]
 
1270
  # ============================================
1271
 
1272
  class AdvancedAIAnalyzer:
1273
+ """LLM 기반 고급 AI 뉴스 분석기"""
1274
 
1275
  def __init__(self):
1276
+ self.llm_analyzer = LLMAnalyzer()
1277
  self.huggingface_data = {
1278
  "models": [],
1279
  "spaces": []
 
1287
  models_list = []
1288
 
1289
  try:
1290
+ # Hugging Face API 사용
1291
  api = HfApi()
1292
+
1293
+ # trending 순위로 모델 가져오기
1294
  models = list(api.list_models(
1295
+ sort="trending_score",
1296
  direction=-1,
1297
  limit=limit
1298
  ))
 
1310
  'rank': idx
1311
  }
1312
 
1313
+ # LLM 분석 추가 (모델 카드 분석)
1314
+ print(f" 🔍 {idx}. {model.id} 분석 중...")
1315
  model_info['analysis'] = self.llm_analyzer.analyze_model(
1316
  model_info['name'],
1317
  model_info['task'],
 
1320
 
1321
  models_list.append(model_info)
1322
 
1323
+ # API rate limit 방지를 위한 짧은 대기
1324
+ time.sleep(0.5)
1325
+
1326
+ # 진행상황 표시
1327
  if idx % 5 == 0:
1328
  print(f" ✓ {idx}개 모델 처리 완료...")
 
1329
 
1330
  except Exception as e:
1331
  print(f" ⚠️ 모델 {idx} 처리 오류: {e}")
 
1333
 
1334
  print(f"✅ {len(models_list)}개 트렌딩 모델 수집 완료")
1335
 
1336
+ # DB에 저장
1337
  if models_list:
1338
  save_models_to_db(models_list)
1339
 
 
1351
  spaces_list = []
1352
 
1353
  try:
1354
+ # Hugging Face API 사용
1355
  api = HfApi()
1356
+
1357
+ # trending 순위로 스페이스 가져오기
1358
  spaces = list(api.list_spaces(
1359
+ sort="trending_score",
1360
  direction=-1,
1361
  limit=limit
1362
  ))
 
1376
  'rank': idx
1377
  }
1378
 
1379
+ # LLM 분석 추가 (app.py 분석)
1380
+ print(f" 🔍 {idx}. {space.id} 분석 중...")
1381
  space_analysis = self.llm_analyzer.analyze_space(
1382
  space_info['name'],
1383
+ space_info['space_id'],
1384
  space_info['title']
1385
  )
1386
 
 
1390
 
1391
  spaces_list.append(space_info)
1392
 
1393
+ # API rate limit 방지를 위한 짧은 대기
1394
+ time.sleep(0.5)
1395
+
1396
+ # 진행상황 표시
1397
  if idx % 5 == 0:
1398
  print(f" ✓ {idx}개 스페이스 처리 완료...")
 
1399
 
1400
  except Exception as e:
1401
  print(f" ⚠️ 스페이스 {idx} 처리 오류: {e}")
 
1403
 
1404
  print(f"✅ {len(spaces_list)}개 트렌딩 스페이스 수집 완료")
1405
 
1406
+ # DB에 저장
1407
  if spaces_list:
1408
  save_spaces_to_db(spaces_list)
1409
 
 
1446
  news = self.create_sample_news()
1447
  analyzed_news = []
1448
 
1449
+ for article in news:
 
 
1450
  analysis = self.llm_analyzer.analyze_news_simple(
1451
  article['title'],
1452
  ""
 
1454
 
1455
  article['analysis'] = analysis
1456
  analyzed_news.append(article)
 
 
1457
 
1458
  print(f"✅ {len(analyzed_news)}개 뉴스 분석 완료")
1459
 
1460
+ # DB에 저장
1461
  save_news_to_db(analyzed_news)
1462
 
1463
  return analyzed_news
1464
 
1465
  def get_all_data(self, force_refresh: bool = False) -> Dict:
1466
+ """모든 데이터 수집 및 분석
1467
+
1468
+ Args:
1469
+ force_refresh: True면 새로 수집, False면 DB에서 로드 후 없으면 수집
1470
+ """
1471
  print("\n" + "="*60)
1472
+ print("🚀 AI 뉴스 & 허깅페이스 LLM 분석 시작")
1473
  print("="*60 + "\n")
1474
 
1475
  if force_refresh:
 
1480
  else:
1481
  print("💾 DB 우선 로드 모드")
1482
 
1483
+ # DB에서 먼저 로드
1484
  analyzed_news = load_news_from_db()
1485
  if not analyzed_news:
1486
  print("📰 DB에 뉴스 없음 → 새로 수집")
 
1502
  else:
1503
  print(f"✅ DB에서 {len(analyzed_spaces)}개 스페이스 로드")
1504
 
1505
+ # 통계
1506
  stats = {
1507
  'total_news': len(analyzed_news),
1508
  'hf_models': len(analyzed_models),
 
1532
  def index():
1533
  """메인 페이지"""
1534
  try:
1535
+ # refresh 파라미터 확인
1536
  force_refresh = request.args.get('refresh', 'false').lower() == 'true'
1537
 
1538
  analyzer = AdvancedAIAnalyzer()
 
1600
  def health():
1601
  """헬스 체크"""
1602
  try:
1603
+ # DB 연결 확인
1604
  conn = sqlite3.connect(DB_PATH)
1605
  cursor = conn.cursor()
1606
  cursor.execute("SELECT COUNT(*) FROM news")
 
1613
 
1614
  return jsonify({
1615
  "status": "healthy",
1616
+ "service": "AI News LLM Analyzer",
1617
  "version": "3.1.0",
 
1618
  "database": {
1619
  "connected": True,
1620
  "news_count": news_count,
1621
  "models_count": models_count,
1622
  "spaces_count": spaces_count
1623
  },
1624
+ "fireworks_api": {
1625
+ "configured": bool(os.environ.get('FIREWORKS_API_KEY'))
1626
+ },
1627
  "timestamp": datetime.now().isoformat()
1628
  })
1629
  except Exception as e:
 
1644
  ╔════════════════════════════════════════════════════════════╗
1645
  ║ ║
1646
  ║ 🤖 AI 뉴스 & 허깅페이스 LLM 분석 웹앱 v3.1 ║
 
1647
  ║ ║
1648
  ╚════════════════════════════════════════════════════════════╝
1649
 
1650
  ✨ 주요 기능:
 
1651
  • 💾 SQLite DB 영구 스토리지
1652
  • 📰 뉴스 초등학생 수준 분석
1653
+ • 🤗 허깅페이스 트렌딩 모델 TOP 30 (모델 카드 분석)
1654
+ • 🚀 허깅페이스 트렌딩 스페이스 TOP 30 (app.py 분석)
1655
+ • 🧠 Fireworks AI (Qwen3-235B) 실시간 LLM 분석
1656
  • 🎨 탭 UI (뉴스/모델/스페이스)
1657
 
1658
+ 🔑 API 설정:
1659
+ FIREWORKS_API_KEY: {"✅ 설정됨" if os.environ.get('FIREWORKS_API_KEY') else "❌ 미설정 (템플릿 모드)"}
1660
+
1661
  🚀 서버 정보:
1662
  📍 메인: http://localhost:{port}
1663
  🔄 강제갱신: http://localhost:{port}/?refresh=true
 
1666
  💚 Health: http://localhost:{port}/health
1667
 
1668
  💾 데이터베이스: {DB_PATH}
 
1669
 
1670
  초기화 중...
1671
  """)
1672
 
1673
+ # 데이터베이스 초기화
1674
  try:
1675
  init_database()
1676
  except Exception as e: