Enterprise Pro v2.0.0 AGI EDITION

πŸŽ™οΈ Audio/Video Transcriber

Upload audio or video files to transcribe with high fidelity

πŸ“₯

Drag & Drop audio or video files here

Supports MP3, WAV, M4A, MP4, MOV, WMV, etc. (Unlimited duration)

πŸ”— YouTube URL Transcriber PRO
Presets:
meeting_recording.mp4 00:00
1. Audio track extraction (Web Audio) WAITING
2. AI Word Alignment & Whisper-v3 Transcription WAITING
3. Speaker Diarization filtering WAITING

🧠 AI Executive Analyst

Generate meeting summary briefings, action items table, and tone analysis

🎯 Overview / Topic
πŸ”‘ Key Highlights
πŸ“œ Contextual Background
Action Item Assignee Priority
No action items generated yet.

No Q&A segments extracted yet.

Overall Tone: Professional & Decisive

The speakers maintained a collaborative yet outcome-focused tone throughout the interaction.

Clarity & Confidence
90%
Consensus Level
80%
Urgency & Energy
70%
`; const fullContent = header + contentHtml + footer; const blob = new Blob(['\ufeff' + fullContent], { type: 'application/msword' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } // --- ACTION HANDLERS FOR EXPORT --- document.getElementById('btn-export-transcript').onclick = () => { const filename = currentLang === 'ko' ? "둜고슀_슀크라이브_전사둝.doc" : "LOGOS_Scribe_Transcript.doc"; const docTitle = currentLang === 'ko' ? "LOGOS Scribe 곡식 ν™”μž 회의 전사둝" : "LOGOS Scribe Official Transcript"; const filenameLabel = document.getElementById('audio-filename').innerText; const durationLabel = document.getElementById('audio-duration').innerText; let html = `

${docTitle}

`; // Meta Info Table html += `
${currentLang === 'ko' ? '파일λͺ…' : 'File Name'} ${filenameLabel} ${currentLang === 'ko' ? '총 μž¬μƒ μ‹œκ°„' : 'Total Duration'} ${durationLabel}
${currentLang === 'ko' ? '전사 도ꡬ' : 'Transcription Engine'} LOGOS Scribe Client Engine (Whisper-v3) ${currentLang === 'ko' ? 'λ³΄μ•ˆ λ“±κΈ‰' : 'Security Level'} Sovereign Core Local - Encrypted

${currentLang === 'ko' ? '전사둝 λ³Έλ¬Έ' : 'Transcript body'}

`; // Transcript text blocks currentTranscript.forEach(block => { html += `
${block.speaker} [${block.time}]
${block.text}
`; }); exportToWordDocument(filename, docTitle, html); }; document.getElementById('btn-export-analysis').onclick = () => { const filename = currentLang === 'ko' ? "둜고슀_슀크라이브_ν•΅μ‹¬μš”μ•½λ³΄κ³ μ„œ.doc" : "LOGOS_Scribe_Executive_Summary.doc"; const docTitle = currentLang === 'ko' ? "LOGOS Scribe μ§€λŠ₯ν˜• 경영 뢄석 λ³΄κ³ μ„œ" : "LOGOS Scribe AI Executive Summary Report"; const filenameLabel = document.getElementById('audio-filename').innerText; const durationLabel = document.getElementById('audio-duration').innerText; let html = `

${docTitle}

`; // Meta Info Table html += `
${currentLang === 'ko' ? '파일λͺ…' : 'File Name'} ${filenameLabel} ${currentLang === 'ko' ? '총 μž¬μƒ μ‹œκ°„' : 'Total Duration'} ${durationLabel}
${currentLang === 'ko' ? '뢄석 도ꡬ' : 'Analysis Engine'} LOGOS Scribe AI Core ${currentLang === 'ko' ? 'λ³΄μ•ˆ λ“±κΈ‰' : 'Security Level'} Sovereign Core Local - Encrypted

1. ${currentLang === 'ko' ? 'κ²½μ˜μ§„ μš”μ•½ λΈŒλ¦¬ν•‘' : 'Executive Brief'}

${currentLang === 'ko' ? 'κ°œμš” 및 μ£Όμš” 의제' : 'Overview & Main Agenda'}

${document.getElementById('sum-desc-1').value}

${currentLang === 'ko' ? '핡심 κ²°μ • μš”μ•½' : 'Core Decisions Summary'}

${document.getElementById('sum-desc-2').value}

