pycache 추가
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,167 +0,0 @@
|
||||
import json
|
||||
import os
|
||||
import secrets
|
||||
import time
|
||||
|
||||
from utils.redis_utils import get_redis_client
|
||||
|
||||
# Redis에 API 키를 저장할 때 사용할 접두사
|
||||
API_KEY_PREFIX = "api_key:"
|
||||
# Docker 컨테이너의 /workspace 디렉토리에 파일을 저장하도록 절대 경로 사용
|
||||
API_KEYS_FILE = "/workspace/api_keys.json"
|
||||
|
||||
|
||||
def _read_keys_from_file():
|
||||
"""Helper function to read all keys from the JSON file."""
|
||||
if not os.path.exists(API_KEYS_FILE):
|
||||
return {}
|
||||
with open(API_KEYS_FILE, "r") as f:
|
||||
try:
|
||||
return json.load(f)
|
||||
except json.JSONDecodeError:
|
||||
return {}
|
||||
|
||||
|
||||
def _write_keys_to_file(keys):
|
||||
"""Helper function to write all keys to the JSON file."""
|
||||
with open(API_KEYS_FILE, "w") as f:
|
||||
json.dump(keys, f, indent=4)
|
||||
|
||||
|
||||
import redis
|
||||
|
||||
|
||||
def load_api_keys_from_file():
|
||||
"""
|
||||
JSON 파일에서 API 키를 읽어 Redis에 로드합니다.
|
||||
Redis 연결 실패 시 몇 초간 재시도하여 시작 시점의 문제를 해결합니다.
|
||||
"""
|
||||
keys_from_file = _read_keys_from_file()
|
||||
if not keys_from_file:
|
||||
print("API key file not found or empty. Skipping loading.")
|
||||
return
|
||||
|
||||
redis_client = get_redis_client()
|
||||
max_retries = 5
|
||||
retry_delay = 2 # 초
|
||||
|
||||
for i in range(max_retries):
|
||||
try:
|
||||
# Redis 연결 테스트
|
||||
redis_client.ping()
|
||||
|
||||
# 연결 성공 시 키 로드
|
||||
for key_name, key_data in keys_from_file.items():
|
||||
if not redis_client.exists(key_name):
|
||||
redis_client.hset(key_name, mapping=key_data)
|
||||
print(f"Loaded API key from file: {key_name}")
|
||||
|
||||
print("Successfully loaded all keys into Redis.")
|
||||
return # 성공 시 함수 종료
|
||||
|
||||
except redis.exceptions.ConnectionError as e:
|
||||
print(f"Could not connect to Redis (attempt {i+1}/{max_retries}): {e}")
|
||||
if i < max_retries - 1:
|
||||
print(f"Retrying in {retry_delay} seconds...")
|
||||
time.sleep(retry_delay)
|
||||
else:
|
||||
print("Failed to load API keys into Redis after multiple retries.")
|
||||
break
|
||||
|
||||
|
||||
def generate_api_key(prefix="sk") -> str:
|
||||
"""안전한 API 키를 생성합니다. (예: sk-xxxxxxxx)"""
|
||||
return f"{prefix}-{secrets.token_hex(16)}"
|
||||
|
||||
|
||||
def create_api_key(client_name: str, key_prefix="sk") -> dict:
|
||||
"""
|
||||
새로운 API 키를 생성하고 Redis와 파일에 저장합니다.
|
||||
"""
|
||||
api_key = generate_api_key(prefix=key_prefix)
|
||||
redis_client = get_redis_client()
|
||||
|
||||
key_storage_name = f"{API_KEY_PREFIX}{api_key}"
|
||||
key_data = {
|
||||
"client_name": client_name,
|
||||
"created_at": str(int(time.time())),
|
||||
"is_active": "true",
|
||||
}
|
||||
|
||||
# Redis에 저장 (hset 사용)
|
||||
redis_client.hset(key_storage_name, mapping=key_data)
|
||||
|
||||
# 파일에 즉시 저장
|
||||
all_keys = _read_keys_from_file()
|
||||
all_keys[key_storage_name] = key_data
|
||||
_write_keys_to_file(all_keys)
|
||||
|
||||
return {"api_key": api_key, **key_data}
|
||||
|
||||
|
||||
def validate_api_key(api_key: str) -> bool:
|
||||
"""
|
||||
제공된 API 키가 유효한지 검증합니다. decode_responses=True로 인해 모든 값은 문자열입니다.
|
||||
1. Redis에서 먼저 확인합니다.
|
||||
2. Redis에 없으면 api_keys.json 파일에서 확인합니다.
|
||||
3. 파일에서 유효한 키를 찾으면 Redis에 다시 동기화합니다.
|
||||
"""
|
||||
if not api_key:
|
||||
return False
|
||||
|
||||
redis_client = get_redis_client()
|
||||
key_storage_name = f"{API_KEY_PREFIX}{api_key}"
|
||||
|
||||
# 1. Redis에서 확인 (decode_responses=True이므로 반환값은 문자열)
|
||||
is_active_in_redis = redis_client.hget(key_storage_name, "is_active")
|
||||
if is_active_in_redis == "true":
|
||||
return True
|
||||
|
||||
# 2. Redis에 없으면 파일에서 확인
|
||||
all_keys_from_file = _read_keys_from_file()
|
||||
key_data_from_file = all_keys_from_file.get(key_storage_name)
|
||||
|
||||
if key_data_from_file and key_data_from_file.get("is_active") == "true":
|
||||
# 3. 파일에 유효한 키가 있으면 Redis에 다시 기록 (Self-healing, hset 사용)
|
||||
redis_client.hset(key_storage_name, mapping=key_data_from_file)
|
||||
print(f"Key '{key_storage_name}' not found in Redis, but restored from file.")
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def revoke_api_key(api_key: str) -> bool:
|
||||
"""
|
||||
API 키를 Redis와 파일에서 삭제하여 폐기합니다.
|
||||
"""
|
||||
redis_client = get_redis_client()
|
||||
key_storage_name = f"{API_KEY_PREFIX}{api_key}"
|
||||
|
||||
# Redis에서 삭제
|
||||
result = redis_client.delete(key_storage_name)
|
||||
|
||||
if result > 0:
|
||||
# 파일에서도 삭제
|
||||
all_keys = _read_keys_from_file()
|
||||
if key_storage_name in all_keys:
|
||||
del all_keys[key_storage_name]
|
||||
_write_keys_to_file(all_keys)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def list_api_keys() -> list:
|
||||
"""
|
||||
저장된 모든 API 키의 목록을 반환합니다.
|
||||
(주의: 실제 환경에서는 키 자체를 노출하지 않는 것이 좋습니다)
|
||||
"""
|
||||
redis_client = get_redis_client()
|
||||
keys = []
|
||||
|
||||
# decode_responses=True이므로 모든 키와 값은 문자열.
|
||||
for key_name in redis_client.scan_iter(f"{API_KEY_PREFIX}*"):
|
||||
key_data = redis_client.hgetall(key_name)
|
||||
key_data["api_key"] = key_name.replace(API_KEY_PREFIX, "", 1)
|
||||
keys.append(key_data)
|
||||
|
||||
return keys
|
||||
@@ -1,22 +0,0 @@
|
||||
import os
|
||||
import google.generativeai as genai
|
||||
from dotenv import load_dotenv
|
||||
from typing import List
|
||||
|
||||
load_dotenv()
|
||||
|
||||
class GeminiService:
|
||||
def __init__(self):
|
||||
self.api_key = os.getenv("GEMINI_API_KEY")
|
||||
if not self.api_key:
|
||||
raise ValueError("GEMINI_API_KEY not found in .env file")
|
||||
genai.configure(api_key=self.api_key)
|
||||
|
||||
async def generate_content(self, prompts: List[str], model: str = "gemini-2.5-flash"):
|
||||
"""
|
||||
Generates content using the Gemini API.
|
||||
"""
|
||||
model_instance = genai.GenerativeModel(model)
|
||||
response = await model_instance.generate_content_async(prompts)
|
||||
return response.text
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import httpx
|
||||
|
||||
OLLAMA_API_URL = "http://172.16.10.176:11534/api/generate"
|
||||
|
||||
|
||||
class OllamaService:
|
||||
async def generate_content(self, prompt: str, model: str = "gemma:latest"):
|
||||
"""Ollama API를 호출하여 콘텐츠를 생성합니다."""
|
||||
async with httpx.AsyncClient(timeout=120.0) as client:
|
||||
try:
|
||||
payload = {
|
||||
"model": model,
|
||||
"prompt": prompt,
|
||||
"stream": False,
|
||||
"keep_alive": "30m",
|
||||
}
|
||||
response = await client.post(OLLAMA_API_URL, json=payload)
|
||||
response.raise_for_status()
|
||||
|
||||
response_json = response.json()
|
||||
return response_json.get("response", "")
|
||||
except httpx.RequestError as e:
|
||||
print(f"Ollama API 요청 중 오류 발생: {e}")
|
||||
return f"Error: {e}"
|
||||
except Exception as e:
|
||||
print(f"Ollama 서비스에서 예기치 않은 오류 발생: {e}")
|
||||
return f"An unexpected error occurred: {e}"
|
||||
Reference in New Issue
Block a user