fix: 2-phase model/space fetch — basic info immediate + LLM best-effort + sort fallback (resolves empty models/spaces issue)
Browse files
app.py
CHANGED
|
@@ -1369,37 +1369,63 @@ class LLMAnalyzer:
|
|
| 1369 |
print("⚠️ FIREWORKS_API_KEY 환경변수가 설정되지 않았습니다. 템플릿 모드로 동작합니다.")
|
| 1370 |
|
| 1371 |
def call_llm(self, messages: List[Dict], max_tokens: int = 2000) -> str:
|
| 1372 |
-
"""Fireworks AI API 호출"""
|
| 1373 |
if not self.api_available:
|
| 1374 |
return None
|
| 1375 |
-
|
| 1376 |
-
|
| 1377 |
-
|
| 1378 |
-
|
| 1379 |
-
|
| 1380 |
-
|
| 1381 |
-
|
| 1382 |
-
|
| 1383 |
-
|
| 1384 |
-
|
| 1385 |
-
|
| 1386 |
-
|
| 1387 |
-
|
| 1388 |
-
|
| 1389 |
-
|
| 1390 |
-
|
| 1391 |
-
|
| 1392 |
-
|
| 1393 |
-
|
| 1394 |
-
|
| 1395 |
-
|
| 1396 |
-
|
| 1397 |
-
|
| 1398 |
-
|
| 1399 |
-
|
| 1400 |
-
|
| 1401 |
-
|
| 1402 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1403 |
|
| 1404 |
def fetch_model_card(self, model_id: str) -> str:
|
| 1405 |
"""허깅페이스 모델 카드(README.md) 가져오기"""
|
|
@@ -1992,20 +2018,22 @@ class AdvancedAIAnalyzer:
|
|
| 1992 |
# ===== PHASE 1: HF API에서 기본 정보 즉시 수집 =====
|
| 1993 |
try:
|
| 1994 |
api = HfApi()
|
|
|
|
| 1995 |
try:
|
| 1996 |
models = list(api.list_models(
|
| 1997 |
sort="trending_score",
|
| 1998 |
-
direction=-1,
|
| 1999 |
limit=limit
|
| 2000 |
))
|
| 2001 |
except (TypeError, Exception) as e_sort:
|
| 2002 |
-
# trending_score 미지원 huggingface_hub 버전 fallback
|
| 2003 |
print(f" ⚠️ trending_score sort 미지원 ({e_sort}), downloads로 fallback")
|
| 2004 |
-
|
| 2005 |
-
|
| 2006 |
-
|
| 2007 |
-
|
| 2008 |
-
|
|
|
|
|
|
|
|
|
|
| 2009 |
|
| 2010 |
print(f"📊 API에서 {len(models)}개 모델 받음")
|
| 2011 |
|
|
@@ -2081,16 +2109,18 @@ class AdvancedAIAnalyzer:
|
|
| 2081 |
try:
|
| 2082 |
spaces = list(api.list_spaces(
|
| 2083 |
sort="trending_score",
|
| 2084 |
-
direction=-1,
|
| 2085 |
limit=limit
|
| 2086 |
))
|
| 2087 |
except (TypeError, Exception) as e_sort:
|
| 2088 |
print(f" ⚠️ trending_score sort 미지원 ({e_sort}), likes로 fallback")
|
| 2089 |
-
|
| 2090 |
-
|
| 2091 |
-
|
| 2092 |
-
|
| 2093 |
-
|
|
|
|
|
|
|
|
|
|
| 2094 |
|
| 2095 |
print(f"📊 API에서 {len(spaces)}개 스페이스 받음")
|
| 2096 |
|
|
|
|
| 1369 |
print("⚠️ FIREWORKS_API_KEY 환경변수가 설정되지 않았습니다. 템플릿 모드로 동작합니다.")
|
| 1370 |
|
| 1371 |
def call_llm(self, messages: List[Dict], max_tokens: int = 2000) -> str:
|
| 1372 |
+
"""Fireworks AI API 호출 — 다중 모델 fallback (404 등 모델 deprecate 대응)"""
|
| 1373 |
if not self.api_available:
|
| 1374 |
return None
|
| 1375 |
+
|
| 1376 |
+
# 모델 후보 — 첫 번째부터 시도, 404/실패 시 다음 모델로
|
| 1377 |
+
model_candidates = [
|
| 1378 |
+
"accounts/fireworks/models/qwen3-235b-a22b-instruct-2507",
|
| 1379 |
+
"accounts/fireworks/models/qwen3-235b-a22b",
|
| 1380 |
+
"accounts/fireworks/models/qwen3-30b-a3b-instruct-2507",
|
| 1381 |
+
"accounts/fireworks/models/qwen2p5-72b-instruct",
|
| 1382 |
+
"accounts/fireworks/models/llama-v3p3-70b-instruct",
|
| 1383 |
+
"accounts/fireworks/models/deepseek-v3-0324",
|
| 1384 |
+
]
|
| 1385 |
+
|
| 1386 |
+
headers = {
|
| 1387 |
+
"Accept": "application/json",
|
| 1388 |
+
"Content-Type": "application/json",
|
| 1389 |
+
"Authorization": f"Bearer {self.api_key}"
|
| 1390 |
+
}
|
| 1391 |
+
|
| 1392 |
+
last_err = None
|
| 1393 |
+
for model in model_candidates:
|
| 1394 |
+
try:
|
| 1395 |
+
payload = {
|
| 1396 |
+
"model": model,
|
| 1397 |
+
"max_tokens": max_tokens,
|
| 1398 |
+
"top_p": 1,
|
| 1399 |
+
"top_k": 40,
|
| 1400 |
+
"presence_penalty": 0,
|
| 1401 |
+
"frequency_penalty": 0,
|
| 1402 |
+
"temperature": 0.6,
|
| 1403 |
+
"messages": messages
|
| 1404 |
+
}
|
| 1405 |
+
|
| 1406 |
+
response = requests.post(self.api_url, headers=headers, json=payload, timeout=30)
|
| 1407 |
+
# 404 (모델 미존재/deprecate) → 다음 모델 시도
|
| 1408 |
+
if response.status_code == 404:
|
| 1409 |
+
last_err = f"404 {model}"
|
| 1410 |
+
continue
|
| 1411 |
+
response.raise_for_status()
|
| 1412 |
+
|
| 1413 |
+
result = response.json()
|
| 1414 |
+
return result['choices'][0]['message']['content']
|
| 1415 |
+
|
| 1416 |
+
except requests.exceptions.HTTPError as e:
|
| 1417 |
+
# 4xx 류는 다음 모델 시도
|
| 1418 |
+
if e.response is not None and e.response.status_code in (400, 404, 410):
|
| 1419 |
+
last_err = f"{e.response.status_code} {model}"
|
| 1420 |
+
continue
|
| 1421 |
+
last_err = str(e)
|
| 1422 |
+
break # 5xx/타임아웃 등은 즉시 종료
|
| 1423 |
+
except Exception as e:
|
| 1424 |
+
last_err = str(e)
|
| 1425 |
+
break
|
| 1426 |
+
|
| 1427 |
+
print(f" ⚠️ LLM API 호출 오류: 모든 모델 fallback 실패 (last: {last_err})")
|
| 1428 |
+
return None
|
| 1429 |
|
| 1430 |
def fetch_model_card(self, model_id: str) -> str:
|
| 1431 |
"""허깅페이스 모델 카드(README.md) 가져오기"""
|
|
|
|
| 2018 |
# ===== PHASE 1: HF API에서 기본 정보 즉시 수집 =====
|
| 2019 |
try:
|
| 2020 |
api = HfApi()
|
| 2021 |
+
# 새 huggingface_hub는 'direction' 키워드 미지원 → 제거
|
| 2022 |
try:
|
| 2023 |
models = list(api.list_models(
|
| 2024 |
sort="trending_score",
|
|
|
|
| 2025 |
limit=limit
|
| 2026 |
))
|
| 2027 |
except (TypeError, Exception) as e_sort:
|
|
|
|
| 2028 |
print(f" ⚠️ trending_score sort 미지원 ({e_sort}), downloads로 fallback")
|
| 2029 |
+
try:
|
| 2030 |
+
models = list(api.list_models(
|
| 2031 |
+
sort="downloads",
|
| 2032 |
+
limit=limit
|
| 2033 |
+
))
|
| 2034 |
+
except Exception as e2:
|
| 2035 |
+
print(f" ⚠️ downloads sort도 실패 ({e2}), 기본 list로 fallback")
|
| 2036 |
+
models = list(api.list_models(limit=limit))
|
| 2037 |
|
| 2038 |
print(f"📊 API에서 {len(models)}개 모델 받음")
|
| 2039 |
|
|
|
|
| 2109 |
try:
|
| 2110 |
spaces = list(api.list_spaces(
|
| 2111 |
sort="trending_score",
|
|
|
|
| 2112 |
limit=limit
|
| 2113 |
))
|
| 2114 |
except (TypeError, Exception) as e_sort:
|
| 2115 |
print(f" ⚠️ trending_score sort 미지원 ({e_sort}), likes로 fallback")
|
| 2116 |
+
try:
|
| 2117 |
+
spaces = list(api.list_spaces(
|
| 2118 |
+
sort="likes",
|
| 2119 |
+
limit=limit
|
| 2120 |
+
))
|
| 2121 |
+
except Exception as e2:
|
| 2122 |
+
print(f" ⚠️ likes sort도 실패 ({e2}), 기본 list로 fallback")
|
| 2123 |
+
spaces = list(api.list_spaces(limit=limit))
|
| 2124 |
|
| 2125 |
print(f"📊 API에서 {len(spaces)}개 스페이스 받음")
|
| 2126 |
|