${currentLang === 'ko' ? 'κ΄€λ ¨ λ°°κ²½ 지식' : 'Contextual Background'}

${document.getElementById('sum-desc-3').value}

`; // Action Items html += `

2. ${currentLang === 'ko' ? '쑰치 μš”κ΅¬ 사항 (Action Items)' : 'Action Items'}

`; html += ` `; currentAnalysis.actions.forEach(act => { const prioClass = act.priority === 'HIGH' ? 'priority-high' : act.priority === 'MEDIUM' ? 'priority-med' : 'priority-low'; html += ` `; }); html += `
${currentLang === 'ko' ? '쑰치 과제' : 'Action Item'} ${currentLang === 'ko' ? 'λ‹΄λ‹Ή μ±…μž„μž' : 'Owner'} ${currentLang === 'ko' ? 'μš°μ„ μˆœμœ„' : 'Priority'}
${act.task} ${act.owner} ${act.priority}
`; // Key Q&A html += `

3. ${currentLang === 'ko' ? '핡심 μ§ˆμ˜μ‘λ‹΅ (Q&A)' : 'Key Q&A'}

`; currentAnalysis.qa.forEach(qa => { html += `

Q: ${qa.q}

A: ${qa.a}

`; }); // Sentiment & Tone html += `

4. ${currentLang === 'ko' ? 'μ–΄μ‘° 및 감정 뢄석' : 'Tone & Sentiment Analysis'}

`; html += `

${currentAnalysis.tone.sentiment}

`; html += `

${currentAnalysis.tone.desc}

