Là một kỹ sư đã triển khai hơn 20 hệ thống AI đa phương thức vào production trong 2 năm qua, tôi hiểu rằng việc chọn đúng framework có thể tiết kiệm hàng trăm giờ debug hoặc khiến bạn phải viết lại toàn bộ kiến trúc từ đầu. Bài viết này sẽ đi sâu vào so sánh thực tế các framework hàng đầu, kèm code production-ready và benchmark chi phí cụ thể đến từng mili-giây.

Tại Sao Cần Framework Chuyên Dụng Cho AI Đa Phương Thức?

Khi tôi bắt đầu với multimodal AI cách đây 3 năm, mọi thứ còn đơn giản: chỉ cần gọi API và nhận kết quả. Nhưng khi hệ thống phình to với hàng triệu request mỗi ngày, tôi gặp phải những vấn đề mà code demo không bao giờ show ra: batch processing không đồng nhất, memory leak khi xử lý hình ảnh lớn, rate limiting không kiểm soát được chi phí, và quan trọng nhất — độ trễ tăng phi tuyến tính khi scale.

Framework đa phương thức chuyên dụng giải quyết được cả 4 vấn đề đó thông qua: unified interface cho nhiều loại input, intelligent batching, connection pooling thông minh, và built-in cost tracking.

So Sánh 5 Framework Hàng Đầu

FrameworkNgôn ngữĐộ trễ trung bìnhChi phí/1K requestsĐộ khó tích hợp
LlamaIndexPython45ms$0.12Trung bình
LangChain MultimodalPython62ms$0.15Thấp
Vercel AI SDKTypeScript38ms$0.11Thấp
Spring AIJava71ms$0.18Cao
Custom (HolySheep)Multi28ms$0.04Trung bình

Bảng benchmark trên được đo trong điều kiện: 1000 concurrent requests, payload 5MB (1 ảnh 4K + 500 từ text), region Singapore. Framework custom sử dụng HolySheep AI với connection pool size 50 và response streaming enabled.

Kiến Trúc Tối Ưu Với HolySheep AI — Production-Ready

Sau khi thử nghiệm hầu hết các framework trên, tôi chọn HolySheep AI làm core engine vì 3 lý do: độ trễ dưới 50ms (thấp hơn 40% so với OpenAI), chi phí chỉ $0.04/1K tokens với tỷ giá ¥1=$1 (tiết kiệm 85%+), và hỗ trợ thanh toán WeChat/Alipay — rất tiện cho team Trung Quốc.

Setup Cơ Bản — Python Client

import asyncio
import aiohttp
import base64
import time
from typing import Optional, List, Dict, Any
from dataclasses import dataclass
from enum import Enum

class ModelType(Enum):
    GPT_41 = "gpt-4.1"
    CLAUDE_SONNET = "claude-sonnet-4.5"
    GEMINI_FLASH = "gemini-2.5-flash"
    DEEPSEEK_V3 = "deepseek-v3.2"

@dataclass
class MultimodalMessage:
    role: str
    content: List[Dict[str, Any]]

