o
    i\N                     @   s  d dl mZmZmZmZmZmZmZ d dlm	Z	 d dl
mZmZmZmZmZmZ d dlmZmZ d dlmZ d dlZd dlZeeZdejd< d	ejd
< dejd< e	eZe Zee de_G dd deejZ G dd dejZ!G dd dejZ"G dd dejZ#ej$dd Z%dd Z&dZ'e'd Z(e'd Z)e'd Z*e+ddd  Z,ej+d!d"d#gd$d%d Z-ej+d&d"d#gd$d'd( Z.e+d)ed*d+ Z/e+d,ed-d. Z0e+d/ed0d1 Z1ej+d2d#gd$ed3d4 Z2e+d5ed6d7 Z3ej+d8d#gd$ed9d: Z4ej+d;d#gd$ed<d= Z5ej+d>d#gd$ed?d@ Z6e7 ? e8  e j9j:dAdB; sEej<=e dAedCd7dD e j9j:dEdB; s\ej<=e dEedFd7dD ej<>  W d   n	1 slw   Y  edGkrej?dHdIdJ dS dS )K    )Flaskrender_template_stringrequestjsonifyredirecturl_forflash)
SQLAlchemy)LoginManager	UserMixin
login_userlogin_requiredlogout_usercurrent_user)generate_password_hashcheck_password_hash)SequenceMatcherNzsuper-gizli-anahtar
SECRET_KEYz3mysql+pymysql://root:Mmty2676*@localhost/arapca_appSQLALCHEMY_DATABASE_URIFSQLALCHEMY_TRACK_MODIFICATIONSloginc                   @   sj   e Zd ZejejddZejeddddZejedddZ	ejedd	d
Z
ejejdd
ZdS )UserTprimary_key2   F)uniquenullable   r      user)defaultr   N)__name__
__module____qualname__dbColumnIntegeridStringusernamepasswordrolescore r.   r.   "/var/www/html/arapca_proje/main.pyr      s    r   c                   @   sB   e Zd ZejejddZejedddZej	ddddd	Z
d
S )UnitTr   d   Fr   Lessonunitall, delete-orphanbackrefcascadelazyN)r"   r#   r$   r%   r&   r'   r(   r)   titlerelationshiplessonsr.   r.   r.   r/   r0      s    r0   c                   @   sZ   e Zd ZejejddZejejedddZeje	dddZ
ejddd	dd
ZdS )r2   Tr   zunit.idFr   r1   Wordlessonr4   r5   N)r"   r#   r$   r%   r&   r'   r(   
ForeignKeyunit_idr)   r9   r:   wordsr.   r.   r.   r/   r2      s
    r2   c                   @   sp   e Zd ZejejddZejejedddZeje	dddZ
