sixfingerdev commited on
Commit
db0ff49
·
verified ·
1 Parent(s): 444850f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +757 -232
app.py CHANGED
@@ -1,10 +1,8 @@
1
- # app.py
2
- # Flask tabanlı Kayra Türkçe Dil Modeli Test Uygulaması
3
- # sixfingerdev/kayra-1 ve sixfingerdev/kayra-1-exp modellerini test etmenizi sağlar.
4
-
5
- from flask import Flask, request, jsonify, render_template_string
6
  import torch
7
- from transformers import AutoModelForCausalLM, AutoTokenizer
 
 
8
 
9
  app = Flask(__name__)
10
 
@@ -173,10 +171,201 @@ select:focus {
173
  transform: none;
174
  }
175
 
 
 
 
 
 
 
 
 
 
 
 
176
  .form-group {
177
  margin-bottom: 1.5rem;
178
  }
179
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  .response-box {
181
  background: linear-gradient(135deg, #f8f9fa, #e9ecef);
182
  border-radius: var(--radius);
@@ -207,6 +396,16 @@ select:focus {
207
  font-weight: 600;
208
  }
209
 
 
 
 
 
 
 
 
 
 
 
210
  .response-content {
211
  white-space: pre-wrap;
212
  font-size: 1rem;
@@ -216,6 +415,21 @@ select:focus {
216
  color: var(--primary);
217
  }
218
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
219
  .loading {
220
  text-align: center;
221
  padding: 2rem;
@@ -384,6 +598,10 @@ tr:hover {
384
  .two-column {
385
  grid-template-columns: 1fr;
386
  }
 
 
 
 
387
  }
388
 
389
  .two-column {
@@ -391,6 +609,52 @@ tr:hover {
391
  grid-template-columns: 1fr 1fr;
392
  gap: 1rem;
393
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
394
  """
395
 
396
  # ==================== ANA SAYFA HTML ====================
@@ -405,7 +669,7 @@ INDEX_HTML = """
405
  </head>
406
  <body>
407
  <nav class="navbar">
408
- <h1>Kayra Türkçe Dil Modeli</h1>
409
  <div class="nav-links">
410
  <a href="/" class="active">Test</a>
411
  <a href="/info">Bilgi</a>
@@ -432,8 +696,113 @@ INDEX_HTML = """
432
  </select>
433
  </div>
434
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
435
  <button class="btn btn-primary" id="submitBtn" onclick="generate()">
436
- Gönder ve Cevap Al
 
 
 
 
437
  </button>
438
 
439
  <div class="loading" id="loading">
@@ -445,8 +814,13 @@ INDEX_HTML = """
445
  <div class="response-header">
446
  <span>Model:</span>
447
  <span class="model-badge" id="modelBadge"></span>
 
448
  </div>
449
  <div class="response-content" id="responseContent"></div>
 
 
 
 
450
  </div>
451
 
452
  <div class="error-box" id="errorBox" style="display:none;"></div>
@@ -459,13 +833,97 @@ INDEX_HTML = """
459
  </div>
460
 
461
  <script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
462
  async function generate() {
463
  const prompt = document.getElementById("prompt").value.trim();
464
  const model = document.getElementById("model").value;
 
 
 
 
 
 
 
 
 
 
465
  const responseBox = document.getElementById("responseBox");
466
  const loading = document.getElementById("loading");
467
  const errorBox = document.getElementById("errorBox");
468
  const submitBtn = document.getElementById("submitBtn");
 
 
469
 
470
  if (!prompt) {
471
  errorBox.textContent = "Lütfen bir mesaj girin!";
@@ -476,34 +934,97 @@ INDEX_HTML = """
476
 
477
  errorBox.style.display = "none";
478
  responseBox.classList.remove("active");
479
- loading.classList.add("active");
480
  submitBtn.disabled = true;
 
 
 
 
 
481
 
482
- try {
483
- const response = await fetch("/generate", {
484
- method: "POST",
485
- headers: { "Content-Type": "application/json" },
486
- body: JSON.stringify({ prompt, model })
 
 
 
 
 
487
  });
488
 
489
- const data = await response.json();
 
 
 
490
 
491
- if (data.error) {
492
- errorBox.textContent = "Hata: " + data.error;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
493
  errorBox.style.display = "block";
494
- } else {
495
- document.getElementById("modelBadge").textContent = data.model;
496
- document.getElementById("responseContent").innerHTML =
497
- "<strong>Soru:</strong> " + escapeHtml(data.prompt) +
498
- "\\n\\n<strong>Cevap:</strong>\\n" + escapeHtml(data.response);
499
- responseBox.classList.add("active");
500
  }
501
- } catch (err) {
502
- errorBox.textContent = "Bağlantı hatası: " + err.message;
503
- errorBox.style.display = "block";
504
- } finally {
505
- loading.classList.remove("active");
506
- submitBtn.disabled = false;
507
  }
508
  }
509
 
@@ -535,7 +1056,7 @@ INFO_HTML = """
535
  </head>
536
  <body>
537
  <nav class="navbar">
538
- <h1>Kayra Türkçe Dil Modeli</h1>
539
  <div class="nav-links">
540
  <a href="/">Test</a>
541
  <a href="/info" class="active">Bilgi</a>
@@ -573,6 +1094,92 @@ INFO_HTML = """
573
  </div>
574
  </div>
575
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
576
  <!-- Model Karşılaştırması -->
577
  <div class="card">
578
  <div class="card-header">
@@ -671,154 +1278,6 @@ INFO_HTML = """
671
  </table>
672
  </div>
673
 
674
- <!-- Hallucination Problemi -->
675
- <div class="card">
676
- <div class="card-header">
677
- <h2>Neden Küçük Modeller Yanlış Bilgi Üretir?</h2>
678
- </div>
679
-
680
- <div class="highlight">
681
- <strong>Temel Bulgu:</strong> Loss azalması, gerçek bilgi doğruluğu anlamına gelmez.
682
- (loss down != factual accuracy up)
683
- </div>
684
-
685
- <div class="info-section">
686
- <h3>Eğitim Sürecinde Gözlemlenen Davranış</h3>
687
- <table class="comparison-table">
688
- <thead>
689
- <tr>
690
- <th>Step</th>
691
- <th>Val Loss</th>
692
- <th>Val PPL</th>
693
- <th>Üretilen Başkent</th>
694
- <th>Doğru mu?</th>
695
- </tr>
696
- </thead>
697
- <tbody>
698
- <tr>
699
- <td>1000</td>
700
- <td>5.98</td>
701
- <td>397.3</td>
702
- <td>Ankara</td>
703
- <td><span class="badge badge-success">Evet</span></td>
704
- </tr>
705
- <tr>
706
- <td>3000</td>
707
- <td>3.94</td>
708
- <td>51.7</td>
709
- <td>Ankara</td>
710
- <td><span class="badge badge-success">Evet</span></td>
711
- </tr>
712
- <tr>
713
- <td>5000</td>
714
- <td>4.02</td>
715
- <td>56.2</td>
716
- <td>Rastgele şehir</td>
717
- <td><span class="badge badge-danger">Hayır</span></td>
718
- </tr>
719
- <tr>
720
- <td>6500</td>
721
- <td>3.90</td>
722
- <td>49.6</td>
723
- <td>Bolu</td>
724
- <td><span class="badge badge-danger">Hayır</span></td>
725
- </tr>
726
- <tr>
727
- <td>7500</td>
728
- <td>3.83</td>
729
- <td>46.1</td>
730
- <td>Konya</td>
731
- <td><span class="badge badge-danger">Hayır</span></td>
732
- </tr>
733
- <tr>
734
- <td>9000</td>
735
- <td>3.75</td>
736
- <td>42.7</td>
737
- <td>Ankara (bazen)</td>
738
- <td><span class="badge badge-warning">Belirsiz</span></td>
739
- </tr>
740
- </tbody>
741
- </table>
742
- </div>
743
-
744
- <div class="two-column">
745
- <div class="info-section">
746
- <h3>Modelin Başarıyla Öğrendikleri</h3>
747
- <ul style="margin-left: 1.5rem;">
748
- <li>Dilbilgisi (Türkçe morfoloji)</li>
749
- <li>Cümle yapısı (syntax)</li>
750
- <li>Stil (resmi/gündelik ton eşleştirme)</li>
751
- <li>Bağlam tutarlılığı (konu tutarlılığı)</li>
752
- <li>Örüntü eşleme (Wikipedia tarzında metin)</li>
753
- </ul>
754
- </div>
755
-
756
- <div class="info-section">
757
- <h3>Modelin Öğrenemedikleri</h3>
758
- <ul style="margin-left: 1.5rem;">
759
- <li>Gerçek temeli: "Ankara = başkent" deterministik kuralı</li>
760
- <li>Mantıksal tutarlılık: Aynı prompt aynı gerçeği vermeli</li>
761
- <li>Bilgi geri çağırma: Güvenilir bilgi hatırlaması</li>
762
- <li>Gerçek vs örüntü: Doğruluğu olabilirlikten ayırt etme</li>
763
- </ul>
764
- </div>
765
- </div>
766
- </div>
767
-
768
- <!-- Model Boyutu Karşılaştırması -->
769
- <div class="card">
770
- <div class="card-header">
771
- <h2>Model Boyutu ve Gerçeklik İlişkisi</h2>
772
- </div>
773
-
774
- <table>
775
- <thead>
776
- <tr>
777
- <th>Model</th>
778
- <th>Parametre</th>
779
- <th>Gerçeklik Güvenilirliği</th>
780
- </tr>
781
- </thead>
782
- <tbody>
783
- <tr>
784
- <td>Kayra (bu model)</td>
785
- <td>85M</td>
786
- <td><span class="badge badge-danger">Düşük - hallucination yaygın</span></td>
787
- </tr>
788
- <tr>
789
- <td>GPT-2 Small</td>
790
- <td>124M</td>
791
- <td><span class="badge badge-danger">Düşük - benzer sorunlar</span></td>
792
- </tr>
793
- <tr>
794
- <td>GPT-2 Medium</td>
795
- <td>355M</td>
796
- <td><span class="badge badge-warning">Orta - hala güvenilmez</span></td>
797
- </tr>
798
- <tr>
799
- <td>GPT-3</td>
800
- <td>175B</td>
801
- <td><span class="badge badge-success">İyi tutarlılık</span></td>
802
- </tr>
803
- <tr>
804
- <td>GPT-4</td>
805
- <td>~1.7T + RLHF</td>
806
- <td><span class="badge badge-success">Güvenilir</span></td>
807
- </tr>
808
- <tr>
809
- <td>GPT-5</td>
810
- <td>~10T (tahmini)</td>
811
- <td><span class="badge badge-info">Çok yüksek (beklenen)</span></td>
812
- </tr>
813
- </tbody>
814
- </table>
815
-
816
- <div class="highlight">
817
- <strong>Sonuç:</strong> 85M parametre dil örüntülerini öğrenir, bilgi tabanı oluşturmaz.
818
- Gerçek bilgi güvenilirliği için milyarlarca parametre ve RLHF/DPO gibi hizalama teknikleri gerekir.
819
- </div>
820
- </div>
821
-
822
  <!-- Kullanım Örneği -->
823
  <div class="card">
824
  <div class="card-header">
@@ -842,6 +1301,7 @@ outputs = model.generate(
842
  max_new_tokens=100,
843
  temperature=0.8,
844
  top_k=50,
 
845
  repetition_penalty=1.2,
846
  do_sample=True
847
  )
@@ -850,51 +1310,6 @@ print(tokenizer.decode(outputs[0], skip_special_tokens=True))</pre>
850
  </div>
851
  </div>
852
 
853
- <!-- Uygun Kullanım Alanları -->
854
- <div class="card">
855
- <div class="card-header">
856
- <h2>Kullanım Alanları</h2>
857
- </div>
858
-
859
- <div class="two-column">
860
- <div>
861
- <h4 style="color: var(--success); margin-bottom: 0.5rem;">Önerilen Kullanım</h4>
862
- <ul style="margin-left: 1.5rem;">
863
- <li>Türkçe NLP limitasyonları araştırması</li>
864
- <li>Pretraining baseline karşılaştırmaları</li>
865
- <li>Hallucination örüntü çalışmaları</li>
866
- <li>Eğitim amaçlı demonstrasyonlar</li>
867
- <li>LLM başarısızlık modlarını anlama</li>
868
- </ul>
869
- </div>
870
- <div>
871
- <h4 style="color: var(--accent); margin-bottom: 0.5rem;">Önerilmeyen Kullanım</h4>
872
- <ul style="margin-left: 1.5rem;">
873
- <li>Production uygulamaları</li>
874
- <li>Gerçek soru-cevap sistemleri</li>
875
- <li>Bilgi erişim sistemleri</li>
876
- <li>Eğitim içeriği üretimi</li>
877
- <li>Doğruluk gerektiren her iş</li>
878
- </ul>
879
- </div>
880
- </div>
881
- </div>
882
-
883
- <!-- Gelecek Planları -->
884
- <div class="card">
885
- <div class="card-header">
886
- <h2>Gelecek: Kayra-v2</h2>
887
- </div>
888
-
889
- <ul style="margin-left: 1.5rem;">
890
- <li><strong>Daha büyük model:</strong> 350M-750M parametre</li>
891
- <li><strong>Daha iyi tokenizer:</strong> NFC Unicode normalization</li>
892
- <li><strong>Instruction tuning:</strong> 10K doğrulanmış QA çifti</li>
893
- <li><strong>Alignment:</strong> Gerçeklik için RLHF veya DPO</li>
894
- <li><strong>Değerlendirme:</strong> Gerçek kontrol benchmark'ları</li>
895
- </ul>
896
- </div>
897
-
898
  <!-- Lisans ve Atıf -->
899
  <div class="card">
900
  <div class="card-header">
@@ -952,7 +1367,8 @@ tokenizer_exp = AutoTokenizer.from_pretrained("sixfingerdev/kayra-1-exp")
952
  print("Modeller başarıyla yüklendi!")
953
 
954
  # ==================== YARDIMCI FONKSİYONLAR ====================
955
- def generate_response(model, tokenizer, prompt, max_new_tokens=150):
 
956
  if model == model_stable:
957
  formatted_prompt = f"### Soru: {prompt}\n\n### Cevap:"
958
  else:
@@ -968,20 +1384,58 @@ def generate_response(model, tokenizer, prompt, max_new_tokens=150):
968
  outputs = model.generate(
969
  **inputs,
970
  max_new_tokens=max_new_tokens,
971
- temperature=0.7,
972
  do_sample=True,
973
- top_p=0.9,
974
- repetition_penalty=1.3,
 
975
  pad_token_id=tokenizer.eos_token_id
976
  )
977
 
978
  response = tokenizer.decode(outputs[0], skip_special_tokens=True)
 
979
 
980
  if model == model_stable:
981
  if "### Cevap:" in response:
982
  response = response.split("### Cevap:")[-1].strip()
983
 
984
- return response
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
985
 
986
  # ==================== ROUTE'LAR ====================
987
  @app.route("/")
@@ -998,22 +1452,93 @@ def generate():
998
  prompt = data.get("prompt", "").strip()
999
  model_choice = data.get("model", "stable")
1000
 
 
 
 
 
 
 
 
1001
  if not prompt:
1002
  return jsonify({"error": "Lütfen bir soru veya mesaj girin."})
1003
 
1004
  if model_choice == "stable":
1005
- response = generate_response(model_stable, tokenizer_stable, prompt)
 
 
 
 
 
 
 
1006
  model_name = "kayra-1 (Stable)"
1007
  else:
1008
- response = generate_response(model_exp, tokenizer_exp, prompt)
 
 
 
 
 
 
 
1009
  model_name = "kayra-1-exp (Deneysel)"
1010
 
1011
  return jsonify({
1012
  "model": model_name,
1013
  "prompt": prompt,
1014
- "response": response
 
1015
  })
1016
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1017
  # ==================== UYGULAMA BAŞLATMA ====================
1018
  if __name__ == "__main__":
1019
- app.run(host="0.0.0.0", port=7860, debug=False)
 
1
+ from flask import Flask, request, jsonify, render_template_string, Response
 
 
 
 
2
  import torch
3
+ from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer
4
+ from threading import Thread
5
+ import json
6
 
7
  app = Flask(__name__)
8
 
 
171
  transform: none;
172
  }
173
 
174
+ .btn-stop {
175
+ background: linear-gradient(135deg, var(--accent), #c0392b);
176
+ color: var(--white);
177
+ margin-top: 0.5rem;
178
+ display: none;
179
+ }
180
+
181
+ .btn-stop.active {
182
+ display: block;
183
+ }
184
+
185
  .form-group {
186
  margin-bottom: 1.5rem;
187
  }
188
 
189
+ /* ==================== SETTINGS PANEL ==================== */
190
+ .settings-panel {
191
+ background: linear-gradient(135deg, #f8f9fa, #e9ecef);
192
+ border-radius: var(--radius);
193
+ padding: 1.5rem;
194
+ margin-bottom: 1.5rem;
195
+ }
196
+
197
+ .settings-header {
198
+ display: flex;
199
+ justify-content: space-between;
200
+ align-items: center;
201
+ cursor: pointer;
202
+ margin-bottom: 1rem;
203
+ }
204
+
205
+ .settings-header h3 {
206
+ color: var(--primary);
207
+ font-size: 1.1rem;
208
+ display: flex;
209
+ align-items: center;
210
+ gap: 0.5rem;
211
+ }
212
+
213
+ .settings-toggle {
214
+ background: var(--secondary);
215
+ color: var(--white);
216
+ border: none;
217
+ padding: 0.3rem 0.8rem;
218
+ border-radius: 6px;
219
+ cursor: pointer;
220
+ font-size: 0.85rem;
221
+ transition: all 0.3s ease;
222
+ }
223
+
224
+ .settings-toggle:hover {
225
+ background: #2980b9;
226
+ }
227
+
228
+ .settings-content {
229
+ display: none;
230
+ }
231
+
232
+ .settings-content.active {
233
+ display: block;
234
+ }
235
+
236
+ .settings-grid {
237
+ display: grid;
238
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
239
+ gap: 1.5rem;
240
+ }
241
+
242
+ .setting-item {
243
+ background: var(--white);
244
+ padding: 1rem;
245
+ border-radius: 8px;
246
+ box-shadow: 0 2px 8px rgba(0,0,0,0.05);
247
+ }
248
+
249
+ .setting-item label {
250
+ display: flex;
251
+ justify-content: space-between;
252
+ align-items: center;
253
+ margin-bottom: 0.8rem;
254
+ }
255
+
256
+ .setting-item label span.value {
257
+ background: var(--secondary);
258
+ color: var(--white);
259
+ padding: 0.2rem 0.6rem;
260
+ border-radius: 4px;
261
+ font-size: 0.85rem;
262
+ min-width: 50px;
263
+ text-align: center;
264
+ }
265
+
266
+ .setting-item input[type="range"] {
267
+ width: 100%;
268
+ height: 8px;
269
+ border-radius: 4px;
270
+ background: var(--light);
271
+ outline: none;
272
+ -webkit-appearance: none;
273
+ }
274
+
275
+ .setting-item input[type="range"]::-webkit-slider-thumb {
276
+ -webkit-appearance: none;
277
+ width: 20px;
278
+ height: 20px;
279
+ border-radius: 50%;
280
+ background: var(--secondary);
281
+ cursor: pointer;
282
+ box-shadow: 0 2px 6px rgba(0,0,0,0.2);
283
+ transition: transform 0.2s ease;
284
+ }
285
+
286
+ .setting-item input[type="range"]::-webkit-slider-thumb:hover {
287
+ transform: scale(1.1);
288
+ }
289
+
290
+ .setting-item input[type="number"] {
291
+ width: 100%;
292
+ padding: 0.6rem;
293
+ border: 2px solid var(--light);
294
+ border-radius: 6px;
295
+ font-size: 1rem;
296
+ text-align: center;
297
+ }
298
+
299
+ .setting-item input[type="number"]:focus {
300
+ outline: none;
301
+ border-color: var(--secondary);
302
+ }
303
+
304
+ .setting-description {
305
+ font-size: 0.8rem;
306
+ color: var(--gray);
307
+ margin-top: 0.5rem;
308
+ }
309
+
310
+ /* Stream Toggle */
311
+ .stream-toggle {
312
+ display: flex;
313
+ align-items: center;
314
+ gap: 1rem;
315
+ padding: 0.5rem 0;
316
+ }
317
+
318
+ .toggle-switch {
319
+ position: relative;
320
+ width: 60px;
321
+ height: 30px;
322
+ }
323
+
324
+ .toggle-switch input {
325
+ opacity: 0;
326
+ width: 0;
327
+ height: 0;
328
+ }
329
+
330
+ .toggle-slider {
331
+ position: absolute;
332
+ cursor: pointer;
333
+ top: 0;
334
+ left: 0;
335
+ right: 0;
336
+ bottom: 0;
337
+ background-color: var(--gray);
338
+ transition: 0.4s;
339
+ border-radius: 30px;
340
+ }
341
+
342
+ .toggle-slider:before {
343
+ position: absolute;
344
+ content: "";
345
+ height: 22px;
346
+ width: 22px;
347
+ left: 4px;
348
+ bottom: 4px;
349
+ background-color: white;
350
+ transition: 0.4s;
351
+ border-radius: 50%;
352
+ }
353
+
354
+ .toggle-switch input:checked + .toggle-slider {
355
+ background-color: var(--success);
356
+ }
357
+
358
+ .toggle-switch input:checked + .toggle-slider:before {
359
+ transform: translateX(30px);
360
+ }
361
+
362
+ .toggle-label {
363
+ font-weight: 600;
364
+ color: var(--primary);
365
+ }
366
+
367
+ /* ==================== END SETTINGS PANEL ==================== */
368
+
369
  .response-box {
370
  background: linear-gradient(135deg, #f8f9fa, #e9ecef);
371
  border-radius: var(--radius);
 
396
  font-weight: 600;
397
  }
398
 
399
+ .stream-badge {
400
+ background: var(--success);
401
+ color: var(--white);
402
+ padding: 0.2rem 0.6rem;
403
+ border-radius: 12px;
404
+ font-size: 0.75rem;
405
+ font-weight: 600;
406
+ margin-left: 0.5rem;
407
+ }
408
+
409
  .response-content {
410
  white-space: pre-wrap;
411
  font-size: 1rem;
 
415
  color: var(--primary);
416
  }
417
 
418
+ .cursor-blink {
419
+ display: inline-block;
420
+ width: 8px;
421
+ height: 1.2em;
422
+ background: var(--secondary);
423
+ margin-left: 2px;
424
+ animation: blink 1s infinite;
425
+ vertical-align: text-bottom;
426
+ }
427
+
428
+ @keyframes blink {
429
+ 0%, 50% { opacity: 1; }
430
+ 51%, 100% { opacity: 0; }
431
+ }
432
+
433
  .loading {
434
  text-align: center;
435
  padding: 2rem;
 
598
  .two-column {
599
  grid-template-columns: 1fr;
600
  }
601
+
602
+ .settings-grid {
603
+ grid-template-columns: 1fr;
604
+ }
605
  }
606
 
607
  .two-column {
 
609
  grid-template-columns: 1fr 1fr;
610
  gap: 1rem;
611
  }
612
+
613
+ /* Preset buttons */
614
+ .preset-buttons {
615
+ display: flex;
616
+ gap: 0.5rem;
617
+ margin-bottom: 1rem;
618
+ flex-wrap: wrap;
619
+ }
620
+
621
+ .preset-btn {
622
+ padding: 0.4rem 0.8rem;
623
+ border: 2px solid var(--secondary);
624
+ background: var(--white);
625
+ color: var(--secondary);
626
+ border-radius: 6px;
627
+ cursor: pointer;
628
+ font-size: 0.85rem;
629
+ font-weight: 500;
630
+ transition: all 0.3s ease;
631
+ }
632
+
633
+ .preset-btn:hover {
634
+ background: var(--secondary);
635
+ color: var(--white);
636
+ }
637
+
638
+ .preset-btn.active {
639
+ background: var(--secondary);
640
+ color: var(--white);
641
+ }
642
+
643
+ /* Token counter */
644
+ .token-info {
645
+ display: flex;
646
+ justify-content: space-between;
647
+ font-size: 0.85rem;
648
+ color: var(--gray);
649
+ margin-top: 1rem;
650
+ padding-top: 0.5rem;
651
+ border-top: 1px dashed var(--light);
652
+ }
653
+
654
+ .token-count {
655
+ color: var(--secondary);
656
+ font-weight: 600;
657
+ }
658
  """
659
 
660
  # ==================== ANA SAYFA HTML ====================
 
669
  </head>
670
  <body>
671
  <nav class="navbar">
672
+ <h1>🤖 Kayra Türkçe Dil Modeli</h1>
673
  <div class="nav-links">
674
  <a href="/" class="active">Test</a>
675
  <a href="/info">Bilgi</a>
 
696
  </select>
697
  </div>
698
 
699
+ <!-- ==================== SETTINGS PANEL ==================== -->
700
+ <div class="settings-panel">
701
+ <div class="settings-header" onclick="toggleSettings()">
702
+ <h3>⚙️ Gelişmiş Ayarlar</h3>
703
+ <button class="settings-toggle" id="settingsToggleBtn">Göster</button>
704
+ </div>
705
+
706
+ <div class="settings-content" id="settingsContent">
707
+ <!-- Preset Buttons -->
708
+ <div class="preset-buttons">
709
+ <button class="preset-btn" onclick="applyPreset('creative')">🎨 Yaratıcı</button>
710
+ <button class="preset-btn active" onclick="applyPreset('balanced')">⚖️ Dengeli</button>
711
+ <button class="preset-btn" onclick="applyPreset('precise')">🎯 Kesin</button>
712
+ <button class="preset-btn" onclick="applyPreset('random')">🎲 Rastgele</button>
713
+ </div>
714
+
715
+ <div class="settings-grid">
716
+ <!-- Temperature -->
717
+ <div class="setting-item">
718
+ <label>
719
+ 🌡️ Temperature
720
+ <span class="value" id="tempValue">0.7</span>
721
+ </label>
722
+ <input type="range" id="temperature" min="0.1" max="2.0" step="0.1" value="0.7"
723
+ oninput="updateSlider('temperature', 'tempValue')">
724
+ <p class="setting-description">
725
+ Düşük = daha tutarlı, Yüksek = daha yaratıcı
726
+ </p>
727
+ </div>
728
+
729
+ <!-- Max Tokens -->
730
+ <div class="setting-item">
731
+ <label>
732
+ 📝 Max Tokens
733
+ <span class="value" id="maxTokensValue">150</span>
734
+ </label>
735
+ <input type="range" id="maxTokens" min="10" max="512" step="10" value="150"
736
+ oninput="updateSlider('maxTokens', 'maxTokensValue')">
737
+ <p class="setting-description">
738
+ Üretilecek maksimum token sayısı
739
+ </p>
740
+ </div>
741
+
742
+ <!-- Top K -->
743
+ <div class="setting-item">
744
+ <label>
745
+ 🔝 Top K
746
+ <span class="value" id="topKValue">50</span>
747
+ </label>
748
+ <input type="range" id="topK" min="1" max="100" step="1" value="50"
749
+ oninput="updateSlider('topK', 'topKValue')">
750
+ <p class="setting-description">
751
+ Her adımda değerlendirilecek en olası K token
752
+ </p>
753
+ </div>
754
+
755
+ <!-- Top P -->
756
+ <div class="setting-item">
757
+ <label>
758
+ 📊 Top P (Nucleus)
759
+ <span class="value" id="topPValue">0.9</span>
760
+ </label>
761
+ <input type="range" id="topP" min="0.1" max="1.0" step="0.05" value="0.9"
762
+ oninput="updateSlider('topP', 'topPValue')">
763
+ <p class="setting-description">
764
+ Kümülatif olasılık eşiği
765
+ </p>
766
+ </div>
767
+
768
+ <!-- Repetition Penalty -->
769
+ <div class="setting-item">
770
+ <label>
771
+ 🔄 Repetition Penalty
772
+ <span class="value" id="repPenaltyValue">1.3</span>
773
+ </label>
774
+ <input type="range" id="repPenalty" min="1.0" max="2.0" step="0.1" value="1.3"
775
+ oninput="updateSlider('repPenalty', 'repPenaltyValue')">
776
+ <p class="setting-description">
777
+ Tekrar eden kelimeleri engelleme gücü
778
+ </p>
779
+ </div>
780
+
781
+ <!-- Stream Toggle -->
782
+ <div class="setting-item">
783
+ <label>🌊 Stream Modu</label>
784
+ <div class="stream-toggle">
785
+ <label class="toggle-switch">
786
+ <input type="checkbox" id="streamMode" checked>
787
+ <span class="toggle-slider"></span>
788
+ </label>
789
+ <span class="toggle-label" id="streamLabel">Açık</span>
790
+ </div>
791
+ <p class="setting-description">
792
+ Cevabı kelime kelime göster
793
+ </p>
794
+ </div>
795
+ </div>
796
+ </div>
797
+ </div>
798
+ <!-- ==================== END SETTINGS PANEL ==================== -->
799
+
800
  <button class="btn btn-primary" id="submitBtn" onclick="generate()">
801
+ 🚀 Gönder ve Cevap Al
802
+ </button>
803
+
804
+ <button class="btn btn-stop" id="stopBtn" onclick="stopGeneration()">
805
+ ⏹️ Durdur
806
  </button>
807
 
808
  <div class="loading" id="loading">
 
814
  <div class="response-header">
815
  <span>Model:</span>
816
  <span class="model-badge" id="modelBadge"></span>
817
+ <span class="stream-badge" id="streamBadge" style="display:none;">STREAM</span>
818
  </div>
819
  <div class="response-content" id="responseContent"></div>
820
+ <div class="token-info">
821
+ <span>Üretilen token: <span class="token-count" id="tokenCount">0</span></span>
822
+ <span>Süre: <span class="token-count" id="genTime">0</span>s</span>
823
+ </div>
824
  </div>
825
 
826
  <div class="error-box" id="errorBox" style="display:none;"></div>
 
833
  </div>
834
 
835
  <script>
836
+ let eventSource = null;
837
+ let isGenerating = false;
838
+ let startTime = null;
839
+
840
+ // Settings toggle
841
+ function toggleSettings() {
842
+ const content = document.getElementById('settingsContent');
843
+ const btn = document.getElementById('settingsToggleBtn');
844
+ content.classList.toggle('active');
845
+ btn.textContent = content.classList.contains('active') ? 'Gizle' : 'Göster';
846
+ }
847
+
848
+ // Update slider value display
849
+ function updateSlider(sliderId, valueId) {
850
+ const slider = document.getElementById(sliderId);
851
+ const valueSpan = document.getElementById(valueId);
852
+ valueSpan.textContent = slider.value;
853
+ }
854
+
855
+ // Stream toggle
856
+ document.getElementById('streamMode').addEventListener('change', function() {
857
+ document.getElementById('streamLabel').textContent = this.checked ? 'Açık' : 'Kapalı';
858
+ });
859
+
860
+ // Presets
861
+ const presets = {
862
+ creative: { temperature: 1.2, maxTokens: 200, topK: 80, topP: 0.95, repPenalty: 1.1 },
863
+ balanced: { temperature: 0.7, maxTokens: 150, topK: 50, topP: 0.9, repPenalty: 1.3 },
864
+ precise: { temperature: 0.3, maxTokens: 100, topK: 20, topP: 0.8, repPenalty: 1.5 },
865
+ random: { temperature: 1.8, maxTokens: 250, topK: 100, topP: 1.0, repPenalty: 1.0 }
866
+ };
867
+
868
+ function applyPreset(presetName) {
869
+ const preset = presets[presetName];
870
+
871
+ document.getElementById('temperature').value = preset.temperature;
872
+ document.getElementById('tempValue').textContent = preset.temperature;
873
+
874
+ document.getElementById('maxTokens').value = preset.maxTokens;
875
+ document.getElementById('maxTokensValue').textContent = preset.maxTokens;
876
+
877
+ document.getElementById('topK').value = preset.topK;
878
+ document.getElementById('topKValue').textContent = preset.topK;
879
+
880
+ document.getElementById('topP').value = preset.topP;
881
+ document.getElementById('topPValue').textContent = preset.topP;
882
+
883
+ document.getElementById('repPenalty').value = preset.repPenalty;
884
+ document.getElementById('repPenaltyValue').textContent = preset.repPenalty;
885
+
886
+ // Update active button
887
+ document.querySelectorAll('.preset-btn').forEach(btn => btn.classList.remove('active'));
888
+ event.target.classList.add('active');
889
+ }
890
+
891
+ // Stop generation
892
+ function stopGeneration() {
893
+ if (eventSource) {
894
+ eventSource.close();
895
+ eventSource = null;
896
+ }
897
+ isGenerating = false;
898
+ document.getElementById('submitBtn').disabled = false;
899
+ document.getElementById('stopBtn').classList.remove('active');
900
+ document.getElementById('loading').classList.remove('active');
901
+
902
+ // Remove cursor
903
+ const cursor = document.querySelector('.cursor-blink');
904
+ if (cursor) cursor.remove();
905
+ }
906
+
907
+ // Main generate function
908
  async function generate() {
909
  const prompt = document.getElementById("prompt").value.trim();
910
  const model = document.getElementById("model").value;
911
+ const streamMode = document.getElementById("streamMode").checked;
912
+
913
+ const settings = {
914
+ temperature: parseFloat(document.getElementById("temperature").value),
915
+ max_tokens: parseInt(document.getElementById("maxTokens").value),
916
+ top_k: parseInt(document.getElementById("topK").value),
917
+ top_p: parseFloat(document.getElementById("topP").value),
918
+ repetition_penalty: parseFloat(document.getElementById("repPenalty").value)
919
+ };
920
+
921
  const responseBox = document.getElementById("responseBox");
922
  const loading = document.getElementById("loading");
923
  const errorBox = document.getElementById("errorBox");
924
  const submitBtn = document.getElementById("submitBtn");
925
+ const stopBtn = document.getElementById("stopBtn");
926
+ const streamBadge = document.getElementById("streamBadge");
927
 
928
  if (!prompt) {
929
  errorBox.textContent = "Lütfen bir mesaj girin!";
 
934
 
935
  errorBox.style.display = "none";
936
  responseBox.classList.remove("active");
 
937
  submitBtn.disabled = true;
938
+ isGenerating = true;
939
+ startTime = Date.now();
940
+
941
+ document.getElementById("tokenCount").textContent = "0";
942
+ document.getElementById("genTime").textContent = "0";
943
 
944
+ if (streamMode) {
945
+ // Stream mode
946
+ loading.classList.add("active");
947
+ stopBtn.classList.add("active");
948
+ streamBadge.style.display = "inline-block";
949
+
950
+ const params = new URLSearchParams({
951
+ prompt: prompt,
952
+ model: model,
953
+ ...settings
954
  });
955
 
956
+ eventSource = new EventSource("/generate_stream?" + params.toString());
957
+
958
+ let fullResponse = "";
959
+ let tokenCount = 0;
960
 
961
+ document.getElementById("modelBadge").textContent = model === "stable" ? "kayra-1 (Stable)" : "kayra-1-exp (Deneysel)";
962
+ document.getElementById("responseContent").innerHTML =
963
+ "<strong>Soru:</strong> " + escapeHtml(prompt) +
964
+ "\\n\\n<strong>Cevap:</strong>\\n<span id='streamOutput'></span><span class='cursor-blink'></span>";
965
+ responseBox.classList.add("active");
966
+ loading.classList.remove("active");
967
+
968
+ eventSource.onmessage = function(event) {
969
+ const data = JSON.parse(event.data);
970
+
971
+ if (data.token) {
972
+ fullResponse += data.token;
973
+ tokenCount++;
974
+ document.getElementById("streamOutput").textContent = fullResponse;
975
+ document.getElementById("tokenCount").textContent = tokenCount;
976
+ document.getElementById("genTime").textContent = ((Date.now() - startTime) / 1000).toFixed(1);
977
+ }
978
+
979
+ if (data.done) {
980
+ stopGeneration();
981
+ }
982
+
983
+ if (data.error) {
984
+ errorBox.textContent = "Hata: " + data.error;
985
+ errorBox.style.display = "block";
986
+ stopGeneration();
987
+ }
988
+ };
989
+
990
+ eventSource.onerror = function() {
991
+ stopGeneration();
992
+ };
993
+
994
+ } else {
995
+ // Non-stream mode
996
+ loading.classList.add("active");
997
+ streamBadge.style.display = "none";
998
+
999
+ try {
1000
+ const response = await fetch("/generate", {
1001
+ method: "POST",
1002
+ headers: { "Content-Type": "application/json" },
1003
+ body: JSON.stringify({ prompt, model, ...settings })
1004
+ });
1005
+
1006
+ const data = await response.json();
1007
+
1008
+ if (data.error) {
1009
+ errorBox.textContent = "Hata: " + data.error;
1010
+ errorBox.style.display = "block";
1011
+ } else {
1012
+ document.getElementById("modelBadge").textContent = data.model;
1013
+ document.getElementById("responseContent").innerHTML =
1014
+ "<strong>Soru:</strong> " + escapeHtml(data.prompt) +
1015
+ "\\n\\n<strong>Cevap:</strong>\\n" + escapeHtml(data.response);
1016
+ document.getElementById("tokenCount").textContent = data.token_count || "N/A";
1017
+ document.getElementById("genTime").textContent = ((Date.now() - startTime) / 1000).toFixed(1);
1018
+ responseBox.classList.add("active");
1019
+ }
1020
+ } catch (err) {
1021
+ errorBox.textContent = "Bağlantı hatası: " + err.message;
1022
  errorBox.style.display = "block";
1023
+ } finally {
1024
+ loading.classList.remove("active");
1025
+ submitBtn.disabled = false;
1026
+ isGenerating = false;
 
 
1027
  }
 
 
 
 
 
 
1028
  }
1029
  }
1030
 
 
1056
  </head>
1057
  <body>
1058
  <nav class="navbar">
1059
+ <h1>🤖 Kayra Türkçe Dil Modeli</h1>
1060
  <div class="nav-links">
1061
  <a href="/">Test</a>
1062
  <a href="/info" class="active">Bilgi</a>
 
1094
  </div>
1095
  </div>
1096
 
1097
+ <!-- Parametre Açıklamaları -->
1098
+ <div class="card">
1099
+ <div class="card-header">
1100
+ <h2>⚙️ Parametre Açıklamaları</h2>
1101
+ </div>
1102
+
1103
+ <table>
1104
+ <thead>
1105
+ <tr>
1106
+ <th>Parametre</th>
1107
+ <th>Aralık</th>
1108
+ <th>Varsayılan</th>
1109
+ <th>Açıklama</th>
1110
+ </tr>
1111
+ </thead>
1112
+ <tbody>
1113
+ <tr>
1114
+ <td><strong>Temperature</strong></td>
1115
+ <td>0.1 - 2.0</td>
1116
+ <td>0.7</td>
1117
+ <td>Çıktının rastgeleliğini kontrol eder. Düşük değerler daha tutarlı, yüksek değerler daha yaratıcı sonuçlar üretir.</td>
1118
+ </tr>
1119
+ <tr>
1120
+ <td><strong>Max Tokens</strong></td>
1121
+ <td>10 - 512</td>
1122
+ <td>150</td>
1123
+ <td>Üretilecek maksimum token (kelime parçası) sayısı.</td>
1124
+ </tr>
1125
+ <tr>
1126
+ <td><strong>Top K</strong></td>
1127
+ <td>1 - 100</td>
1128
+ <td>50</td>
1129
+ <td>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.</td>
1130
+ </tr>
1131
+ <tr>
1132
+ <td><strong>Top P (Nucleus)</strong></td>
1133
+ <td>0.1 - 1.0</td>
1134
+ <td>0.9</td>
1135
+ <td>Kümülatif olasılığı P'yi geçen tokenlerden seçim yapılır. Temperature ile birlikte kullanılır.</td>
1136
+ </tr>
1137
+ <tr>
1138
+ <td><strong>Repetition Penalty</strong></td>
1139
+ <td>1.0 - 2.0</td>
1140
+ <td>1.3</td>
1141
+ <td>Tekrarlayan kelimeleri cezalandırır. Yüksek değerler tekrarı azaltır ama anlam bozulabilir.</td>
1142
+ </tr>
1143
+ <tr>
1144
+ <td><strong>Stream Mode</strong></td>
1145
+ <td>Açık/Kapalı</td>
1146
+ <td>Açık</td>
1147
+ <td>Açıkken cevap kelime kelime gösterilir, kapalıyken tamamı bir anda gösterilir.</td>
1148
+ </tr>
1149
+ </tbody>
1150
+ </table>
1151
+ </div>
1152
+
1153
+ <!-- Preset Açıklamaları -->
1154
+ <div class="card">
1155
+ <div class="card-header">
1156
+ <h2>🎛️ Hazır Ayarlar (Presets)</h2>
1157
+ </div>
1158
+
1159
+ <div class="two-column">
1160
+ <div class="setting-item">
1161
+ <h4>🎨 Yaratıcı</h4>
1162
+ <p>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.</p>
1163
+ <code>temp=1.2, top_k=80, top_p=0.95, rep=1.1</code>
1164
+ </div>
1165
+ <div class="setting-item">
1166
+ <h4>⚖️ Dengeli</h4>
1167
+ <p>Varsayılan ayarlar. Çoğu kullanım senaryosu için uygundur.</p>
1168
+ <code>temp=0.7, top_k=50, top_p=0.9, rep=1.3</code>
1169
+ </div>
1170
+ <div class="setting-item">
1171
+ <h4>🎯 Kesin</h4>
1172
+ <p>Düşük temperature ile daha tutarlı ve tahmin edilebilir çıktılar. Bilgi gerektiren sorular için.</p>
1173
+ <code>temp=0.3, top_k=20, top_p=0.8, rep=1.5</code>
1174
+ </div>
1175
+ <div class="setting-item">
1176
+ <h4>🎲 Rastgele</h4>
1177
+ <p>Maksimum rastgelelik. Çılgın ve beklenmedik sonuçlar için. Dikkatli kullanın!</p>
1178
+ <code>temp=1.8, top_k=100, top_p=1.0, rep=1.0</code>
1179
+ </div>
1180
+ </div>
1181
+ </div>
1182
+
1183
  <!-- Model Karşılaştırması -->
1184
  <div class="card">
1185
  <div class="card-header">
 
1278
  </table>
1279
  </div>
1280
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1281
  <!-- Kullanım Örneği -->
1282
  <div class="card">
1283
  <div class="card-header">
 
1301
  max_new_tokens=100,
1302
  temperature=0.8,
1303
  top_k=50,
1304
+ top_p=0.9,
1305
  repetition_penalty=1.2,
1306
  do_sample=True
1307
  )
 
1310
  </div>
1311
  </div>
1312
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1313
  <!-- Lisans ve Atıf -->
1314
  <div class="card">
1315
  <div class="card-header">
 
1367
  print("Modeller başarıyla yüklendi!")
1368
 
1369
  # ==================== YARDIMCI FONKSİYONLAR ====================
1370
+ def generate_response(model, tokenizer, prompt, max_new_tokens=150, temperature=0.7,
1371
+ top_k=50, top_p=0.9, repetition_penalty=1.3):
1372
  if model == model_stable:
1373
  formatted_prompt = f"### Soru: {prompt}\n\n### Cevap:"
1374
  else:
 
1384
  outputs = model.generate(
1385
  **inputs,
1386
  max_new_tokens=max_new_tokens,
1387
+ temperature=temperature,
1388
  do_sample=True,
1389
+ top_k=top_k,
1390
+ top_p=top_p,
1391
+ repetition_penalty=repetition_penalty,
1392
  pad_token_id=tokenizer.eos_token_id
1393
  )
1394
 
1395
  response = tokenizer.decode(outputs[0], skip_special_tokens=True)
1396
+ token_count = outputs.shape[1] - inputs['input_ids'].shape[1]
1397
 
1398
  if model == model_stable:
1399
  if "### Cevap:" in response:
1400
  response = response.split("### Cevap:")[-1].strip()
1401
 
1402
+ return response, token_count
1403
+
1404
+ def generate_stream(model, tokenizer, prompt, max_new_tokens=150, temperature=0.7,
1405
+ top_k=50, top_p=0.9, repetition_penalty=1.3):
1406
+ """Generator function for streaming responses"""
1407
+ if model == model_stable:
1408
+ formatted_prompt = f"### Soru: {prompt}\n\n### Cevap:"
1409
+ else:
1410
+ formatted_prompt = prompt
1411
+
1412
+ inputs = tokenizer(formatted_prompt, return_tensors="pt")
1413
+ inputs = inputs.to(model.device)
1414
+
1415
+ if "token_type_ids" in inputs:
1416
+ inputs.pop("token_type_ids")
1417
+
1418
+ streamer = TextIteratorStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True)
1419
+
1420
+ generation_kwargs = dict(
1421
+ **inputs,
1422
+ max_new_tokens=max_new_tokens,
1423
+ temperature=temperature,
1424
+ do_sample=True,
1425
+ top_k=top_k,
1426
+ top_p=top_p,
1427
+ repetition_penalty=repetition_penalty,
1428
+ pad_token_id=tokenizer.eos_token_id,
1429
+ streamer=streamer
1430
+ )
1431
+
1432
+ thread = Thread(target=model.generate, kwargs=generation_kwargs)
1433
+ thread.start()
1434
+
1435
+ for text in streamer:
1436
+ yield text
1437
+
1438
+ thread.join()
1439
 
1440
  # ==================== ROUTE'LAR ====================
1441
  @app.route("/")
 
1452
  prompt = data.get("prompt", "").strip()
1453
  model_choice = data.get("model", "stable")
1454
 
1455
+ # Get settings with defaults
1456
+ max_tokens = data.get("max_tokens", 150)
1457
+ temperature = data.get("temperature", 0.7)
1458
+ top_k = data.get("top_k", 50)
1459
+ top_p = data.get("top_p", 0.9)
1460
+ repetition_penalty = data.get("repetition_penalty", 1.3)
1461
+
1462
  if not prompt:
1463
  return jsonify({"error": "Lütfen bir soru veya mesaj girin."})
1464
 
1465
  if model_choice == "stable":
1466
+ response, token_count = generate_response(
1467
+ model_stable, tokenizer_stable, prompt,
1468
+ max_new_tokens=max_tokens,
1469
+ temperature=temperature,
1470
+ top_k=top_k,
1471
+ top_p=top_p,
1472
+ repetition_penalty=repetition_penalty
1473
+ )
1474
  model_name = "kayra-1 (Stable)"
1475
  else:
1476
+ response, token_count = generate_response(
1477
+ model_exp, tokenizer_exp, prompt,
1478
+ max_new_tokens=max_tokens,
1479
+ temperature=temperature,
1480
+ top_k=top_k,
1481
+ top_p=top_p,
1482
+ repetition_penalty=repetition_penalty
1483
+ )
1484
  model_name = "kayra-1-exp (Deneysel)"
1485
 
1486
  return jsonify({
1487
  "model": model_name,
1488
  "prompt": prompt,
1489
+ "response": response,
1490
+ "token_count": token_count
1491
  })
1492
 
1493
+ @app.route("/generate_stream")
1494
+ def generate_stream_route():
1495
+ prompt = request.args.get("prompt", "").strip()
1496
+ model_choice = request.args.get("model", "stable")
1497
+
1498
+ # Get settings with defaults
1499
+ max_tokens = int(request.args.get("max_tokens", 150))
1500
+ temperature = float(request.args.get("temperature", 0.7))
1501
+ top_k = int(request.args.get("top_k", 50))
1502
+ top_p = float(request.args.get("top_p", 0.9))
1503
+ repetition_penalty = float(request.args.get("repetition_penalty", 1.3))
1504
+
1505
+ if not prompt:
1506
+ def error_gen():
1507
+ yield f"data: {json.dumps({'error': 'Prompt gerekli'})}\n\n"
1508
+ return Response(error_gen(), mimetype="text/event-stream")
1509
+
1510
+ if model_choice == "stable":
1511
+ model = model_stable
1512
+ tokenizer = tokenizer_stable
1513
+ else:
1514
+ model = model_exp
1515
+ tokenizer = tokenizer_exp
1516
+
1517
+ def event_stream():
1518
+ try:
1519
+ for token in generate_stream(
1520
+ model, tokenizer, prompt,
1521
+ max_new_tokens=max_tokens,
1522
+ temperature=temperature,
1523
+ top_k=top_k,
1524
+ top_p=top_p,
1525
+ repetition_penalty=repetition_penalty
1526
+ ):
1527
+ yield f"data: {json.dumps({'token': token})}\n\n"
1528
+ yield f"data: {json.dumps({'done': True})}\n\n"
1529
+ except Exception as e:
1530
+ yield f"data: {json.dumps({'error': str(e)})}\n\n"
1531
+
1532
+ return Response(
1533
+ event_stream(),
1534
+ mimetype="text/event-stream",
1535
+ headers={
1536
+ "Cache-Control": "no-cache",
1537
+ "Connection": "keep-alive",
1538
+ "X-Accel-Buffering": "no"
1539
+ }
1540
+ )
1541
+
1542
  # ==================== UYGULAMA BAŞLATMA ====================
1543
  if __name__ == "__main__":
1544
+ app.run(host="0.0.0.0", port=7860, debug=False, threaded=True)