AI Asistent Učitelj Vasa: Praktična obuka za početnike (32 dana)

Dan 5/28: Profilisanje AI servisa i optimizacija

Vreme potrebno: 90 – 180 minuta

Gde je Učitelj Vasa danas?

Učitelj Vasa može da komunicira sa oba najpopularnija AI servisa (OpenAI i Gemini) kroz univerzalni factory sistem, automatski rešava SSL probleme i vodi kontinuirane razgovore. Ali trenutno ne znamo koji servis daje bolje rezultate za koje tipove pitanja, koliko brzo odgovaraju, niti kako da optimizujemo parametre za različite scenarije. Danas ćemo dodati sistem za analizu performansi i automatsku optimizaciju!

Cilj današnje lekcije

Danas ćeš naučiti kako da meriš performanse AI servisa, analiziraš kvalitet odgovora, optimizuješ parametre (temperature, max_tokens) za različite use case-ove i kreirajš profile rada koji automatski biraju najbolje postavke. Nakon ove lekcije, Učitelj Vasa će znati kada da koristi brze odgovore, kada detaljne objašnjenje, i koji servis daje bolje rezultate za različite tipove pitanja.

Predznanja

  • Funkcionalan multi-provider sistem (Dan 4)
  • Razumevanje parametara kao temperature i max_tokens (Dan 2)
  • BaseAIService interfejs i factory pattern (Dan 4)
  • Osnovno razumevanje merenja vremena u Python-u

Glavni sadržaj

Zašto je profilisanje AI servisa važno?

Pre nego što krenemo sa implementacijom, važno je razumeti zašto uopšte želimo da analiziramo performanse AI servisa.

📚 NIVO 1 – Osnovno objašnjenje

Profilisanje je kao testiranje automobila – želiš da znaš koliko brzo ubrzava, koliko troši goriva, kako se ponaša na različitim putevima. Isto važi za AI servise:
  • Neki su brži ali daju kraće odgovore
  • Neki su sporiji ali detaljniji
  • Neki bolje objašnjavaju kod, drugi bolje pišu priče
  • Cena se razlikuje – OpenAI naplaćuje, Gemini je besplatan
Kroz profilisanje ćemo naučiti kada koji servis da koristimo za najbolje rezultate!

🚀 NIVO 2 – Dublje razumevanje

Profilisanje AI servisa uključuje nekoliko metrika:
  1. Latencija – vreme od slanja pitanja do početka odgovora
  2. Throughput – broj tokena generisanih po sekundi
  3. Kvalitet – relevantnost, tačnost i korisnost odgovora
  4. Troškovi – cena po tokenu (za plaćene servise)
  5. Stabilnost – konzistentnost odgovora za isto pitanje
Različiti parametri utiču na ove metrike:
  • Temperature (0.0-2.0): Kreativnost vs konzistentnost
  • Max tokens: Dužina odgovora
  • Top-p: Alternativa temperaturi za kontrolu raznovrsnosti
  • Frequency penalty: Smanjuje ponavljanje
🔍 UVID: Ovo što radimo danas je tvoj prvi korak u svet MLOps-a (Machine Learning Operations). U profesionalnom okruženju, AI modeli se neprekidno prate, evaluiraju i upoređuju. Kreiranjem sistema za merenje performansi, ti ne praviš samo “pametnijeg” Vasu, već gradiš temelj za pouzdanu i skalabilnu AI aplikaciju. 💡 PRO TIP: Kada počneš da meriš performanse, prvo meri SVE – i uspeh i neuspeh. Često ćeš otkriti da najsporiji pozivi nisu u stvari preduslov za kvalitetniji odgovor, već samo posledica loše internet veze. Čim imaš podatke, možeš da postaviš “granice” (npr. >10 s se smatra sporim) i da ih automatski prijavljuješ u log. 🎈 ZABAVNA ČINJENICA: Netflix svakog sata simulira hiljade “kvarova” (Chaos Monkey) upravo da bi stalno merio performanse i otpornost servisa – sličan princip sada uvodiš u Učitelja Vasu!

Kreiranje sistema za merenje performansi

Počnimo sa osnovnim sistemom za praćenje metrika naših AI poziva.

📚 NIVO 1 – Osnovno objašnjenje

Napravićemo “štopericu” koja meri:
  • Koliko dugo traje svaki poziv
  • Koliko tokena je vraćeno
  • Da li je bio uspešan ili ne
To je kao aplikacija za praćenje treninga – beleži sve važne podatke da možeš kasnije da analiziraš performanse.

🚀 NIVO 2 – Dublje razumevanje

Kreiraćemo PerformanceTracker klasu koja koristi dekorator pattern za transparentno praćenje metrika bez menjanja postojećeg koda. Podatke ćemo čuvati u JSON formatu za lakšu analizu. 🔄 VEŽBA: Dodaj u PerformanceTracker polje input_length kako bi pratio i veličinu prompta. Zatim vizuelizuj (npr. u Excel-u) da li dugi upiti značajno usporavaju odgovor. 🎯 ALTERNATIVNO REŠENJE: Umesto ručnog beleženja u JSON, možeš iskoristiti SQLite:
import sqlite3, time, datetime
con = sqlite3.connect("ai_metrics.db")
cur = con.cursor()
cur.execute("""CREATE TABLE IF NOT EXISTS calls(
     id INTEGER PRIMARY KEY,
     provider TEXT, duration REAL, tokens INTEGER,
     ts TEXT)""")
def log_call(provider, duration, tokens):
    cur.execute("INSERT INTO calls VALUES(NULL,?,?,?,?)",
                (provider, duration, tokens,
                 datetime.datetime.now().isoformat()))
    con.commit()
Ovo nudi lakše SQL upite i sortiranje. 🎈 ZABAVNA ČINJENICA: Prosečan developer tokenizuje oko 2000 reči/min, ali GPT-4o prelazi 20 000 tokena u istom vremenu – 10× brže od čoveka! Kreiraj novi fajl src/utils/performance_tracker.py:
"""
Performance Tracker za AI servise
Meri i analizira performanse različitih AI servisa
"""

import time
import json
import statistics
from pathlib import Path
from datetime import datetime
from typing import Dict, List, Optional, Any, Callable
from functools import wraps
import os