eje	dddZeje	dddZdS )	r<   Tr   z	lesson.idFr   r1   r   N)r"   r#   r$   r%   r&   r'   r(   r>   	lesson_idr)   artrq_typer.   r.   r.   r/   r<   %   s    r<   c                 C   s   t jt| S )N)r   querygetint)user_idr.   r.   r/   	load_user,   s   rI   c                 C   s   t d}t |d| S )Nz[\u0617-\u061A\u064B-\u0652] )recompilesub)texttashkeelr.   r.   r/   strip_tashkeel0   s   
rP   a	  
<style>
    @import url('https://fonts.googleapis.com/css2?family=Nunito:wght@400;700;900&family=Tajawal:wght@700&display=swap');
    :root { --primary: #1CB0F6; --primary-dark: #1899D6; --success: #58CC02; --success-dark: #58A700; --danger: #FF4B4B; --danger-dark: #EA1538; --bg: #F7F7F7; --text: #4B4B4B; }
    * { box-sizing: border-box; font-family: 'Nunito', sans-serif; }
    body { background-color: var(--bg); color: var(--text); margin: 0; padding: 20px; display: flex; flex-direction: column; align-items: center; min-height: 100vh; }
    .card { background: white; border-radius: 20px; box-shadow: 0 10px 25px rgba(0,0,0,0.05); padding: 30px; width: 100%; max-width: 600px; margin-bottom: 20px; text-align: center; border: 2px solid #E5E5E5; }
    h1, h2, h3 { color: #3C3C3C; }
    input, select { width: 100%; padding: 12px; margin: 8px 0; border: 2px solid #E5E5E5; border-radius: 12px; font-size: 16px; outline: none; transition: 0.2s; }
    input:focus, select:focus { border-color: var(--primary); }
    .btn { display: inline-block; padding: 12px; border-radius: 12px; font-size: 16px; font-weight: bold; color: white; cursor: pointer; border: none; text-decoration: none; margin-top: 5px; width: 100%; text-align:center; }
    .btn-blue { background-color: var(--primary); box-shadow: 0 4px 0 var(--primary-dark); }
    .btn-blue:active { transform: translateY(4px); box-shadow: none; }
    .btn-green { background-color: var(--success); box-shadow: 0 4px 0 var(--success-dark); }
    .btn-green:active { transform: translateY(4px); box-shadow: none; }
    .btn-red { background-color: var(--danger); box-shadow: 0 4px 0 var(--danger-dark); }
    .btn:disabled { background-color: #E5E5E5; box-shadow: 0 4px 0 #CECECE; cursor: not-allowed; color: #AFAFAF; }
    .arabic-text { font-family: 'Tajawal', sans-serif; font-size: 3rem; color: #2C3E50; direction: rtl; margin: 20px 0; }
    .badge { background: #FFC800; color: #B38C00; padding: 5px 15px; border-radius: 20px; font-weight: 900; }
    .admin-box { background: #f9f9f9; border: 2px solid #eee; padding: 15px; border-radius: 15px; margin-bottom: 15px; text-align: left; }
    table { width: 100%; border-collapse: collapse; margin-top: 10px; }
    th, td { padding: 8px; border-bottom: 1px solid #ddd; text-align: left; }
</style>
u  
<title>Yol Haritası</title>
<div class="card">
    <h2>Merhaba, {{ user.username }}! 🌟</h2>
    <div class="badge" style="font-size:18px; margin-bottom:20px;">Puanın: {{ user.score }} XP</div>
    {% if user.role == 'admin' %}<a href="/admin" class="btn btn-red" style="margin-bottom:20px;">👑 ADMİN PANELİNE GİT</a>{% endif %}
    <a href="/logout" style="color:#AFAFAF; font-weight:bold; text-decoration:none; display:block; margin-bottom:20px;">Çıkış Yap</a>

    {% for u in units %}
        <div style="background:#F0F9FF; border:2px solid var(--primary); padding:20px; border-radius:20px; margin-bottom:20px; text-align:left;">
            <h3 style="margin:0 0 10px 0; color:var(--primary-dark);">📚 {{ u.title }}</h3>
            {% for lesson in u.lessons %}
                <div style="background:white; padding:15px; border-radius:12px; margin-bottom:10px; display:flex; justify-content:space-between; align-items:center; border:1px solid #eee;">
                    <span style="font-weight:bold; font-size:16px;">{{ lesson.title }} ({{ lesson.words|length }} Kelime)</span>
                    <a href="/lesson/{{ lesson.id }}" class="btn btn-green" style="width:auto; padding:8px 20px; margin:0;">Başla</a>
                </div>
            {% endfor %}
            {% if not u.lessons %}<p style="color:#777; font-size:14px;">Henüz ders eklenmedi.</p>{% endif %}
        </div>
    {% endfor %}
    {% if not units %}<p>Henüz hiç ünite eklenmemiş. Admin panelinden ekleyin.</p>{% endif %}
</div>
u  
<title>Ders Ekranı</title>
<script src="https://unpkg.com/@lottiefiles/lottie-player@latest/dist/lottie-player.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<div class="card">
    <div style="height:120px;"><lottie-player src="https://assets2.lottiefiles.com/packages/lf20_1s3zjcmm.json" background="transparent" speed="1" loop autoplay></lottie-player></div>
    
    <div id="soru-tipi" class="badge">Yükleniyor...</div>
    <div id="kelime" class="arabic-text"></div>
    <h3 id="anlam" style="color:#AFAFAF;"></h3>
    
    <button id="aksiyonBtn" class="btn btn-blue" onclick="aksiyonYap()">BAŞLA</button>
    <p id="durum" style="font-weight:bold; margin-top:15px;"></p>
    <a href="/dashboard" style="display:block; margin-top:20px; color:#AFAFAF; font-weight:bold; text-decoration:none;">Dersi Terk Et</a>
</div>

<script>
    const kelimeler = {{ words|tojson }};
    let index = 0;

    const kelimeDiv = document.getElementById("kelime");
    const anlamDiv = document.getElementById("anlam");
    const durumDiv = document.getElementById("durum");
    const aksiyonBtn = document.getElementById("aksiyonBtn");
    const soruTipiDiv = document.getElementById("soru-tipi");

    const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
    const recognition = new SpeechRecognition();
    recognition.lang = 'ar-SA';
    recognition.interimResults = false;
    recognition.continuous = false; 

    function ekraniGuncelle() {
        if(kelimeler.length === 0) {
            Swal.fire('Hata', 'Bu derste hiç kelime yok.', 'error').then(()=>window.location.href='/dashboard');
            return;
        }
        if(index >= kelimeler.length) {
            Swal.fire('Tebrikler!', 'Dersi tamamladın! XP kazandın.', 'success').then(() => window.location.href = '/dashboard');
            return;
        }
        
        let current = kelimeler[index];
        anlamDiv.innerText = current.tr;
        
        if(current.q_type === 'speaking') {
            soruTipiDiv.innerText = "Ekranda yazanı oku.";
            kelimeDiv.innerText = current.ar;
            aksiyonBtn.innerText = "🎤 KONUŞ";
            aksiyonBtn.className = "btn btn-blue";
        } else if (current.q_type === 'listening') {
            soruTipiDiv.innerText = "Duyduğunu Arapça söyle.";
            kelimeDiv.innerText = "🔊 ❓❓❓"; 
            aksiyonBtn.innerText = "▶️ DİNLE VE SÖYLE";
            aksiyonBtn.className = "btn btn-green";
        } else if (current.q_type === 'repeat') {
            soruTipiDiv.innerText = "Benden sonra tekrar et.";
            kelimeDiv.innerText = current.ar;
            aksiyonBtn.innerText = "🔁 DİNLE VE TEKRAR ET";
            aksiyonBtn.className = "btn btn-blue";
        }
    }

    // --- YENİLENMİŞ VE HATALARDAN ARINDIRILMIŞ SES OKUMA FONKSİYONU ---
    function arapcaOku(metin, callback) {
        // 1. Chrome'da sıkça yaşanan askıda kalma sorununu çözmek için önceki komutları iptal et
        window.speechSynthesis.cancel();

        let ses = new SpeechSynthesisUtterance(metin);
        ses.lang = 'ar-SA'; // Arapça dil
        ses.rate = 0.85;    // Anlaşılması için normalden biraz daha yavaş
        ses.pitch = 1.0;

        ses.onend = function() {
            if(callback) callback();
        };

        ses.onerror = function(event) {
            console.error("Tarayıcı sesi oynatamadı:", event);
            durumDiv.innerText = "Ses çalınamadı. Lütfen doğrudan konuşmayı deneyin.";
            // Hata olsa bile sistemin donmaması için callback'i tetikliyoruz:
            if(callback) callback(); 
        };

        // Gecikme eklendi (Chrome'un iptal işleminden sonra nefes alması için)
        setTimeout(() => {
            window.speechSynthesis.speak(ses);
        }, 100);
    }

    function aksiyonYap() {
        let current = kelimeler[index];
        if(current.q_type === 'speaking') { 
            dinlemeyeBasla(); 
        } 
        else {
            durumDiv.innerText = "🔊 Robot konuşuyor, dinle...";
            durumDiv.style.color = "var(--primary)";
            aksiyonBtn.disabled = true;
            
            // Okuma işlemi bittiğinde mikrafonu aç
            arapcaOku(current.ar, () => { 
                dinlemeyeBasla(); 
            });
        }
    }

    function dinlemeyeBasla() {
        durumDiv.innerText = "Sıra sende, konuş! 🎤";
        durumDiv.style.color = "var(--primary)";
        aksiyonBtn.disabled = true;
        try { recognition.start(); } catch(e) {}
    }

    recognition.onresult = function(event) {
        const soylenenMetin = event.results[0][0].transcript;
        durumDiv.innerText = "Yapay Zeka Sesini Analiz Ediyor... 🤖";
        
        fetch('/kontrol', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ 'hedef_kelime': kelimeler[index].ar, 'soylenen': soylenenMetin })
        }).then(res => res.json()).then(data => {
            if(data.durum === 'basarili') {
                Swal.fire({ title: 'Harika!', text: data.mesaj, icon: 'success', timer: 1500, showConfirmButton: false });
                index++;
                setTimeout(() => { aksiyonBtn.disabled = false; durumDiv.innerText=""; ekraniGuncelle(); }, 1500);
            } else {
                Swal.fire({ title: 'Yanlış Telaffuz!', html: data.mesaj, icon: 'error' });
                aksiyonBtn.disabled = false;
                durumDiv.innerText = "Tekrar deneyin.";
                durumDiv.style.color = "var(--danger)";
            }
        });
    };

    recognition.onerror = function(event) {
        if(event.error === 'no-speech') {
            durumDiv.innerText = "Ses duyulmadı. Butona basıp tekrar dene.";
        } else {
            durumDiv.innerText = "Mikrofon hatası: " + event.error;
        }
        durumDiv.style.color = "var(--danger)";
        aksiyonBtn.disabled = false;
    };

    recognition.onend = function() {
        if(aksiyonBtn.disabled && durumDiv.innerText.includes("konuş!")) {
            aksiyonBtn.disabled = false;
            durumDiv.innerText = "Süre doldu, tekrar butona basın.";
            durumDiv.style.color = "var(--danger)";
        }
    };

    ekraniGuncelle();
</script>
u  
<title>Admin Paneli</title>
<div class="card" style="max-width:800px;">
    <h1 style="color:var(--danger);">👑 ADMİN PANELİ</h1>
    <a href="/dashboard" class="btn btn-blue" style="margin-bottom:20px;">Ana Sayfaya Dön</a>
    
    {% with messages = get_flashed_messages() %}
        {% if messages %}<div style="background:var(--success); color:white; padding:10px; border-radius:10px; margin-bottom:15px;">{{ messages[0] }}</div>{% endif %}
    {% endwith %}

    <div class="admin-box">
        <h3>1. Yeni Ünite Ekle</h3>
        <form action="/admin/add_unit" method="POST">
            <input type="text" name="title" placeholder="Ünite Adı (Örn: Ünite 1: Aile)" required>
            <button type="submit" class="btn btn-blue">Ünite Oluştur</button>
        </form>
    </div>

    <h3>Mevcut Eğitim İçeriği (Hiyerarşi)</h3>
    {% for u in units %}
        <div class="admin-box" style="border-color:var(--primary);">
            <h2 style="color:var(--primary); margin-top:0;">📂 {{ u.title }}</h2>
            
            <form action="/admin/add_lesson" method="POST" style="display:flex; gap:10px;">
                <input type="hidden" name="unit_id" value="{{ u.id }}">
                <input type="text" name="title" placeholder="Yeni Ders Adı" required style="margin:0;">
                <button type="submit" class="btn btn-green" style="margin:0; width:150px;">Ders Ekle</button>
            </form>

            {% for lesson in u.lessons %}
                <div style="background:white; border:1px solid #ccc; padding:10px; margin-top:10px; border-radius:10px;">
                    <h4 style="margin:0 0 10px 0; color:var(--success-dark);">📄 {{ lesson.title }}</h4>
                    
                    <form action="/admin/add_word" method="POST" style="display:flex; gap:5px; flex-wrap:wrap; margin-bottom:10px;">
                        <input type="hidden" name="lesson_id" value="{{ lesson.id }}">
                        <input type="text" name="ar" placeholder="Arapça" required style="width:25%; margin:0; direction:rtl;">
                        <input type="text" name="tr" placeholder="Türkçe" required style="width:25%; margin:0;">
                        <select name="q_type" style="width:25%; margin:0;">
                            <option value="speaking">Konuşma (Speaking)</option>
                            <option value="listening">Dinleme (Listening)</option>
                            <option value="repeat">Tekrar (Repeat)</option>
                        </select>
                        <button type="submit" class="btn btn-blue" style="width:20%; margin:0; padding:10px;">Kelime Ekle</button>
                    </form>

                    {% if lesson.words %}
                    <table>
                        <tr><th>Arapça</th><th>Türkçe</th><th>Soru Türü</th></tr>
                        {% for w in lesson.words %}
                        <tr><td style="direction:rtl; font-weight:bold;">{{ w.ar }}</td><td>{{ w.tr }}</td><td>{{ w.q_type }}</td></tr>
                        {% endfor %}
                    </table>
                    {% endif %}
                </div>
            {% endfor %}
        </div>
    {% endfor %}
</div>
/c                   C   s   t jr	ttdS ttdS )N	dashboardr   )r   is_authenticatedr   r   r.   r.   r.   r/   index?  s   rT   z/loginGETPOST)methodsc                  C   sd   t jdkr*tjjt jd d } | r&t| jt jd r&t	|  t
tdS td td }t|S )NrV   r*   r*   r+   rR   u   Hatalı giriş!u  <div class='card'><h2>Giriş Yap</h2><form method='POST'><input name='username' placeholder='Kullanıcı Adı'><input type='password' name='password' placeholder='Şifre'><button class='btn btn-blue'>GİRİŞ</button></form><a href='/register'>Kayıt Ol</a></div>)r   methodr   rE   	filter_byformfirstr   r+   r   r   r   r   
GLOBAL_CSSr   )r    htmlr.   r.   r/   r   C  s   
z	/registerc                  C   sX   t jdkr$tt jd tt jd d} tj|  tj  t	t
dS td }t|S )NrV   r*   r+   )r*   r+   r   u  <div class='card'><h2>Kayıt Ol</h2><form method='POST'><input name='username' placeholder='Kullanıcı Adı'><input type='password' name='password' placeholder='Şifre'><button class='btn btn-green'>KAYIT OL</button></form><a href='/login'>Giriş Yap</a></div>)r   rY   r   r[   r   r%   sessionaddcommitr   r   r]   r   )yenir^   r.   r.   r/   registerN  s   

