from flask import Flask, request, jsonify, render_template_string, Response import torch from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer from threading import Thread import json app = Flask(__name__) # ==================== CSS STİLLERİ ==================== STYLES = """ :root { --primary: #2c3e50; --secondary: #3498db; --accent: #e74c3c; --success: #27ae60; --warning: #f39c12; --light: #ecf0f1; --dark: #1a252f; --gray: #95a5a6; --white: #ffffff; --shadow: 0 4px 20px rgba(0,0,0,0.1); --radius: 12px; } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; color: var(--dark); line-height: 1.6; } .navbar { background: var(--dark); padding: 1rem 2rem; display: flex; justify-content: space-between; align-items: center; box-shadow: var(--shadow); } .navbar h1 { color: var(--white); font-size: 1.5rem; font-weight: 600; } .nav-links { display: flex; gap: 1.5rem; } .nav-links a { color: var(--light); text-decoration: none; font-weight: 500; padding: 0.5rem 1rem; border-radius: 6px; transition: all 0.3s ease; } .nav-links a:hover, .nav-links a.active { background: var(--secondary); color: var(--white); } .container { max-width: 1000px; margin: 2rem auto; padding: 0 1rem; } .card { background: var(--white); border-radius: var(--radius); box-shadow: var(--shadow); padding: 2rem; margin-bottom: 1.5rem; } .card-header { border-bottom: 2px solid var(--light); padding-bottom: 1rem; margin-bottom: 1.5rem; } .card-header h2 { color: var(--primary); font-size: 1.5rem; } .card-header p { color: var(--gray); margin-top: 0.5rem; } label { display: block; font-weight: 600; color: var(--primary); margin-bottom: 0.5rem; } textarea { width: 100%; height: 140px; padding: 1rem; border: 2px solid var(--light); border-radius: 8px; font-size: 1rem; font-family: inherit; resize: vertical; transition: border-color 0.3s ease; } textarea:focus { outline: none; border-color: var(--secondary); } select { width: 100%; padding: 0.8rem 1rem; border: 2px solid var(--light); border-radius: 8px; font-size: 1rem; font-family: inherit; background: var(--white); cursor: pointer; margin-bottom: 1rem; } select:focus { outline: none; border-color: var(--secondary); } .btn { display: inline-block; padding: 1rem 2rem; font-size: 1rem; font-weight: 600; border: none; border-radius: 8px; cursor: pointer; transition: all 0.3s ease; width: 100%; text-align: center; } .btn-primary { background: linear-gradient(135deg, var(--secondary), #2980b9); color: var(--white); } .btn-primary:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(52, 152, 219, 0.4); } .btn-primary:disabled { background: var(--gray); cursor: not-allowed; transform: none; } .btn-stop { background: linear-gradient(135deg, var(--accent), #c0392b); color: var(--white); margin-top: 0.5rem; display: none; } .btn-stop.active { display: block; } .form-group { margin-bottom: 1.5rem; } /* ==================== SETTINGS PANEL ==================== */ .settings-panel { background: linear-gradient(135deg, #f8f9fa, #e9ecef); border-radius: var(--radius); padding: 1.5rem; margin-bottom: 1.5rem; } .settings-header { display: flex; justify-content: space-between; align-items: center; cursor: pointer; margin-bottom: 1rem; } .settings-header h3 { color: var(--primary); font-size: 1.1rem; display: flex; align-items: center; gap: 0.5rem; } .settings-toggle { background: var(--secondary); color: var(--white); border: none; padding: 0.3rem 0.8rem; border-radius: 6px; cursor: pointer; font-size: 0.85rem; transition: all 0.3s ease; } .settings-toggle:hover { background: #2980b9; } .settings-content { display: none; } .settings-content.active { display: block; } .settings-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1.5rem; } .setting-item { background: var(--white); padding: 1rem; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.05); } .setting-item label { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.8rem; } .setting-item label span.value { background: var(--secondary); color: var(--white); padding: 0.2rem 0.6rem; border-radius: 4px; font-size: 0.85rem; min-width: 50px; text-align: center; } .setting-item input[type="range"] { width: 100%; height: 8px; border-radius: 4px; background: var(--light); outline: none; -webkit-appearance: none; } .setting-item input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; width: 20px; height: 20px; border-radius: 50%; background: var(--secondary); cursor: pointer; box-shadow: 0 2px 6px rgba(0,0,0,0.2); transition: transform 0.2s ease; } .setting-item input[type="range"]::-webkit-slider-thumb:hover { transform: scale(1.1); } .setting-item input[type="number"] { width: 100%; padding: 0.6rem; border: 2px solid var(--light); border-radius: 6px; font-size: 1rem; text-align: center; } .setting-item input[type="number"]:focus { outline: none; border-color: var(--secondary); } .setting-description { font-size: 0.8rem; color: var(--gray); margin-top: 0.5rem; } /* Stream Toggle */ .stream-toggle { display: flex; align-items: center; gap: 1rem; padding: 0.5rem 0; } .toggle-switch { position: relative; width: 60px; height: 30px; } .toggle-switch input { opacity: 0; width: 0; height: 0; } .toggle-slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: var(--gray); transition: 0.4s; border-radius: 30px; } .toggle-slider:before { position: absolute; content: ""; height: 22px; width: 22px; left: 4px; bottom: 4px; background-color: white; transition: 0.4s; border-radius: 50%; } .toggle-switch input:checked + .toggle-slider { background-color: var(--success); } .toggle-switch input:checked + .toggle-slider:before { transform: translateX(30px); } .toggle-label { font-weight: 600; color: var(--primary); } /* ==================== END SETTINGS PANEL ==================== */ .response-box { background: linear-gradient(135deg, #f8f9fa, #e9ecef); border-radius: var(--radius); padding: 1.5rem; margin-top: 1.5rem; display: none; } .response-box.active { display: block; } .response-header { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 1rem; padding-bottom: 0.5rem; border-bottom: 1px solid var(--gray); } .model-badge { background: var(--secondary); color: var(--white); padding: 0.3rem 0.8rem; border-radius: 20px; font-size: 0.85rem; font-weight: 600; } .stream-badge { background: var(--success); color: var(--white); padding: 0.2rem 0.6rem; border-radius: 12px; font-size: 0.75rem; font-weight: 600; margin-left: 0.5rem; } .response-content { white-space: pre-wrap; font-size: 1rem; } .response-content strong { color: var(--primary); } .cursor-blink { display: inline-block; width: 8px; height: 1.2em; background: var(--secondary); margin-left: 2px; animation: blink 1s infinite; vertical-align: text-bottom; } @keyframes blink { 0%, 50% { opacity: 1; } 51%, 100% { opacity: 0; } } .loading { text-align: center; padding: 2rem; color: var(--gray); display: none; } .loading.active { display: block; } .spinner { width: 40px; height: 40px; border: 4px solid var(--light); border-top: 4px solid var(--secondary); border-radius: 50%; animation: spin 1s linear infinite; margin: 0 auto 1rem; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .error-box { background: #fdeaea; border: 1px solid var(--accent); color: var(--accent); padding: 1rem; border-radius: 8px; margin-top: 1rem; } .info-section { margin-bottom: 2rem; } .info-section h3 { color: var(--primary); margin-bottom: 1rem; padding-bottom: 0.5rem; border-bottom: 2px solid var(--secondary); } .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; margin: 1rem 0; } .stat-card { background: linear-gradient(135deg, var(--light), #dfe6e9); padding: 1.5rem; border-radius: 8px; text-align: center; } .stat-value { font-size: 2rem; font-weight: 700; color: var(--secondary); } .stat-label { color: var(--gray); font-size: 0.9rem; margin-top: 0.3rem; } table { width: 100%; border-collapse: collapse; margin: 1rem 0; } th, td { padding: 0.8rem; text-align: left; border-bottom: 1px solid var(--light); } th { background: var(--primary); color: var(--white); } tr:hover { background: var(--light); } .badge { display: inline-block; padding: 0.2rem 0.6rem; border-radius: 4px; font-size: 0.8rem; font-weight: 600; } .badge-success { background: #d4edda; color: var(--success); } .badge-danger { background: #f8d7da; color: var(--accent); } .badge-warning { background: #fff3cd; color: #856404; } .badge-info { background: #d1ecf1; color: #0c5460; } .code-block { background: var(--dark); color: #a6e22e; padding: 1rem; border-radius: 8px; overflow-x: auto; font-family: 'Consolas', 'Monaco', monospace; font-size: 0.9rem; margin: 1rem 0; } .highlight { background: linear-gradient(135deg, #fff3cd, #ffeeba); padding: 1rem; border-radius: 8px; border-left: 4px solid var(--warning); margin: 1rem 0; } .comparison-table tr:nth-child(even) { background: #f8f9fa; } .footer { text-align: center; padding: 2rem; color: var(--white); opacity: 0.8; } .footer a { color: var(--white); } @media (max-width: 768px) { .navbar { flex-direction: column; gap: 1rem; } .stats-grid { grid-template-columns: 1fr; } .two-column { grid-template-columns: 1fr; } .settings-grid { grid-template-columns: 1fr; } } .two-column { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; } /* Preset buttons */ .preset-buttons { display: flex; gap: 0.5rem; margin-bottom: 1rem; flex-wrap: wrap; } .preset-btn { padding: 0.4rem 0.8rem; border: 2px solid var(--secondary); background: var(--white); color: var(--secondary); border-radius: 6px; cursor: pointer; font-size: 0.85rem; font-weight: 500; transition: all 0.3s ease; } .preset-btn:hover { background: var(--secondary); color: var(--white); } .preset-btn.active { background: var(--secondary); color: var(--white); } /* Token counter */ .token-info { display: flex; justify-content: space-between; font-size: 0.85rem; color: var(--gray); margin-top: 1rem; padding-top: 0.5rem; border-top: 1px dashed var(--light); } .token-count { color: var(--secondary); font-weight: 600; } """ # ==================== ANA SAYFA HTML ==================== INDEX_HTML = """
Küçük ölçekli Türkçe dil modellerini karşılaştırmalı olarak test edin.
Düşük = daha tutarlı, Yüksek = daha yaratıcı
Üretilecek maksimum token sayısı
Her adımda değerlendirilecek en olası K token
Kümülatif olasılık eşiği
Tekrar eden kelimeleri engelleme gücü
Cevabı kelime kelime göster
Yanıt oluşturuluyor, lütfen bekleyin...
Sıfırdan Türkçe ile eğitilmiş deneysel GPT modelleri
Kayra, Türkçe dil işleme araştırmaları için geliştirilmiş, sıfırdan eğitilmiş küçük ölçekli GPT tabanlı dil modelleridir. Bu projede iki farklı model bulunmaktadır:
| Parametre | Aralık | Varsayılan | Açıklama |
|---|---|---|---|
| Temperature | 0.1 - 2.0 | 0.7 | Çıktının rastgeleliğini kontrol eder. Düşük değerler daha tutarlı, yüksek değerler daha yaratıcı sonuçlar üretir. |
| Max Tokens | 10 - 512 | 150 | Üretilecek maksimum token (kelime parçası) sayısı. |
| Top K | 1 - 100 | 50 | Her adımda sadece en olası K tokenden seçim yapılır. Düşük K daha odaklı, yüksek K daha çeşitli çıktı üretir. |
| Top P (Nucleus) | 0.1 - 1.0 | 0.9 | Kümülatif olasılığı P'yi geçen tokenlerden seçim yapılır. Temperature ile birlikte kullanılır. |
| Repetition Penalty | 1.0 - 2.0 | 1.3 | Tekrarlayan kelimeleri cezalandırır. Yüksek değerler tekrarı azaltır ama anlam bozulabilir. |
| Stream Mode | Açık/Kapalı | Açık | Açıkken cevap kelime kelime gösterilir, kapalıyken tamamı bir anda gösterilir. |
Yüksek temperature ve top-k ile daha özgün ve beklenmedik çıktılar üretir. Hikaye yazımı, beyin fırtınası için ideal.
temp=1.2, top_k=80, top_p=0.95, rep=1.1
Varsayılan ayarlar. Çoğu kullanım senaryosu için uygundur.
temp=0.7, top_k=50, top_p=0.9, rep=1.3
Düşük temperature ile daha tutarlı ve tahmin edilebilir çıktılar. Bilgi gerektiren sorular için.
temp=0.3, top_k=20, top_p=0.8, rep=1.5
Maksimum rastgelelik. Çılgın ve beklenmedik sonuçlar için. Dikkatli kullanın!
temp=1.8, top_k=100, top_p=1.0, rep=1.0
| Özellik | kayra-1 (Stable) | kayra-1-exp (Deneysel) |
|---|---|---|
| Tür | Instruction-tuned | Sadece Pretrained |
| Kullanım | Soru-Cevap formatında | Metin tamamlama |
| Stabilite | Stabil | Deneysel |
| Prompt Formatı | ### Soru: ... ### Cevap: | Düz metin |
| Önerilen Kullanım | Genel test ve demo | Araştırma ve analiz |
| Model Türü | Decoder-only Transformer (GPT-style) |
| Katman Sayısı | 10 |
| Hidden Size | 640 |
| Attention Heads | 10 |
| FFN Size | 2560 |
| Vocabulary | 32,000 BPE tokens |
| Context Length | 512 tokens |
| Toplam Parametre | ~85 milyon |
| Kaynak | Doküman Sayısı | Açıklama |
|---|---|---|
| Wikipedia TR | ~170,000 | Türkçe Vikipedi makaleleri |
| mC4 Turkish | ~330,000 | Common Crawl web dokümanları |
| Toplam | ~500,000 | MinHash LSH ile dedupe edilmiş |
from transformers import AutoModelForCausalLM, AutoTokenizer
model = AutoModelForCausalLM.from_pretrained(
"sixfingerdev/kayra-1-exp",
trust_remote_code=True # ONEMLI!
)
tokenizer = AutoTokenizer.from_pretrained("sixfingerdev/kayra-1-exp")
prompt = "Türkiye'nin başkenti"
inputs = tokenizer(prompt, return_tensors="pt")
outputs = model.generate(
inputs.input_ids,
max_new_tokens=100,
temperature=0.8,
top_k=50,
top_p=0.9,
repetition_penalty=1.2,
do_sample=True
)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
Lisans: MIT License - Ticari ve akademik kullanım serbesttir.
@misc{kayra2024hallucination,
title={Why Small Turkish GPTs Hallucinate Facts: An Experimental 85M Model},
author={sixfingerdev},
year={2024},
publisher={HuggingFace},
howpublished={\\url{https://huggingface.co/sixfingerdev/kayra-1-exp}},
note={Research on loss-factuality divergence in low-resource language models}
}