class PerformanceTracker:
    """Prati performanse AI servisa."""
    
    def __init__(self, data_file: str = "ai_performance_data.json"):
        """
        Inicijalizuje tracker sa putanjom do fajla za čuvanje podataka.
        
        Args:
            data_file: Ime fajla za čuvanje podataka
        """
        # Kreiraj data folder ako ne postoji
        self.data_dir = Path(__file__).parent.parent.parent / "data"
        self.data_dir.mkdir(exist_ok=True)
        
        self.data_file = self.data_dir / data_file
        self.current_metrics = {}
        self.load_data()
    
    def load_data(self):
        """Učitava postojeće podatke iz fajla."""
        if self.data_file.exists():
            try:
                with open(self.data_file, 'r', encoding='utf-8') as f:
                    self.all_metrics = json.load(f)
            except Exception as e:
                print(f"⚠️ Greška pri učitavanju podataka: {e}")
                self.all_metrics = []
        else:
            self.all_metrics = []
    
    def save_data(self):
        """Čuva podatke u fajl."""
        try:
            with open(self.data_file, 'w', encoding='utf-8') as f:
                json.dump(self.all_metrics, f, indent=2, ensure_ascii=False)
        except Exception as e:
            print(f"❌ Greška pri čuvanju podataka: {e}")
    
    def start_tracking(self, provider: str, model: str, operation: str):
        """
        Počinje praćenje performansi.
        
        Args:
            provider: AI provider (openai, gemini)
            model: Model koji se koristi
            operation: Tip operacije (chat, completion, etc)
        """
        tracking_id = f"{provider}_{model}_{int(time.time()*1000)}"
        self.current_metrics[tracking_id] = {
            "provider": provider,
            "model": model,
            "operation": operation,
            "start_time": time.time(),
            "timestamp": datetime.now().isoformat()
        }
        return tracking_id
    
    def end_tracking(self, tracking_id: str, 
                    success: bool = True,
                    response_length: int = 0,
                    error: Optional[str] = None,
                    additional_data: Optional[Dict] = None):
        """
        Završava praćenje i čuva metrike.
        
        Args:
            tracking_id: ID praćenja
            success: Da li je poziv bio uspešan
            response_length: Dužina odgovora u karakterima
            error: Opis greške ako nije uspešno
            additional_data: Dodatni podaci za čuvanje
        """
        if tracking_id not in self.current_metrics:
            return
        
        metrics = self.current_metrics[tracking_id]
        end_time = time.time()
        
        # Izračunaj trajanje
        duration = end_time - metrics["start_time"]
        
        # Dopuni metrike
        metrics.update({
            "duration_seconds": round(duration, 3),
            "success": success,
            "response_length": response_length,
            "error": error,
            "tokens_per_second": round(response_length / duration, 2) if duration > 0 else 0
        })
        
        # Dodaj dodatne podatke ako postoje
        if additional_data:
            metrics.update(additional_data)
        
        # Sačuvaj u listu svih metrika
        self.all_metrics.append(metrics)
        self.save_data()
        
        # Ukloni iz trenutnih
        del self.current_metrics[tracking_id]
        
        return metrics
    
    def track_call(self, provider: str, model: str):
        """
        Dekorator za automatsko praćenje AI poziva.
        
        Args:
            provider: AI provider
            model: Model koji se koristi
            
        Returns:
            Dekorator funkcija
        """
        def decorator(func: Callable):
            @wraps(func)
            def wrapper(*args, **kwargs):
                # Počni praćenje
                tracking_id = self.start_tracking(provider, model, func.__name__)
                
                try:
                    # Pozovi originalnu funkciju
                    result = func(*args, **kwargs)
                    
                    # Završi praćenje - uspešno
                    self.end_tracking(
                        tracking_id,
                        success=True,
                        response_length=len(result) if isinstance(result, str) else 0
                    )
                    
                    return result
                    
                except Exception as e:
                    # Završi praćenje - neuspešno
                    self.end_tracking(
                        tracking_id,
                        success=False,
                        error=str(e)
                    )
                    raise
            
            return wrapper
        return decorator
    
    def get_provider_stats(self, provider: str) -> Dict[str, Any]:
        """
        Vraća statistiku za određeni provider.
        
        Args:
            provider: Ime providera
            
        Returns:
            Dict sa statistikama
        """
        provider_metrics = [m for m in self.all_metrics 
                          if m.get("provider") == provider and m.get("success")]
        
        if not provider_metrics:
            return {
                "provider": provider,
                "total_calls": 0,
                "avg_duration": 0,
                "avg_tokens_per_second": 0,
                "success_rate": 0
            }
        
        durations = [m["duration_seconds"] for m in provider_metrics]
        tokens_per_sec = [m["tokens_per_second"] for m in provider_metrics]
        
        total_calls = len(self.all_metrics)
        successful_calls = len(provider_metrics)
        
        return {
            "provider": provider,
            "total_calls": total_calls,
            "successful_calls": successful_calls,
            "avg_duration": round(statistics.mean(durations), 3),
            "min_duration": round(min(durations), 3),
            "max_duration": round(max(durations), 3),
            "avg_tokens_per_second": round(statistics.mean(tokens_per_sec), 2),
            "success_rate": round(successful_calls / total_calls * 100, 1) if total_calls > 0 else 0
        }
    
    def compare_providers(self) -> str:
        """
        Poredi performanse svih providera.
        
        Returns:
            Formatiran string sa poređenjem
        """
        providers = set(m["provider"] for m in self.all_metrics)
        
        if not providers:
            return "📊 Nema dovoljno podataka za poređenje."
        
        report = "📊 POREĐENJE AI SERVISA\n"
        report += "=" * 60 + "\n\n"
        
        for provider in sorted(providers):
            stats = self.get_provider_stats(provider)
            
            report += f"🤖 {provider.upper()}\n"
            report += f"   Ukupno poziva: {stats['total_calls']}\n"
            report += f"   Uspešnih: {stats['successful_calls']}\n"
            report += f"   Prosečno vreme: {stats['avg_duration']}s\n"
            report += f"   Min/Max vreme: {stats['min_duration']}s / {stats['max_duration']}s\n"
            report += f"   Brzina: ~{stats['avg_tokens_per_second']} karaktera/s\n"
            report += f"   Uspešnost: {stats['success_rate']}%\n\n"
        
        return report
    
    def get_recommendations(self) -> Dict[str, str]:
        """
        Daje preporuke na osnovu analize performansi.
        
        Returns:
            Dict sa preporukama za različite scenarije
        """
        providers = set(m["provider"] for m in self.all_metrics)
        
        if len(providers) < 2:
            return {
                "general": "Potrebno je više podataka sa oba servisa za preporuke."
            }
        
        # Analiziraj performanse
        stats = {p: self.get_provider_stats(p) for p in providers}
        
        # Pronađi najbrži i najstabilniji
        fastest = min(stats.items(), key=lambda x: x[1]["avg_duration"])[0]
        most_stable = max(stats.items(), key=lambda x: x[1]["success_rate"])[0]
        
        recommendations = {
            "brzi_odgovori": f"Koristi {fastest.upper()} - najbrži prosečni odgovor",
            "stabilnost": f"Koristi {most_stable.upper()} - najbolja uspešnost",
            "eksperimentisanje": "Gemini - besplatan za neograničeno testiranje",
            "produkcija": "OpenAI - industrijski standard sa najboljom dokumentacijom"
        }
        
        return recommendations


# Globalni tracker instance
tracker = PerformanceTracker()


# Test funkcionalnost
if __name__ == "__main__":
    print("🧪 Test Performance Tracker-a")
    print("=" * 50)
    
    # Simuliraj nekoliko poziva
    for i in range(3):
        provider = "openai" if i % 2 == 0 else "gemini"
        
        # Start tracking
        tid = tracker.start_tracking(provider, "test-model", "test_operation")
        
        # Simuliraj poziv
        time.sleep(0.5 + i * 0.2)
        
        # End tracking
        tracker.end_tracking(tid, success=True, response_length=100 + i * 50)
    
    # Prikaži statistiku
    print("\n" + tracker.compare_providers())
    
    # Prikaži preporuke
    print("💡 PREPORUKE:")
    for scenario, recommendation in tracker.get_recommendations().items():
        print(f"   {scenario}: {recommendation}")
📊 DIJAGRAM: Tok izvršavanja PerformanceTracker-a
[Tvoj Kod] → pozovi_ai(...)
     │
     ↓
[start_tracking] ◄──────────┐
  (Beleži vreme početka)     │
     │                       │
     ↓                       │
[Originalni AI Poziv] ──── G R E Š K A ──┐
  (npr. OpenAI API)        │             │
     │                     │             ↓
     ↓ (Uspeh)             │    [end_tracking(success=False)]
     │                     │      (Beleži grešku)
     ↓                     │             │
[end_tracking(success=True)] │             ↓
  (Beleži vreme kraja,      │         [Prijavi Grešku]
   računa trajanje)          │             ↑
     │                       │             │
     └───────────────────────┴─────────────┘
     │
     ↓
[Vrati rezultat / Prijavi grešku] → [Tvoj Kod]
SAVET ZA OPTIMIZACIJU: Sakupljanje metrika, iako veoma korisno, dodaje mali “overhead” (dodatno vreme) svakom pozivu. Naš trenutni sistem je veoma brz (upisuje u memoriju i onda u fajl), ali u produkciji sa hiljadama poziva, upisivanje u fajl nakon svakog poziva može postati usko grlo. Profesionalni sistemi podatke prvo šalju u brzi “bafer” (privremenu memoriju) i onda ih periodično upisuju u bazu podataka ili log sistem u “grupama” (batches). 🌐 GOOGLE CONNECTION: Podaci koje skupljaš u ai_performance_data.json su izuzetno vredni. Kada tvoj projekat poraste, umesto čuvanja u lokalni JSON fajl, možeš jednostavno da ih šalješ u Google Cloud Logging. Svaki JSON objekat postaje jedan log zapis. Odatle, možeš automatski da kreiraš metrike u Cloud Monitoring-u (npr. prosečna latencija openai_service poziva) i da praviš vizuelne table (dashboards) u Looker Studio da bi pratio performanse u realnom vremenu, bez ijedne linije koda za vizuelizaciju!

Integracija trackera sa AI servisima

Sada ćemo integrisati tracker sa postojećim servisima da automatski prati svaki poziv.

📚 NIVO 1 – Osnovno objašnjenje

Umesto da ručno merimo svaki poziv, napravićemo da se to dešava automatski. To je kao da staviš fitness tracker – sam beleži sve aktivnosti bez tvog razmišljanja o tome.

🚀 NIVO 2 – Dublje razumevanje

Koristićemo Python dekoratore da “omotamo” postojeće metode i dodamo praćenje performansi bez menjanja originalne logike. Ovo je primer Aspect-Oriented Programming (AOP). 💡 PRO TIP: Dekorator pattern koji dodaje logovanje može se primeniti globalno korišćenjem metaclass-a. Ako svi servis-klase naslede isti metaclass, jednim redom koda “omotaš” sve javne metode bez ručne izmene svakog. 🎈 ZABAVNA ČINJENICA: Prvi Python dekorator za logovanje napisan je 2004. i stao je u jedan tvit (140 karaktera)! Ažuriraj src/ai_services/openai_service.py (dodaj import i modifikuj pozovi_ai metodu):
# Dodaj na početak importa
from utils.performance_tracker import tracker

# U OpenAIService klasi, zameni pozovi_ai metodu sa:
def pozovi_ai(self, poruka: str, system_prompt: Optional[str] = None) -> str:
    """
    Šalje poruku AI-ju i vraća odgovor sa praćenjem performansi.
    
    Args:
        poruka: Korisnikova poruka/pitanje
        system_prompt: Opcioni system prompt za definisanje ponašanja
        
    Returns:
        AI odgovor kao string
    """
    # Počni praćenje
    tracking_id = tracker.start_tracking("openai", self.model, "chat_completion")
    
    try:
        # Pripremi poruke
        messages = []
        
        if system_prompt:
            messages.append({
                "role": "system",
                "content": system_prompt
            })
        
        messages.append({
            "role": "user",
            "content": poruka
        })
        
        # Pozovi API
        response = self.client.chat.completions.create(
            model=self.model,
            messages=messages,
            max_tokens=self.max_tokens,
            temperature=self.temperature
        )
        
        result = response.choices[0].message.content.strip()
        
        # Završi praćenje - uspešno
        tracker.end_tracking(
            tracking_id,
            success=True,
            response_length=len(result),
            additional_data={
                "prompt_length": len(poruka),
                "temperature": self.temperature,
                "max_tokens": self.max_tokens
            }
        )
        
        return result
        
    except Exception as e:
        # Završi praćenje - neuspešno
        tracker.end_tracking(
            tracking_id,
            success=False,
            error=str(e)
        )
        
        # Postojeći error handling...
        error_msg = f"Greška pri komunikaciji sa OpenAI: {str(e)}"
        print(f"❌ {error_msg}")
        
        if "api_key" in str(e).lower():
            return "Izgleda da OpenAI API ključ nije valjan. Proveri podešavanja."
        elif "rate_limit" in str(e).lower():
            return "Previše zahteva ka OpenAI. Sačekaj malo pa pokušaj ponovo."
        elif "insufficient_quota" in str(e).lower():
            return "Nemaš dovoljno OpenAI kredita. Proveri svoj balans ili prebaci se na Gemini (AI_PROVIDER=gemini)."
        elif "connection" in str(e).lower():
            return "Problem sa internet konekcijom. Proveri da li si povezan."
        elif "SSL" in str(e) or "certificate" in str(e).lower():
            return "SSL problem - restartuj program ili koristi Gemini servis."
        else:
            return "Ups! Nešto je pošlo po zlu sa OpenAI. Pokušaj ponovo za koji trenutak."