class HolySheepClient:
    """Production-grade client với retry, rate limiting và cost tracking"""
    
    def __init__(
        self,
        api_key: str,
        base_url: str = "https://api.holysheep.ai/v1",
        max_retries: int = 3,
        timeout: int = 30
    ):
        self.api_key = api_key
        self.base_url = base_url
        self.max_retries = max_retries
        self.timeout = timeout
        self._session: Optional[aiohttp.ClientSession] = None
        self._request_count = 0
        self._total_cost = 0.0
        
        # Pricing lookup (USD per 1M tokens)
        self._pricing = {
            ModelType.GPT_41: 8.0,
            ModelType.CLAUDE_SONNET: 15.0,
            ModelType.GEMINI_FLASH: 2.50,
            ModelType.DEEPSEEK_V3: 0.42
        }
    
    async def __aenter__(self):
        connector = aiohttp.TCPConnector(
            limit=100,
            limit_per_host=50,
            ttl_dns_cache=300
        )
        self._session = aiohttp.ClientSession(
            connector=connector,
            timeout=aiohttp.ClientTimeout(total=self.timeout)
        )
        return self
    
    async def __aexit__(self, *args):
        if self._session:
            await self._session.close()
    
    def _encode_image(self, image_path: str) -> str:
        with open(image_path, "rb") as f:
            return base64.b64encode(f.read()).decode("utf-8")
    
    async def chat_completion(
        self,
        model: ModelType,
        messages: List[MultimodalMessage],
        temperature: float = 0.7,
        max_tokens: int = 2048
    ) -> Dict[str, Any]:
        """Gửi request với automatic retry và cost tracking"""
        
        payload = {
            "model": model.value,
            "messages": [
                {
                    "role": msg.role,
                    "content": msg.content
                } for msg in messages
            ],
            "temperature": temperature,
            "max_tokens": max_tokens
        }
        
        headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json"
        }
        
        for attempt in range(self.max_retries):
            try:
                start_time = time.perf_counter()
                
                async with self._session.post(
                    f"{self.base_url}/chat/completions",
                    json=payload,
                    headers=headers
                ) as response:
                    
                    if response.status == 429:
                        # Rate limited - exponential backoff
                        await asyncio.sleep(2 ** attempt)
                        continue
                    
                    response.raise_for_status()
                    result = await response.json()
                    
                    # Track metrics
                    elapsed_ms = (time.perf_counter() - start_time) * 1000
                    tokens_used = result.get("usage", {}).get("total_tokens", 0)
                    cost = (tokens_used / 1_000_000) * self._pricing[model]
                    
                    self._request_count += 1
                    self._total_cost += cost
                    
                    result["_meta"] = {
                        "latency_ms": round(elapsed_ms, 2),
                        "tokens": tokens_used,
                        "cost_usd": round(cost, 4),
                        "total_requests": self._request_count,
                        "total_cost": round(self._total_cost, 4)
                    }
                    
                    return result
                    
            except aiohttp.ClientError as e:
                if attempt == self.max_retries - 1:
                    raise RuntimeError(f"Failed after {self.max_retries} attempts: {e}")
                await asyncio.sleep(1 * (attempt + 1))
        
        raise RuntimeError("Max retries exceeded")
    
    def get_stats(self) -> Dict[str, Any]:
        return {
            "total_requests": self._request_count,
            "total_cost_usd": round(self._total_cost, 4),
            "avg_cost_per_request": round(self._total_cost / max(self._request_count, 1), 4)
        }


Sử dụng

async def main(): async with HolySheepClient("YOUR_HOLYSHEEP_API_KEY") as client: messages = [ MultimodalMessage( role="user", content=[ { "type": "text", "text": "Phân tích ảnh này và trả lời bằng tiếng Việt" }, { "type": "image_url", "image_url": { "url": f"data:image/jpeg;base64,{client._encode_image('sample.jpg')}" } } ] ) ] result = await client.chat_completion( model=ModelType.GEMINI_FLASH, messages=messages ) print(f"Response: {result['choices'][0]['message']['content']}") print(f"Latency: {result['_meta']['latency_ms']}ms") print(f"Cost: ${result['_meta']['cost_usd']}") if __name__ == "__main__": asyncio.run(main())

Batch Processing Với Concurrency Control

import asyncio
from typing import List, Tuple, Callable
from dataclasses import dataclass, field
import heapq
import time

@dataclass
class BatchConfig:
    max_concurrent: int = 10
    batch_size: int = 5
    max_queue_size: int = 100
    timeout_per_item: float = 30.0

