ai_giga_tcg/app/services/external_api/base_external_service.py
2025-04-18 15:19:57 -04:00

95 lines
3.5 KiB
Python

from typing import Any, Dict, Optional, Union
import aiohttp
import logging
import json
import csv
import io
from app.services.service_manager import ServiceManager
from app.schemas.file import FileInDB
from sqlalchemy.orm import Session
logger = logging.getLogger(__name__)
class BaseExternalService:
def __init__(self, base_url: str, api_key: Optional[str] = None):
self.base_url = base_url
self.api_key = api_key
self.session = None
self.service_manager = ServiceManager()
self._services = {}
async def _get_session(self) -> aiohttp.ClientSession:
if self.session is None or self.session.closed:
self.session = aiohttp.ClientSession()
return self.session
async def _make_request(
self,
method: str,
endpoint: str,
params: Optional[Dict[str, Any]] = None,
headers: Optional[Dict[str, str]] = None,
data: Optional[Dict[str, Any]] = None,
content_type: str = "application/json",
binary: bool = False
) -> Union[Dict[str, Any], str, bytes]:
session = await self._get_session()
url = f"{self.base_url}{endpoint}"
if self.api_key:
headers = headers or {}
headers["Authorization"] = f"Bearer {self.api_key}"
try:
async with session.request(method, url, params=params, headers=headers, json=data) as response:
response.raise_for_status()
# Get the actual content type from the response
response_content_type = response.headers.get('content-type', '').lower()
logger.info(f"Making request to {url}")
if binary:
return await response.read()
# Get the raw response text first
raw_response = await response.text()
# Only try to parse as JSON if the content type indicates JSON
if 'application/json' in response_content_type or 'text/json' in response_content_type:
try:
# First try to parse the response directly
return await response.json()
except Exception as e:
try:
# If that fails, try parsing the raw text as JSON (in case it's double-encoded)
return json.loads(raw_response)
except Exception as e:
logger.error(f"Failed to parse JSON response: {e}")
return raw_response
return raw_response
except aiohttp.ClientError as e:
logger.error(f"Request failed: {e}")
raise
except Exception as e:
logger.error(f"Unexpected error during API request: {str(e)}")
raise
async def close(self):
"""Close the aiohttp session if it exists"""
if self.session and not self.session.closed:
await self.session.close()
self.session = None
logger.info(f"Closed session for {self.__class__.__name__}")
def get_service(self, name: str) -> Any:
"""Get a service by name with lazy loading"""
if name not in self._services:
self._services[name] = self.service_manager.get_service(name)
return self._services[name]
@property
def file_service(self):
"""Convenience property for file service"""
return self.get_service('file')