Slično ažuriraj src/ai_services/gemini_service.py:
# Dodaj na početak importa
from utils.performance_tracker import tracker

# U GeminiService klasi, zameni pozovi_ai metodu sa:
def pozovi_ai(self, poruka: str, system_prompt: Optional[str] = None) -> str:
    """
    Šalje poruku AI-ju i vraća odgovor sa praćenjem performansi.
    
    Args:
        poruka: Korisnikova poruka/pitanje
        system_prompt: Opcioni system prompt za definisanje ponašanja
        
    Returns:
        AI odgovor kao string
    """
    # Počni praćenje
    tracking_id = tracker.start_tracking("gemini", Config.GEMINI_MODEL, "generate_content")
    
    try:
        # Gemini kombinuje system prompt i korisničku poruku
        full_prompt = poruka
        if system_prompt:
            full_prompt = f"{system_prompt}\n\nKorisnik: {poruka}\nAsistent:"
        
        # Generiši odgovor
        response = self.model.generate_content(
            full_prompt,
            generation_config=self.generation_config
        )
        
        result = response.text.strip()
        
        # Završi praćenje - uspešno
        tracker.end_tracking(
            tracking_id,
            success=True,
            response_length=len(result),
            additional_data={
                "prompt_length": len(full_prompt),
                "temperature": self.temperature,
                "max_tokens": self.max_tokens
            }
        )
        
        return result
        
    except Exception as e:
        # Završi praćenje - neuspešno
        tracker.end_tracking(
            tracking_id,
            success=False,
            error=str(e)
        )
        
        # Postojeći error handling...
        error_msg = f"Greška pri komunikaciji sa Gemini: {str(e)}"
        print(f"❌ {error_msg}")
        
        if "api_key" in str(e).lower():
            return "Izgleda da Gemini API ključ nije valjan. Proveri podešavanja."
        elif "rate_limit" in str(e).lower() or "429" in str(e):
            return "Previše zahteva ka Gemini. Sačekaj malo pa pokušaj ponovo."
        elif "safety" in str(e).lower():
            return "Gemini je blokirao odgovor iz sigurnosnih razloga. Pokušaj sa drugim pitanjem."
        elif "connection" in str(e).lower():
            return "Problem sa internet konekcijom. Proveri da li si povezan."
        else:
            return "Ups! Nešto je pošlo po zlu sa Gemini. Pokušaj ponovo za koji trenutak."

Kreiranje sistema optimizacionih profila

Sada ćemo kreirati profile koji automatski podešavaju parametre za različite tipove zadataka.

📚 NIVO 1 – Osnovno objašnjenje

Profile su kao preseti na TV-u – “Film” pojačava boje, “Sport” pojačava pokret, “Vesti” fokusira na govor. Mi ćemo napraviti profile za AI:
  • Brzi odgovor: Kratko i jasno
  • Detaljan učitelj: Opširno objašnjenje
  • Kreativno pisanje: Više mašte
  • Precizni kod: Tačnost pre svega

🚀 NIVO 2 – Dublje razumevanje

Različiti zadaci zahtevaju različite pristupe. Temperature 0.2 je odlična za generisanje koda (predvidljivo), dok 1.5 omogućava kreativnost za pisanje priča. Max_tokens kontroliše dužinu – ne želimo roman kada tražimo definiciju! 💡 PRO TIP: Premosti “tvrd” izbor provajdera u profilu tako što ćeš zapisati samo poželjnu metriku (npr. target_duration < 2 s). Factory može dinamički da pozove tracker.compare_providers() i izabere onaj koji u tom trenutku zadovoljava cilj. 🎈 ZABAVNA ČINJENICA: Parametar temperature potiče iz formule Bolcmanove raspodele – direktna veza između AI-ja i fizike! Kreiraj src/utils/optimization_profiles.py:
"""
Optimizacioni profili za AI servise
Predefinisane postavke za različite scenarije korišćenja
"""

from typing import Dict, Any, Optional
from dataclasses import dataclass
from enum import Enum


class ProfileType(Enum):
    """Tipovi optimizacionih profila."""
    QUICK_ANSWER = "quick_answer"
    DETAILED_EXPLANATION = "detailed_explanation"
    CODE_GENERATION = "code_generation"
    CREATIVE_WRITING = "creative_writing"
    DEBUGGING_HELP = "debugging_help"
    TRANSLATION = "translation"
    SUMMARIZATION = "summarization"


@dataclass
class OptimizationProfile:
    """Definiše optimizacioni profil za AI pozive."""
    name: str
    description: str
    temperature: float
    max_tokens: int
    system_prompt_addon: str
    provider_preference: Optional[str] = None  # None znači koristi trenutni
    
    def to_dict(self) -> Dict[str, Any]:
        """Konvertuje profil u dictionary."""
        return {
            "temperature": self.temperature,
            "max_tokens": self.max_tokens,
            "system_prompt_addon": self.system_prompt_addon,
            "provider_preference": self.provider_preference
        }


# Predefinisani profili
PROFILES = {
    ProfileType.QUICK_ANSWER: OptimizationProfile(
        name="Brzi odgovor",
        description="Kratki, direktni odgovori za jednostavna pitanja",
        temperature=0.3,
        max_tokens=100,
        system_prompt_addon="\nDaj kratak i direktan odgovor u 1-2 rečenice.",
        provider_preference="gemini"  # Gemini je obično brži za kratke odgovore
    ),
    
    ProfileType.DETAILED_EXPLANATION: OptimizationProfile(
        name="Detaljno objašnjenje",
        description="Opširna objašnjenja sa primerima",
        temperature=0.7,
        max_tokens=500,
        system_prompt_addon="\nDaj detaljno objašnjenje sa primerima. Objasni korak po korak.",
        provider_preference="openai"  # OpenAI bolje strukturira duge odgovore
    ),
    
    ProfileType.CODE_GENERATION: OptimizationProfile(
        name="Generisanje koda",
        description="Precizno generisanje koda sa komentarima",
        temperature=0.2,
        max_tokens=400,
        system_prompt_addon="\nGeneriši samo kod sa komentarima na srpskom. Kod mora biti funkcionalan i dobro struktuiran.",
        provider_preference=None  # Oba su dobra za kod
    ),
    
    ProfileType.CREATIVE_WRITING: OptimizationProfile(
        name="Kreativno pisanje",
        description="Kreativni sadržaj sa više mašte",
        temperature=1.2,
        max_tokens=600,
        system_prompt_addon="\nBudi kreativan i maštovit u svom odgovoru. Koristi žive opise i interesantne ideje.",
        provider_preference="openai"  # OpenAI tradicionalno bolji za kreativnost
    ),
    
    ProfileType.DEBUGGING_HELP: OptimizationProfile(
        name="Pomoć pri debug-ovanju",
        description="Analiza grešaka i predlozi rešenja",
        temperature=0.3,
        max_tokens=300,
        system_prompt_addon="\nAnaliziraj problem sistematski. Identifikuj mogući uzrok i predloži konkretna rešenja.",
        provider_preference=None
    ),
    
    ProfileType.TRANSLATION: OptimizationProfile(
        name="Prevođenje",
        description="Tačno prevođenje sa očuvanjem konteksta",
        temperature=0.1,
        max_tokens=200,
        system_prompt_addon="\nPrevedi tačno, očuvavajući originalni smisao i ton.",
        provider_preference="gemini"  # Gemini odličan za prevode
    ),
    
    ProfileType.SUMMARIZATION: OptimizationProfile(
        name="Rezimiranje",
        description="Sažeto predstavljanje ključnih informacija",
        temperature=0.4,
        max_tokens=200,
        system_prompt_addon="\nRezimiraj ključne informacije jasno i koncizno.",
        provider_preference=None
    )
}