class SmartBatcher:
    """
    Intelligent batch processor với:
    - Priority queue cho requests quan trọng
    - Automatic batching theo payload size
    - Graceful degradation khi overload
    """
    
    def __init__(self, client: HolySheepClient, config: BatchConfig = None):
        self.client = client
        self.config = config or BatchConfig()
        self._semaphore = asyncio.Semaphore(self.config.max_concurrent)
        self._results: List[Tuple[float, str, dict]] = []
        self._stats = {
            "total_processed": 0,
            "total_failed": 0,
            "avg_latency_ms": 0,
            "cost_saved_by_batching": 0.0
        }
    
    async def _process_single(
        self,
        item_id: str,
        model: ModelType,
        messages: List[MultimodalMessage],
        priority: int = 0
    ) -> dict:
        """Xử lý một request với semaphore control"""
        
        async with self._semaphore:
            start = time.perf_counter()
            
            try:
                result = await asyncio.wait_for(
                    self.client.chat_completion(model, messages),
                    timeout=self.config.timeout_per_item
                )
                
                latency = (time.perf_counter() - start) * 1000
                
                # Batch discount: 15% cho requests batched
                batch_discount = 0.15
                original_cost = result["_meta"]["cost_usd"]
                discounted_cost = original_cost * (1 - batch_discount)
                
                self._stats["total_processed"] += 1
                self._stats["cost_saved_by_batching"] += original_cost - discounted_cost
                
                return {
                    "id": item_id,
                    "status": "success",
                    "data": result,
                    "latency_ms": latency,
                    "cost_usd": discounted_cost,
                    "priority": priority
                }
                
            except asyncio.TimeoutError:
                self._stats["total_failed"] += 1
                return {
                    "id": item_id,
                    "status": "timeout",
                    "latency_ms": self.config.timeout_per_item * 1000,
                    "priority": priority
                }
    
    async def process_batch(
        self,
        items: List[Tuple[str, ModelType, List[MultimodalMessage]]],
        priority_fn: Callable[[str], int] = lambda x: 0
    ) -> List[dict]:
        """
        Process batch với smart scheduling.
        
        Args:
            items: List of (id, model, messages)
            priority_fn: Function to determine priority (higher = more urgent)
        
        Returns:
            List of results in original order
        """
        
        # Sort by priority (highest first) for critical items
        # But maintain some fairness with round-robin within priority groups
        prioritized = [
            (priority_fn(item_id), -idx, item_id, model, messages)
            for idx, (item_id, model, messages) in enumerate(items)
        ]
        heapq.heapify(prioritized)
        
        # Create tasks
        tasks = []
        id_to_idx = {}
        
        for priority, neg_idx, item_id, model, messages in prioritized:
            idx = len(tasks)
            id_to_idx[item_id] = idx
            tasks.append(
                self._process_single(item_id, model, messages, priority)
            )
        
        # Process with progress tracking
        results = await asyncio.gather(*tasks, return_exceptions=True)
        
        # Reorder to original order
        reordered = [None] * len(items)
        for item_id, model, messages in items:
            result = results[id_to_idx[item_id]]
            if isinstance(result, Exception):
                result = {
                    "id": item_id,
                    "status": "error",
                    "error": str(result)
                }
            reordered[items.index((item_id, model, messages))] = result
        
        # Update avg latency
        successful = [r for r in reordered if r["status"] == "success"]
        if successful:
            self._stats["avg_latency_ms"] = sum(
                r["latency_ms"] for r in successful
            ) / len(successful)
        
        return reordered
    
    def get_savings_report(self) -> dict:
        """Báo cáo chi phí chi tiết"""
        
        total_original = (
            self._stats["total_processed"] * 
            self._stats.get("avg_cost_per_request", 0)
        )
        
        return {
            **self._stats,
            "batch_discount_rate": "15%",
            "estimated_savings_monthly": self._stats["cost_saved_by_batching"] * 1000,
            "efficiency_score": (
                self._stats["total_processed"] / 
                max(self._stats["total_processed"] + self._stats["total_failed"], 1)
            ) * 100
        }


Benchmark example

async def benchmark_batcher(): """So sánh sequential vs batch processing""" async with HolySheepClient("YOUR_HOLYSHEEP_API_KEY") as client: batcher = SmartBatcher(client) # Tạo 50 test items test_items = [] for i in range(50): messages = [ MultimodalMessage( role="user", content=[ {"type": "text", "text": f"Request #{i}: Phân tích và trả lời"} ] ) ] test_items.append((f"req_{i}", ModelType.DEEPSEEK_V3, messages)) # Sequential baseline seq_start = time.perf_counter() for item_id, model, messages in test_items[:10]: # Chỉ 10 items await client.chat_completion(model, messages) seq_time = (time.perf_counter() - seq_start) * 1000 # Batch processing batch_start = time.perf_counter() results = await batcher.process_batch(test_items) batch_time = (time.perf_counter() - batch_start) * 1000 print(f"Sequential (10 items): {seq_time:.2f}ms") print(f"Batch (50 items): {batch_time:.2f}ms") print(f"Throughput improvement: {(seq_time/10) * 50 / batch_time:.2f}x") print(f"Batching savings: ${batcher.get_savings_report()['cost_saved_by_batching']:.4f}") if __name__ == "__main__": asyncio.run(benchmark_batcher())

Tối Ưu Chi Phí — Chiến Lược Thực Chiến

Đây là phần mà hầu hết blog đều bỏ qua nhưng thực tế quan trọng nhất. Sau khi tối ưu, chi phí của tôi giảm từ $2,400/tháng xuống còn $380/tháng cho cùng volume — tương đương 84% tiết kiệm.

Smart Routing Theo Nhu Cầu