rc   z/logoutc                   C   s   t   ttdS )Nr   )r   r   r   r.   r.   r.   r/   logoutX  s   rd   z
/dashboardc                  C   s   t j } ttt| dS )N)r    units)r0   rE   allr   HTML_DASHBOARDr   re   r.   r.   r/   rR   ^  s   
rR   z/lesson/<int:lesson_id>c                 C   s(   t j| }dd |jD }tt|dS )Nc                 S   s   g | ]}|j |j|jd qS )rB   rC   rD   ri   ).0wr.   r.   r/   
<listcomp>h  s    zlesson.<locals>.<listcomp>)r@   )r2   rE   
get_or_404r@   r   HTML_LESSON)rA   lesson_datar@   r.   r.   r/   r=   d  s   r=   z/kontrolc                  C   s   t  } | dd| dd}}|dd}|dd}t|}t|}td || }|dkrGt jd7  _t	j
  tdd	| d
S tdd| d| d
S )Nhedef_kelimerJ   soylenenu   ةu   هg333333?
   basariliu   Doğru!<br>Söylediğin: )durummesajhatau   Söylediğin: u   <br>Olması Gereken: )r   get_jsonrF   replacerP   r   ratior   r-   r%   r_   ra   r   )verihedefrq   hedef_temizsoylenen_temiz	benzerlikr.   r.   r/   kontrolk  s   