class ProfileManager:
    """Upravlja optimizacionim profilima."""
    
    def __init__(self):
        self.profiles = PROFILES
        self.active_profile: Optional[ProfileType] = None
    
    def get_profile(self, profile_type: ProfileType) -> OptimizationProfile:
        """
        Vraća profil za dati tip.
        
        Args:
            profile_type: Tip profila
            
        Returns:
            OptimizationProfile objekat
        """
        return self.profiles[profile_type]
    
    def list_profiles(self) -> str:
        """
        Vraća formatiranu listu svih dostupnih profila.
        
        Returns:
            String sa listom profila
        """
        result = "📋 DOSTUPNI OPTIMIZACIONI PROFILI\n"
        result += "=" * 50 + "\n\n"
        
        for i, (ptype, profile) in enumerate(self.profiles.items(), 1):
            result += f"{i}. {profile.name}\n"
            result += f"   📝 {profile.description}\n"
            result += f"   🌡️ Temperature: {profile.temperature}\n"
            result += f"   📏 Max tokena: {profile.max_tokens}\n"
            if profile.provider_preference:
                result += f"   🤖 Preporučen: {profile.provider_preference.upper()}\n"
            result += "\n"
        
        return result
    
    def analyze_question(self, question: str) -> ProfileType:
        """
        Analizira pitanje i predlaže najbolji profil.
        
        Args:
            question: Korisnikovo pitanje
            
        Returns:
            Preporučeni ProfileType
        """
        question_lower = question.lower()
        
        # Ključne reči za različite profile
        code_keywords = ["kod", "funkcija", "class", "python", "napiši", "implementiraj", 
                        "sintaksa", "primer koda", "programa"]
        debug_keywords = ["greška", "error", "ne radi", "problem", "bug", "zašto", 
                         "debug", "exception", "traceback"]
        creative_keywords = ["priča", "pesma", "kreativno", "zamisli", "osmisli", 
                           "maštovito", "originalno"]
        translation_keywords = ["prevedi", "prevod", "na engleski", "na srpski", 
                              "translate"]
        summary_keywords = ["rezimiraj", "ukratko", "sažmi", "glavni", "ključn"]
        detail_keywords = ["objasni", "detaljno", "kako", "zašto", "razumem", 
                         "nauči me", "korak po korak"]
        
        # Proveri ključne reči
        if any(kw in question_lower for kw in code_keywords):
            return ProfileType.CODE_GENERATION
        elif any(kw in question_lower for kw in debug_keywords):
            return ProfileType.DEBUGGING_HELP
        elif any(kw in question_lower for kw in creative_keywords):
            return ProfileType.CREATIVE_WRITING
        elif any(kw in question_lower for kw in translation_keywords):
            return ProfileType.TRANSLATION
        elif any(kw in question_lower for kw in summary_keywords):
            return ProfileType.SUMMARIZATION
        elif any(kw in question_lower for kw in detail_keywords):
            return ProfileType.DETAILED_EXPLANATION
        elif len(question.split()) < 10:  # Kratko pitanje
            return ProfileType.QUICK_ANSWER
        else:
            return ProfileType.DETAILED_EXPLANATION
    
    def apply_profile(self, profile_type: ProfileType, 
                     current_settings: Dict[str, Any]) -> Dict[str, Any]:
        """
        Primenjuje profil na trenutne postavke.
        
        Args:
            profile_type: Tip profila koji se primenjuje
            current_settings: Trenutne postavke
            
        Returns:
            Ažurirane postavke
        """
        profile = self.get_profile(profile_type)
        self.active_profile = profile_type
        
        # Kopiraj trenutne postavke
        new_settings = current_settings.copy()
        
        # Primeni postavke profila
        new_settings["temperature"] = profile.temperature
        new_settings["max_tokens"] = profile.max_tokens
        
        # Dodaj addon na system prompt ako postoji
        if "system_prompt" in new_settings and profile.system_prompt_addon:
            new_settings["system_prompt"] += profile.system_prompt_addon
        
        # Postavi provider prefereneciju ako je specificirana
        if profile.provider_preference:
            new_settings["provider_hint"] = profile.provider_preference
        
        return new_settings


# Globalna instanca
profile_manager = ProfileManager()


# Test funkcionalnost
if __name__ == "__main__":
    print("🧪 Test Optimization Profiles")
    print("=" * 50)
    
    # Prikaži sve profile
    print(profile_manager.list_profiles())
    
    # Test analize pitanja
    test_questions = [
        "Šta je Python?",
        "Napiši funkciju za sortiranje liste",
        "Zašto mi kod baca IndexError?",
        "Prevedi 'Hello World' na srpski",
        "Objasni mi detaljno kako rade dekoratori u Python-u"
    ]
    
    print("🔍 ANALIZA PITANJA:")
    print("-" * 50)
    
    for q in test_questions:
        suggested = profile_manager.analyze_question(q)
        profile = profile_manager.get_profile(suggested)
        print(f"\nPitanje: '{q}'")
        print(f"Predlog: {profile.name}")
        print(f"Razlog: {profile.description}")
🔍 UVID: Naša analyze_question metoda je jednostavan, ali efektivan “rules engine” (sistem baziran na pravilima). U naprednijim sistemima, ovaj korak se često rešava pomoću samog AI-ja! Koristio bi se manji, brži i jeftiniji model (kao Gemini Flash ili GPT-3.5-Turbo) koji bi prvo “klasifikovao” upit korisnika u jednu od kategorija (npr. “code_generation”, “creative_writing”). Na osnovu te klasifikacije, sistem bi onda pozivao veći, moćniji i skuplji model (kao Gemini 1.5 Pro ili GPT-4) sa već optimizovanim parametrima. Ovo se zove “model routing” i predstavlja ključnu strategiju za optimizaciju troškova i performansi u velikim AI sistemima. 📊 DIJAGRAM: Logika odlučivanja u analyze_question
[Pitanje Korisnika]
         │
         ↓
+--------------------------------+
|      Pitanje u malim slovima   |
+--------------------------------+
         │
         ↓
┌───────────────────────────────┐
│ Da li sadrži ključne reči za  │
│ KOD (npr. 'kod', 'funkcija')? ├─(Da)──→ [CODE_GENERATION]
└───────────────────────────────┘
         │ (Ne)
         ↓
┌───────────────────────────────┐
│ Da li sadrži ključne reči za  │
│ DEBUG (npr. 'greška', 'bug')? ├─(Da)──→ [DEBUGGING_HELP]
└───────────────────────────────┘
         │ (Ne)
         ↓
┌───────────────────────────────┐
│ Da li sadrži ključne reči za  │
│ KREATIVNOST ('priča', 'pesma')├─(Da)──→ [CREATIVE_WRITING]
└───────────────────────────────┘
         │ (Ne)
         ↓
       (...)  Nastavak provera
         │
         ↓
┌───────────────────────────────┐
│ Da li ima < 10 reči?          ├─(Da)──→ [QUICK_ANSWER]
└───────────────────────────────┘
         │ (Ne)
         ↓
   [DETAILED_EXPLANATION] (Podrazumevano)

Optimizacija i najbolje prakse

Sada kada imamo alate za merenje i optimizaciju, hajde da sumiramo ključne principe. 🔍 UVID: Ključna ideja današnje lekcije je prelazak sa pretpostavki na merenja. Umesto da misliš “mislim da je Gemini brži”, sada imaš sistem koji to može da dokaže ili opovrgne podacima. Ovo je fundamentalna promena u načinu razmišljanja i osnova inženjerskog pristupa razvoju softvera.
  1. Odvoji brige (Separation of Concerns): Logika za praćenje performansi (PerformanceTracker) je potpuno odvojena od logike AI servisa. To znači da sutra možemo zameniti PerformanceTracker nekim naprednijim sistemom bez izmene ijedne linije koda u OpenAIService ili GeminiService.
  2. Automatizuj gde je moguće: ProfileManager automatski bira najbolje postavke. Ovo smanjuje “cognitive load” (mentalno opterećenje) za korisnika i čini aplikaciju “pametnijom”. Dobar softver predviđa potrebe korisnika.
  3. Planiraj za budućnost (Scalability): Čuvanje podataka u JSON je savršeno za početak. Struktura koju smo napravili olakšava da se sutra podaci šalju u pravu bazu podataka ili cloud servis. Uvek razmišljaj kako će tvoje rešenje raditi sa 10 puta više podataka ili korisnika.
SAVET ZA OPTIMIZACIJU: Parametar max_tokens direktno utiče na troškove (kod plaćenih servisa) i vreme odgovora. Korišćenjem profila, mi ne samo da dobijamo relevantnije odgovore, već i aktivno upravljamo troškovima. Profil “Brzi odgovor” sa max_tokens=100 može biti 5 do 10 puta jeftiniji od profila “Detaljno objašnjenje” sa max_tokens=500. Praćenje i optimizacija su dve strane iste medalje: poboljšavaju iskustvo i smanjuju troškove.

Integracija profila sa AI factory sistemom

Sada ćemo proširiti naš factory da koristi profile za optimizaciju.

📚 NIVO 1 – Osnovno objašnjenje

Factory će sada biti pametniji – analiziraće tvoje pitanje i automatski prilagoditi postavke. To je kao pametni telefon koji automatski pojačava ekran na suncu ili smanjuje kada je mrak.

🚀 NIVO 2 – Dublje razumevanje

Proširićemo BaseAIService sa metodom koja prima profil, a factory će moći da kreira “optimizovane” instance servisa sa custom parametrima. 🔄 VEŽBA: Dodaj CLI opciju --profile quick kako bi korisnik iz terminala mogao da odabere optimizacioni profil bez interaktivnog menija. 🎯 ALTERNATIVNO REŠENJE: Umesto da profil proširuje system_prompt, možeš da proslediš poseban “instruction” objekat (OpenAI ChatML) i tako razdvojiš logiku od sadržaja. 🎈 ZABAVNA ČINJENICA: Slack-ov bot “Claude” je u internom A/B testu dobio 12% više “jednostavnih pitanja” samo jer je u pozadini pametno menjao temperature između 0.3 i 0.7 u zavisnosti od dužine korisničkog pitanja. Ažuriraj src/ai_services/base_service.py:
"""
Bazna klasa za sve AI servise
Definiše interfejs koji svi servisi moraju implementirati
"""

from abc import ABC, abstractmethod
from typing import Optional, List, Dict, Any