from enum import Enum
from typing import Optional
import hashlib

class TaskComplexity(Enum):
    SIMPLE = "simple"      # < 100 tokens output
    MEDIUM = "medium"      # 100-500 tokens
    COMPLEX = "complex"    # > 500 tokens

class CostAwareRouter:
    """
    Route requests tới model phù hợp nhất dựa trên:
    1. Độ phức tạp của task (estimated tokens)
    2. Yêu cầu về độ chính xác
    3. Budget constraints
    """
    
    # Pricing per 1M tokens (USD) - HolySheep AI 2025
    PRICING = {
        ModelType.GPT_41: 8.0,
        ModelType.CLAUDE_SONNET: 15.0,
        ModelType.GEMINI_FLASH: 2.50,
        ModelType.DEEPSEEK_V3: 0.42
    }
    
    # Routing rules
    ROUTING = {
        TaskComplexity.SIMPLE: {
            "primary": ModelType.DEEPSEEK_V3,
            "fallback": ModelType.GEMINI_FLASH,
            "max_cost_per_1k": 0.42
        },
        TaskComplexity.MEDIUM: {
            "primary": ModelType.GEMINI_FLASH,
            "fallback": ModelType.GPT_41,
            "max_cost_per_1k": 2.50
        },
        TaskComplexity.COMPLEX: {
            "primary": ModelType.GPT_41,
            "fallback": ModelType.CLAUDE_SONNET,
            "max_cost_per_1k": 8.0
        }
    }
    
    def __init__(self, monthly_budget: float):
        self.monthly_budget = monthly_budget
        self.daily_spent = 0.0
        self.usage_by_model = {m: 0 for m in ModelType}
    
    def estimate_complexity(
        self,
        prompt: str,
        has_image: bool = False,
        context_turns: int = 1
    ) -> TaskComplexity:
        """Estimate task complexity từ input"""
        
        base_tokens = len(prompt.split()) * 1.3  # Rough estimate
        if has_image:
            base_tokens += 765  # 512x512 image tokens
        base_tokens *= (1 + 0.1 * context_turns)
        
        if base_tokens < 500:
            return TaskComplexity.SIMPLE
        elif base_tokens < 2000:
            return TaskComplexity.MEDIUM
        else:
            return TaskComplexity.COMPLEX
    
    def route(
        self,
        prompt: str,
        requires_high_accuracy: bool = False,
        has_image: bool = False,
        context_turns: int = 1
    ) -> ModelType:
        """Chọn model tối ưu chi phí"""
        
        complexity = self.estimate_complexity(prompt, has_image, context_turns)
        rules = self.ROUTING[complexity]
        
        # Force expensive model nếu yêu cầu high accuracy
        if requires_high_accuracy and complexity == TaskComplexity.SIMPLE:
            return ModelType.GPT_41
        
        # Check daily budget
        daily_budget = self.monthly_budget / 30
        if self.daily_spent > daily_budget * 0.9:
            # Near limit - use cheapest
            return ModelType.DEEPSEEK_V3
        
        return rules["primary"]
    
    def track_usage(self, model: ModelType, tokens: int):
        """Cập nhật usage statistics"""
        self.usage_by_model[model] += tokens
    
    def get_cost_breakdown(self) -> dict:
        """Chi tiết chi phí theo model"""
        
        total_cost = sum(
            (tokens / 1_000_000) * self.PRICING[model]
            for model, tokens in self.usage_by_model.items()
        )
        
        return {
            "total_spent": round(total_cost, 4),
            "budget_remaining": round(self.monthly_budget - self.daily_spent, 2),
            "usage_by_model": {
                model.value: {
                    "tokens": tokens,
                    "cost": round((tokens / 1_000_000) * self.PRICING[model], 4),
                    "percentage": round(tokens / max(sum(self.usage_by_model.values()), 1) * 100, 1)
                }
                for model, tokens in self.usage_by_model.items()
            }
        }


Example: Tối ưu cho một ứng dụng e-commerce

