|
""" |
|
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__) |
|
|
|
|
|
def get_api_configs(): |
|
|
|
api_configs_str = os.getenv('API_CONFIGS', '') |
|
|
|
if not api_configs_str: |
|
logger.error("API_CONFIGS νκ²½λ³μκ° μ€μ λμ§ μμμ΅λλ€.") |
|
return [], [], [], [] |
|
|
|
try: |
|
|
|
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 [], [], [], [] |
|
|
|
|
|
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_models = {} |
|
|
|
|
|
def initialize_api_configs(): |
|
"""API μ€μ μ μ΄κΈ°ννκ³ λλ€νκ² μ λ ¬""" |
|
global NAVER_API_CONFIGS, NAVER_SHOPPING_CONFIGS, NAVER_DATALAB_CONFIGS, GEMINI_API_CONFIGS |
|
|
|
|
|
NAVER_API_CONFIGS, NAVER_SHOPPING_CONFIGS, NAVER_DATALAB_CONFIGS, GEMINI_API_CONFIGS = get_api_configs() |
|
|
|
|
|
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: |
|
|
|
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 |
|
|
|
|
|
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 ν€κ° μ€μ λμ΄ μμ΅λλ€." |