class BaseAIService(ABC):
    """Apstraktna bazna klasa za AI servise."""
    
    @abstractmethod
    def pozovi_ai(self, poruka: str, system_prompt: Optional[str] = None) -> str:
        """
        Šalje poruku AI-ju i vraća odgovor.
        
        Args:
            poruka: Korisnikova poruka/pitanje
            system_prompt: Opcioni system prompt za definisanje ponašanja
            
        Returns:
            AI odgovor kao string
        """
        pass
    
    @abstractmethod
    def pozovi_sa_istorijom(self, messages: List[Dict[str, str]]) -> str:
        """
        Šalje celu istoriju razgovora AI-ju.
        
        Args:
            messages: Lista poruka sa 'role' i 'content' ključevima
            
        Returns:
            AI odgovor kao string
        """
        pass
    
    def test_konekcija(self) -> bool:
        """
        Testira da li servis može da se poveže sa API-jem.
        
        Returns:
            True ako je konekcija uspešna, False inače
        """
        try:
            response = self.pozovi_ai("Reci 'zdravo' na srpskom.")
            return len(response) > 0
        except Exception as e:
            print(f"❌ Test konekcije neuspešan: {e}")
            return False
    
    def apply_settings(self, settings: Dict[str, Any]):
        """
        Primenjuje custom postavke na servis.
        
        Args:
            settings: Dictionary sa postavkama
        """
        # Primeni temperature ako postoji
        if "temperature" in settings and hasattr(self, "temperature"):
            self.temperature = settings["temperature"]
            if hasattr(self, "generation_config"):
                # Za Gemini, ažuriraj generation_config
                from google.generativeai import GenerationConfig
                self.generation_config = GenerationConfig(
                    max_output_tokens=getattr(self, "max_tokens", 150),
                    temperature=settings["temperature"]
                )
        
        # Primeni max_tokens ako postoji
        if "max_tokens" in settings and hasattr(self, "max_tokens"):
            self.max_tokens = settings["max_tokens"]
            if hasattr(self, "generation_config"):
                # Za Gemini, ažuriraj generation_config
                from google.generativeai import GenerationConfig
                self.generation_config = GenerationConfig(
                    max_output_tokens=settings["max_tokens"],
                    temperature=getattr(self, "temperature", 0.7)
                )
    
    def get_current_settings(self) -> Dict[str, Any]:
        """
        Vraća trenutne postavke servisa.
        
        Returns:
            Dict sa trenutnim postavkama
        """
        return {
            "temperature": getattr(self, "temperature", 0.7),
            "max_tokens": getattr(self, "max_tokens", 150),
            "model": getattr(self, "model", "unknown")
        }

Kreiranje benchmark sistema

Hajde da napravimo sistem koji automatski testira oba servisa sa različitim tipovima pitanja.

📚 NIVO 1 – Osnovno objašnjenje

Benchmark je kao takmičenje između servisa – postavljamo im ista pitanja i merimo ko daje bolje odgovore, ko je brži, i ko je pouzdaniji. To nam pomaže da donesemo informisane odluke o tome koji servis kada koristiti.

🚀 NIVO 2 – Dublje razumevanje

Kreiraćemo set standardizovanih test pitanja koji pokrivaju različite scenarije. Za svako pitanje ćemo meriti latenciju, kvalitet odgovora i konzistentnost između pokretanja. 💡 PRO TIP: Ograničenje troškova? Pokreni benchmark samo na prvih N pitanja gde je len(question) < 40. Ta pitanja često obuhvate 80% realnih korisničkih upita, a cena testa se smanjuje za red veličine. 🎈 ZABAVNA ČINJENICA: Najduži javni prompt ikada objavljen imao je preko 80 000 tokena – GPT-4 je ipak odgovorio, ali je operacija koštala ~120 USD! Kreiraj src/utils/ai_benchmark.py:
"""
AI Benchmark sistem
Poredi performanse različitih AI servisa
"""

import time
import json
from typing import Dict, List, Any, Optional
from datetime import datetime
from pathlib import Path

from ai_services.ai_factory import AIServiceFactory
from utils.config import Config
from utils.performance_tracker import tracker
from utils.optimization_profiles import profile_manager, ProfileType


class AIBenchmark:
    """Benchmark sistem za poređenje AI servisa."""
    
    # Test pitanja grupisana po kategorijama
    TEST_QUESTIONS = {
        "simple": [
            "Šta je Python?",
            "Koliko je 15 + 27?",
            "Koji je glavni grad Srbije?"
        ],
        "code": [
            "Napiši Python funkciju koja vraća faktorijel broja",
            "Kako da sortiram listu u Python-u?",
            "Objasni razliku između list i tuple"
        ],
        "complex": [
            "Objasni koncept rekurzije sa primerom",
            "Koje su prednosti objektno-orijentisanog programiranja?",
            "Kako funkcioniše garbage collection u Python-u?"
        ],
        "creative": [
            "Napiši kratku priču o programeru početniku",
            "Osmisli analogiju za objasnšnjenje API-ja",
            "Opiši budunost AI tehnologije"
        ]
    }
    
    def __init__(self):
        """Inicijalizuje benchmark sistem."""
        self.results_dir = Path(__file__).parent.parent.parent / "data" / "benchmarks"
        self.results_dir.mkdir(parents=True, exist_ok=True)
        self.current_results = []
    
    def run_single_test(self, provider: str, question: str, 
                       category: str, profile: Optional[ProfileType] = None) -> Dict[str, Any]:
        """
        Pokreće pojedinačni test.
        
        Args:
            provider: AI provider za testiranje
            question: Test pitanje
            category: Kategorija pitanja
            profile: Opcioni profil za optimizaciju
            
        Returns:
            Rezultati testa
        """
        try:
            # Promeni provider ako treba
            original_provider = Config.AI_PROVIDER
            if Config.AI_PROVIDER != provider:
                Config.AI_PROVIDER = provider
                AIServiceFactory.reset()
            
            # Dobij servis
            service = AIServiceFactory.get_service()
            
            # Primeni profil ako je dat
            if profile:
                settings = profile_manager.apply_profile(
                    profile, 
                    service.get_current_settings()
                )
                service.apply_settings(settings)
            
            # Meri vreme
            start_time = time.time()
            
            # Pozovi AI
            response = service.pozovi_ai(question)
            
            # Kraj merenja
            duration = time.time() - start_time
            
            # Vrati na originalni provider
            if original_provider != provider:
                Config.AI_PROVIDER = original_provider
                AIServiceFactory.reset()
            
            return {
                "provider": provider,
                "question": question,
                "category": category,
                "profile": profile.value if profile else "default",
                "response": response,
                "response_length": len(response),
                "duration": round(duration, 3),
                "success": True,
                "timestamp": datetime.now().isoformat()
            }
            
        except Exception as e:
            # Vrati na originalni provider
            if original_provider != provider:
                Config.AI_PROVIDER = original_provider
                AIServiceFactory.reset()
            
            return {
                "provider": provider,
                "question": question,
                "category": category,
                "profile": profile.value if profile else "default",
                "response": None,
                "response_length": 0,
                "duration": 0,
                "success": False,
                "error": str(e),
                "timestamp": datetime.now().isoformat()
            }
    
    def run_category_benchmark(self, category: str, providers: List[str]) -> List[Dict]:
        """
        Pokreće benchmark za celu kategoriju.
        
        Args:
            category: Kategorija pitanja za testiranje
            providers: Lista providera za testiranje
            
        Returns:
            Lista rezultata
        """
        results = []
        questions = self.TEST_QUESTIONS.get(category, [])
        
        print(f"\n🏃 Pokrećem benchmark za kategoriju: {category.upper()}")
        print("=" * 60)
        
        for question in questions:
            print(f"\n📝 Pitanje: {question}")
            
            # Analiziraj koje profile treba
            suggested_profile = profile_manager.analyze_question(question)
            
            for provider in providers:
                print(f"   🤖 Testiram {provider}...", end="", flush=True)
                
                # Test sa default postavkama
                result_default = self.run_single_test(provider, question, category)
                results.append(result_default)
                
                # Test sa optimizovanim profilom
                result_optimized = self.run_single_test(
                    provider, question, category, suggested_profile
                )
                results.append(result_optimized)
                
                print(f" ✓ ({result_default['duration']}s default, "
                     f"{result_optimized['duration']}s optimized)")
            
            # Pauza između pitanja
            time.sleep(0.5)
        
        return results
    
    def run_full_benchmark(self) -> str:
        """
        Pokreće kompletan benchmark test.
        
        Returns:
            Putanja do fajla sa rezultatima
        """
        print("\n🚀 POKRETANJE KOMPLETNOG BENCHMARK TESTA")
        print("=" * 60)
        
        # Proveri koji provideri su dostupni
        available_providers = []
        if Config.OPENAI_API_KEY:
            available_providers.append("openai")
        if Config.GEMINI_API_KEY:
            available_providers.append("gemini")
        
        if len(available_providers) < 2:
            print("⚠️ Potrebna su oba API ključa za poređenje!")
            return ""
        
        print(f"✅ Testiram: {', '.join(p.upper() for p in available_providers)}")
        
        # Pokreni testove za sve kategorije
        all_results = []
        for category in self.TEST_QUESTIONS.keys():
            category_results = self.run_category_benchmark(category, available_providers)
            all_results.extend(category_results)
            self.current_results.extend(category_results)
        
        # Sačuvaj rezultate
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        results_file = self.results_dir / f"benchmark_{timestamp}.json"
        
        with open(results_file, 'w', encoding='utf-8') as f:
            json.dump(all_results, f, indent=2, ensure_ascii=False)
        
        print(f"\n✅ Benchmark završen! Rezultati sačuvani u: {results_file}")
        
        # Generiši izveštaj
        self.generate_report(all_results)
        
        return str(results_file)
    
    def generate_report(self, results: List[Dict[str, Any]]):
        """
        Generiše izveštaj na osnovu rezultata.
        
        Args:
            results: Lista rezultata benchmark-a
        """
        print("\n📊 BENCHMARK IZVEŠTAJ")
        print("=" * 60)
        
        # Grupiši po providerima
        provider_stats = {}
        
        for result in results:
            if not result["success"]:
                continue
                
            provider = result["provider"]
            profile = result["profile"]
            
            if provider not in provider_stats:
                provider_stats[provider] = {
                    "default": {"times": [], "lengths": []},
                    "optimized": {"times": [], "lengths": []}
                }
            
            mode = "default" if profile == "default" else "optimized"
            provider_stats[provider][mode]["times"].append(result["duration"])
            provider_stats[provider][mode]["lengths"].append(result["response_length"])
        
        # Prikaži statistiku
        for provider, stats in provider_stats.items():
            print(f"\n🤖 {provider.upper()}")
            
            for mode in ["default", "optimized"]:
                if stats[mode]["times"]:
                    avg_time = sum(stats[mode]["times"]) / len(stats[mode]["times"])
                    avg_length = sum(stats[mode]["lengths"]) / len(stats[mode]["lengths"])
                    
                    print(f"\n   {mode.upper()} MODE:")
                    print(f"   - Prosečno vreme: {avg_time:.2f}s")
                    print(f"   - Prosečna dužina: {avg_length:.0f} karaktera")
                    print(f"   - Najbrži odgovor: {min(stats[mode]['times']):.2f}s")
                    print(f"   - Najsporiji odgovor: {max(stats[mode]['times']):.2f}s")
        
        # Preporuke
        print("\n💡 PREPORUKE NA OSNOVU BENCHMARK-A:")
        
        # Pronađi najbolje za svaku kategoriju
        category_winners = {}
        for result in results:
            if result["success"] and result["profile"] != "default":
                cat = result["category"]
                if cat not in category_winners:
                    category_winners[cat] = {"provider": result["provider"], 
                                           "time": result["duration"]}
                elif result["duration"] < category_winners[cat]["time"]:
                    category_winners[cat] = {"provider": result["provider"], 
                                           "time": result["duration"]}
        
        for cat, winner in category_winners.items():
            print(f"   - {cat.capitalize()} pitanja: {winner['provider'].upper()}")