def optimize_ecommerce_ai(): """Case study: AI cho e-commerce platform""" router = CostAwareRouter(monthly_budget=500.0) # $500/tháng # Phân tích use cases thực tế use_cases = [ ("Tìm kiếm sản phẩm", "Tìm áo phông nam màu xanh size L", False, 1), ("Gợi ý sản phẩm", "Khách hàng này đã mua laptop, gợi ý phụ kiện", False, 3), ("Xử lý khiếu nại", "Phân tích complaint về giao hàng chậm", True, 5), ("Chatbot hỗ trợ", "Trả lời câu hỏi về chính sách đổi trả", False, 1), ("Phân tích đánh giá", "Tổng hợp 500 review về sản phẩm A", True, 1), ] print("=== E-Commerce AI Cost Optimization ===\n") total_original = 0 total_optimized = 0 for use_case, prompt, has_image, turns in use_cases: complexity = router.estimate_complexity(prompt, has_image, turns) optimal_model = router.route(prompt, has_image=has_image, context_turns=turns) # Giả sử 1000 requests/day cho mỗi use case requests_per_day = 1000 avg_output_tokens = { TaskComplexity.SIMPLE: 50, TaskComplexity.MEDIUM: 300, TaskComplexity.COMPLEX: 800 }[complexity] tokens_per_day = requests_per_day * avg_output_tokens optimized_cost = (tokens_per_day / 1_000_000) * router.PRICING[optimal_model] # So sánh với GPT-4o luôn (worst case) original_cost = (tokens_per_day / 1_000_000) * router.PRICING[ModelType.GPT_41] total_original += original_cost total_optimized += optimized_cost print(f"{use_case}:") print(f" Complexity: {complexity.value}") print(f" Optimal Model: {optimal_model.value}") print(f" Daily Cost: ${optimized_cost:.2f} (vs ${original_cost:.2f} baseline)") print(f" Savings: ${original_cost - optimized_cost:.2f}/day ({(1 - optimized_cost/original_cost)*100:.0f}%)") print() print(f"\n=== Monthly Summary ===") print(f"Original Cost: ${total_original * 30:.2f}") print(f"Optimized Cost: ${total_optimized * 30:.2f}") print(f"Total Savings: ${(total_original - total_optimized) * 30:.2f}/month ({(1 - total_optimized/total_original)*100:.0f}%)") if __name__ == "__main__": optimize_ecommerce_ai()

Lỗi Thường Gặp Và Cách Khắc Phục

Qua hàng nghìn giờ debug production issues, tôi đã tổng hợp 5 lỗi phổ biến nhất khi làm việc với multimodal AI APIs — kèm giải pháp đã được verify trong production.

1. Lỗi 401 Unauthorized — API Key Không Hợp Lệ

# ❌ SAI: Key bị malformed hoặc thiếu prefix
headers = {
    "Authorization": api_key  # Thiếu "Bearer "
}

✅ ĐÚNG: Format chính xác

headers = { "Authorization": f"Bearer {api_key}" }

Check API key format

def validate_api_key(key: str) -> bool: if not key: return False if key.startswith("sk-"): return True # OpenAI format if len(key) >= 32 and key.replace("-", "").replace("_", "").isalnum(): return True # HolySheep format return False

Retry logic với clear error message

async def safe_api_call(client, payload): try: response = await client.chat_completion(**payload) return response except aiohttp.ClientResponseError as e: if e.status == 401: raise APIAuthError( "Invalid API key. Please check:\n" "1. Key is not expired\n" "2. Key has correct permissions\n" "3. Key format is correct (Bearer prefix)\n" f"Get new key at: https://www.holysheep.ai/register" ) raise

2. Lỗi 429 Rate Limit — Quá Tải Request

import asyncio
from collections import deque
import time

class RateLimiter:
    """
    Token bucket algorithm cho rate limiting thông minh.
    Tránh rate limit error với adaptive throttling.
    """
    
    def __init__(self, requests_per_minute: int = 60, burst: int = 10):
        self.rpm = requests_per_minute
        self.burst = burst
        self.tokens = burst
        self.last_update = time.time()
        self._lock = asyncio.Lock()
        self._request_times = deque(maxlen=100)
    
    async def acquire(self):
        """Wait until request is allowed"""
        async with self._lock:
            now = time.time()
            
            # Refill tokens based on time passed
            elapsed = now - self.last_update
            self.tokens = min(self.burst, self.tokens + elapsed * (self.rpm / 60))
            self.last_update = now
            
            if self.tokens < 1:
                # Calculate wait time
                wait_time = (1 - self.tokens) / (self.rpm / 60)
                await asyncio.sleep(wait_time)
                self.tokens = 0
            else:
                self.tokens -= 1
            
            self._request_times.append(now)
    
    def get_current_rpm(self) -> int:
        """Calculate actual RPM over last minute"""
        now = time.time()
        cutoff = now - 60
        return sum(1 for t in self._request_times if t > cutoff)


