|
import logging |
|
import time |
|
from functools import lru_cache |
|
from typing import Dict, List, Optional, Tuple |
|
|
|
import pandas as pd |
|
import plotly.express as px |
|
import plotly.graph_objects as go |
|
|
|
from data_manager import data_manager |
|
|
|
logger = logging.getLogger(__name__) |
|
|
|
@lru_cache(maxsize=128) |
|
def filter_leaderboard( |
|
family: Optional[str] = None, |
|
quantization_level: Optional[str] = None |
|
) -> pd.DataFrame: |
|
"""Önbellekleme ile kriterlere göre liderlik tablosu verilerini filtrele.""" |
|
try: |
|
df = data_manager.leaderboard_data.copy() |
|
|
|
if df.empty: |
|
logger.warning("Liderlik tablosu verileri boş, boş DataFrame döndürülüyor") |
|
return pd.DataFrame() |
|
|
|
|
|
if family and family != "Tümü": |
|
df = df[df["family"] == family] |
|
if quantization_level and quantization_level != "Tümü": |
|
df = df[df["quantization_level"] == quantization_level] |
|
|
|
|
|
if "score" in df.columns: |
|
df = df.sort_values("score", ascending=False) |
|
|
|
|
|
if not df.empty and "score" in df.columns: |
|
df = df.reset_index(drop=True) |
|
df.insert(0, "Sıra", range(1, len(df) + 1)) |
|
|
|
return df |
|
except Exception as e: |
|
logger.error(f"Liderlik tablosu filtreleme hatası: {e}") |
|
return pd.DataFrame() |
|
|
|
def get_all_responses(model: str = None, page: int = 1, page_size: int = 50) -> pd.DataFrame: |
|
"""Sayfalama ile arama sorgusu olmadan göz atmak için tüm model cevaplarını al.""" |
|
try: |
|
df = data_manager.responses_data |
|
|
|
if df.empty: |
|
logger.warning("Cevap verileri boş, boş DataFrame döndürülüyor") |
|
return pd.DataFrame({"ℹ️ Bilgi": ["Cevap verisi mevcut değil. Lütfen veri yüklemeyi kontrol edin."]}) |
|
|
|
|
|
logger.info(f"Cevap verilerindeki mevcut sütunlar: {list(df.columns)}") |
|
|
|
|
|
required_columns = ["bolum", "soru", "cevap"] |
|
missing_columns = [col for col in required_columns if col not in df.columns] |
|
if missing_columns: |
|
return pd.DataFrame({ |
|
"❌ Hata": [f"Eksik gerekli sütunlar: {', '.join(missing_columns)}"], |
|
"Mevcut Sütunlar": [", ".join(df.columns.tolist())] |
|
}) |
|
|
|
|
|
available_models = [col.replace("_cevap", "") for col in df.columns if col.endswith("_cevap")] |
|
|
|
if not available_models: |
|
return pd.DataFrame({ |
|
"ℹ️ Bilgi": ["Model cevap sütunları bulunamadı."], |
|
"Mevcut Sütunlar": [", ".join(df.columns.tolist())] |
|
}) |
|
|
|
|
|
total_rows = len(df) |
|
start_idx = (page - 1) * page_size |
|
end_idx = start_idx + page_size |
|
|
|
|
|
if start_idx >= total_rows: |
|
return pd.DataFrame({ |
|
"ℹ️ Bilgi": [f"Sayfa {page} aralığın dışında. Toplam sayfa: {(total_rows + page_size - 1) // page_size}"] |
|
}) |
|
|
|
|
|
df_page = df.iloc[start_idx:end_idx].copy() |
|
|
|
|
|
if not model or model.strip() == "": |
|
|
|
display_columns = ["bolum", "soru", "cevap"] + [f"{m}_cevap" for m in available_models if f"{m}_cevap" in df_page.columns] |
|
result_df = df_page[display_columns] |
|
|
|
|
|
column_mapping = { |
|
"bolum": "📚 Bölüm", |
|
"soru": "❓ Soru", |
|
"cevap": "✅ Doğru Cevap" |
|
} |
|
|
|
for model_name in available_models: |
|
model_col = f"{model_name}_cevap" |
|
if model_col in result_df.columns: |
|
column_mapping[model_col] = f"🤖 {model_name}" |
|
|
|
result_df = result_df.rename(columns=column_mapping) |
|
|
|
else: |
|
|
|
model_column = f"{model}_cevap" |
|
if model_column not in df.columns: |
|
return pd.DataFrame({ |
|
"❌ Hata": [f"'{model}' modeli cevapları bulunamadı."], |
|
"🤖 Mevcut Modeller": [", ".join(available_models[:10]) + ("..." if len(available_models) > 10 else "")], |
|
"💡 İpucu": ["Lütfen cevap verisi olan açılır menüden bir model seçin."] |
|
}) |
|
|
|
|
|
selected_columns = ["bolum", "soru", "cevap", model_column] |
|
result_df = df_page[selected_columns] |
|
|
|
|
|
result_df = result_df.rename(columns={ |
|
"bolum": "📚 Bölüm", |
|
"soru": "❓ Soru", |
|
"cevap": "✅ Doğru Cevap", |
|
model_column: f"🤖 {model} Cevabı" |
|
}) |
|
|
|
|
|
result_df = result_df.fillna("N/A") |
|
|
|
|
|
global_question_numbers = range(start_idx + 1, start_idx + len(result_df) + 1) |
|
result_df.insert(0, "📝 Soru #", global_question_numbers) |
|
|
|
return result_df |
|
|
|
except Exception as e: |
|
logger.error(f"Tüm cevapları alma hatası: {e}") |
|
return pd.DataFrame({ |
|
"❌ Hata": [f"Cevapları yükleme hatası: {str(e)}"], |
|
"🔧 Hata Ayıklama Bilgisi": [f"Model: '{model}', Sayfa: {page}"] |
|
}) |
|
|
|
def get_pagination_info(page: int = 1, page_size: int = 50) -> dict: |
|
"""Cevap verileri için sayfalama bilgilerini al.""" |
|
try: |
|
df = data_manager.responses_data |
|
total_rows = len(df) |
|
total_pages = (total_rows + page_size - 1) // page_size |
|
|
|
start_idx = (page - 1) * page_size + 1 |
|
end_idx = min(page * page_size, total_rows) |
|
|
|
return { |
|
"current_page": page, |
|
"total_pages": total_pages, |
|
"total_rows": total_rows, |
|
"page_size": page_size, |
|
"start_idx": start_idx, |
|
"end_idx": end_idx, |
|
"has_prev": page > 1, |
|
"has_next": page < total_pages |
|
} |
|
except Exception as e: |
|
logger.error(f"Sayfalama bilgisi alma hatası: {e}") |
|
return { |
|
"current_page": 1, |
|
"total_pages": 1, |
|
"total_rows": 0, |
|
"page_size": page_size, |
|
"start_idx": 1, |
|
"end_idx": 0, |
|
"has_prev": False, |
|
"has_next": False |
|
} |
|
|
|
def search_responses(query: str, model: str, page: int = 1, page_size: int = 50) -> pd.DataFrame: |
|
"""Geliştirilmiş işlevsellik ile sorguya göre model cevaplarını ara.""" |
|
try: |
|
|
|
if not query or not query.strip(): |
|
return get_all_responses(model, page, page_size) |
|
|
|
if not model or not model.strip(): |
|
return pd.DataFrame({"ℹ️ Bilgi": ["Lütfen açılır menüden bir model seçin."]}) |
|
|
|
query = query.strip() |
|
model = model.strip() |
|
|
|
df = data_manager.responses_data |
|
|
|
if df.empty: |
|
logger.warning("Cevap verileri boş, boş DataFrame döndürülüyor") |
|
return pd.DataFrame({"ℹ️ Bilgi": ["Cevap verisi mevcut değil. Lütfen veri yüklemeyi kontrol edin."]}) |
|
|
|
|
|
required_columns = ["bolum", "soru", "cevap"] |
|
for col in required_columns: |
|
if col not in df.columns: |
|
return pd.DataFrame({ |
|
"❌ Hata": [f"Gerekli sütun '{col}' bulunamadı"], |
|
"Mevcut Sütunlar": [", ".join(df.columns.tolist())] |
|
}) |
|
|
|
|
|
model_column = f"{model}_cevap" |
|
if model_column not in df.columns: |
|
available_models = [col.replace("_cevap", "") for col in df.columns if col.endswith("_cevap")] |
|
return pd.DataFrame({ |
|
"❌ Hata": [f"'{model}' modeli cevapları bulunamadı"], |
|
"🤖 Mevcut Modeller": [", ".join(available_models[:10]) + ("..." if len(available_models) > 10 else "")], |
|
"💡 Öneriler": [ |
|
"1. Açılır menüden geçerli bir model seçin", |
|
"2. Model verilerinin yüklendiğinden emin olun", |
|
"3. Modelleri yenilemek için 'Yenile' butonuna tıklayın" |
|
] |
|
}) |
|
|
|
|
|
query_lower = query.lower() |
|
|
|
|
|
search_columns = ["bolum", "soru", "cevap", model_column] |
|
search_mask = pd.Series([False] * len(df)) |
|
|
|
for col in search_columns: |
|
if col in df.columns: |
|
|
|
col_mask = df[col].astype(str).str.lower().str.contains(query_lower, case=False, na=False, regex=False) |
|
search_mask = search_mask | col_mask |
|
|
|
|
|
search_results = df[search_mask] |
|
|
|
if search_results.empty: |
|
return pd.DataFrame({ |
|
"🔍 Arama Sonucu": [f"'{query}' için sonuç bulunamadı"], |
|
"💡 İpucu": [ |
|
"Daha genel terimler deneyin", |
|
"Yazım hatalarını kontrol edin", |
|
"Farklı anahtar kelimeler kullanın" |
|
], |
|
"📊 Aranan Sütunlar": [", ".join(search_columns)] |
|
}) |
|
|
|
|
|
max_results = 50 |
|
if len(search_results) > max_results: |
|
search_results = search_results.head(max_results) |
|
truncated_message = f" (İlk {max_results} sonuç gösteriliyor)" |
|
else: |
|
truncated_message = "" |
|
|
|
|
|
display_columns = ["bolum", "soru", "cevap", model_column] |
|
result_df = search_results[display_columns].copy() |
|
|
|
|
|
result_df = result_df.rename(columns={ |
|
"bolum": "📚 Bölüm", |
|
"soru": "❓ Soru", |
|
"cevap": "✅ Doğru Cevap", |
|
model_column: f"🤖 {model} Cevabı" |
|
}) |
|
|
|
|
|
result_df = result_df.fillna("N/A") |
|
|
|
|
|
summary_info = f"'{query}' için {len(search_results)} sonuç{truncated_message}" |
|
result_df.insert(0, "🔍 Arama Özeti", [summary_info] + [""] * (len(result_df) - 1)) |
|
|
|
return result_df |
|
|
|
except Exception as e: |
|
logger.error(f"Cevap arama hatası: {e}") |
|
error_details = f"Sorgu: '{query}', Model: '{model}', Hata: {str(e)}" |
|
return pd.DataFrame({ |
|
"❌ Arama Hatası": ["Arama sırasında bir hata oluştu"], |
|
"🔧 Hata Detayları": [error_details], |
|
"💡 Öneriler": [ |
|
"Basit sorgu terimleri deneyin", |
|
"Özel karakterleri kaldırın", |
|
"Sayfayı yenileyin ve tekrar deneyin" |
|
] |
|
}) |
|
|
|
def create_plotly_section_results() -> go.Figure: |
|
"""Bölüm sonuçları için etkileşimli Plotly grafiği oluştur.""" |
|
try: |
|
df = data_manager.section_results_data |
|
|
|
if df.empty: |
|
fig = go.Figure() |
|
fig.add_annotation( |
|
text="Bölüm verisi mevcut değil", |
|
xref="paper", yref="paper", |
|
x=0.5, y=0.5, xanchor='center', yanchor='middle', |
|
showarrow=False, |
|
font=dict(size=16, color="gray") |
|
) |
|
fig.update_layout( |
|
title="Bölüm Performans Analizi", |
|
height=500, |
|
plot_bgcolor='white', |
|
paper_bgcolor='white' |
|
) |
|
return fig |
|
|
|
|
|
if len(df.columns) < 2: |
|
fig = go.Figure() |
|
fig.add_annotation( |
|
text="Yeterli veri yok", |
|
xref="paper", yref="paper", |
|
x=0.5, y=0.5, xanchor='center', yanchor='middle', |
|
showarrow=False, |
|
font=dict(size=16, color="gray") |
|
) |
|
fig.update_layout(title="Bölüm Performans Analizi", height=500) |
|
return fig |
|
|
|
|
|
numeric_columns = df.select_dtypes(include=['number']).columns.tolist() |
|
section_column = df.columns[0] if df.columns[0] not in numeric_columns else 'section' |
|
|
|
if not numeric_columns: |
|
|
|
numeric_columns = df.columns[1:].tolist() |
|
for col in numeric_columns: |
|
df[col] = pd.to_numeric(df[col], errors='coerce') |
|
|
|
|
|
fig = go.Figure() |
|
|
|
|
|
colors = px.colors.qualitative.Set3 |
|
for i, model in enumerate(numeric_columns): |
|
fig.add_trace(go.Bar( |
|
name=model, |
|
x=df[section_column] if section_column in df.columns else df.index, |
|
y=df[model], |
|
marker_color=colors[i % len(colors)], |
|
text=[f'{v:.1f}%' if pd.notna(v) else 'N/A' for v in df[model]], |
|
textposition='auto', |
|
hovertemplate=f'<b>{model}</b><br>Bölüm: %{{x}}<br>Puan: %{{y:.1f}}%<extra></extra>' |
|
)) |
|
|
|
fig.update_layout( |
|
title="Model Performanslarının Bölümlere Göre Karşılaştırması", |
|
xaxis_title="Bölümler", |
|
yaxis_title="Doğruluk Puanı (%)", |
|
height=500, |
|
plot_bgcolor='white', |
|
paper_bgcolor='white', |
|
barmode='group', |
|
hovermode='x unified', |
|
legend=dict( |
|
orientation="h", |
|
yanchor="bottom", |
|
y=1.02, |
|
xanchor="right", |
|
x=1 |
|
) |
|
) |
|
|
|
|
|
fig.update_xaxes(showgrid=True, gridwidth=1, gridcolor='lightgray') |
|
fig.update_yaxes(showgrid=True, gridwidth=1, gridcolor='lightgray') |
|
|
|
return fig |
|
|
|
except Exception as e: |
|
logger.error(f"Bölüm sonuçları grafiği oluşturma hatası: {e}") |
|
fig = go.Figure() |
|
fig.add_annotation( |
|
text=f"Grafik oluşturma hatası: {str(e)}", |
|
xref="paper", yref="paper", |
|
x=0.5, y=0.5, xanchor='center', yanchor='middle', |
|
showarrow=False, |
|
font=dict(size=14, color="red") |
|
) |
|
fig.update_layout( |
|
title="Bölüm Performans Analizi", |
|
height=500, |
|
plot_bgcolor='white', |
|
paper_bgcolor='white' |
|
) |
|
return fig |
|
|
|
def validate_model_submission( |
|
model_name: str, |
|
base_model: str, |
|
revision: str, |
|
precision: str, |
|
weight_type: str, |
|
model_type: str |
|
) -> Tuple[bool, str]: |
|
"""Model gönderimini detaylı kontrollerle doğrula.""" |
|
try: |
|
|
|
if not model_name or not model_name.strip(): |
|
return False, "Model adı gereklidir" |
|
|
|
if not base_model or not base_model.strip(): |
|
return False, "Temel model gereklidir" |
|
|
|
|
|
model_name = model_name.strip() |
|
if len(model_name) < 3: |
|
return False, "Model adı en az 3 karakter olmalıdır" |
|
|
|
if len(model_name) > 100: |
|
return False, "Model adı 100 karakterden fazla olamaz" |
|
|
|
|
|
if not model_name.replace('-', '').replace('_', '').replace('.', '').replace('/', '').isalnum(): |
|
return False, "Model adında sadece harf, rakam, tire, alt çizgi, nokta ve eğik çizgi kullanılabilir" |
|
|
|
|
|
existing_data = data_manager.leaderboard_data |
|
if not existing_data.empty and 'model' in existing_data.columns: |
|
if model_name.lower() in existing_data['model'].str.lower().values: |
|
return False, f"'{model_name}' adında bir model zaten mevcut" |
|
|
|
|
|
base_model = base_model.strip() |
|
if '/' not in base_model and not base_model.startswith('http'): |
|
return False, "Temel model formatı 'organization/model' şeklinde olmalıdır" |
|
|
|
|
|
if revision and len(revision.strip()) > 50: |
|
return False, "Revizyon 50 karakterden fazla olamaz" |
|
|
|
|
|
from config import CONFIG |
|
|
|
if precision not in CONFIG["model"].precision_options: |
|
return False, f"Geçersiz hassasiyet seçimi. Geçerli seçenekler: {', '.join(CONFIG['model'].precision_options)}" |
|
|
|
if weight_type not in CONFIG["model"].weight_types: |
|
return False, f"Geçersiz ağırlık türü seçimi. Geçerli seçenekler: {', '.join(CONFIG['model'].weight_types)}" |
|
|
|
if model_type not in CONFIG["model"].model_types: |
|
return False, f"Geçersiz model türü seçimi. Geçerli seçenekler: {', '.join(CONFIG['model'].model_types)}" |
|
|
|
|
|
success_message = f"Model '{model_name}' başarıyla doğrulandı ve değerlendirme kuyruğuna eklendi" |
|
logger.info(f"Model gönderimi doğrulandı: {model_name}") |
|
|
|
return True, success_message |
|
|
|
except Exception as e: |
|
logger.error(f"Model doğrulama hatası: {e}") |
|
return False, f"Doğrulama sırasında hata oluştu: {str(e)}" |
|
|
|
def get_leaderboard_stats() -> Dict[str, any]: |
|
"""Liderlik tablosu istatistiklerini al.""" |
|
try: |
|
df = data_manager.leaderboard_data |
|
|
|
if df.empty: |
|
return { |
|
"toplam_model": 0, |
|
"ortalama_puan": 0, |
|
"en_yuksek_puan": 0, |
|
"aileler": [], |
|
"kuantizasyon_seviyeleri": [] |
|
} |
|
|
|
stats = { |
|
"toplam_model": len(df), |
|
"ortalama_puan": df["score"].mean() if "score" in df.columns else 0, |
|
"en_yuksek_puan": df["score"].max() if "score" in df.columns else 0, |
|
"aileler": df["family"].unique().tolist() if "family" in df.columns else [], |
|
"kuantizasyon_seviyeleri": df["quantization_level"].unique().tolist() if "quantization_level" in df.columns else [] |
|
} |
|
|
|
return stats |
|
|
|
except Exception as e: |
|
logger.error(f"İstatistik alma hatası: {e}") |
|
return { |
|
"toplam_model": 0, |
|
"ortalama_puan": 0, |
|
"en_yuksek_puan": 0, |
|
"aileler": [], |
|
"kuantizasyon_seviyeleri": [] |
|
} |
|
|
|
def format_dataframe_for_display(df: pd.DataFrame, max_rows: int = 100) -> pd.DataFrame: |
|
"""DataFrame'i görüntüleme için formatla.""" |
|
try: |
|
if df.empty: |
|
return pd.DataFrame({"ℹ️ Bilgi": ["Görüntülenecek veri yok"]}) |
|
|
|
|
|
if len(df) > max_rows: |
|
df = df.head(max_rows) |
|
logger.info(f"DataFrame {max_rows} satırla sınırlandırıldı") |
|
|
|
|
|
for col in df.select_dtypes(include=['float']).columns: |
|
if 'score' in col.lower() or 'puan' in col.lower(): |
|
df[col] = df[col].round(2) |
|
|
|
|
|
for col in df.select_dtypes(include=['object']).columns: |
|
df[col] = df[col].astype(str).apply( |
|
lambda x: x[:100] + "..." if len(x) > 100 else x |
|
) |
|
|
|
return df |
|
|
|
except Exception as e: |
|
logger.error(f"DataFrame formatlama hatası: {e}") |
|
return pd.DataFrame({"❌ Hata": [f"Formatlama hatası: {str(e)}"]}) |
|
|
|
|
|
def clear_cache(): |
|
"""Tüm LRU önbelleklerini temizle.""" |
|
try: |
|
filter_leaderboard.cache_clear() |
|
logger.info("Önbellekler temizlendi") |
|
except Exception as e: |
|
logger.error(f"Önbellek temizleme hatası: {e}") |
|
|
|
|
|
def refresh_all_caches(): |
|
"""Veri yenileme sonrası tüm önbellekleri yenile.""" |
|
try: |
|
clear_cache() |
|
|
|
data_manager.refresh_datasets() |
|
logger.info("Tüm önbellekler ve veriler yenilendi") |
|
except Exception as e: |
|
logger.error(f"Önbellek yenileme hatası: {e}") |