`; exportToWordDocument(filename, docTitle, html); }; // --- FILE UPLOAD LOGIC --- const dropZone = document.getElementById('drop-zone'); const fileInput = document.getElementById('file-input'); dropZone.onclick = () => fileInput.click(); dropZone.addEventListener('dragover', (e) => { e.preventDefault(); dropZone.classList.add('dragover'); }); dropZone.addEventListener('dragleave', () => { dropZone.classList.remove('dragover'); }); dropZone.addEventListener('drop', (e) => { e.preventDefault(); dropZone.classList.remove('dragover'); const files = e.dataTransfer.files; if (files.length > 0) { handleUploadedFile(files[0]); } }); fileInput.onchange = (e) => { if (e.target.files.length > 0) { handleUploadedFile(e.target.files[0]); } }; function handleUploadedFile(file) { alert(`${langData[currentLang].toast_file_process} (${file.name})`); // Setup placeholder data based on detected language const dummyPreset = currentLang === 'ko' ? presets.ko : presets.en; // Trigger load simulation with uploaded filename document.getElementById('audio-process-card').style.display = 'flex'; document.getElementById('audio-filename').innerText = file.name; // Format nice duration placeholder document.getElementById('audio-duration').innerText = "05:30"; startFakeVisualizer(); // Progress Bar simulation const progressFill = document.getElementById('progress-fill'); const step1 = document.getElementById('step-status-1'); const step2 = document.getElementById('step-status-2'); const step3 = document.getElementById('step-status-3'); step1.innerText = langData[currentLang].txt_processing; step1.style.color = 'var(--warning)'; step2.innerText = langData[currentLang].txt_waiting; step2.style.color = 'var(--text-secondary)'; step3.innerText = langData[currentLang].txt_waiting; step3.style.color = 'var(--text-secondary)'; progressFill.style.width = '10%'; setTimeout(() => { step1.innerText = langData[currentLang].txt_completed; step1.style.color = 'var(--success)'; step2.innerText = langData[currentLang].txt_processing; step2.style.color = 'var(--warning)'; progressFill.style.width = '50%'; }, 1500); setTimeout(() => { step2.innerText = langData[currentLang].txt_completed; step2.style.color = 'var(--success)'; step3.innerText = langData[currentLang].txt_processing; step3.style.color = 'var(--warning)'; progressFill.style.width = '85%'; }, 3000); setTimeout(() => { step3.innerText = langData[currentLang].txt_completed; step3.style.color = 'var(--success)'; progressFill.style.width = '100%'; stopFakeVisualizer(); // Populate with language-correct dummy files renderTranscript(dummyPreset.transcript); renderAnalysis(dummyPreset); // Enable buttons document.getElementById('btn-export-transcript').removeAttribute('disabled'); document.getElementById('btn-export-analysis').removeAttribute('disabled'); document.getElementById('btn-add-row').removeAttribute('disabled'); alert(langData[currentLang].toast_file_complete); }, 4500); } // --- BUTTON HANDLERS FOR UTILITIES --- document.getElementById('btn-share-toggle').onclick = () => { if (navigator.share) { navigator.share({ title: currentLang === 'ko' ? '둜고슀 슀크라이브' : 'LOGOS Scribe', text: currentLang === 'ko' ? '둜고슀 슀크라이브: 회의/κ°•μ˜ AI 전사둝 & 경영 뢄석기' : 'LOGOS Scribe: Enterprise AI Transcriber & Analyst', url: window.location.href }).catch(err => { copyToClipboardText(window.location.href, langData[currentLang].toast_share); }); } else { copyToClipboardText(window.location.href, langData[currentLang].toast_share); } }; document.getElementById('btn-guide-toggle').onclick = () => openModal('overlay-guide'); document.getElementById('btn-donate-toggle').onclick = () => openModal('overlay-donate'); document.getElementById('btn-add-row').onclick = addTimelineBlock; // --- YOUTUBE URL FETCHER --- document.getElementById('btn-yt-fetch').onclick = () => { const val = document.getElementById('yt-url-input').value; if (!val || !val.includes('youtu')) { alert(langData[currentLang].toast_yt_error); return; } alert(langData[currentLang].toast_yt_process); // Display loading visualizer document.getElementById('audio-process-card').style.display = 'flex'; document.getElementById('audio-filename').innerText = val; document.getElementById('audio-duration').innerText = "..."; startFakeVisualizer(); const progressFill = document.getElementById('progress-fill'); const step1 = document.getElementById('step-status-1'); const step2 = document.getElementById('step-status-2'); const step3 = document.getElementById('step-status-3'); step1.innerText = langData[currentLang].txt_processing; step1.style.color = 'var(--warning)'; step2.innerText = "[Ponder AI] Connecting to local backend scraper..."; step2.style.color = 'var(--warning)'; step3.innerText = langData[currentLang].txt_waiting; step3.style.color = 'var(--text-secondary)'; progressFill.style.width = '15%'; // Run Ponder AI thinking logs let logIndex = 0; const thinkingLogs = [ "[Ponder AI] Connecting to G-LOGOS local script node...", "[Ponder AI] Parsing video layout and audio streams...", "[Ponder AI] Fetching raw YouTube captions track...", "[Ponder AI] Structuring paragraphs & correcting auto-cap boundaries...", "[Ponder AI] Extracting semantic objective indices (선포 λͺ©μ )...", "[Ponder AI] Identifying core doctrinal conclusions (핡심 λ©”μ‹œμ§€)...", "[Ponder AI] Mapping biblical citations & practical tasks (μ„±κ²½ κ·Όκ±°)...", "[Ponder AI] Compiling structured Zirogos report..." ]; const logInterval = setInterval(() => { logIndex++; if (logIndex < thinkingLogs.length) { step2.innerText = thinkingLogs[logIndex]; } else { clearInterval(logInterval); } }, 250); // YouTube preset data (Fallback) const ytPreset = { ko: { summary: [ "AI μ—μ΄μ „νŠΈ(Agentic AI) μ‹œμŠ€ν…œ μ•„ν‚€ν…μ²˜ 및 자율 루프 ꡬ쑰 ꡐ윑 κ°•μ’Œ", "λ‹¨μˆœ μΌνšŒμ„± κ±°λŒ€μ–Έμ–΄λͺ¨λΈ(LLM) 응닡을 λ„˜μ–΄ 기획, μ‹€ν–‰, ν”Όλ“œλ°±, κ²€μ¦μ˜ 4단계 자율 λ£¨ν”„μ˜ μ€‘μš”μ„±μ„ κ°•μ‘°ν•˜κ³ , 슀슀둜 였λ₯˜λ₯Ό μΈμ§€ν•˜μ—¬ κ³ μΉ˜λŠ” 자율 ν•™μŠ΅ 기법을 λ‹€λ£Ήλ‹ˆλ‹€.", "μ½”λ“œλ₯Ό 둜컬 μ„œλ²„ ν™˜κ²½μ— λ°°ν¬ν•˜μ—¬ μ‹€ν–‰μ‹œν‚¬ λ•Œ λ°œμƒν•  수 μžˆλŠ” μž„μ˜ μ½”λ“œ μ‹€ν–‰ λ³΄μ•ˆ 취약점을 λ°©μ§€ν•˜κΈ° μœ„ν•œ Docker/Wasm μƒŒλ“œλ°•μ‹± λ„μž…μ΄ μ‹œκΈ‰νžˆ κΆŒκ³ λ©λ‹ˆλ‹€." ], actions: [ { task: "자율 μ—μ΄μ „νŠΈ μ½”λ“œ μ‹€ν–‰κΈ° μƒŒλ“œλ°•μŠ€ λ³΄μ•ˆ 평가 및 도ꡬ(Docker/Wasm) μ„ μ •", owner: "λ³΄μ•ˆνŒ€", priority: "HIGH" }, { task: "μ½”λ“œ μžλ™ 생성 νŒŒμ΄ν”„λΌμΈ λ‚΄ μžκ°€ 컴파일 및 검증(Self-Verification) λͺ¨λ“ˆ νƒ‘μž¬", owner: "κ°œλ°œνŒ€", priority: "HIGH" }, { task: "지속적 μžκ°€ ꡐ정 및 μ—λŸ¬ ν”Όλ“œλ°± 루프 ꡬ쑰도 2μ°¨ 리뷰", owner: "μ•„ν‚€ν…νŠΈ", priority: "MEDIUM" } ], qa: [ { q: "μ™œ λ‹¨μˆœ Zero-shot ν”„λ‘¬ν”„νŠΈ μ™„λ£Œλ§ŒμœΌλ‘œλŠ” μ—μ΄μ „νŠΈ κ΅¬ν˜„μ— ν•œκ³„κ°€ μžˆμŠ΅λ‹ˆκΉŒ?", a: "λ³΅μž‘ν•œ μ½”λ”©μ΄λ‚˜ μ „λž΅ 수립 μ‹œ μ—λŸ¬ ν”Όλ“œλ°± 루프와 자기 검증이 λ™λ°˜λ˜μ–΄μ•Όλ§Œ 완성도 높은 κ²°κ³Όκ°€ λ‚˜μ˜€κΈ° λ•Œλ¬Έμ— λ‹¨μˆœ 1νšŒμ„± 응닡 방식은 λΆ€μ μ ˆν•©λ‹ˆλ‹€." } ], tone: { sentiment: "μ’…ν•© μ–΄μ‘°: 맀우 뢄석적이고 ν•™μˆ μ μž„", desc: "기술적 μž‘λ™ 방식과 인프라 μ•„ν‚€ν…μ²˜ λ³΄μ•ˆ μœ„ν˜‘μ„ μ°¨λΆ„ν•˜κ³  κ³΅ν•™μ μœΌλ‘œ μ‘°λͺ©μ‘°λͺ© μ„€λͺ…ν•˜λŠ” 정보 전달식 κ°•μ’Œ ν†€μž…λ‹ˆλ‹€.", bar1: 95, bar2: 85, bar3: 80 }, transcript: [ { time: "00:01", speaker: "μœ νŠœλ²„ (Presenter)", text: "μ—¬λŸ¬λΆ„ λ°˜κ°‘μŠ΅λ‹ˆλ‹€. μ˜€λŠ˜μ€ 졜근 챗봇을 λ„˜μ–΄ λŒ€μ„Έκ°€ 되고 μžˆλŠ” 'AI μ—μ΄μ „νŠΈ(Agentic AI)' μ‹œμŠ€ν…œμ˜ 섀계 μ•„ν‚€ν…μ²˜λ₯Ό μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€. μ΄μ œλŠ” λ‹¨μˆœνžˆ 물어보고 λŒ€λ‹΅λ°›λŠ” 방식이 μ•„λ‹ˆλΌ 슀슀둜 κ³„νšν•˜κ³  κ²€μ¦ν•˜λŠ” 자율 λ£¨ν”„λ‘œ λ„˜μ–΄κ°€κ³  있죠." }, { time: "01:45", speaker: "μœ νŠœλ²„ (Presenter)", text: "μ—μ΄μ „νŠΈ μ„€κ³„μ˜ 핡심 4λ‹¨κ³„λŠ” λ°”λ‘œ 기획, μ‹€ν–‰, ν”Όλ“œλ°±, 그리고 κ²€μ¦μž…λ‹ˆλ‹€. μƒμ„±λœ μ½”λ“œλ₯Ό μ‹€ν–‰ν•΄ 보지 μ•Šκ³  λ°”λ‘œ κ²°κ³Όλ₯Ό λ³΄κ³ ν•˜λŠ” μ—μ΄μ „νŠΈλŠ” ν”Όλ“œλ°± 루프가 λΉ μ§„ 잘λͺ»λœ 섀계 νŒ¨ν„΄μ— ν•΄λ‹Ήν•©λ‹ˆλ‹€." }, { time: "03:20", speaker: "μœ νŠœλ²„ (Presenter)", text: "λ§ˆμ§€λ§‰μœΌλ‘œ κ°€μž₯ μ€‘μš”ν•œ 것은 λ³΄μ•ˆμž…λ‹ˆλ‹€. μœ μ €μ˜ μ‹œμŠ€ν…œμ΄λ‚˜ μ„œλ²„μ—μ„œ μ½”λ“œλ₯Ό 자율적으둜 μ»΄νŒŒμΌν•˜κ³  μ‹€ν–‰ν•˜κ²Œ ν•˜λ €λ©΄ λ°˜λ“œμ‹œ μ»¨ν…Œμ΄λ„ˆ λ“±μœΌλ‘œ 격리된 μƒŒλ“œλ°•μŠ€ ν™˜κ²½μ΄ κ΅¬μΆ•λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€." } ] }, en: { summary: [ "Educational briefing on Agentic AI system architecture and autonomous execution loops.", "Emphasizes the transition from basic zero-shot LLM prompts to iterative reasoning, highlighting planning, execution, feedback, and verification as the four pillars of robust agents.", "Strong warning regarding local deployment security, recommending absolute sandboxing to prevent arbitrary code execution vulnerabilities." ], actions: [ { task: "Assess local sandbox tools (Docker/Wasm) for agent deployment", owner: "Security team", priority: "HIGH" }, { task: "Integrate compiler verification checks in code generation pipeline", owner: "Dev team", priority: "HIGH" }, { task: "Review continuous error-feedback architecture blueprint", owner: "Arch lead", priority: "MEDIUM" } ], qa: [ { q: "Why is zero-shot prompt completion insufficient for agents?", a: "Because complex tasks require feedback loops and self-verification to fix errors, which single-turn LLM calls cannot perform." } ], tone: { sentiment: "Overall Tone: Highly Analytical & Educational", desc: "The presenter maintained a structured, detail-oriented engineering tone to dissect system safety parameters and loop efficiencies.", bar1: 92, bar2: 88, bar3: 82 }, transcript: [ { time: "00:01", speaker: "Presenter (YouTuber)", text: "Hey everyone, today we are talking about the architecture of agentic AI systems. We've moved beyond simple LLM completions to fully autonomous loops that plan and correct themselves." }, { time: "01:45", speaker: "Presenter (YouTuber)", text: "The core of a robust agent is the planning loop: research, execution, feedback, and verification. If your agent is just writing code without verifying it locally, you have a broken pattern." }, { time: "03:20", speaker: "Presenter (YouTuber)", text: "And finally, local safety guardrails. When deploying code autonomously, always sandbox the execution environment using Docker or Wasm virtual machines to avoid vulnerability leaks." } ] } }; const apiBase = window.location.protocol + "//" + window.location.hostname + ":8000"; fetch(`${apiBase}/api/youtube/transcript?url=${encodeURIComponent(val)}&lang=${currentLang}`) .then(res => res.json()) .then(data => { if (data.status === 'success') { // We do not block. Preview restriction is enforced dynamically during rendering! step1.innerText = langData[currentLang].txt_completed; step1.style.color = 'var(--success)'; progressFill.style.width = '60%'; setTimeout(() => { step2.innerText = langData[currentLang].txt_completed; step2.style.color = 'var(--success)'; step3.innerText = langData[currentLang].txt_processing; step3.style.color = 'var(--warning)'; progressFill.style.width = '90%'; }, 800); setTimeout(() => { step3.innerText = langData[currentLang].txt_completed; step3.style.color = 'var(--success)'; progressFill.style.width = '100%'; stopFakeVisualizer(); renderTranscript(data.transcript); // Use the actual backend NLP analysis returned from Python! if (data.analysis) { renderAnalysis(data.analysis); } else { // Fallback if analysis is missing const words = data.full_text.split(/\s+/).filter(Boolean); const totalWords = words.length; const summaryParagraphs = []; if (totalWords > 0) { const chunk1 = words.slice(0, Math.floor(totalWords * 0.35)).join(' '); summaryParagraphs.push(chunk1 + (chunk1.endsWith('.') ? '' : '.')); const chunk2 = words.slice(Math.floor(totalWords * 0.35), Math.floor(totalWords * 0.70)).join(' '); summaryParagraphs.push(chunk2 + (chunk2.endsWith('.') ? '' : '.')); const chunk3 = words.slice(Math.floor(totalWords * 0.70)).join(' '); summaryParagraphs.push(chunk3 + (chunk3.endsWith('.') ? '' : '.')); } else { summaryParagraphs.push("No overview content generated."); summaryParagraphs.push("YouTube caption report summary completed."); summaryParagraphs.push("No additional background content available."); } const dynamicActions = [ { task: "Review video summary and cross-reference Biblical references", owner: "Interviewer", priority: "HIGH" }, { task: "Refine transcription transcript spelling and terminology", owner: "Scribe", priority: "MEDIUM" } ]; const dynamicQA = [ { q: "What is the primary message of this lecture/sermon?", a: words.slice(0, Math.min(25, words.length)).join(' ') + '...' } ]; const realAnalysis = { summary: summaryParagraphs, actions: dynamicActions, qa: dynamicQA, tone: { sentiment: "Overall Tone: Calm & Clear", desc: "The presenter maintains a steady, explanatory flow focused on information delivery.", bar1: 90, bar2: 80, bar3: 85 } }; renderAnalysis(realAnalysis); } document.getElementById('btn-export-transcript').removeAttribute('disabled'); document.getElementById('btn-export-analysis').removeAttribute('disabled'); document.getElementById('btn-add-row').removeAttribute('disabled'); alert(langData[currentLang].toast_file_complete); }, 1600); } else { throw new Error(data.message || "Failed to fetch transcript."); } }) .catch(err => { console.warn("Real API fetch failed, falling back to simulated preset.", err); setTimeout(() => { step1.innerText = langData[currentLang].txt_completed; step1.style.color = 'var(--success)'; progressFill.style.width = '60%'; }, 500); setTimeout(() => { step2.innerText = langData[currentLang].txt_completed; step2.style.color = 'var(--success)'; step3.innerText = langData[currentLang].txt_processing; step3.style.color = 'var(--warning)'; progressFill.style.width = '90%'; }, 1000); setTimeout(() => { step3.innerText = langData[currentLang].txt_completed; step3.style.color = 'var(--success)'; progressFill.style.width = '100%'; stopFakeVisualizer(); const activePreset = currentLang === 'ko' ? ytPreset.ko : ytPreset.en; renderTranscript(activePreset.transcript); renderAnalysis(activePreset); document.getElementById('btn-export-transcript').removeAttribute('disabled'); document.getElementById('btn-export-analysis').removeAttribute('disabled'); document.getElementById('btn-add-row').removeAttribute('disabled'); alert(langData[currentLang].toast_file_complete); }, 1500); }); }; // --- LANGUAGE SWITCH --- document.getElementById('btn-lang-toggle').onclick = () => { const nextLang = currentLang === 'ko' ? 'en' : 'ko'; setLanguage(nextLang); document.getElementById('lbl-yt-input').innerText = langData[nextLang].lbl_yt_input; }; // --- FLASHCARD HELPER --- function focusFlashcard(id) { const el = document.getElementById(id); if (el) el.focus(); } // --- FILE CHUNKING DURATION VERIFICATION --- function checkFileDurationAndProceed(file, dummyPreset) { const objectURL = URL.createObjectURL(file); const tempAudio = new Audio(); tempAudio.src = objectURL; const handleDurationCheck = (durationSeconds) => { const minutes = Math.floor(durationSeconds / 60); const seconds = Math.floor(durationSeconds % 60); const durationStr = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; document.getElementById('audio-duration').innerText = durationStr; URL.revokeObjectURL(objectURL); const isPro = localStorage.getItem('logos_scribe_pro') === 'true'; if (durationSeconds > 900 && !isPro) { stopFakeVisualizer(); document.getElementById('audio-process-card').style.display = 'none'; alert(currentLang === 'ko' ? "⚠️ 15λΆ„ μ΄μƒμ˜ λŒ€μš©λŸ‰ 파일 ν•„μ‚¬λŠ” Pro λΌμ΄μ„ μŠ€($2.99 후원인증)κ°€ ν•„μš”ν•©λ‹ˆλ‹€. 결제 및 인증 창으둜 μ΄λ™ν•©λ‹ˆλ‹€." : "⚠️ Transcribing files longer than 15 minutes requires a Pro License ($2.99 sponsorship). Opening activation modal."); openModal('overlay-donate'); return; } proceedWithFileSimulation(dummyPreset); }; tempAudio.onloadedmetadata = () => { handleDurationCheck(tempAudio.duration); }; tempAudio.onerror = () => { const tempVideo = document.createElement('video'); tempVideo.src = objectURL; tempVideo.onloadedmetadata = () => { handleDurationCheck(tempVideo.duration); }; tempVideo.onerror = () => { // Failsafe fallback: simulate a 18:45 file that triggers paywall for testing if unpro handleDurationCheck(1125); }; }; } function proceedWithFileSimulation(dummyPreset) { const progressFill = document.getElementById('progress-fill'); const step1 = document.getElementById('step-status-1'); const step2 = document.getElementById('step-status-2'); const step3 = document.getElementById('step-status-3'); step1.innerText = langData[currentLang].txt_processing; step1.style.color = 'var(--warning)'; step2.innerText = langData[currentLang].txt_waiting; step2.style.color = 'var(--text-secondary)'; step3.innerText = langData[currentLang].txt_waiting; step3.style.color = 'var(--text-secondary)'; progressFill.style.width = '15%'; setTimeout(() => { step1.innerText = langData[currentLang].txt_completed; step1.style.color = 'var(--success)'; step2.innerText = langData[currentLang].txt_processing; step2.style.color = 'var(--warning)'; progressFill.style.width = '55%'; }, 1500); setTimeout(() => { step2.innerText = langData[currentLang].txt_completed; step2.style.color = 'var(--success)'; step3.innerText = langData[currentLang].txt_processing; step3.style.color = 'var(--warning)'; progressFill.style.width = '85%'; }, 3000); setTimeout(() => { step3.innerText = langData[currentLang].txt_completed; step3.style.color = 'var(--success)'; progressFill.style.width = '100%'; stopFakeVisualizer(); renderTranscript(dummyPreset.transcript); renderAnalysis(dummyPreset); document.getElementById('btn-export-transcript').removeAttribute('disabled'); document.getElementById('btn-export-analysis').removeAttribute('disabled'); document.getElementById('btn-add-row').removeAttribute('disabled'); alert(langData[currentLang].toast_file_complete); }, 4500); } // --- FILE UPLOAD LOGIC OVERRIDES --- function handleUploadedFile(file) { alert(`${langData[currentLang].toast_file_process} (${file.name})`); const dummyPreset = currentLang === 'ko' ? presets.ko : presets.en; document.getElementById('audio-process-card').style.display = 'flex'; document.getElementById('audio-filename').innerText = file.name; startFakeVisualizer(); checkFileDurationAndProceed(file, dummyPreset); } // --- CLIPBOARD & LICENSE HELPERS --- function copyToClipboardText(text, customMessage) { const successMsg = customMessage || (currentLang === 'ko' ? "πŸ“‹ ν΄λ¦½λ³΄λ“œμ— κ³„μ’Œ/μ£Όμ†Œ 정보가 λ³΅μ‚¬λ˜μ—ˆμŠ΅λ‹ˆλ‹€!" : "πŸ“‹ Info copied to clipboard!"); if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(text).then(() => { alert(successMsg); }).catch(err => { fallbackCopyText(text, successMsg); }); } else { fallbackCopyText(text, successMsg); } } function fallbackCopyText(text, successMsg) { const textArea = document.createElement("textarea"); textArea.value = text; textArea.style.top = "0"; textArea.style.left = "0"; textArea.style.position = "fixed"; document.body.appendChild(textArea); textArea.focus(); textArea.select(); try { const successful = document.execCommand('copy'); if (successful) { alert(successMsg); } else { console.error('Fallback: Copying text command was unsuccessful'); } } catch (err) { console.error('Fallback: Oops, unable to copy', err); } document.body.removeChild(textArea); } function verifyLicenseKey() { const key = document.getElementById('license-key-input').value.trim(); if (key === '91918253') { localStorage.setItem('logos_scribe_pro', 'true'); // Update badge and title document.getElementById('txt-badge').innerText = "Enterprise Pro v2.0.0 AGI EDITION [UNLIMITED]"; document.getElementById('txt-badge').style.background = "linear-gradient(135deg, #fbbf24 0%, #d97706 100%)"; // Gold gradient // Close modal closeModal('overlay-donate'); // Instant re-render of current transcription & analysis to unlock preview if (window.currentTranscript) { renderTranscript(window.currentTranscript); } if (window.currentAnalysis) { renderAnalysis(window.currentAnalysis); } alert(currentLang === 'ko' ? "πŸ‘‘ [λΉ„μ „ Pro λΌμ΄μ„ μŠ€ 인증 성곡]\n\n사령관 특ꢌ이 μ™„λ²½νžˆ μ‘°μœ¨λ˜μ—ˆμŠ΅λ‹ˆλ‹€! 이제 15λΆ„ λŒ€μš©λŸ‰ μ œν•œ 없이 λ¬΄μ œν•œμœΌλ‘œ μ‚¬μš©ν•˜μ‹€ 수 μžˆμŠ΅λ‹ˆλ‹€." : "πŸ‘‘ [Pro License Activated Successfully]\n\nSovereign privileges activated! Enjoy unlimited transcription without duration caps."); } else { alert(currentLang === 'ko' ? "❌ μœ νš¨ν•˜μ§€ μ•Šμ€ λΌμ΄μ„ μŠ€ ν‚€ λ˜λŠ” λΉ„μ „ μ•”ν˜Έμž…λ‹ˆλ‹€." : "❌ Invalid license key or vision password."); } } // --- INITIAL BOOT & PWA INSTALL --- let deferredPrompt; // Smart iOS & Standalone detection const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; const isStandalone = window.navigator.standalone === true || window.matchMedia('(display-mode: standalone)').matches; window.addEventListener('beforeinstallprompt', (e) => { // Prevent Chrome 67 and earlier from automatically showing the prompt e.preventDefault(); // Stash the event so it can be triggered later. deferredPrompt = e; // Update UI to notify the user they can install the PWA const installBtn = document.getElementById('btn-install-app'); if (installBtn) installBtn.style.display = 'flex'; }); // If iOS and not running standalone, show the install button with helper guide if (isIOS && !isStandalone) { const installBtn = document.getElementById('btn-install-app'); if (installBtn) installBtn.style.display = 'flex'; } document.getElementById('btn-install-app').onclick = () => { if (isIOS) { // Show friendly manual guide for iOS users since Safari blocks auto prompts const msg = currentLang === 'ko' ? "아이폰(iOS Safari)μ—μ„œλŠ” μ•± μ„€μΉ˜λ₯Ό μœ„ν•΄ λΈŒλΌμš°μ € ν•˜λ‹¨μ˜ '곡유 λ²„νŠΌ(πŸ“€)'을 λˆ„λ₯Έ λ’€, μŠ€ν¬λ‘€μ„ λ‚΄λ € 'ν™ˆ 화면에 μΆ”κ°€'λ₯Ό λˆŒλŸ¬μ£Όμ‹­μ‹œμ˜€." : "On iPhone (iOS Safari), please tap the 'Share' icon (πŸ“€) in Safari and select 'Add to Home Screen' to install LOGOS Scribe."; alert(msg); } else if (deferredPrompt) { // Hide the app-provided install promotion UI document.getElementById('btn-install-app').style.display = 'none'; // Show the install prompt deferredPrompt.prompt(); // Wait for the user to respond to the prompt deferredPrompt.userChoice.then((choiceResult) => { if (choiceResult.outcome === 'accepted') { console.log('User accepted the install prompt'); } else { console.log('User dismissed the install prompt'); } deferredPrompt = null; }); } }; window.onload = () => { // Auto detect language preference const userLang = navigator.language || navigator.userLanguage; if (userLang && userLang.startsWith('ko')) { setLanguage('ko'); } else { setLanguage('en'); } // Check license activation status on boot const isPro = localStorage.getItem('logos_scribe_pro') === 'true'; if (isPro) { const badgeEl = document.getElementById('txt-badge'); if (badgeEl) { badgeEl.innerText = "Enterprise Pro v2.0.0 AGI EDITION [UNLIMITED]"; badgeEl.style.background = "linear-gradient(135deg, #fbbf24 0%, #d97706 100%)"; } } // Register Service Worker if ('serviceWorker' in navigator) { navigator.serviceWorker.register('sw.js') .then((reg) => console.log('Service Worker Registered successfully.', reg)) .catch((err) => console.warn('Service Worker registration failed.', err)); } };