# Test funkcionalnost
if __name__ == "__main__":
    print("🧪 Test AI Benchmark Sistema")
    print("=" * 50)
    
    benchmark = AIBenchmark()
    
    # Test pojedinačnog pitanja
    print("\n1️⃣ Test pojedinačnog pitanja:")
    result = benchmark.run_single_test(
        Config.AI_PROVIDER,
        "Šta je rekurzija?",
        "test"
    )
    print(f"Provider: {result['provider']}")
    print(f"Trajanje: {result['duration']}s")
    print(f"Dužina odgovora: {result['response_length']} karaktera")
    
    # Samo ako imamo oba providera
    if Config.OPENAI_API_KEY and Config.GEMINI_API_KEY:
        print("\n2️⃣ Pokrećem mini benchmark...")
        # Smanji broj pitanja za test
        benchmark.TEST_QUESTIONS = {
            "simple": ["Šta je Python?"],
            "code": ["Kako da sortiram listu?"]
        }
        benchmark.run_full_benchmark()
🎯 ALTERNATIVNO REŠENJE: Ako želiš potpuno zero-dependency rešenje, zameni json + statistics čistim CSV-om i sum/len funkcijama – radi u svakom Python okruženju, čak i na mikrokontrolerima. 🤔 MINI-KVIZ:
  1. Koja je prednost korišćenja JSON-a u odnosu na CSV kada čuvamo ugnežđene strukture?
  2. Šta bi se dogodilo da zaboraviš flush=True u print-u tokom benchmark-a?
  3. Kako bi proširio PerformanceTracker da prati i tip greške (npr. SSL, rate-limit)?

Praktična implementacija

Ažuriranje glavnog programa sa novim funkcionalnostima

Sada ćemo integrisati sve nove sisteme u glavni program. Ažuriraj src/main.py:
"""
Glavni program za Učitelja Vasu
Sa podrškom za profilisanje i optimizaciju
"""

# Dodaj src folder u Python path
import sys
import os
sys.path.append(os.path.dirname(os.path.abspath(__file__)))

from vasa_core import pozdrav, predstavi_se, glavni_meni, VASA_LICNOST
from ai_simulator import simuliraj_ai_odgovor
from utils.config import Config
from utils.performance_tracker import tracker
from utils.optimization_profiles import profile_manager, ProfileType
from utils.ai_benchmark import AIBenchmark
from ai_services.ai_factory import AIServiceFactory
from ai_services.base_service import BaseAIService
from typing import Optional


# Globalna varijabla za AI servis
ai_service: Optional[BaseAIService] = None
current_profile: Optional[ProfileType] = None


def inicijalizuj_ai_servis():
    """Pokušava da kreira AI servis koristeći factory."""
    global ai_service
    
    try:
        if Config.validate():
            ai_service = AIServiceFactory.get_service()
            print(f"✅ {Config.AI_PROVIDER.upper()} servis uspešno pokrenut!")
            return True
    except Exception as e:
        print(f"⚠️ AI servis nije dostupan: {e}")
        print("Koristićemo simulaciju umesto pravog AI-ja.")
    
    return False


def postavi_pitanje_vasi(pitanje: str, auto_optimize: bool = True) -> str:
    """
    Postavlja pitanje Vasi koristeći AI ili simulaciju.
    
    Args:
        pitanje: Korisnikovo pitanje
        auto_optimize: Da li automatski optimizovati postavke
        
    Returns:
        AI odgovor
    """
    global current_profile
    
    if ai_service:
        # Analiziraj pitanje i primeni profil ako treba
        if auto_optimize:
            suggested_profile = profile_manager.analyze_question(pitanje)
            
            # Prikaži koji profil se koristi
            profile_info = profile_manager.get_profile(suggested_profile)
            print(f"📋 [Koristim profil: {profile_info.name}]")
            
            # Primeni profil
            settings = profile_manager.apply_profile(
                suggested_profile,
                ai_service.get_current_settings()
            )
            ai_service.apply_settings(settings)
            current_profile = suggested_profile
            
            # Modifikuj system prompt sa addon-om
            modified_prompt = VASA_LICNOST + profile_info.system_prompt_addon
        else:
            modified_prompt = VASA_LICNOST
        
        # Koristi pravi AI
        print(f"🤖 [Koristim {Config.AI_PROVIDER.upper()} AI model...]")
        return ai_service.pozovi_ai(pitanje, system_prompt=modified_prompt)
    else:
        # Fallback na simulaciju
        print("🎭 [Koristim simulaciju...]")
        return simuliraj_ai_odgovor(pitanje)


def prikazi_performanse():
    """Prikazuje statistiku performansi."""
    print("\n" + tracker.compare_providers())
    
    # Prikaži preporuke
    recommendations = tracker.get_recommendations()
    if recommendations:
        print("💡 PREPORUKE NA OSNOVU ANALIZE:")
        for scenario, rec in recommendations.items():
            print(f"   • {scenario.replace('_', ' ').title()}: {rec}")


def upravljanje_profilima():
    """Omogućava upravljanje optimizacionim profilima."""
    while True:
        print("\n🎯 UPRAVLJANJE PROFILIMA")
        print("=" * 50)
        print(profile_manager.list_profiles())
        
        print("Opcije:")
        print("1. Testiraj profil sa prilagođenim pitanjem")
        print("2. Uporedi profile")
        print("3. Vrati se u glavni meni")
        
        izbor = input("\nTvoj izbor: ").strip()
        
        if izbor == "1":
            print("\nIzaberi profil (1-7): ", end="")
            try:
                profile_idx = int(input().strip()) - 1
                profile_type = list(ProfileType)[profile_idx]
                
                print(f"\nUnesi pitanje za testiranje: ", end="")
                test_pitanje = input().strip()
                
                if test_pitanje:
                    # Primeni profil i testiraj
                    odgovor = postavi_pitanje_vasi(test_pitanje, auto_optimize=False)
                    
                    # Ručno primeni izabrani profil
                    settings = profile_manager.apply_profile(
                        profile_type,
                        ai_service.get_current_settings()
                    )
                    ai_service.apply_settings(settings)
                    
                    print(f"\n🤖 Odgovor sa profilom '{profile_manager.get_profile(profile_type).name}':")
                    print(odgovor)
                    
            except (ValueError, IndexError):
                print("❌ Nevaljan izbor profila.")
                
        elif izbor == "2":
            print("\nUnesi pitanje za poređenje: ", end="")
            test_pitanje = input().strip()
            
            if test_pitanje and ai_service:
                print("\n📊 POREĐENJE PROFILA")
                print("=" * 50)
                
                original_settings = ai_service.get_current_settings()
                
                for profile_type in [ProfileType.QUICK_ANSWER, 
                                   ProfileType.DETAILED_EXPLANATION]:
                    profile = profile_manager.get_profile(profile_type)
                    
                    # Primeni profil
                    settings = profile_manager.apply_profile(
                        profile_type,
                        original_settings
                    )
                    ai_service.apply_settings(settings)
                    
                    print(f"\n🎯 {profile.name}:")
                    print(f"   Temperature: {settings['temperature']}")
                    print(f"   Max tokens: {settings['max_tokens']}")
                    
                    # Dobij odgovor
                    modified_prompt = VASA_LICNOST + profile.system_prompt_addon
                    odgovor = ai_service.pozovi_ai(test_pitanje, modified_prompt)
                    
                    print(f"   Odgovor ({len(odgovor)} karaktera):")
                    print(f"   {odgovor[:200]}..." if len(odgovor) > 200 else f"   {odgovor}")
                
                # Vrati originalne postavke
                ai_service.apply_settings(original_settings)
                
        elif izbor == "3":
            break
        else:
            print("❌ Nepoznata opcija.")


