Files
2026-07-14 00:01:48 +03:00

142 lines
6.2 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@extends('admin.layouts.app')
@section('title', 'AI Açıklama Yazma')
@section('page-title', 'AI — Toplu Bölüm Açıklaması')
@section('content')
<div class="row justify-content-center">
<div class="col-xl-7 col-lg-8">
<div class="card mb-4">
<div class="card-header">
<i class="bi bi-stars" style="color:var(--info)"></i>
<h6>Toplu Açıklama Yaz</h6>
</div>
<div class="card-body">
<div style="font-size:13px;color:var(--text2);margin-bottom:20px">
DeepSeek, seçilen animenin açıklaması boş olan tüm bölümlerine sırayla Türkçe açıklama yazar.
Bölüm başına ~2-3 saniye sürer.
</div>
<div class="mb-4">
<label class="form-label">Anime Seç</label>
<select id="anime-select" class="form-select" style="max-width:480px">
<option value="0"> Tüm animeler ({{ $totalMissing }} boş bölüm) </option>
@foreach($animes as $anime)
<option value="{{ $anime->id }}">{{ $anime->title }} ({{ $anime->total_eps }} boş bölüm)</option>
@endforeach
</select>
</div>
<div class="d-flex gap-2">
<button id="start-btn" class="btn btn-info px-4" onclick="startFill()">
<i class="bi bi-stars"></i> Başlat
</button>
<button id="stop-btn" class="btn btn-outline-danger px-4" onclick="stopFill()" style="display:none">
<i class="bi bi-stop-fill"></i> Durdur
</button>
</div>
</div>
</div>
{{-- Progress --}}
<div id="progress-card" class="card mb-4" style="display:none">
<div class="card-header">
<h6>İlerleme</h6>
<span id="prog-count" style="font-size:12.5px;color:var(--text2);margin-left:auto">0 / 0</span>
</div>
<div class="card-body">
<div style="background:var(--surface);border-radius:99px;height:8px;overflow:hidden;margin-bottom:14px">
<div id="prog-bar" style="height:100%;width:0%;background:linear-gradient(90deg,var(--info),var(--accent-lt));border-radius:99px;transition:width .3s"></div>
</div>
<div id="prog-log" style="max-height:360px;overflow-y:auto;font-size:12px;font-family:'JetBrains Mono',monospace;background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:12px;line-height:1.7"></div>
</div>
</div>
{{-- Result --}}
<div id="result-card" class="card" style="display:none">
<div class="card-body">
<div style="font-size:14px;font-weight:700;color:var(--text);margin-bottom:6px">Tamamlandı</div>
<div id="result-text" style="font-size:13.5px;color:var(--text2)"></div>
</div>
</div>
</div>
</div>
@endsection
@push('scripts')
<script>
const CSRF = '{{ csrf_token() }}';
const URL_IDS = '{{ route("admin.ai.episode-ids") }}';
const URL_FILL = '{{ route("admin.ai.fill-one") }}';
let running = false, shouldStop = false;
async function startFill() {
const animeId = document.getElementById('anime-select').value;
running = true; shouldStop = false;
document.getElementById('start-btn').disabled = true;
document.getElementById('stop-btn').style.display = 'inline-flex';
document.getElementById('progress-card').style.display = 'block';
document.getElementById('result-card').style.display = 'none';
document.getElementById('prog-log').innerHTML = '';
document.getElementById('prog-bar').style.width = '0%';
log('📋 Bölüm listesi alınıyor...', 'info');
let episodes;
try {
const res = await post(URL_IDS, { anime_id: animeId });
episodes = res.episodes || [];
} catch(e) { log('❌ ' + e.message, 'danger'); finish(0,0); return; }
if (!episodes.length) { log('✅ Tüm açıklamalar zaten dolu!', 'success'); finish(0,0); return; }
log(`🎯 ${episodes.length} boş açıklama. Başlıyor...`, 'info');
document.getElementById('prog-count').textContent = '0 / ' + episodes.length;
let done = 0, failed = 0;
for (let i = 0; i < episodes.length; i++) {
if (shouldStop) { log('⏹ Durduruldu.', 'warning'); break; }
const ep = episodes[i];
log(`⏳ [${i+1}/${episodes.length}] ${ep.label}`, 'muted');
try {
const res = await post(URL_FILL, { episode_id: ep.id });
if (res.ok) { done++; log(`✓ [${i+1}/${episodes.length}] ${ep.label}`, 'success'); }
else { failed++; log(`✗ [${i+1}/${episodes.length}] ${ep.label} — ${res.error||'Hata'}`, 'danger'); }
} catch(e) { failed++; log(`✗ ${ep.label} — ${e.message}`, 'danger'); }
const pct = Math.round(((i+1)/episodes.length)*100);
document.getElementById('prog-bar').style.width = pct+'%';
document.getElementById('prog-count').textContent = (i+1)+' / '+episodes.length;
document.getElementById('prog-log').scrollTop = document.getElementById('prog-log').scrollHeight;
}
finish(done, failed);
}
function stopFill() { shouldStop = true; }
function finish(done, failed) {
running = false;
document.getElementById('start-btn').disabled = false;
document.getElementById('stop-btn').style.display = 'none';
const res = document.getElementById('result-card');
res.style.display = 'block';
document.getElementById('result-text').innerHTML =
`<span style="color:var(--success);font-weight:700">${done} bölüm</span> yazıldı` +
(failed ? `, <span style="color:var(--danger);font-weight:700">${failed} hata</span>` : '') + '.';
}
function log(msg, type='muted') {
const c = { success:'var(--success)', danger:'var(--danger)', info:'var(--info)', warning:'var(--warning)', muted:'var(--text3)' };
const el = document.getElementById('prog-log');
el.innerHTML += `<div style="color:${c[type]||c.muted}">${msg}</div>`;
}
async function post(url, body) {
const r = await fetch(url, { method:'POST', headers:{'Content-Type':'application/json','X-CSRF-TOKEN':CSRF}, body:JSON.stringify(body) });
const data = await r.json();
if (!r.ok && !data.ok) throw new Error(data.error||r.status);
return data;
}
</script>
@endpush