p763nx9tf / api_utils.py
ssboost's picture
Upload 11 files
1271db4 verified
"""
API κ΄€λ ¨ μœ ν‹Έλ¦¬ν‹° ν•¨μˆ˜ λͺ¨μŒ (ν™˜κ²½λ³€μˆ˜ 버전)
- API ν‚€ 관리 (ν™˜κ²½λ³€μˆ˜μ—μ„œ λ‘œλ“œ)
- μ‹œκ·Έλ‹ˆμ²˜ 생성
- API 헀더 생성
- Gemini API ν‚€ 랜덀 λ‘œν…Œμ΄μ…˜ μΆ”κ°€
"""
import os
import time
import hmac
import hashlib
import base64
import requests
import threading
import random
import google.generativeai as genai
import logging
logger = logging.getLogger(__name__)
# ν™˜κ²½λ³€μˆ˜μ—μ„œ API μ„€μ • λ‘œλ“œ
def get_api_configs():
# ν™˜κ²½λ³€μˆ˜ 'API_CONFIGS'μ—μ„œ 전체 섀정을 κ°€μ Έμ˜΄
api_configs_str = os.getenv('API_CONFIGS', '')
if not api_configs_str:
logger.error("API_CONFIGS ν™˜κ²½λ³€μˆ˜κ°€ μ„€μ •λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€.")
return [], [], [], []
try:
# ν™˜κ²½λ³€μˆ˜ 값을 exec둜 μ‹€ν–‰ν•˜μ—¬ μ„€μ • λ‘œλ“œ
local_vars = {}
exec(api_configs_str, {}, local_vars)
return (
local_vars.get('NAVER_API_CONFIGS', []),
local_vars.get('NAVER_SHOPPING_CONFIGS', []),
local_vars.get('NAVER_DATALAB_CONFIGS', []),
local_vars.get('GEMINI_API_CONFIGS', [])
)
except Exception as e:
logger.error(f"ν™˜κ²½λ³€μˆ˜ νŒŒμ‹± 였λ₯˜: {e}")
return [], [], [], []
# API μ„€μ • λ‘œλ“œ
NAVER_API_CONFIGS, NAVER_SHOPPING_CONFIGS, NAVER_DATALAB_CONFIGS, GEMINI_API_CONFIGS = get_api_configs()
# 순차 μ‚¬μš©μ„ μœ„ν•œ μΈλ±μŠ€μ™€ 락
current_api_index = 0
current_shopping_api_index = 0
current_datalab_api_index = 0
current_gemini_api_index = 0
api_lock = threading.Lock()
shopping_lock = threading.Lock()
datalab_lock = threading.Lock()
gemini_lock = threading.Lock()
# Gemini λͺ¨λΈ μΊμ‹œ
_gemini_models = {}
# API μ„€μ • μ΄ˆκΈ°ν™” ν•¨μˆ˜ μΆ”κ°€
def initialize_api_configs():
"""API 섀정을 μ΄ˆκΈ°ν™”ν•˜κ³  λžœλ€ν•˜κ²Œ μ •λ ¬"""
global NAVER_API_CONFIGS, NAVER_SHOPPING_CONFIGS, NAVER_DATALAB_CONFIGS, GEMINI_API_CONFIGS
# API 섀정을 λ‹€μ‹œ λ‘œλ“œ
NAVER_API_CONFIGS, NAVER_SHOPPING_CONFIGS, NAVER_DATALAB_CONFIGS, GEMINI_API_CONFIGS = get_api_configs()
# API 섀정을 λžœλ€ν•˜κ²Œ μ„žκΈ°
if NAVER_API_CONFIGS:
random.shuffle(NAVER_API_CONFIGS)
if NAVER_SHOPPING_CONFIGS:
random.shuffle(NAVER_SHOPPING_CONFIGS)
if NAVER_DATALAB_CONFIGS:
random.shuffle(NAVER_DATALAB_CONFIGS)
if GEMINI_API_CONFIGS:
random.shuffle(GEMINI_API_CONFIGS)
print(f"API μ„€μ • μ΄ˆκΈ°ν™” μ™„λ£Œ:")
print(f" - 검색광고 API: {len(NAVER_API_CONFIGS)}개")
print(f" - μ‡Όν•‘ API: {len(NAVER_SHOPPING_CONFIGS)}개")
print(f" - λ°μ΄ν„°λž© API: {len(NAVER_DATALAB_CONFIGS)}개")
print(f" - Gemini API: {len(GEMINI_API_CONFIGS)}개")
def generate_signature(timestamp, method, uri, secret_key):
"""μ‹œκ·Έλ‹ˆμ²˜ 생성 ν•¨μˆ˜"""
message = f"{timestamp}.{method}.{uri}"
digest = hmac.new(secret_key.encode("utf-8"), message.encode("utf-8"), hashlib.sha256).digest()
return base64.b64encode(digest).decode()
def get_header(method, uri, api_key, secret_key, customer_id):
"""API 헀더 생성 ν•¨μˆ˜"""
timestamp = str(round(time.time() * 1000))
signature = generate_signature(timestamp, method, uri, secret_key)
return {
"Content-Type": "application/json; charset=UTF-8",
"X-Timestamp": timestamp,
"X-API-KEY": api_key,
"X-Customer": str(customer_id),
"X-Signature": signature
}
def get_next_api_config():
"""순차적으둜 λ‹€μŒ API 섀정을 λ°˜ν™˜ (μŠ€λ ˆλ“œ μ•ˆμ „)"""
global current_api_index
if not NAVER_API_CONFIGS:
logger.error("넀이버 검색광고 API 섀정이 μ—†μŠ΅λ‹ˆλ‹€.")
return None
with api_lock:
config = NAVER_API_CONFIGS[current_api_index]
current_api_index = (current_api_index + 1) % len(NAVER_API_CONFIGS)
return config
def get_next_shopping_api_config():
"""순차적으둜 λ‹€μŒ μ‡Όν•‘ API 섀정을 λ°˜ν™˜ (였λ₯˜ ν‚€ κ±΄λ„ˆλ›°κΈ° μΆ”κ°€)"""
global current_shopping_api_index
if not NAVER_SHOPPING_CONFIGS:
logger.error("넀이버 μ‡Όν•‘ API 섀정이 μ—†μŠ΅λ‹ˆλ‹€.")
return None
with shopping_lock:
# μ΅œλŒ€ 전체 ν‚€ 수만큼 μ‹œλ„ (λ¬΄ν•œ 루프 λ°©μ§€)
for _ in range(len(NAVER_SHOPPING_CONFIGS)):
config = NAVER_SHOPPING_CONFIGS[current_shopping_api_index]
current_shopping_api_index = (current_shopping_api_index + 1) % len(NAVER_SHOPPING_CONFIGS)
# κΈ°λ³Έκ°’ 체크
if config["CLIENT_ID"] and not config["CLIENT_ID"].startswith("YOUR_"):
return config
# λͺ¨λ“  ν‚€κ°€ 기본값인 경우 첫 번째 ν‚€ λ°˜ν™˜
return NAVER_SHOPPING_CONFIGS[0] if NAVER_SHOPPING_CONFIGS else None
def get_next_datalab_api_config():
"""순차적으둜 λ‹€μŒ λ°μ΄ν„°λž© API 섀정을 λ°˜ν™˜ (μŠ€λ ˆλ“œ μ•ˆμ „)"""
global current_datalab_api_index
if not NAVER_DATALAB_CONFIGS:
logger.error("넀이버 λ°μ΄ν„°λž© API 섀정이 μ—†μŠ΅λ‹ˆλ‹€.")
return None
with datalab_lock:
# API ν‚€κ°€ μ„€μ •λ˜μ§€ μ•Šμ•˜μœΌλ©΄ None λ°˜ν™˜
if not NAVER_DATALAB_CONFIGS[0]["CLIENT_ID"] or NAVER_DATALAB_CONFIGS[0]["CLIENT_ID"].startswith("YOUR_"):
return None
config = NAVER_DATALAB_CONFIGS[current_datalab_api_index]
current_datalab_api_index = (current_datalab_api_index + 1) % len(NAVER_DATALAB_CONFIGS)
return config
def get_next_gemini_api_key():
"""순차적으둜 λ‹€μŒ Gemini API ν‚€λ₯Ό λ°˜ν™˜ (μŠ€λ ˆλ“œ μ•ˆμ „)"""
global current_gemini_api_index
if not GEMINI_API_CONFIGS:
logger.warning("μ‚¬μš© κ°€λŠ₯ν•œ Gemini API ν‚€κ°€ μ—†μŠ΅λ‹ˆλ‹€.")
return None
with gemini_lock:
# μ΅œλŒ€ 전체 ν‚€ 수만큼 μ‹œλ„ (λ¬΄ν•œ 루프 λ°©μ§€)
for _ in range(len(GEMINI_API_CONFIGS)):
api_key = GEMINI_API_CONFIGS[current_gemini_api_index]
current_gemini_api_index = (current_gemini_api_index + 1) % len(GEMINI_API_CONFIGS)
# 기본값이 μ•„λ‹Œ ν‚€λ§Œ λ°˜ν™˜
if api_key and not api_key.startswith("YOUR_") and api_key.strip():
return api_key
# λͺ¨λ“  ν‚€κ°€ 기본값인 경우 None λ°˜ν™˜
logger.warning("μ‚¬μš© κ°€λŠ₯ν•œ Gemini API ν‚€κ°€ μ—†μŠ΅λ‹ˆλ‹€.")
return None
def get_gemini_model():
"""μΊμ‹œλœ Gemini λͺ¨λΈμ„ λ°˜ν™˜ν•˜κ±°λ‚˜ μƒˆλ‘œ 생성"""
api_key = get_next_gemini_api_key()
if not api_key:
logger.error("Gemini API ν‚€λ₯Ό κ°€μ Έμ˜¬ 수 μ—†μŠ΅λ‹ˆλ‹€.")
return None
# μΊμ‹œμ—μ„œ λͺ¨λΈ 확인
if api_key in _gemini_models:
return _gemini_models[api_key]
try:
# μƒˆ λͺ¨λΈ 생성
genai.configure(api_key=api_key)
model = genai.GenerativeModel("gemini-2.0-flash-exp")
# μΊμ‹œμ— μ €μž₯
_gemini_models[api_key] = model
logger.info(f"Gemini λͺ¨λΈ 생성 성곡: {api_key[:8]}***{api_key[-4:]}")
return model
except Exception as e:
logger.error(f"Gemini λͺ¨λΈ 생성 μ‹€νŒ¨ ({api_key[:8]}***): {e}")
return None
def validate_api_config(api_config):
"""API μ„€μ • μœ νš¨μ„± 검사"""
if not api_config:
return False, "API 섀정이 μ—†μŠ΅λ‹ˆλ‹€."
API_KEY = api_config.get("API_KEY", "")
SECRET_KEY = api_config.get("SECRET_KEY", "")
CUSTOMER_ID_STR = api_config.get("CUSTOMER_ID", "")
if not all([API_KEY, SECRET_KEY, CUSTOMER_ID_STR]):
return False, "API ν‚€κ°€ μ„€μ •λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€."
if CUSTOMER_ID_STR.startswith("YOUR_") or API_KEY.startswith("YOUR_"):
return False, "API ν‚€κ°€ ν”Œλ ˆμ΄μŠ€ν™€λ”μž…λ‹ˆλ‹€."
try:
CUSTOMER_ID = int(CUSTOMER_ID_STR)
except ValueError:
return False, f"CUSTOMER_ID λ³€ν™˜ 였λ₯˜: '{CUSTOMER_ID_STR}'λŠ” μœ νš¨ν•œ μˆ«μžκ°€ μ•„λ‹™λ‹ˆλ‹€."
return True, "μœ νš¨ν•œ API μ„€μ •μž…λ‹ˆλ‹€."
def validate_datalab_config(datalab_config):
"""λ°μ΄ν„°λž© API μ„€μ • μœ νš¨μ„± 검사"""
if not datalab_config:
return False, "λ°μ΄ν„°λž© API 섀정이 μ—†μŠ΅λ‹ˆλ‹€."
CLIENT_ID = datalab_config.get("CLIENT_ID", "")
CLIENT_SECRET = datalab_config.get("CLIENT_SECRET", "")
if not all([CLIENT_ID, CLIENT_SECRET]):
return False, "λ°μ΄ν„°λž© API ν‚€κ°€ μ„€μ •λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€."
if CLIENT_ID.startswith("YOUR_") or CLIENT_SECRET.startswith("YOUR_"):
return False, "λ°μ΄ν„°λž© API ν‚€κ°€ ν”Œλ ˆμ΄μŠ€ν™€λ”μž…λ‹ˆλ‹€."
return True, "μœ νš¨ν•œ λ°μ΄ν„°λž© API μ„€μ •μž…λ‹ˆλ‹€."
def validate_gemini_config():
"""Gemini API μ„€μ • μœ νš¨μ„± 검사"""
valid_keys = 0
for api_key in GEMINI_API_CONFIGS:
if api_key and not api_key.startswith("YOUR_") and api_key.strip():
valid_keys += 1
if valid_keys == 0:
return False, "μ‚¬μš© κ°€λŠ₯ν•œ Gemini API ν‚€κ°€ μ—†μŠ΅λ‹ˆλ‹€."
return True, f"{valid_keys}개의 μœ νš¨ν•œ Gemini API ν‚€κ°€ μ„€μ •λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€."