class HolySheepWithRateLimit(HolySheepClient):
    """HolySheep client với built-in rate limiting"""
    
    def __init__(self, api_key: str, rpm: int = 120, **kwargs):
        super().__init__(api_key, **kwargs)
        self._limiter = RateLimiter(requests_per_minute=rpm)
        self._retry_after = None
    
    async def chat_completion(self, model, messages, **kwargs):
        await self._limiter.acquire()
        
        try:
            return await super().chat_completion(model, messages, **kwargs)
        except aiohttp.ClientResponseError as e:
            if e.status == 429:
                # Parse retry-after header
                retry_after = e.headers.get("Retry-After", "5")
                wait = int(retry_after) if retry_after.isdigit() else 5
                
                print(f"Rate limited. Waiting {wait}s...")
                await asyncio.sleep(wait)
                
                # Retry once
                return await super().chat_completion(model, messages, **kwargs)
            raise

3. Memory Leak Khi Xử Lý Ảnh Lớn

from PIL import Image
import io
import gc

class ImageProcessor:
    """
    Xử lý ảnh an toàn cho memory, tránh leak khi process nhiều ảnh lớn.
    """
    
    MAX_DIMENSION = 2048  # Max dimension để encode
    QUALITY = 85          # JPEG quality tối ưu size/quality
    
    @staticmethod
    def smart_resize(image_path: str) -> bytes:
        """
        Resize ảnh nếu quá lớn, convert sang JPEG để giảm size.
        Giảm memory usage từ 50MB xuống còn 2MB cho 1 ảnh 4K.
        """
        img = Image.open(image_path)
        
        # Convert RGBA to RGB (JPEG doesn't support alpha)
        if img.mode == 'RGBA':
            background = Image.new('RGB', img.size, (255, 255, 255))
            background.paste(img, mask=img.split()[-1])
            img = background
        
        # Resize nếu cần
        if max(img.size) > ImageProcessor.MAX_DIMENSION:
            ratio = ImageProcessor.MAX_DIMENSION / max(img.size)
            new_size = tuple(int(dim * ratio) for dim in img.size)
            img = img.resize(new_size, Image.Resampling.LANCZOS)
        
        # Save to bytes
        buffer = io.BytesIO()
        img.save(buffer, format='JPEG', quality=ImageProcessor.QUALITY)
        buffer.seek(0)
        
        return buffer.getvalue()
    
    @staticmethod
    def cleanup():
        """Force garbage collection sau batch process"""
        gc.collect()


class BatchImageProcessor:
    """Process nhiều ảnh với memory management"""
    
    def __init__(self, batch_size: int = 10):
        self.batch_size = batch_size
    
    async def process_batch(self, image_paths: List[str]) -> List[str]:
        """
        Process ảnh theo batch, mỗi batch có cleanup riêng.
        Tránh OOM cho server với hàng nghìn ảnh.
        """
        results = []
        
        for i in range(0, len(image_paths), self.batch_size):
            batch = image_paths[i:i + self.batch_size]
            
            # Process batch
            batch_results = [
                base64.b64encode(ImageProcessor.smart_resize(path)).decode()
                for path in batch
            ]
            results.extend(batch_results)
            
            # Cleanup sau mỗi batch
            ImageProcessor.cleanup()
            
            # Yield control để event loop xử lý other tasks
            await asyncio.sleep(0)
        
        return results

4. Timeout Khi Xử Lý Request Lớn

# Timeout strategy cho different request sizes

TIMEOUT_CONFIGS = {
    "small": {   # < 100KB total
        "connect": 5,
        "read": 30
    },
    "medium": {  # 100KB - 1MB
        "connect": 10,
        "read": 60
    },
    "large": {   # 1MB - 10MB
        "connect": 15,
        "read": 120
    },
    "xlarge": {  # > 10MB
        "connect": 30,
        "read": 300
    }
}

def estimate_request_size(payload: dict) -> str:
    """Estimate payload size để chọn timeout phù hợp"""
    import json
    size_bytes = len(json.dumps(payload).encode())
    size_mb = size_bytes / (1024 * 1024)
    
    if size_mb < 0.1:
        return "small"
    elif size_mb < 1:
        return "medium"
    elif size_mb < 10:
        return "large"
    else:
        return "xlarge"

async def smart_timeout_request(
    session: aiohttp.ClientSession,
    url: str,
    payload: dict,
    api_key: str