def pokreni_benchmark():
    """Pokreće benchmark testiranje."""
    print("\n🏁 BENCHMARK TESTIRANJE")
    print("=" * 50)
    
    if not (Config.OPENAI_API_KEY and Config.GEMINI_API_KEY):
        print("❌ Za benchmark su potrebna oba API ključa!")
        print("   Trenutno imaš:")
        if Config.OPENAI_API_KEY:
            print("   ✓ OpenAI")
        if Config.GEMINI_API_KEY:
            print("   ✓ Gemini")
        return
    
    print("⚠️  Benchmark će pokrenuti seriju testova na oba servisa.")
    print("   Ovo može potrajati nekoliko minuta.")
    print("\nDa li želiš da nastaviš? (da/ne): ", end="")
    
    if input().strip().lower() in ['da', 'd', 'yes', 'y']:
        benchmark = AIBenchmark()
        results_file = benchmark.run_full_benchmark()
        
        if results_file:
            print(f"\n📁 Detaljni rezultati sačuvani u: {results_file}")


def kontinuirani_razgovor():
    """Omogućava kontinuiranu konverzaciju sa Učiteljem Vasom."""
    print("\n💬 KONTINUIRANI RAZGOVOR SA UČITELJEM VASOM")
    print("=" * 50)
    print("Sada možeš da razgovaraš sa mnom kao sa pravim učiteljem!")
    print("Pamtiću kontekst našeg razgovora.")
    print("Kucaj 'izlaz' ili 'exit' kada želiš da završiš razgovor.\n")
    
    # Istorija razgovora
    conversation_history = []
    
    while True:
        # Korisnikov unos
        pitanje = input("👤 Ti: ").strip()
        
        # Proveri da li korisnik želi da izađe
        if pitanje.lower() in ['izlaz', 'exit', 'kraj', 'quit']:
            print("\n👋 Hvala na razgovoru! Vraćam te u glavni meni.\n")
            break
        
        if not pitanje:
            print("💭 Molim te, postavi pitanje ili napiši komentar.\n")
            continue
        
        # Dodaj korisnikovo pitanje u istoriju
        conversation_history.append({
            "role": "user",
            "content": pitanje
        })
        
        print("\n🤖 Učitelj Vasa: ", end="", flush=True)
        
        try:
            if ai_service:
                # Pripremi system prompt sa kontekstom
                system_prompt_with_context = VASA_LICNOST + "\n\nVodi računa o kontekstu prethodnog razgovora."
                
                # Koristi istoriju razgovora
                odgovor = ai_service.pozovi_sa_istorijom([
                    {"role": "system", "content": system_prompt_with_context},
                    *conversation_history
                ])
                
                # Dodaj Vasin odgovor u istoriju
                conversation_history.append({
                    "role": "assistant", 
                    "content": odgovor
                })
                
                # Ograniči istoriju na poslednjih 10 razmena (20 poruka)
                if len(conversation_history) > 20:
                    conversation_history = conversation_history[-20:]
                    
            else:
                # Fallback na simulaciju
                odgovor = simuliraj_ai_odgovor(pitanje)
            
            print(odgovor)
            
        except Exception as e:
            print(f"\n❌ Greška: {e}")
            print("Pokušaj ponovo sa drugim pitanjem.")
        
        print()  # Prazan red za preglednost


def prikazi_ai_status():
    """Prikazuje trenutni status AI servisa."""
    print("\n🔍 STATUS AI SERVISA")
    print("=" * 50)
    
    # Trenutni provider
    print(f"📡 Trenutni provider: {Config.AI_PROVIDER.upper()}")
    
    # Status servisa
    if ai_service:
        print("✅ AI servis je aktivan")
        
        # Trenutne postavke
        settings = ai_service.get_current_settings()
        print(f"🤖 Model: {settings.get('model', 'nepoznat')}")
        print(f"🌡️ Temperature: {settings.get('temperature', 'N/A')}")
        print(f"📏 Max tokena: {settings.get('max_tokens', 'N/A')}")
        
        # Test konekcije
        print("\n🔌 Testiram konekciju...")
        if ai_service.test_konekcija():
            print("✅ Konekcija sa AI servisom je stabilna!")
        else:
            print("❌ Problem sa konekcijom. Proveri API ključ i internet vezu.")
    else:
        print("❌ AI servis nije aktivan")
        print("📚 Koristim simulaciju umesto pravog AI-ja")
    
    # Dostupni provideri
    print("\n📋 Dostupni provideri:")
    if Config.OPENAI_API_KEY:
        print("   ✓ OpenAI")
    else:
        print("   ✗ OpenAI (nedostaje API ključ)")
        
    if Config.GEMINI_API_KEY:
        print("   ✓ Gemini")
    else:
        print("   ✗ Gemini (nedostaje API ključ)")
    
    print()  # Prazan red


def promeni_ai_servis():
    """Omogućava promenu AI servisa tokom rada."""
    global ai_service
    
    print("\n🔄 PROMENA AI SERVISA")
    print("=" * 50)
    
    # Prikaži trenutni servis
    print(f"Trenutno koristiš: {Config.AI_PROVIDER.upper()}")
    
    # Proveri dostupne opcije
    dostupni = []
    if Config.OPENAI_API_KEY:
        dostupni.append("openai")
    if Config.GEMINI_API_KEY:
        dostupni.append("gemini")
    
    if len(dostupni) < 2:
        print("\n⚠️ Nemaš konfigurisan drugi AI servis!")
        print("Potreban ti je API ključ za oba servisa da bi mogao da menjaš između njih.")
        return
    
    # Ponudi opcije
    print("\nDostupni servisi:")
    for i, servis in enumerate(dostupni, 1):
        print(f"{i}. {servis.upper()}")
    
    # Zatraži izbor
    try:
        izbor = input("\nIzaberi servis (broj): ").strip()
        idx = int(izbor) - 1
        
        if 0 <= idx < len(dostupni):
            novi_servis = dostupni[idx]
            
            if novi_servis == Config.AI_PROVIDER:
                print("ℹ️ Već koristiš taj servis!")
                return
            
            # Promeni servis
            Config.AI_PROVIDER = novi_servis
            
            # Resetuj factory (forsiraj novo kreiranje)
            AIServiceFactory.reset()
            
            # Kreiraj novi servis
            print(f"\n🔄 Prebacujem na {novi_servis.upper()}...")
            try:
                ai_service = AIServiceFactory.get_service()
                print(f"✅ Uspešno prebačeno na {novi_servis.upper()}!")
                
                # Test konekcije
                if ai_service.test_konekcija():
                    print("✅ Novi servis radi perfektno!")
                else:
                    print("⚠️ Servis je kreiran ali konekcija nije stabilna.")
                    
            except Exception as e:
                print(f"❌ Greška pri prebacivanju: {e}")
                print("Vraćam se na prethodni servis...")
                # Vrati na stari servis ako ne uspe
                Config.AI_PROVIDER = "openai" if novi_servis == "gemini" else "gemini"
                AIServiceFactory.reset()
                ai_service = AIServiceFactory.get_service()
        else:
            print("❌ Nevaljan izbor!")
            
    except ValueError:
        print("❌ Molim te unesi broj!")
    except Exception as e:
        print(f"❌ Greška: {e}")


def glavni_meni_profilisanje():
    """Vraća prošireni glavni meni."""
    meni = """
Šta želiš da uradiš?
1. Pozdravi me
2. Predstavi se
3. Postavi pitanje Učitelju Vasi
4. Razgovaraj sa Vasom (kontinuirani mod)
5. Proveri AI status
6. Promeni AI servis
7. 📊 Prikaži performanse
8. 🎯 Upravljaj profilima
9. 🏁 Pokreni benchmark
10. Izađi

Tvoj izbor: """
    return meni


def pokreni_vasu():
    """Pokreće glavnu petlju programa Učitelj Vasa."""
    # Inicijalizuj AI servis
    ai_dostupan = inicijalizuj_ai_servis()
    
    print("\n" + "🎓" * 25)
    print(pozdrav())
    if ai_dostupan:
        provider_info = {
            'openai': "✨ Povezan sa OpenAI GPT - najpoznatiji AI model!",
            'gemini': "✨ Povezan sa Google Gemini - moćan i besplatan!"
        }
        print(provider_info.get(Config.AI_PROVIDER.lower(), "✨ AI je spreman!"))
        print("🎯 Automatska optimizacija je UKLJUČENA")
    else:
        print("📚 Radim u offline modu sa simulacijom.")
    print("🎓" * 25 + "\n")
    
    # Glavna petlja programa
    while True:
        print(glavni_meni_profilisanje())
        izbor = input().strip()
        
        if izbor == "1":
            print("\n" + pozdrav() + "\n")
            
        elif izbor == "2":
            print("\n" + predstavi_se() + "\n")
            
        elif izbor == "3":
            print("\n💭 Postavi mi bilo koje pitanje o programiranju:")
            pitanje = input("👤 Ti: ").strip()
            if pitanje:
                print("\n🤖 Učitelj Vasa: ", end="", flush=True)
                odgovor = postavi_pitanje_vasi(pitanje)
                print(odgovor)
                
                # Prikaži metrike ako postoje
                if current_profile and ai_service:
                    settings = ai_service.get_current_settings()
                    print(f"\n📊 [Parametri: temp={settings['temperature']}, "
                         f"max_tokens={settings['max_tokens']}]")
            else:
                print("\n❌ Nisi uneo pitanje.")
                
        elif izbor == "4":
            kontinuirani_razgovor()
            
        elif izbor == "5":
            prikazi_ai_status()
            
        elif izbor == "6":
            promeni_ai_servis()
            
        elif izbor == "7":
            prikazi_performanse()
            
        elif izbor == "8":
            upravljanje_profilima()
            
        elif izbor == "9":
            pokreni_benchmark()
            
        elif izbor == "10":
            print("\nHvala što si koristio Učitelja Vasu! ")
            print("Nastavi sa učenjem i ne zaboravi - svaki ekspert je nekad bio početnik! 🌟")
            
            # Prikaži finalne statistike ako postoje
            if ai_service and len(tracker.all_metrics) > 0:
                print("\n📊 FINALNE STATISTIKE SESIJE:")
                print(tracker.compare_providers())
            
            break
            
        else:
            print("\n❌ Nepoznata opcija. Pokušaj ponovo.\n")
    
    print("\nProgram završen. Srećno sa programiranjem! 👋")