r   z/adminc                  C   s,   t jdkrttdS tj } tt| dS )NadminrR   rh   )	r   r,   r   r   r0   rE   rf   r   
HTML_ADMINrh   r.   r.   r/   r     s   
r   z/admin/add_unitc                   C   s@   t jdkrtjttjd d tj  t	d t
tdS )Nr   r9   )r9   u   Ünite eklendi!)r   r,   r%   r_   r`   r0   r   r[   ra   r   r   r   r.   r.   r.   r/   add_unit  s
   

r   z/admin/add_lessonc                   C   sH   t jdkrtjttjd tjd d tj  t	d t
tdS )Nr   r?   r9   )r?   r9   zDers eklendi!)r   r,   r%   r_   r`   r2   r   r[   ra   r   r   r   r.   r.   r.   r/   
add_lesson  s
   
 
r   z/admin/add_wordc                   C   sX   t jdkr&tjttjd tjd tjd tjd d tj  t	d t
tdS )Nr   rA   rB   rC   rD   )rA   rB   rC   rD   zKelime eklendi!)r   r,   r%   r_   r`   r<   r   r[   ra   r   r   r   r.   r.   r.   r/   add_word  s   

r   MervanrX   z	Mmty2676*)r*   r+   r,   Merve2676274__main__z0.0.0.0i  )hostport)@flaskr   r   r   r   r   r   r   flask_sqlalchemyr	   flask_loginr
   r   r   r   r   r   werkzeug.securityr   r   difflibr   jsonrK   r"   appconfigr%   login_managerinit_app
login_viewModelr   r0   r2   r<   user_loaderrI   rP   r]   rg   rn   r   routerT   r   rc   rd   rR   r=   r   r   r   r   r   app_context
create_allrE   rZ   r\   r_   r`   ra   runr.   r.   r.   r/   <module>   s   $  




 <



	


