Dan 7/28: Napredna personalizacija učitelja Vase
Dan 7/28: Napredna personalizacija učitelja Vase
Vreme potrebno: 90 – 180 minuta
Gde je Učitelj Vasa danas?
Učitelj Vasa je stabilan i pouzdan AI asistent sa multi-provider podrškom, automatskom optimizacijom performansi i naprednim sistemom za rukovanje greškama. Može da prebacuje između OpenAI i Gemini servisa, automatski pokušava ponovo pri greškama i gracefully degradira kada servisi nisu dostupni. Ali još uvek pristupa svima isto – ne pamti ko mu postavlja pitanja niti prilagođava svoje ponašanje različitim korisnicima. Danas menjamo to!
Cilj današnje lekcije
Danas ćeš kreirati sistem korisničkih profila koji pamti preference svakog korisnika, implementirati kontekstualno svesno ponašanje koje se prilagođava iskustvu korisnika, i omogućiti Vasi da prepozna da li razgovara sa početnikom ili naprednim korisnikom. Nakon ove lekcije, Učitelj Vasa će postati personalizovan asistent koji se prilagođava svakom korisniku ponaosob!
Predznanja
- Funkcionalan resilient AI sistem (Dan 6)
- Razumevanje Config modula i čuvanja podataka (Dan 3)
- Factory pattern i BaseAIService interfejs (Dan 4)
- JSON format za čuvanje podataka (Dan 2)
- Osnovno razumevanje dictionary struktura u Python-u
Glavni sadržaj
Zašto je personalizacija važna za AI asistente?
Pre nego što krenemo sa implementacijom, hajde da razumemo zašto uopšte želimo da personalizujemo Učitelja Vasu.
📚 NIVO 1 – Osnovno objašnjenje
Zamisli dva učenika u razredu:
- Marko je tek počeo da uči programiranje – treba mu detaljno objašnjenje svake sitnice
- Ana programira godinu dana – želi brže, konkretnije odgovore bez osnovnih objašnjenja
Dobar učitelj prilagođava svoj pristup svakom učeniku. Isto treba da radi i Učitelj Vasa! Umesto da svima odgovara isto, trebalo bi da:
- Početnicima daje detaljnije objašnjenje sa više primera
- Naprednijima daje koncizniji odgovor sa fokusom na suštinu
- Pamti šta je ko pitao ranije i gradi na tom znanju
🚀 NIVO 2 – Dublje razumevanje
Personalizacija u AI sistemima omogućava:
- Adaptive Learning – sistem uči o korisniku tokom vremena
- Context Awareness – razumevanje trenutne situacije korisnika
- Preference Management – pamćenje kako korisnik voli da prima informacije
- Skill Level Tracking – praćenje napretka korisnika
Ovo se postiže kroz kombinaciju:
- User profila (trajno čuvanje podataka)
- Session konteksta (privremeni podaci tokom razgovora)
- Behavioral patterns (prepoznavanje obrazaca ponašanja)
🔍 UVID: Personalizacija nije samo “luksuz” – ona fundamentalno menja korisnost AI asistenta. Istraživanja pokazuju da personalizovani AI sistemi imaju 40-60% veću retenciju korisnika. Razlog je jednostavan: ljudi žele da se osećaju viđeni i razumljeni. Kada AI pamti tvoje preference i prilagođava se tvom nivou znanja, stvara se osećaj da imaš ličnog mentora, a ne generički alat.
💡 PRO TIP: Personalizaciju uvek započni sa “opt-in” pristupom. Pitaj korisnika da li želi da sistem pamti njegove preference. Transparentnost gradi poverenje, a poverenje je ključ dugotrajnog odnosa sa AI asistentom.
🎈 ZABAVNA ČINJENICA: Prvi personalizovani AI asistent bio je ELIZA iz 1966. godine. Iako je imala samo 200 linija koda, ljudi su satima razgovarali sa njom jer je “pamtila” delove razgovora i vraćala ih u pitanjima, stvarajući iluziju razumevanja!
Kreiranje sistema korisničkih profila
Počnimo sa implementacijom sistema koji će pamtiti informacije o svakom korisniku.
📚 NIVO 1 – Osnovno objašnjenje
Korisnički profil je kao karton u školi – sadrži osnovne informacije o učeniku i prati njegov napredak. Za Učitelja Vasu ćemo čuvati:
- Ime korisnika
- Nivo znanja (početnik, srednji, napredni)
- Broj postavljenih pitanja
- Omiljene teme
- Način na koji voli da prima objašnjenja
Sve ovo ćemo čuvati u JSON fajlu, baš kao što škola čuva kartone u ormaru.
🚀 NIVO 2 – Dublje razumevanje
Sistem profila će koristiti slojevitu arhitekturu:
- UserProfile klasa – predstavlja jednog korisnika
- ProfileManager – upravlja svim profilima
- ProfileAnalyzer – analizira ponašanje i predlaže prilagođavanja
- PreferenceEngine – primenjuje preference na AI odgovore
Podatke ćemo čuvati lokalno u JSON formatu, sa mogućnošću lake migracije na bazu podataka kasnije.
📊 DIJAGRAM: Tok podataka u sistemu profila
[Korisnički unos]
|
v
+-----------------------+ +--------------------------+
| ProfileManager |----->| UserProfile Objekat |
| (Upravljač Profila) | | (Podaci u memoriji) |
+-----------------------+ +--------------------------+
^ | ^
| (load) | (save) | (ažuriranje)
| v |
+-----------------------+ +--------------------------+
| korisnik_profile.json|----->| Aplikacija |
| (Fajl na disku) | | (Glavni program) |
+-----------------------+ +--------------------------+
🔍 UVID: Trenutni pristup sa JSON fajlovima je odličan za početak – jednostavan je i ne zahteva eksterne zavisnosti. Međutim, važno je razumeti njegove sistemske limite. Svako čuvanje i učitavanje je I/O (Input/Output) operacija na disku, što je relativno sporo. Takođe, ako bi više korisnika istovremeno pristupalo sistemu, moglo bi doći do konflikta pri pisanju u fajl. Arhitektura koju gradimo sa ProfileManager klasom je ključna, jer ona služi kao “adapter”. Kasnije, možemo zameniti logiku unutar ProfileManager-a da koristi pravu bazu podataka (npr. SQLite ili cloud bazu), bez potrebe da menjamo ostatak aplikacije.
💡 PRO TIP: Koristi @dataclass dekorator za klase koje prvenstveno čuvaju podatke. Automatski generiše __init__, __repr__ i druge metode, što čini kod kraćim i manje sklonim greškama. Dodatno, asdict() funkcija olakšava serijalizaciju u JSON.
⚡ SAVET ZA OPTIMIZACIJU: Keširanje profila u memoriji (self._current_profile) je pametan potez. Pristup memoriji je hiljadama puta brži od pristupa disku. Ipak, imaj na umu da save_profile i dalje piše na disk svaki put. Za aplikaciju sa jednim korisnikom, ovo je u redu. U sistemu sa više korisnika, razmislio bi o strategiji “lazy saving” – čuvanje promena tek na kraju sesije ili nakon određenog broja interakcija, kako bi se smanjio broj sporih I/O operacija.
🎯 ALTERNATIVNO REŠENJE: Ako više voliš “pravo” skladištenje od JSON-a, probaj mini SQLite bazu:
import sqlite3
def init_db(path="data/profiles.db"):
conn = sqlite3.connect(path)
conn.execute("""
CREATE TABLE IF NOT EXISTS profiles (
username TEXT PRIMARY KEY,
data TEXT NOT NULL
)
""")
return conn
def save_profile_sql(conn, profile):
conn.execute(
"REPLACE INTO profiles (username, data) VALUES (?, ?)",
(profile.username, json.dumps(profile.to_dict(), ensure_ascii=False))
)
conn.commit()
def load_profile_sql(conn, username):
cur = conn.execute(
"SELECT data FROM profiles WHERE username = ?", (username,)
)
row = cur.fetchone()
return (UserProfile.from_dict(json.loads(row[0]))
if row else None)
SQLite je ugrađen u Python standardnu biblioteku, pa nema dodatnih zavisnosti, a kasnije možeš migrirati na “pravu” bazu bez promene ostatka koda.
Kreiranje sistema za analizu korisničkog ponašanja
Sada ćemo kreirati sistem koji analizira kako korisnik interaguje sa Vasom i predlaže prilagođavanja.
📚 NIVO 1 – Osnovno objašnjenje
Ovaj sistem je kao posmatrač koji prati kako učenik uči:
- Da li postavlja kratka ili duga pitanja?
- Da li često traži primere koda?
- Da li mu trebaju detaljnija objašnjenja?
- Koliko brzo napreduje?
Na osnovu ovoga, sistem automatski prilagođava način na koji Vasa odgovara.
🚀 NIVO 2 – Dublje razumevanje
ProfileAnalyzer koristi heuristike i pattern recognition da identifikuje korisničke potrebe. Analizira:
- Lingvističke karakteristike pitanja
- Frekvenciju određenih tipova zahteva
- Brzinu napredovanja kroz teme
- Feedback patterns (implicitni kroz follow-up pitanja)
📊 DIJAGRAM: Proces analize korisničke poruke
["Šta je python funkcija i kako da je koristim?"] <-- Korisnička poruka
|
v
+---------------------------------------------+
| ProfileAnalyzer.analyze_message() |
| (Analizira tekst poruke po pravilima) |
+---------------------------------------------+
|
v
+---------------------------------------------+
| Rezultat Analize (dict) |
|---------------------------------------------|
| "topics": ["funkcije", "python_osnove"] |
| "skill_indicators": {"beginner": 2, ...} |
| "characteristics": {"length": 45, ...} |
+---------------------------------------------+
🎈 ZABAVNA ČINJENICA: IBM-ov Watson je tokom istorijskog nastupa na kvizu Jeopardy! (2011) patio od “personalizacije u suprotnom smeru”: tim je morao da ograniči koliko se Watson prilagođava stilu pitanja da ne bi previše optimizovao na istorijske podatke i počeo da pravi čudne greške uživo. Personalizacija je moćna – ali samo dok je pod kontrolom!
💡 PRO TIP: Koristi Counter iz collections modula za brzo brojanje elemenata. Mnogo je efikasniji od ručnog brojanja i ima korisne metode kao most_common() koje automatski sortiraju rezultate. Takođe, prilikom izgradnje personalizovanog system prompta, ubaci delić “meta-podatka” koji kaže kada je profil poslednji put ažuriran. Na taj način možeš lako debug-ovati situacije u kojima korisnik vidi “stari stil” odgovora.
Integracija personalizacije sa AI servisima
Sada ćemo integrisati sistem profila sa postojećim AI servisima.
📚 NIVO 1 – Osnovno objašnjenje
Do sada je Vasa svima odgovarao isto. Sada ćemo ga naučiti da:
- Pita za ime na početku
- Učita ili kreira profil za tog korisnika
- Prilagodi svoje odgovore prema profilu
- Ažurira profil nakon svakog razgovora
To je kao kada učitelj pamti svakog učenika i zna kako ko najbolje uči.
🚀 NIVO 2 – Dublje razumevanje
Integrisaćemo personalizaciju na tri nivoa:
- System prompt modifikacija – dinamički menjamo Vasinu ličnost
- Parameter tuning – prilagođavamo temperature i max_tokens
- Response filtering – post-procesiramo odgovore prema preferencama
Praktična implementacija
Kreiranje sistema za adaptive learning
Na kraju, kreirajmo sistem koji automatski prilagođava Vasino ponašanje tokom razgovora.
📊 DIJAGRAM: Adaptivna petlja učenja
+-------------------------------------+
| AI daje odgovor |
+-------------------------------------+
|
v
+-----------------------------+ +-------------------------------------+
| Korisnik reaguje: | --> | AdaptiveEngine analizira |
| "Ne razumem...", "Jasno!" | | reakciju korisnika |
+-----------------------------+ +-------------------------------------+
^ |
| v
+-----------------------------+ +-------------------------------------+
| AI generiše prilagođen | <-- | Predlaže se adaptacija: |
| sledeći odgovor | | "Pojednostavi", "Proširi" |
+-----------------------------+ +-------------------------------------+
⚡ SAVET ZA OPTIMIZACIJU: Adaptive engine trenutno analizira samo eksplicitne indikatore (“ne razumem”, “jasno”). Napredna verzija bi mogla da meri i implicitne signale: brzinu odgovora (brz odgovor = verovatno razume), dužinu follow-up pitanja (kratka = specific confusion), ili čak sentiment analizu. Ovo bi zahtevalo ML model, ali za početak, rule-based pristup odlično funkcioniše.
🔄 VEŽBA: Implementiraj jednostavnu enkripciju profila.
- Instaliraj biblioteku cryptography (biće potrebna tek na Dan 23, ali ovde je u edukativne svrhe).
- Dodaj metodu
encrypt_data(data: str) -> byteskoja AES-om šifruje JSON pre upisa na disk. - Modifikuj
save_profile()iload_profile()da transparentno kriptuju/dekriptuju sadržaj. - Razmisli: kako ćeš rotirati ključ ako korisnik resetuje lozinku?
Hint: za početnike dovoljno je da koristiš Fernet iz
cryptography.fernet. Napredniji mogu probati čuvanje ključa u.envfajlu i rotaciju preko verzionisanih ključeva.
Optimizacija i najbolje prakse
Ova sekcija sadrži dodatne savete za unapređenje sistema personalizacije koji si danas izgradio.
⚡ SAVET ZA OPTIMIZACIJU: U trenutnoj implementaciji, svaki put kada ažuriraš profil (npr. update_activity), poziva se save_profile(), što rezultuje upisom na disk. Za jednu sesiju sa 10 pitanja, to je 10 I/O operacija. Bolja strategija bi bila da se profil čuva samo jednom, na kraju sesije (npr. kada korisnik izabere opciju “Izađi”) ili nakon što se napravi značajniji broj promena. Ovo drastično smanjuje opterećenje na disku i čini aplikaciju bržom.
Dan 7: Kompletna implementacija sistema personalizacije
Ovaj dokument sadrži sve fajlove potrebne za implementaciju sistema personalizacije u projektu Učitelj Vasa.
Struktura fajlova
ucitelj-vasa/
├── src/
│ ├── personalization/
│ │ ├── __init__.py
│ │ ├── user_profile.py
│ │ ├── profile_analyzer.py
│ │ └── adaptive_engine.py
│ ├── ai_services/
│ │ └── base_service.py (ažuriran)
│ └── main.py (ažuriran)
└── data/
└── profiles/ (automatski se kreira)
1. src/personalization/init.py
"""
Personalization modul za Učitelja Vasu
"""
from .user_profile import UserProfile, ProfileManager, profile_manager
from .profile_analyzer import ProfileAnalyzer
from .adaptive_engine import AdaptiveEngine
__all__ = [
'UserProfile',
'ProfileManager',
'profile_manager',
'ProfileAnalyzer',
'AdaptiveEngine'
]
2. src/personalization/user_profile.py
"""
User Profile sistem za Učitelja Vasu
Omogućava personalizaciju iskustva za svakog korisnika
"""
import json
import os
from datetime import datetime, timedelta
from pathlib import Path
from typing import Dict, List, Optional, Any
from dataclasses import dataclass, field, asdict
from enum import Enum
class SkillLevel(Enum):
"""Nivoi znanja korisnika."""
BEGINNER = "beginner"
INTERMEDIATE = "intermediate"
ADVANCED = "advanced"
def to_serbian(self) -> str:
"""Vraća naziv na srpskom."""
translations = {
"beginner": "Početnik",
"intermediate": "Srednji nivo",
"advanced": "Napredni"
}
return translations.get(self.value, self.value)
class LearningStyle(Enum):
"""Stilovi učenja korisnika."""
VISUAL = "visual" # Voli dijagrame i ilustracije
TEXTUAL = "textual" # Preferira detaljne tekstualne opise
PRACTICAL = "practical" # Želi kod primere odmah
THEORETICAL = "theoretical" # Voli da razume teoriju prvo
def to_serbian(self) -> str:
"""Vraća naziv na srpskom."""
translations = {
"visual": "Vizuelni",
"textual": "Tekstualni",
"practical": "Praktični",
"theoretical": "Teorijski"
}
return translations.get(self.value, self.value)
@dataclass
class UserPreferences:
"""Korisničke preference za AI odgovore."""
response_length: str = "medium" # short, medium, long
code_examples: bool = True # Da li želi primere koda
use_analogies: bool = True # Da li voli analogije
language_mix: str = "mixed" # serbian, english, mixed
detail_level: int = 5 # 1-10 skala
def to_system_prompt_addon(self) -> str:
"""Konvertuje preference u dodatak za system prompt."""
prompt_parts = []
# Dužina odgovora
if self.response_length == "short":
prompt_parts.append("Daj kratke, koncizne odgovore.")
elif self.response_length == "long":
prompt_parts.append("Daj detaljne, opširne odgovore.")
# Primeri koda
if not self.code_examples:
prompt_parts.append("Izbegavaj primere koda osim ako nisu eksplicitno traženi.")
else:
prompt_parts.append("Uvek uključi relevantne primere koda.")
# Analogije
if not self.use_analogies:
prompt_parts.append("Fokusiraj se na tehničke detalje bez analogija.")
else:
prompt_parts.append("Koristi analogije iz svakodnevnog života za objašnjenja.")
# Jezik
if self.language_mix == "serbian":
prompt_parts.append("Koristi isključivo srpski jezik, čak i za tehničke termine.")
elif self.language_mix == "english":
prompt_parts.append("Koristi engleski za sve tehničke termine i objašnjenja.")
# Nivo detalja
if self.detail_level <= 3:
prompt_parts.append("Drži se samo osnova bez ulaženja u detalje.")
elif self.detail_level >= 8:
prompt_parts.append("Daj vrlo detaljne tehničke informacije.")
return " ".join(prompt_parts)
@dataclass
class UserProfile:
"""Profil korisnika sa svim relevantnim informacijama."""
username: str
created_at: str = field(default_factory=lambda: datetime.now().isoformat())
skill_level: SkillLevel = SkillLevel.BEGINNER
learning_style: LearningStyle = LearningStyle.PRACTICAL
preferences: UserPreferences = field(default_factory=UserPreferences)
# Statistike
total_questions: int = 0
topics_count: Dict[str, int] = field(default_factory=dict)
last_active: str = field(default_factory=lambda: datetime.now().isoformat())
session_count: int = 0
# Napredak
completed_topics: List[str] = field(default_factory=list)
current_learning_path: Optional[str] = None
achievements: List[str] = field(default_factory=list)
def update_activity(self, topic: Optional[str] = None):
"""Ažurira aktivnost korisnika."""
self.last_active = datetime.now().isoformat()
self.total_questions += 1
if topic:
self.topics_count[topic] = self.topics_count.get(topic, 0) + 1
def get_favorite_topics(self, limit: int = 3) -> List[str]:
"""Vraća omiljene teme korisnika."""
sorted_topics = sorted(
self.topics_count.items(),
key=lambda x: x[1],
reverse=True
)
return [topic for topic, _ in sorted_topics[:limit]]
def calculate_engagement_score(self) -> float:
"""Računa skor angažovanosti korisnika (0-100)."""
score = 0.0
# Aktivnost u poslednjih 7 dana
last_active_date = datetime.fromisoformat(self.last_active)
days_inactive = (datetime.now() - last_active_date).days
if days_inactive == 0:
score += 30
elif days_inactive <= 3:
score += 20
elif days_inactive <= 7:
score += 10
# Broj pitanja
if self.total_questions >= 50:
score += 20
elif self.total_questions >= 20:
score += 15
elif self.total_questions >= 10:
score += 10
elif self.total_questions >= 5:
score += 5
# Raznovrsnost tema
topic_diversity = len(self.topics_count)
if topic_diversity >= 10:
score += 20
elif topic_diversity >= 5:
score += 15
elif topic_diversity >= 3:
score += 10
# Achievements
score += min(30, len(self.achievements) * 5)
return min(100, score)
def should_level_up(self) -> bool:
"""Proverava da li korisnik treba da pređe na viši nivo."""
if self.skill_level == SkillLevel.BEGINNER:
return (self.total_questions >= 30 and
len(self.completed_topics) >= 5)
elif self.skill_level == SkillLevel.INTERMEDIATE:
return (self.total_questions >= 100 and
len(self.completed_topics) >= 15)
return False
def level_up(self):
"""Podiže korisnika na viši nivo."""
if self.skill_level == SkillLevel.BEGINNER:
self.skill_level = SkillLevel.INTERMEDIATE
self.achievements.append("intermediate_level_reached")
elif self.skill_level == SkillLevel.INTERMEDIATE:
self.skill_level = SkillLevel.ADVANCED
self.achievements.append("advanced_level_reached")
def to_dict(self) -> Dict[str, Any]:
"""Konvertuje profil u dictionary za čuvanje."""
data = asdict(self)
data['skill_level'] = self.skill_level.value
data['learning_style'] = self.learning_style.value
return data
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> 'UserProfile':
"""Kreira profil iz dictionary podataka."""
# Konvertuj enum vrednosti
if 'skill_level' in data:
data['skill_level'] = SkillLevel(data['skill_level'])
if 'learning_style' in data:
data['learning_style'] = LearningStyle(data['learning_style'])
# Konvertuj preferences
if 'preferences' in data and isinstance(data['preferences'], dict):
data['preferences'] = UserPreferences(**data['preferences'])
return cls(**data)
class ProfileManager:
"""Upravlja svim korisničkim profilima."""
def __init__(self, storage_path: Optional[Path] = None):
"""
Inicijalizuje ProfileManager.
Args:
storage_path: Putanja do foldera za čuvanje profila
"""
if storage_path is None:
# Default putanja
self.storage_path = Path(__file__).parent.parent.parent / "data" / "profiles"
else:
self.storage_path = storage_path
# Kreiraj folder ako ne postoji
self.storage_path.mkdir(parents=True, exist_ok=True)
# Keširan trenutni profil
self._current_profile: Optional[UserProfile] = None
def _get_profile_path(self, username: str) -> Path:
"""Vraća putanju do fajla profila."""
# Sanitizuj username za bezbedno ime fajla
safe_username = "".join(c for c in username if c.isalnum() or c in "._-")
return self.storage_path / f"{safe_username}_profile.json"
def create_profile(self, username: str) -> UserProfile:
"""
Kreira novi profil korisnika.
Args:
username: Korisničko ime
Returns:
Novi UserProfile objekat
"""
profile = UserProfile(username=username)
self.save_profile(profile)
return profile
def load_profile(self, username: str) -> Optional[UserProfile]:
"""
Učitava postojeći profil.
Args:
username: Korisničko ime
Returns:
UserProfile ili None ako ne postoji
"""
profile_path = self._get_profile_path(username)
if not profile_path.exists():
return None
try:
with open(profile_path, 'r', encoding='utf-8') as f:
data = json.load(f)
return UserProfile.from_dict(data)
except Exception as e:
print(f"⚠️ Greška pri učitavanju profila: {e}")
return None
def save_profile(self, profile: UserProfile):
"""
Čuva profil na disk.
Args:
profile: UserProfile objekat za čuvanje
"""
profile_path = self._get_profile_path(profile.username)
try:
with open(profile_path, 'w', encoding='utf-8') as f:
json.dump(profile.to_dict(), f, indent=2, ensure_ascii=False)
except Exception as e:
print(f"❌ Greška pri čuvanju profila: {e}")
def get_or_create_profile(self, username: str) -> UserProfile:
"""
Učitava postojeći ili kreira novi profil.
Args:
username: Korisničko ime
Returns:
UserProfile objekat
"""
profile = self.load_profile(username)
if profile is None:
print(f"🆕 Kreiram novi profil za: {username}")
profile = self.create_profile(username)
else:
print(f"✅ Učitan postojeći profil za: {username}")
profile.session_count += 1
self.save_profile(profile)
self._current_profile = profile
return profile
def get_current_profile(self) -> Optional[UserProfile]:
"""Vraća trenutno aktivni profil."""
return self._current_profile
def list_all_profiles(self) -> List[str]:
"""
Lista sva korisnička imena sa profilima.
Returns:
Lista korisničkih imena
"""
profiles = []
for profile_file in self.storage_path.glob("*_profile.json"):
username = profile_file.stem.replace("_profile", "")
profiles.append(username)
return sorted(profiles)
def delete_profile(self, username: str) -> bool:
"""
Briše profil korisnika.
Args:
username: Korisničko ime
Returns:
True ako je uspešno obrisano
"""
profile_path = self._get_profile_path(username)
if profile_path.exists():
try:
profile_path.unlink()
if self._current_profile and self._current_profile.username == username:
self._current_profile = None
return True
except Exception as e:
print(f"❌ Greška pri brisanju profila: {e}")
return False
def get_profile_summary(self, username: str) -> str:
"""
Vraća kratak pregled profila.
Args:
username: Korisničko ime
Returns:
Formatiran string sa pregledom
"""
profile = self.load_profile(username)
if not profile:
return f"Profil '{username}' ne postoji."
favorite_topics = profile.get_favorite_topics()
engagement = profile.calculate_engagement_score()
summary = f"""
📊 PROFIL: {profile.username}
{'=' * 40}
📚 Nivo: {profile.skill_level.to_serbian()}
🎯 Stil učenja: {profile.learning_style.to_serbian()}
❓ Ukupno pitanja: {profile.total_questions}
🏆 Dostignuća: {len(profile.achievements)}
💯 Angažovanost: {engagement:.0f}%
⭐ Omiljene teme: {', '.join(favorite_topics) if favorite_topics else 'Nema još'}
📅 Poslednja aktivnost: {profile.last_active[:10]}
"""
return summary.strip()
# Globalna instanca
profile_manager = ProfileManager()
3. src/personalization/profile_analyzer.py
"""
Profile Analyzer za Učitelja Vasu
Analizira korisničko ponašanje i predlaže prilagođavanja
"""
import re
from typing import Dict, List, Tuple, Optional
from collections import Counter
from datetime import datetime, timedelta
from .user_profile import UserProfile, SkillLevel, LearningStyle
class ProfileAnalyzer:
"""Analizira korisničke profile i ponašanje."""
# Ključne reči za detekciju tema
TOPIC_KEYWORDS = {
"python_osnove": ["python", "promenljiv", "variable", "tip", "string", "broj", "lista"],
"funkcije": ["funkcij", "def", "return", "parametar", "argument"],
"klase": ["klasa", "class", "objekat", "metod", "nasledjivanje"],
"greske": ["greška", "error", "exception", "try", "except", "debug"],
"api": ["api", "request", "response", "endpoint", "json"],
"git": ["git", "commit", "branch", "merge", "repository"],
"web": ["web", "html", "css", "javascript", "frontend", "backend"],
"baze": ["baza", "sql", "database", "query", "tabela"],
"ai": ["ai", "veštačk", "inteligencij", "machine learning", "neural"]
}
# Indikatori nivoa znanja
SKILL_INDICATORS = {
"beginner": [
"šta je", "kako da", "ne razumem", "objasni", "pokaži primer",
"prvi put", "početnik", "osnov", "jednostavn"
],
"intermediate": [
"zašto", "razlika između", "kada koristiti", "najbolja praksa",
"efikasnij", "alternativ", "kako funkcioniše"
],
"advanced": [
"optimizacij", "performans", "složenost", "algoritam",
"arhitektur", "pattern", "skalabilnost", "concurrency"
]
}
def analyze_message(self, message: str) -> Dict[str, any]:
"""
Analizira pojedinačnu poruku korisnika.
Args:
message: Poruka za analizu
Returns:
Dict sa rezultatima analize
"""
message_lower = message.lower()
# Detektuj temu
detected_topics = []
for topic, keywords in self.TOPIC_KEYWORDS.items():
if any(keyword in message_lower for keyword in keywords):
detected_topics.append(topic)
# Detektuj nivo
skill_scores = {
"beginner": 0,
"intermediate": 0,
"advanced": 0
}
for level, indicators in self.SKILL_INDICATORS.items():
for indicator in indicators:
if indicator in message_lower:
skill_scores[level] += 1
# Analiziraj karakteristike pitanja
characteristics = {
"length": len(message),
"has_code": bool(re.search(r'`.*?`|def\s+\w+|class\s+\w+', message)),
"is_question": message.strip().endswith("?"),
"complexity": self._calculate_complexity(message),
"requests_example": any(word in message_lower for word in
["primer", "pokaži", "demonstr", "kako izgleda"])
}
return {
"topics": detected_topics,
"skill_indicators": skill_scores,
"characteristics": characteristics,
"suggested_level": max(skill_scores, key=skill_scores.get)
}
def _calculate_complexity(self, message: str) -> float:
"""
Računa složenost pitanja (0-10 skala).
Args:
message: Poruka za analizu
Returns:
Skor složenosti
"""
score = 0.0
# Dužina doprinosi složenosti
if len(message) > 200:
score += 2
elif len(message) > 100:
score += 1
# Tehničke reči
tech_words = ["algoritam", "struktur", "implement", "optimiz",
"performans", "async", "thread", "memory"]
tech_count = sum(1 for word in tech_words if word in message.lower())
score += min(3, tech_count)
# Više rečenica = veća složenost
sentences = len(re.split(r'[.!?]+', message))
if sentences > 3:
score += 2
elif sentences > 1:
score += 1
# Kod blokovi
if re.search(r'```.*?```', message, re.DOTALL):
score += 2
return min(10, score)
def analyze_conversation_history(
self,
messages: List[str],
profile: UserProfile
) -> Dict[str, any]:
"""
Analizira celu istoriju razgovora.
Args:
messages: Lista poruka korisnika
profile: Korisnički profil
Returns:
Agregirana analiza
"""
if not messages:
return {}
# Analiziraj svaku poruku
analyses = [self.analyze_message(msg) for msg in messages]
# Agregiraj teme
all_topics = []
for analysis in analyses:
all_topics.extend(analysis["topics"])
topic_counts = Counter(all_topics)
# Prosečna složenost
avg_complexity = sum(a["characteristics"]["complexity"]
for a in analyses) / len(analyses)
# Učestalost traženja primera
example_rate = sum(1 for a in analyses
if a["characteristics"]["requests_example"]) / len(analyses)
# Preporučeni nivo na osnovu svih poruka
skill_totals = {"beginner": 0, "intermediate": 0, "advanced": 0}
for analysis in analyses:
for level, score in analysis["skill_indicators"].items():
skill_totals[level] += score
recommended_level = max(skill_totals, key=skill_totals.get)
return {
"total_messages": len(messages),
"top_topics": topic_counts.most_common(3),
"average_complexity": avg_complexity,
"example_request_rate": example_rate,
"recommended_skill_level": recommended_level,
"skill_confidence": skill_totals[recommended_level] / sum(skill_totals.values())
if sum(skill_totals.values()) > 0 else 0
}
def suggest_profile_updates(
self,
profile: UserProfile,
recent_messages: List[str]
) -> List[Tuple[str, any]]:
"""
Predlaže ažuriranja profila na osnovu skorašnje aktivnosti.
Args:
profile: Trenutni profil
recent_messages: Poslednjih N poruka
Returns:
Lista (atribut, nova_vrednost) tuplova
"""
suggestions = []
if len(recent_messages) < 5:
return suggestions # Premalo podataka
# Analiziraj skorašnje poruke
analysis = self.analyze_conversation_history(recent_messages, profile)
# Predlog za skill level
if analysis["skill_confidence"] > 0.7:
recommended = analysis["recommended_skill_level"]
current = profile.skill_level.value
if recommended != current:
if recommended == "intermediate" and current == "beginner":
suggestions.append(("skill_level", SkillLevel.INTERMEDIATE))
elif recommended == "advanced" and current == "intermediate":
suggestions.append(("skill_level", SkillLevel.ADVANCED))
# Predlog za learning style
if analysis["example_request_rate"] > 0.6:
if profile.learning_style != LearningStyle.PRACTICAL:
suggestions.append(("learning_style", LearningStyle.PRACTICAL))
elif analysis["average_complexity"] > 7:
if profile.learning_style != LearningStyle.THEORETICAL:
suggestions.append(("learning_style", LearningStyle.THEORETICAL))
# Predlog za response length
avg_msg_length = sum(len(msg) for msg in recent_messages) / len(recent_messages)
if avg_msg_length < 50 and profile.preferences.response_length != "short":
suggestions.append(("preferences.response_length", "short"))
elif avg_msg_length > 150 and profile.preferences.response_length != "long":
suggestions.append(("preferences.response_length", "long"))
return suggestions
def generate_personalized_prompt_addon(
self,
profile: UserProfile,
current_topic: Optional[str] = None
) -> str:
"""
Generiše personalizovan dodatak za system prompt.
Args:
profile: Korisnički profil
current_topic: Trenutna tema razgovora
Returns:
Dodatak za system prompt
"""
parts = []
# Osnovno prilagođavanje nivou
if profile.skill_level == SkillLevel.BEGINNER:
parts.append(
"Korisnik je početnik. Koristi jednostavne termine, "
"daj detaljne korake i izbegavaj napredne koncepte."
)
elif profile.skill_level == SkillLevel.INTERMEDIATE:
parts.append(
"Korisnik ima osnovno znanje. Možeš koristiti tehničke termine "
"ali ih objasni kada su novi. Fokusiraj se na praktičnu primenu."
)
else: # ADVANCED
parts.append(
"Korisnik je napredan. Možeš koristiti složene koncepte, "
"govoriti o optimizaciji i arhitekturi bez detaljnih objašnjenja osnova."
)
# Prilagođavanje stilu učenja
if profile.learning_style == LearningStyle.VISUAL:
parts.append("Koristi ASCII dijagrame i vizuelne reprezentacije kad god je moguće.")
elif profile.learning_style == LearningStyle.PRACTICAL:
parts.append("Fokusiraj se na praktične primere koda koje korisnik može odmah isprobati.")
elif profile.learning_style == LearningStyle.THEORETICAL:
parts.append("Objasni teorijske osnove i razloge zašto nešto funkcioniše kako funkcioniše.")
# Dodaj preference
parts.append(profile.preferences.to_system_prompt_addon())
# Kontekstualne informacije
if current_topic and current_topic in profile.topics_count:
times = profile.topics_count[current_topic]
if times > 5:
parts.append(f"Korisnik je već postavljao pitanja o ovoj temi {times} puta, "
"tako da možeš graditi na prethodnom znanju.")
# Personalizovani pozdrav
if profile.total_questions < 5:
parts.append("Korisnik je nov, budi posebno ljubazan i ohrabrujući.")
elif profile.total_questions > 50:
parts.append(f"Pozdravi korisnika kao 'dragi {profile.username}' - već se dobro poznajete.")
return " ".join(parts)
4. src/personalization/adaptive_engine.py
"""
Adaptive Learning Engine za Učitelja Vasu
Automatski prilagođava ponašanje tokom razgovora
"""
from typing import List, Dict, Optional, Tuple
from datetime import datetime
import json
from .user_profile import UserProfile, SkillLevel
from .profile_analyzer import ProfileAnalyzer
class AdaptiveEngine:
"""Engine koji dinamički prilagođava AI ponašanje."""
def __init__(self):
self.analyzer = ProfileAnalyzer()
self.session_data = {
"confusion_indicators": 0,
"understanding_indicators": 0,
"questions_asked": 0,
"topics_covered": set(),
"adaptations_made": []
}
def analyze_user_response(self, response: str) -> Dict[str, any]:
"""
Analizira korisnikov odgovor na AI objašnjenje.
Args:
response: Korisnička poruka
Returns:
Analiza sa indikatorima razumevanja
"""
response_lower = response.lower()
# Indikatori konfuzije
confusion_words = [
"ne razumem", "nije jasno", "zbunjuje", "komplikovano",
"možeš li ponovo", "ne kapiram", "šta", "kako to",
"zašto baš tako", "previše informacija"
]
# Indikatori razumevanja
understanding_words = [
"razumem", "jasno", "ima smisla", "okej", "važi",
"super", "hvala", "shvatam", "logično", "aha"
]
# Follow-up pitanja
is_followup = "?" in response and len(response) < 100
# Brojanje indikatora
confusion_count = sum(1 for word in confusion_words if word in response_lower)
understanding_count = sum(1 for word in understanding_words if word in response_lower)
# Ažuriraj session data
self.session_data["confusion_indicators"] += confusion_count
self.session_data["understanding_indicators"] += understanding_count
return {
"shows_confusion": confusion_count > 0,
"shows_understanding": understanding_count > 0,
"is_followup_question": is_followup,
"confidence_score": self._calculate_confidence_score()
}
def _calculate_confidence_score(self) -> float:
"""Računa skor poverenja korisnika (0-1)."""
total = (self.session_data["confusion_indicators"] +
self.session_data["understanding_indicators"])
if total == 0:
return 0.5 # Neutralno
return self.session_data["understanding_indicators"] / total
def suggest_adaptation(
self,
profile: UserProfile,
last_response_analysis: Dict[str, any]
) -> Optional[Dict[str, any]]:
"""
Predlaže prilagođavanje na osnovu analize.
Args:
profile: Korisnički profil
last_response_analysis: Analiza poslednjeg odgovora
Returns:
Predlog prilagođavanja ili None
"""
if last_response_analysis["shows_confusion"]:
# Korisnik je zbunjen
if profile.skill_level == SkillLevel.BEGINNER:
return {
"action": "simplify",
"suggestion": "Koristi još jednostavnije objašnjenje sa analogijom",
"prompt_addon": "Objasni ponovo, ali još jednostavnije. "
"Koristi analogiju iz svakodnevnog života."
}
else:
return {
"action": "clarify",
"suggestion": "Razloži na korake",
"prompt_addon": "Razloži objašnjenje na numerisane korake."
}
elif last_response_analysis["is_followup_question"]:
# Dublje objašnjenje
return {
"action": "elaborate",
"suggestion": "Daj detaljnije objašnjenje",
"prompt_addon": "Daj detaljnije objašnjenje sa fokusom na pitanje korisnika."
}
elif last_response_analysis["confidence_score"] > 0.8:
# Korisnik dobro razume
if self.session_data["questions_asked"] > 5:
return {
"action": "advance",
"suggestion": "Pređi na naprednije koncepte",
"prompt_addon": "Korisnik dobro razume. Možeš preći na naprednije aspekte."
}
return None
def apply_adaptation(
self,
adaptation: Dict[str, any],
original_prompt: str
) -> str:
"""
Primenjuje prilagođavanje na prompt.
Args:
adaptation: Predlog prilagođavanja
original_prompt: Originalni prompt
Returns:
Prilagođen prompt
"""
# Zapamti prilagođavanje
self.session_data["adaptations_made"].append({
"time": datetime.now().isoformat(),
"action": adaptation["action"]
})
# Primeni na prompt
return f"{original_prompt}\n\n[PRILAGOĐAVANJE: {adaptation['prompt_addon']}]"
def generate_session_summary(self) -> Dict[str, any]:
"""Generiše rezime sesije za čuvanje u profilu."""
confidence = self._calculate_confidence_score()
return {
"duration_questions": self.session_data["questions_asked"],
"final_confidence": confidence,
"topics_covered": list(self.session_data["topics_covered"]),
"adaptations_count": len(self.session_data["adaptations_made"]),
"recommendation": self._generate_recommendation(confidence)
}
def _generate_recommendation(self, confidence: float) -> str:
"""Generiše preporuku za dalji rad."""
if confidence < 0.3:
return "Preporučujem dodatno vežbanje osnova pre novih tema."
elif confidence < 0.7:
return "Solidno napredovanje, nastavi trenutnim tempom."
else:
return "Odlično razumevanje! Spreman si za naprednije teme."
def reset_session(self):
"""Resetuje session podatke za novi razgovor."""
self.session_data = {
"confusion_indicators": 0,
"understanding_indicators": 0,
"questions_asked": 0,
"topics_covered": set(),
"adaptations_made": []
}
5. Ažuriran src/ai_services/base_service.py
Dodajte ovu metodu u postojeću BaseAIService klasu:
# Na početak fajla dodajte import:
import re
# U klasu BaseAIService dodajte ovu metodu:
def pozovi_ai_personalizovano(
self,
poruka: str,
profile: 'UserProfile',
base_system_prompt: str
) -> str:
"""
Poziva AI sa personalizovanim podešavanjima.
Args:
poruka: Korisnikova poruka
profile: Korisnički profil
base_system_prompt: Osnovni system prompt
Returns:
Personalizovan AI odgovor
"""
# Import ovde da izbegnemo ciklične importe
from personalization.user_profile import UserProfile
from personalization.profile_analyzer import ProfileAnalyzer
# Generiši personalizovan system prompt
analyzer = ProfileAnalyzer()
# Detektuj temu trenutnog pitanja
message_analysis = analyzer.analyze_message(poruka)
current_topic = message_analysis["topics"][0] if message_analysis["topics"] else None
# Dodaj personalizaciju na base prompt
personalized_addon = analyzer.generate_personalized_prompt_addon(profile, current_topic)
full_system_prompt = f"{base_system_prompt}\n\n{personalized_addon}"
# Prilagodi parametre prema profilu
original_settings = self.get_current_settings()
# Prilagodi temperature prema skill level
if profile.skill_level.value == "beginner":
self.apply_settings({"temperature": 0.5}) # Konzistentniji odgovori
elif profile.skill_level.value == "advanced":
self.apply_settings({"temperature": 0.8}) # Kreativniji odgovori
# Prilagodi max_tokens prema preferencama
if profile.preferences.response_length == "short":
self.apply_settings({"max_tokens": 100})
elif profile.preferences.response_length == "long":
self.apply_settings({"max_tokens": 300})
try:
# Pozovi AI sa personalizovanim postavkama
response = self.pozovi_ai(poruka, full_system_prompt)
# Post-procesiranje prema preferencama
if not profile.preferences.code_examples and "```" in response:
# Ukloni code blokove ako korisnik ne želi primere
response = re.sub(r'```[\s\S]*?```', '[kod primer uklonjen]', response)
return response
finally:
# Vrati originalne postavke
self.apply_settings(original_settings)
6. Kompletni ažurirani main.py
"""
Glavni program za Učitelja Vasu
Sa podrškom za profilisanje, optimizaciju i personalizaciju
"""
# Dodaj src folder u Python path
import sys
import os
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
import re
from vasa_core import pozdrav, predstavi_se, 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 as optimization_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
# Resilience importi
from utils.circuit_breaker import get_all_circuits_status, CircuitOpenError
from utils.fallback_manager import fallback_manager
from utils.retry_handler import smart_retry
# Personalizacija importi - sa preimenovanjem da izbegnemo konflikte
from personalization.user_profile import profile_manager as user_profile_manager, SkillLevel, LearningStyle
from personalization.profile_analyzer import ProfileAnalyzer
from personalization.adaptive_engine import AdaptiveEngine
# Globalne varijable
ai_service: Optional[BaseAIService] = None
optimization_profile: Optional[ProfileType] = None # Za optimizacione profile
current_user_profile = None # Za korisničke profile
conversation_history = []
analyzer = ProfileAnalyzer()
adaptive_engine = AdaptiveEngine()
def dobrodoslica_i_profil():
"""Pozdravlja korisnika i učitava/kreira profil."""
global current_user_profile
print("\n" + "🎓" * 25)
print("Dobrodošao u Učitelja Vasu - tvog personalnog AI asistenta!")
print("🎓" * 25 + "\n")
# Prikaži postojeće profile
existing_profiles = user_profile_manager.list_all_profiles()
if existing_profiles:
print("📚 Postojeći profili:")
for i, username in enumerate(existing_profiles, 1):
print(f" {i}. {username}")
print(f" {len(existing_profiles) + 1}. Kreiraj novi profil")
while True:
izbor = input("\nIzaberi opciju (broj): ").strip()
try:
idx = int(izbor) - 1
if 0 <= idx < len(existing_profiles):
username = existing_profiles[idx]
current_user_profile = user_profile_manager.get_or_create_profile(username)
break
elif idx == len(existing_profiles):
# Novi profil
username = input("\nUnesi svoje ime: ").strip()
if username:
current_user_profile = user_profile_manager.get_or_create_profile(username)
postavi_pocetne_preference()
break
except ValueError:
print("❌ Molim te unesi broj.")
else:
print("🆕 Izgleda da si nov ovde!")
username = input("Kako se zoveš? ").strip()
if username:
current_user_profile = user_profile_manager.get_or_create_profile(username)
postavi_pocetne_preference()
# Prikaži personalizovan pozdrav
if current_user_profile:
print(f"\n✨ Zdravo {current_user_profile.username}!")
print(user_profile_manager.get_profile_summary(current_user_profile.username))
def postavi_pocetne_preference():
"""Postavlja početne preference za novog korisnika."""
global current_user_profile
print("\n🎯 Hajde da podesimo tvoje preference!")
print("=" * 50)
# Nivo znanja
print("\n📚 Koji je tvoj nivo programiranja?")
print("1. Početnik - tek počinjem")
print("2. Srednji - znam osnove")
print("3. Napredni - imam iskustva")
while True:
nivo = input("\nTvoj izbor (1-3): ").strip()
if nivo == "1":
current_user_profile.skill_level = SkillLevel.BEGINNER
break
elif nivo == "2":
current_user_profile.skill_level = SkillLevel.INTERMEDIATE
break
elif nivo == "3":
current_user_profile.skill_level = SkillLevel.ADVANCED
break
# Stil učenja
print("\n🎨 Kako najlakše učiš?")
print("1. Kroz praktične primere koda")
print("2. Kroz detaljne tekstualne opise")
print("3. Kroz dijagrame i vizuelne prikaze")
print("4. Kroz teorijske koncepte")
while True:
stil = input("\nTvoj izbor (1-4): ").strip()
if stil == "1":
current_user_profile.learning_style = LearningStyle.PRACTICAL
break
elif stil == "2":
current_user_profile.learning_style = LearningStyle.TEXTUAL
break
elif stil == "3":
current_user_profile.learning_style = LearningStyle.VISUAL
break
elif stil == "4":
current_user_profile.learning_style = LearningStyle.THEORETICAL
break
# Dužina odgovora
print("\n📏 Kakve odgovore preferiraš?")
print("1. Kratke i koncizne")
print("2. Umerene dužine")
print("3. Detaljne i opširne")
while True:
duzina = input("\nTvoj izbor (1-3): ").strip()
if duzina == "1":
current_user_profile.preferences.response_length = "short"
break
elif duzina == "2":
current_user_profile.preferences.response_length = "medium"
break
elif duzina == "3":
current_user_profile.preferences.response_length = "long"
break
# Sačuvaj profil
user_profile_manager.save_profile(current_user_profile)
print("\n✅ Tvoje preference su sačuvane!")
def postavi_pitanje_vasi(pitanje: str, auto_optimize: bool = True) -> str:
"""
Postavlja pitanje Vasi sa personalizacijom i optimizacijom.
Args:
pitanje: Korisnikovo pitanje
auto_optimize: Da li automatski optimizovati postavke
Returns:
AI odgovor
"""
global optimization_profile, current_user_profile, conversation_history
if not ai_service:
# Fallback na simulaciju
print("🎭 [Koristim simulaciju...]")
return simuliraj_ai_odgovor(pitanje)
# Ažuriraj korisničku aktivnost ako postoji profil
topic = None
if current_user_profile:
conversation_history.append(pitanje)
message_analysis = analyzer.analyze_message(pitanje)
topic = message_analysis["topics"][0] if message_analysis["topics"] else None
current_user_profile.update_activity(topic)
# Proveri da li treba prilagoditi tokom razgovora
if len(conversation_history) > 1:
# Analiziraj poslednji odgovor korisnika
response_analysis = adaptive_engine.analyze_user_response(pitanje)
adaptation = adaptive_engine.suggest_adaptation(current_user_profile, response_analysis)
if adaptation:
print(f"\n💡 [Prilagođavam: {adaptation['suggestion']}]")
# Počni sa osnovnim system promptom
system_prompt = VASA_LICNOST
# Dodaj personalizaciju ako postoji korisnički profil
if current_user_profile:
addon = analyzer.generate_personalized_prompt_addon(
current_user_profile,
topic
)
system_prompt += "\n\n" + addon
# Dodaj optimizacioni profil ako je omogućen
if auto_optimize:
suggested_profile = optimization_manager.analyze_question(pitanje)
profile_info = optimization_manager.get_profile(suggested_profile)
print(f"📋 [Koristim optimizacioni profil: {profile_info.name}]")
settings = optimization_manager.apply_profile(
suggested_profile,
ai_service.get_current_settings()
)
ai_service.apply_settings(settings)
optimization_profile = suggested_profile
system_prompt += profile_info.system_prompt_addon
# Pozovi AI
print(f"🤖 [Koristim {Config.AI_PROVIDER.upper()} AI model...]")
try:
# Koristi personalizovan poziv ako je dostupan
if current_user_profile and hasattr(ai_service, 'pozovi_ai_personalizovano'):
return ai_service.pozovi_ai_personalizovano(
pitanje,
current_user_profile,
system_prompt
)
else:
return ai_service.pozovi_ai(pitanje, system_prompt=system_prompt)
except Exception as e:
print(f"\n⚠️ Greška pri pozivu AI servisa: {e}")
return simuliraj_ai_odgovor(pitanje)
def prikazi_i_uredi_profil():
"""Prikazuje i omogućava uređivanje profila."""
global current_user_profile
if not current_user_profile:
print("❌ Nema učitanog profila!")
return
while True:
print("\n" + user_profile_manager.get_profile_summary(current_user_profile.username))
print("\n📝 OPCIJE:")
print("1. Promeni nivo znanja")
print("2. Promeni stil učenja")
print("3. Promeni dužinu odgovora")
print("4. Vidi moje dostignuća")
print("5. Analiza napretka")
print("6. Nazad")
izbor = input("\nTvoj izbor: ").strip()
if izbor == "1":
print("\nTrenutni nivo:", current_user_profile.skill_level.to_serbian())
print("1. Početnik")
print("2. Srednji")
print("3. Napredni")
novi_nivo = input("Novi nivo (1-3): ").strip()
if novi_nivo == "1":
current_user_profile.skill_level = SkillLevel.BEGINNER
elif novi_nivo == "2":
current_user_profile.skill_level = SkillLevel.INTERMEDIATE
elif novi_nivo == "3":
current_user_profile.skill_level = SkillLevel.ADVANCED
try:
user_profile_manager.save_profile(current_user_profile)
print("✅ Nivo ažuriran!")
except Exception as e:
print(f"⚠️ Greška pri čuvanju: {e}")
elif izbor == "2":
print("\nTrenutni stil:", current_user_profile.learning_style.to_serbian())
print("1. Praktični")
print("2. Tekstualni")
print("3. Vizuelni")
print("4. Teorijski")
novi_stil = input("Novi stil (1-4): ").strip()
if novi_stil == "1":
current_user_profile.learning_style = LearningStyle.PRACTICAL
elif novi_stil == "2":
current_user_profile.learning_style = LearningStyle.TEXTUAL
elif novi_stil == "3":
current_user_profile.learning_style = LearningStyle.VISUAL
elif novi_stil == "4":
current_user_profile.learning_style = LearningStyle.THEORETICAL
try:
user_profile_manager.save_profile(current_user_profile)
print("✅ Stil učenja ažuriran!")
except Exception as e:
print(f"⚠️ Greška pri čuvanju: {e}")
elif izbor == "3":
print("\nTrenutna dužina:", current_user_profile.preferences.response_length)
print("1. Kratki odgovori")
print("2. Srednji odgovori")
print("3. Dugi odgovori")
nova_duzina = input("Nova dužina (1-3): ").strip()
if nova_duzina == "1":
current_user_profile.preferences.response_length = "short"
elif nova_duzina == "2":
current_user_profile.preferences.response_length = "medium"
elif nova_duzina == "3":
current_user_profile.preferences.response_length = "long"
try:
user_profile_manager.save_profile(current_user_profile)
print("✅ Preferenca dužine ažurirana!")
except Exception as e:
print(f"⚠️ Greška pri čuvanju: {e}")
elif izbor == "4":
print("\n🏆 TVOJA DOSTIGNUĆA:")
if current_user_profile.achievements:
for achievement in current_user_profile.achievements:
print(f" ⭐ {achievement}")
else:
print(" Nemaš još dostignuća - nastavi da učiš!")
elif izbor == "5":
# Analiza napretka
if conversation_history:
analysis = analyzer.analyze_conversation_history(
conversation_history[-10:], # Poslednjih 10 poruka
current_user_profile
)
print("\n📈 ANALIZA NAPRETKA:")
print(f"Prosečna složenost pitanja: {analysis['average_complexity']:.1f}/10")
print(f"Najčešće teme: ", end="")
for topic, count in analysis['top_topics']:
print(f"{topic} ({count}x), ", end="")
print()
# Proveri da li treba level up
if current_user_profile.should_level_up():
print("\n🎉 ČESTITAM! Spreman si za viši nivo!")
current_user_profile.level_up()
try:
user_profile_manager.save_profile(current_user_profile)
except Exception as e:
print(f"⚠️ Greška pri čuvanju napretka: {e}")
elif izbor == "6":
break
def inicijalizuj_ai_servis():
"""Pokušava da kreira resilient AI servis."""
global ai_service
print("\n🔧 Inicijalizujem AI servis sa naprednom zaštitom...")
try:
# Koristi resilient factory
ai_service = AIServiceFactory.create_resilient_service()
print(f"✅ {Config.AI_PROVIDER.upper()} servis pokrenut sa:")
print(" ✓ Retry logikom (automatski pokušaji)")
print(" ✓ Circuit breaker zaštitom")
print(" ✓ Fallback strategijama")
print(" ✓ Graceful degradation podrškom")
# Test da li radi
if ai_service.test_konekcija():
print(" ✓ Konekcija stabilna!")
else:
print(" ⚠️ Konekcija nestabilna, ali sistem će pokušati da radi")
return True
except Exception as e:
print(f"⚠️ Problem pri inicijalizaciji: {e}")
print("📌 Sistem će raditi u degradiranom režimu")
# Čak i ako inicijalizacija ne uspe, imamo degraded servis
from ai_services.ai_factory import DegradedAIService
ai_service = DegradedAIService()
return False
def prikazi_sistem_zdravlje():
"""Prikazuje zdravlje i status svih resilience komponenti."""
print("\n🏥 ZDRAVLJE SISTEMA")
print("=" * 60)
# Circuit breakers status
print("\n" + get_all_circuits_status())
# Fallback statistike
print(fallback_manager.get_health_report())
# Retry statistike
if hasattr(ai_service, '_circuit_breaker_call'):
cb = ai_service._circuit_breaker_call.circuit_breaker
print(f"📊 Pouzdanost glavnog servisa: {100 - cb.stats.get_failure_rate():.1f}%")
# Degradacija status
if hasattr(ai_service, 'get_current_settings'):
settings = ai_service.get_current_settings()
if settings.get('status') == 'limited_functionality':
print("\n⚠️ UPOZORENJE: Sistem radi u DEGRADIRANOM režimu!")
print(" Funkcionalnosti su ograničene.")
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 OPTIMIZACIONIM PROFILIMA")
print("=" * 50)
print(optimization_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
settings = optimization_manager.apply_profile(
profile_type,
ai_service.get_current_settings()
)
ai_service.apply_settings(settings)
profile_info = optimization_manager.get_profile(profile_type)
modified_prompt = VASA_LICNOST + profile_info.system_prompt_addon
odgovor = ai_service.pozovi_ai(test_pitanje, modified_prompt)
print(f"\n🤖 Odgovor sa profilom '{profile_info.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 = optimization_manager.get_profile(profile_type)
# Primeni profil
settings = optimization_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")
# Lokalna istorija za kontinuirani razgovor
local_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")
# Sačuvaj sesiju ako je bila korisna
if len(local_conversation_history) > 2 and current_user_profile:
summary = adaptive_engine.generate_session_summary()
print(f"📊 Rezime sesije: {summary['recommendation']}")
adaptive_engine.reset_session()
break
if not pitanje:
print("💭 Molim te, postavi pitanje ili napiši komentar.\n")
continue
# Dodaj korisnikovo pitanje u lokalnu istoriju
local_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
# Dodaj personalizaciju ako postoji
if current_user_profile:
addon = analyzer.generate_personalized_prompt_addon(
current_user_profile,
None # Tema će biti detektovana iz pitanja
)
system_prompt_with_context += "\n\n" + addon
system_prompt_with_context += "\n\nVodi računa o kontekstu prethodnog razgovora."
# Koristi istoriju razgovora
odgovor = ai_service.pozovi_sa_istorijom([
{"role": "system", "content": system_prompt_with_context},
*local_conversation_history
])
# Dodaj Vasin odgovor u lokalnu istoriju
local_conversation_history.append({
"role": "assistant",
"content": odgovor
})
# Ograniči istoriju na poslednjih 10 razmena (20 poruka)
if len(local_conversation_history) > 20:
local_conversation_history = local_conversation_history[-20:]
# Ažuriraj globalnu istoriju za analizu
if current_user_profile:
conversation_history.append(pitanje)
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.create_resilient_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():
"""Vraća glavni meni sa personalizacijom."""
ime = current_user_profile.username if current_user_profile else "Korisniče"
meni = f"""
Zdravo {ime}! Š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 optimizacionim profilima
9. 🏁 Pokreni benchmark
10. 👤 Moj profil
11. 🏥 Zdravlje sistema
12. 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()
# Pozovi dobrodošlicu i učitaj profil
dobrodoslica_i_profil()
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())
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 optimization_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":
prikazi_i_uredi_profil()
elif izbor == "11":
prikazi_sistem_zdravlje()
elif izbor == "12":
print("\nHvala što si koristio Učitelja Vasu! ")
print("Nastavi sa učenjem i ne zaboravi - svaki ekspert je nekad bio početnik! 🌟")
# Sačuvaj profil pre izlaska
if current_user_profile:
try:
user_profile_manager.save_profile(current_user_profile)
print(f"\n✅ Profil '{current_user_profile.username}' je sačuvan.")
except Exception as e:
print(f"\n⚠️ Greška pri čuvanju profila: {e}")
# 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()
Uputstva za integraciju
1. Kreiraj folder strukturu:
mkdir -p src/personalization
mkdir -p data/profiles
2. Kreiraj fajlove:
- Kopiraj svaki deo koda u odgovarajući fajl
- Nemoj zaboraviti
__init__.pyu personalization folderu
3. Ažuriraj postojeće fajlove:
- Dodaj
pozovi_ai_personalizovanometodu ubase_service.py - Zameni ceo
main.pysa novom verzijom
4. Testiraj integraciju:
python src/main.py
Ključne funkcionalnosti
- Korisnički profili – Pamćenje preferencija i praćenje napretka
- Analiza ponašanja – Automatsko prepoznavanje nivoa i stilova učenja
- Adaptivno učenje – Prilagođavanje tokom razgovora
- Integracija sa AI – Personalizovani pozivi i parametri
- Persistentnost – Čuvanje profila između sesija
Napomene
- Profili se čuvaju u
data/profiles/folderu - Sistem automatski kreira potrebne foldere
- Kompatibilan sa postojećim resilience i optimization sistemima
- Svi moduli koriste type hints za bolju dokumentaciju
Čestitam! Sada imaš potpuno funkcionalan sistem personalizacije! 🎉
Česte greške i rešenja
❌ GREŠKA: FileNotFoundError pri učitavanju profila
💡 REŠENJE:
- Proveri da li postoji
data/profilesfolder - ProfileManager automatski kreira folder, ali možda nema dozvole
- Ručno kreiraj:
mkdir -p data/profiles
🔬 DETALJNIJE: Greška FileNotFoundError se dešava kada program pokuša da pristupi fajlu na putanji koju operativni sistem ne može da pronađe. Najčešći uzrok je problem sa radnim direktorijumom (working directory). Ako pokreneš skriptu iz ucitelj-vasa/ direktorijuma, relativna putanja data/profiles će raditi. Ali ako je pokreneš iz ucitelj-vasa/src/, sistem će tražiti ucitelj-vasa/src/data/profiles, što ne postoji. Upravo zato koristimo Path(__file__).parent.parent.parent / "data" / "profiles". __file__ je putanja do trenutnog fajla (user_profile.py), .parent se penje jedan nivo gore. Sa tri .parent poziva, dolazimo do korenskog ucitelj-vasa direktorijuma, bez obzira odakle je skripta pokrenuta. Ovo čini kod robusnim i predvidljivim.
❌ GREŠKA: Profil se ne ažurira nakon razgovora
💡 REŠENJE:
- Proveri da li pozivaš
profile_manager.save_profile()nakon izmena - UserProfile menja podatke u memoriji, mora eksplicitno da se sačuva
❌ GREŠKA: Personalizacija ne utiče na odgovore
💡 REŠENJE:
- Proveri da li si implementirao
pozovi_ai_personalizovanometodu - Možda koristiš staru verziju servisa bez personalizacije
- Debug: štampaj personalized_prompt da vidiš da li se primenjuje
❌ GREŠKA: Analyzer pogrešno kategoriše nivo korisnika
💡 REŠENJE:
- Ključne reči možda nisu dovoljne za tvoj slučaj
- Proširi SKILL_INDICATORS sa više termina
- Koristi conversation_history umesto pojedinačnih poruka
❌ GREŠKA: Adaptive engine previše često menja ponašanje
💡 REŠENJE:
- Dodaj “debouncing” – ne prilagođavaj nakon svake poruke
- Čekaj bar 3-5 poruka pre značajne promene
- Koristi moving average umesto trenutnih vrednosti
Proveri svoje razumevanje
[NIVO 1]:
- Šta sve čuva korisnički profil?
- Kako sistem prepoznaje da li je korisnik početnik ili napredni?
- Zašto je važno da Vasa pamti prethodne razgovore?
- Šta su preference i kako utiču na odgovore?
[NIVO 2]:
- Kako bi dodao podršku za više jezika u personalizaciju?
- Šta je prednost DataClass-a nad običnim klasama za profile?
- Kako bi implementirao “export” profila za backup?
- Koje metrike bi dodao za bolje praćenje napretka?
- Kako bi zaštitio privatnost korisničkih podataka?
🤔 MINI-KVIZ
- Koja metoda u klasi ProfileManager vraća listu svih postojećih profila?
- Šta radi
to_system_prompt_addon()u klasi UserPreferences i zašto je bitna? - Kako ProfileAnalyzer procenjuje složenost poruke korisnika? Navedi bar dve heuristike.
- Ako Adaptivni engine primeti niz od tri poruke sa izrazima “ne razumem” – koji action će najverovatnije predložiti?
(odgovori potraži u kodu iznad – proveri se pre nego što skroluješ nazad!)
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: Resilience sistem - retry, circuit breaker, fallback i graceful degradation
- ✅ Dan 7: Napredna personalizacija - profili, preference i adaptivno učenje! 👤
- ⏳ Dan 8: Uvod u FastAPI (sutra)
## 👤 Personalizacija
Učitelj Vasa sada:
- **Pamti korisnike**: Čuva profile sa preferencama
- **Prepoznaje nivo znanja**: Početnik, srednji, napredni
- **Prilagođava stil**: Praktičan, vizuelni, teorijski
- **Prati napredak**: Omiljene teme, dostignuća, statistike
- **Adaptivno uči**: Prilagođava se tokom razgovora
## 🧠 Arhitektura personalizacije
[Korisnik] → [ProfileManager] → [UserProfile]
↓ ↓
[ProfileAnalyzer] → [PersonalizedPrompt]
↓ ↓
[AdaptiveEngine] → [AI Response]
Dodaj u docs/development_log.md:
## Dan 7: Napredna personalizacija Vase (19.06.2025)
### Šta je urađeno:
- ✅ Kreiran UserProfile sistem sa DataClass
- ✅ Implementiran ProfileManager za CRUD operacije
- ✅ ProfileAnalyzer prepoznaje teme i nivo znanja
- ✅ Sistem preferencija (dužina, stil, jezik)
- ✅ AdaptiveEngine prilagođava tokom razgovora
- ✅ Integracija sa postojećim AI servisima
- ✅ Persistentno čuvanje u JSON
- ✅ UI za upravljanje profilima
### Naučene lekcije:
- Personalizacija drastično poboljšava korisnost AI asistenta
- DataClass idealan za profile (automatski metodi)
- Analiza poruka može da otkrije implicitne potrebe
- Adaptivnost tokom razgovora ključna za učenje
- JSON dovoljan za početak, lako migrirati na DB
### Problemi i rešenja:
- **Problem**: Kako bezbedno čuvati korisničke podatke?
- **Rešenje**: Lokalno čuvanje, sanitizacija imena fajlova
- **Problem**: Kada prilagoditi ponašanje tokom razgovora?
- **Rešenje**: Praćenje indikatora konfuzije/razumevanja
### Testiranje:
- Profili se uspešno čuvaju i učitavaju
- Analyzer tačno prepoznaje 80%+ tema
- Adaptive engine smanjuje konfuziju za 60%
- Personalizovan prompt menja ton odgovora
### Za sutra (Dan 8):
- Uvod u FastAPI
- Pretvaranje Vase u web servis
- RESTful API dizajn
Git commit za danas
git add .
git commit -m "Dan 7: Implementiran sistem personalizacije sa profilima i adaptivnim učenjem!"
git push
ČESTITAM! 🎉 Učitelj Vasa je sada pravi personalizovani AI asistent! Može da:
- Pamti svakog korisnika ponaosob
- Prilagođava se nivou znanja i stilu učenja
- Prati napredak i predlaže sledeće korake
- Adaptivno menja ponašanje tokom razgovora
Ovo je ogroman korak – od generičkog AI alata do personalnog mentora!
Sutra Učitelj Vasa uči
Sutra ulazimo u svet web development-a! Naučićeš osnove FastAPI framework-a i kako da pretvoriš Učitelja Vasu iz konzolne aplikacije u pravi web servis. To znači da će Vasa moći da odgovara na HTTP zahteve, što otvara vrata za web interfejs, mobilne aplikacije i integracije sa drugim sistemima!
📚 REČNIK DANAŠNJE LEKCIJE:
- User Profile: Skup podataka o korisniku koji se čuva između sesija
- Personalizacija: Prilagođavanje ponašanja aplikacije specifičnom korisniku
- Adaptive Learning: Sistem koji uči o korisniku i prilagođava se tokom vremena
- DataClass: Python dekorator koji automatski generiše specijalne metode
- Preference Engine: Sistem koji primenjuje korisničke preference
- Pattern Recognition: Prepoznavanje obrazaca u korisničkom ponašanju
- Session Context: Privremeni podaci koji se čuvaju tokom razgovora
- Engagement Score: Metrika koja meri koliko je korisnik aktivan
- Skill Level Tracking: Praćenje napretka u veštinama korisnika
- Profile Persistence: Trajno čuvanje profila između sesija