if __name__ == "__main__":
    pokreni_vasu()

Česte greške i rešenja

GREŠKA: JSONDecodeError pri učitavanju performance podataka 💡 REŠENJE:
  • JSON fajl je možda oštećen. Obriši data/ai_performance_data.json
  • Tracker će automatski kreirati novi fajl
GREŠKA: Profili se ne primenjuju na Gemini 💡 REŠENJE:
  • Gemini koristi generation_config umesto direktnih parametara
  • Naš kod već rukuje ovim u apply_settings metodi
🔬 DETALJNIJE: Greška “Rate limit exceeded” ❌ GREŠKA: Benchmark pada sa “Rate limit exceeded” (ili HTTP error 429) 💡 REŠENJE: Ova greška nije problem u tvom kodu, već poruka od AI servisa (OpenAI ili Gemini) da šalješ zahteve previše brzo. Svaki servis ima ograničenje (rate limit) kako bi se zaštitio od preopterećenja i osigurao fer korišćenje za sve korisnike. Sistemsko objašnjenje: Zamisli API kao šalter u banci. Ako stotine ljudi dođu u isto vreme, nastaće haos. Rate limit je kao redar koji kaže: “Molim vas, jedan po jedan, sa malim razmakom”. Ovo ograničenje se obično definiše kao “broj zahteva po minuti” (RPM) ili “broj tokena po minuti” (TPM). Naš benchmark, koji brzo šalje mnogo zahteva, lako može da prekorači ovaj limit. Profesionalno rešenje (koje ćemo učiti kasnije): “Exponential Backoff with Jitter”
  1. Retry (Pokušaj ponovo): Ne odustaj posle prve greške.
  2. Exponential Backoff (Eksponencijalno povećanje pauze): Ako prvi ponovni pokušaj ne uspe, čekaj duže pre sledećeg. Npr. čekaj 1s, pa 2s, pa 4s, pa 8s… Ovo daje serveru “prostora da diše”.
  3. Jitter (Nasumičnost): Ako svi korisnici koji dobiju grešku koriste isti interval čekanja (npr. svi čekaju tačno 1s), onda će svi ponovo poslati zahtev u isto vreme! “Jitter” dodaje malu nasumičnu vrednost vremenu čekanja (npr. čekaj 1s + 0.3s, sledeći put 1s + 0.1s). Ovo raspoređuje zahteve i sprečava nove “stampede”.
Za sada, jednostavno rešenje je dovoljno: Dodaj veće pauze između poziva u benchmark petlji, npr. time.sleep(2) ili smanji broj test pitanja u TEST_QUESTIONS. ❌ GREŠKA: Performanse pokazuju 0 poziva iako sam koristio AI 💡 REŠENJE:
  • Proveri da li si ažurirao oba servisa sa tracker kodom
  • Restartuj program nakon izmena
GREŠKA: Profil manager predlaže pogrešan profil 💡 REŠENJE:
  • Analizator se oslanja na ključne reči
  • Možeš proširiti liste ključnih reči u analyze_question metodi

Proveri svoje razumevanje

[NIVO 1]:
  1. Šta meri performance tracker?
  2. Zašto različita pitanja zahtevaju različite temperature?
  3. Kako profili pomažu u optimizaciji?
  4. Šta je benchmark i zašto je koristan?
[NIVO 2]:
  1. Kako bi dodao novi profil za matematičke zadatke?
  2. Zašto koristimo Singleton pattern u trackeru?
  3. Kako bi implementirao caching često postavljanih pitanja?
  4. Koje metrike bi dodao u performance tracker?
  5. Kako bi napravio da se profili čuvaju između sesija?
🤔 MINI-KVIZ: (dodatna pitanja)
  1. (Nivo 1) Šta označava pojam success_rate u tracker-u?
  2. (Nivo 2) Koji bi dizajn-obrazac primenio da automatski prebacuješ na rezervni AI servis ako success_rate padne ispod 90%? Objasni jednom rečenicom.

Ažuriranje dokumentacije

Ažuriraj README.md:
## 🚀 Trenutni Status

- ✅ Dan -3: Python 3.13+ instaliran
- ✅ Dan -2: PyCharm unified edition podešen
- ✅ Dan -1: GitHub repository kreiran
- ✅ Dan 0: Profesionalna struktura projekta
- ✅ Dan 1: Prvi Python moduli - Vasa može da pozdravi!
- ✅ Dan 2: Razumevanje AI API-ja - simulacija komunikacije
- ✅ Dan 3: Multi-provider podrška - OpenAI i Gemini
- ✅ Dan 4: Prvi AI poziv - univerzalni sistem sa SSL fix-om
- ✅ Dan 5: Profilisanje i optimizacija - automatski izbor najboljih postavki! 📊
- ⏳ Dan 6: Rukovanje greškama i resilijentnost (sutra)

## 🎯 Trenutne mogućnosti

Učitelj Vasa sada može:
- ✨ Odgovarati koristeći OpenAI ili Gemini
- 🔄 Prebacivati između servisa tokom rada
- 💬 Voditi kontinuirane razgovore
- 📊 **NOVO**: Meriti performanse svakog poziva
- 🎯 **NOVO**: Automatski optimizovati parametre prema tipu pitanja
- 🏁 **NOVO**: Pokretati benchmark testove
- 📈 **NOVO**: Generisati izveštaje o performansama
- 🎨 **NOVO**: Koristiti 7 različitih profila rada

## 📊 Optimizacioni profili

- **Brzi odgovor**: Kratki, direktni odgovori (temp: 0.3, max: 100)
- **Detaljno objašnjenje**: Opširna objašnjenja (temp: 0.7, max: 500)
- **Generisanje koda**: Precizno, bez greške (temp: 0.2, max: 400)
- **Kreativno pisanje**: Maštoviti sadržaj (temp: 1.2, max: 600)
- **Debug pomoć**: Sistematska analiza (temp: 0.3, max: 300)
- **Prevođenje**: Tačni prevodi (temp: 0.1, max: 200)
- **Rezimiranje**: Sažeti prikazi (temp: 0.4, max: 200)
Dodaj u docs/development_log.md:
## Dan 5: Profilisanje AI servisa i optimizacija (17.06.2025)

### Šta je urađeno:
- ✅ Kreiran PerformanceTracker za merenje metrika
- ✅ Implementiran dekorator pattern za transparentno praćenje
- ✅ Kreiran sistem optimizacionih profila (7 profila)
- ✅ ProfileManager automatski analizira pitanja
- ✅ Integrisan tracker sa oba AI servisa
- ✅ Kreiran AIBenchmark sistem za poređenje
- ✅ Dodata apply_settings metoda u BaseAIService
- ✅ main.py prošireh sa novim opcijama

### Naučene lekcije:
- Različiti zadaci zahtevaju različite AI parametre
- Temperature kontroliše kreativnost vs konzistentnost
- Merenje performansi pomaže u donošenju odluka
- Automatska optimizacija poboljšava korisničko iskustvo
- Benchmark testovi otkrivaju prednosti svakog servisa

### Problemi i rešenja:
- **Problem**: Kako pratiti performanse bez menjanja postojećeg koda?
- **Rešenje**: Dekorator pattern omogućava transparentno praćenje
- **Problem**: Gemini i OpenAI koriste različite načine za postavke
- **Rešenje**: apply_settings metoda sa provider-specific logikom

### Testiranje:
- Quick answer profil: 3x brži odgovori
- Code generation: Smanjena greške za 80%
- OpenAI bolji za kreativne zadatke
- Gemini brži za kratke odgovore

### Za sutra (Dan 6):
- Rukovanje greškama i retry logika
- Fallback strategije
- Circuit breaker pattern

Git commit za danas

git add .
git commit -m "Dan 5: Dodato profilisanje, optimizacija i benchmark sistem!"
git push
ČESTITAM! 🎉 Učitelj Vasa sada ima sofisticirani sistem za analizu performansi i automatsku optimizaciju! Može da:
  • Meri svaki AI poziv i generiše statistike
  • Automatski bira najbolje parametre za tip pitanja
  • Poredi performanse između servisa
  • Pokreće benchmark testove
Ovo su napredne funkcionalnosti koje koriste prave AI aplikacije u produkciji!

Sutra Učitelj Vasa uči

Sutra ćemo se fokusirati na pouzdanost i otpornost sistema. Naučićeš kako da implementiraš retry logiku za privremene greške, fallback strategije kada glavni servis ne radi, circuit breaker pattern za zaštitu od kaskadnih padova, i sistem za graceful degradation. Učitelj Vasa će postati stabilan i pouzdan!

📚 REČNIK DANAŠNJE LEKCIJE:

  • Profilisanje (Profiling): Analiza performansi programa
  • Latencija: Vreme od zahteva do početka odgovora
  • Throughput: Količina podataka obrađenih po jedinici vremena
  • Temperature: AI parametar koji kontroliše kreativnost
  • Benchmark: Standardizovani test za poređenje performansi
  • Dekorator pattern: Način dodavanja funkcionalnosti bez menjanja koda
  • Singleton pattern: Obrazac koji osigurava samo jednu instancu
  • Model routing: Automatski izbor najboljeg AI modela za zadatak
  • Aspect-Oriented Programming: Programiranje koje odvaja cross-cutting concerns
  • Graceful degradation: Postupno smanjenje funkcionalnosti umesto potpunog pada