diff --git a/Frontend/.DS_Store b/Frontend/.DS_Store deleted file mode 100644 index 47583d6..0000000 Binary files a/Frontend/.DS_Store and /dev/null differ diff --git a/Frontend/images.jpeg b/Frontend/images.jpeg deleted file mode 100644 index 9744200..0000000 Binary files a/Frontend/images.jpeg and /dev/null differ diff --git a/Frontend/index.html b/Frontend/index.html deleted file mode 100644 index ac0d4e2..0000000 --- a/Frontend/index.html +++ /dev/null @@ -1,340 +0,0 @@ - - - - - - SignBridge - AI cho giáo dục hòa nhập - - - - - -
-
- - - -
-
- - -
-
-
-
-

AI cho giáo dục hòa nhập

-

Chuyển giọng nói thành ký hiệu, mở cánh cửa tri thức

-
- - -
-
-
-
- Video demo - -
-
-
-
-
- - -
-
- -
-

KHOÁ HỌC TẬP CHÍNH (LEARNING HUB)

- -
- - -
- -
- - - - -

About Section

-
-
-
🎯
-
-

Mục tiêu

-

Câu nói tri thức giúp em! Nói là ngôn ngữ im lặng

-
-
-
-
🌍
-
-

Ảnh hưởng

-

Giáo dục, Truyền thông, Dịch vụ xã hội

-
-
-
-
👥
-
-

Người mở

-

Người khiếm thính

-
-
-
-
⚙️
-
-

Công nghệ

-

mT5 LITS + MediaPipe + Three.js

-
-
-
-
- - -
-

Khu Tải Lên (Tìm bài mới)

-
-
-

Tùy chọn

-
- -
-
- - - - -
-
- - -
-
-
- - -
-
- - -
-
-
-
-
-
- -
- -

Tạo ký hiệu

-
-
-
-
- -
-
-
Xem YouTube
-
-
-
-
-
-
- Video demo - -
-
-
-
-
-
-
-
-
- - -
-

About Section

-
-
-
-
-
- - -
-
TÔI – HỌC – CÙNG – BẠN
-
-
-
- -

Giúp 2,5 triệu người khiếm thính Việt Nam của nhập thôn cần lịch sự.

- -
- Avatar 1 - Avatar 2 - Avatar 3 - Avatar 4 -
- -
-
-
-
-
-
- - - -
-
- AI Demo - -
-

AI đang dịch: Speech → Text → Gloss → Motion → Melon Avatar

-
-
-
-
-
- - - - - - - - diff --git a/Frontend/logo.png b/Frontend/logo.png deleted file mode 100644 index 063d2e3..0000000 Binary files a/Frontend/logo.png and /dev/null differ diff --git a/Frontend/script.js b/Frontend/script.js deleted file mode 100644 index 7a9188a..0000000 --- a/Frontend/script.js +++ /dev/null @@ -1,333 +0,0 @@ -/** - * SignBridge - JavaScript Vanilla - * Xử lý các tương tác: carousel, filters, search, toggles - */ - -// ============================================ -// CAROUSEL FUNCTIONALITY -// ============================================ - -class Carousel { - constructor(containerSelector) { - this.container = document.querySelector(containerSelector); - this.track = this.container.querySelector(".carousel-track"); - this.prevBtn = this.container.querySelector(".carousel-prev"); - this.nextBtn = this.container.querySelector(".carousel-next"); - this.cardWidth = 280 + 24; // card width + gap - this.scrollAmount = this.cardWidth; - - this.init(); - } - - init() { - if (this.prevBtn) { - this.prevBtn.addEventListener("click", () => - this.scroll(-this.scrollAmount), - ); - } - if (this.nextBtn) { - this.nextBtn.addEventListener("click", () => - this.scroll(this.scrollAmount), - ); - } - } - - scroll(amount) { - this.track.scrollBy({ - left: amount, - behavior: "smooth", - }); - } -} - -// Khởi tạo carousel -document.addEventListener("DOMContentLoaded", () => { - new Carousel(".carousel-section"); -}); - -// ============================================ -// FILTER & SEARCH FUNCTIONALITY -// ============================================ - -class FilterSearch { - constructor() { - this.subjectFilter = document.querySelector( - 'select[aria-label="Lọc theo môn"]', - ); - this.gradeFilter = document.querySelector( - 'select[aria-label="Lọc theo cấp lớp"]', - ); - this.searchInput = document.querySelector(".search-box input"); - this.courseCards = document.querySelectorAll(".course-card"); - - this.init(); - } - - init() { - if (this.subjectFilter) { - this.subjectFilter.addEventListener("change", () => this.applyFilters()); - } - if (this.gradeFilter) { - this.gradeFilter.addEventListener("change", () => this.applyFilters()); - } - if (this.searchInput) { - this.searchInput.addEventListener("input", () => this.applyFilters()); - } - } - - applyFilters() { - const subject = this.subjectFilter?.value || ""; - const grade = this.gradeFilter?.value || ""; - const searchTerm = this.searchInput?.value.toLowerCase() || ""; - - this.courseCards.forEach((card) => { - const text = card.textContent.toLowerCase(); - const matchesSearch = searchTerm === "" || text.includes(searchTerm); - const matchesSubject = subject === "Môn" || text.includes(subject); - const matchesGrade = grade === "Cấp lớp" || text.includes(grade); - - card.style.display = - matchesSearch && matchesSubject && matchesGrade ? "block" : "none"; - }); - } -} - -// Khởi tạo filter & search -document.addEventListener("DOMContentLoaded", () => { - new FilterSearch(); -}); - -// ============================================ -// TOGGLE SWITCHES FUNCTIONALITY -// ============================================ - -class ToggleSwitches { - constructor() { - this.toggles = document.querySelectorAll(".toggle-switch"); - this.init(); - } - - init() { - this.toggles.forEach((toggle) => { - toggle.addEventListener("change", (e) => { - this.handleToggle(e.target); - }); - }); - } - - handleToggle(toggle) { - const label = toggle.previousElementSibling; - const isChecked = toggle.checked; - - // Log để debug - console.log(`${label.textContent}: ${isChecked ? "ON" : "OFF"}`); - - // Có thể thêm logic xử lý khác ở đây - if (toggle.id === "toggle-record") { - this.handleRecordToggle(isChecked); - } else if (toggle.id === "toggle-avatar") { - this.handleAvatarToggle(isChecked); - } - } - - handleRecordToggle(isChecked) { - // Xử lý logic ghi âm - console.log("Ghi âm ảnh:", isChecked ? "bật" : "tắt"); - } - - handleAvatarToggle(isChecked) { - // Xử lý logic avatar - console.log("Có avatar:", isChecked ? "bật" : "tắt"); - } -} - -// Khởi tạo toggle switches -document.addEventListener("DOMContentLoaded", () => { - new ToggleSwitches(); -}); - -// ============================================ -// AVATAR SELECTION FUNCTIONALITY -// ============================================ - -class AvatarSelection { - constructor() { - this.avatarRadios = document.querySelectorAll('input[name="avatar"]'); - this.avatarPreview = document.querySelector(".avatar-preview img"); - this.init(); - } - - init() { - this.avatarRadios.forEach((radio) => { - radio.addEventListener("change", (e) => { - this.handleAvatarChange(e.target); - }); - }); - } - - handleAvatarChange(radio) { - const avatarValue = radio.value; - console.log("Avatar được chọn:", avatarValue); - - // Cập nhật preview (có thể thay đổi src của ảnh) - // this.avatarPreview.src = `path/to/avatar/${avatarValue}.png`; - } -} - -// Khởi tạo avatar selection -document.addEventListener("DOMContentLoaded", () => { - new AvatarSelection(); -}); - -// ============================================ -// PLAY BUTTON FUNCTIONALITY -// ============================================ - -class PlayButton { - constructor() { - this.playButtons = document.querySelectorAll(".play-button"); - this.init(); - } - - init() { - this.playButtons.forEach((btn) => { - btn.addEventListener("click", (e) => { - e.preventDefault(); - this.handlePlay(btn); - }); - }); - } - - handlePlay(button) { - const videoContainer = - button.closest(".video-container") || button.closest(".demo-video"); - console.log("Phát video:", videoContainer); - - // Có thể thêm logic mở modal video hoặc redirect đến video player - alert("Video player sẽ được mở tại đây"); - } -} - -// Khởi tạo play button -document.addEventListener("DOMContentLoaded", () => { - new PlayButton(); -}); - -// ============================================ -// BUTTON INTERACTIONS -// ============================================ - -class ButtonInteractions { - constructor() { - this.uploadBtns = document.querySelectorAll(".upload-btn"); - this.demoBtns = document.querySelectorAll(".demo-btn"); - this.ctaBtns = document.querySelectorAll(".btn"); - this.init(); - } - - init() { - this.uploadBtns.forEach((btn) => { - btn.addEventListener("click", () => this.handleUploadBtn(btn)); - }); - - this.demoBtns.forEach((btn) => { - btn.addEventListener("click", () => this.handleDemoBtn(btn)); - }); - - this.ctaBtns.forEach((btn) => { - btn.addEventListener("click", () => this.handleCTABtn(btn)); - }); - } - - handleUploadBtn(btn) { - const text = btn.textContent; - console.log("Upload button clicked:", text); - } - - handleDemoBtn(btn) { - const text = btn.textContent; - console.log("Demo button clicked:", text); - } - - handleCTABtn(btn) { - const text = btn.textContent; - console.log("CTA button clicked:", text); - } -} - -// Khởi tạo button interactions -document.addEventListener("DOMContentLoaded", () => { - new ButtonInteractions(); -}); - -// ============================================ -// SMOOTH SCROLL FOR NAVIGATION -// ============================================ - -class SmoothScroll { - constructor() { - this.navLinks = document.querySelectorAll(".nav-item"); - this.init(); - } - - init() { - this.navLinks.forEach((link) => { - link.addEventListener("click", (e) => { - const href = link.getAttribute("href"); - if (href.startsWith("#")) { - e.preventDefault(); - const target = document.querySelector(href); - if (target) { - target.scrollIntoView({ behavior: "smooth" }); - } - } - }); - }); - } -} - -// Khởi tạo smooth scroll -document.addEventListener("DOMContentLoaded", () => { - new SmoothScroll(); -}); - -// ============================================ -// UTILITY FUNCTIONS -// ============================================ - -/** - * Hàm debounce để tối ưu hóa performance - */ -function debounce(func, wait) { - let timeout; - return function executedFunction(...args) { - const later = () => { - clearTimeout(timeout); - func(...args); - }; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - }; -} - -/** - * Hàm throttle để giới hạn tần suất gọi hàm - */ -function throttle(func, limit) { - let inThrottle; - return function (...args) { - if (!inThrottle) { - func.apply(this, args); - inThrottle = true; - setTimeout(() => (inThrottle = false), limit); - } - }; -} - -// ============================================ -// INITIALIZATION -// ============================================ - -document.addEventListener("DOMContentLoaded", () => { - console.log("SignBridge website loaded successfully!"); -}); diff --git a/Frontend/styles.css b/Frontend/styles.css deleted file mode 100644 index 7bb1a19..0000000 --- a/Frontend/styles.css +++ /dev/null @@ -1,1248 +0,0 @@ -/* ============================================ - CSS VARIABLES - COLOR PALETTE & SPACING - ============================================ */ -:root { - /* Colors */ - --color-primary-dark: #1e40af; - --color-primary: #3b82f6; - --color-primary-darker: #1e3a8a; - --color-primary-darkest: #1a2d6b; - --color-gray-light: #f3f4f6; - --color-gray: #6b7280; - --color-gray-border: #d1d5db; - --color-white: #ffffff; - --color-black: #111827; - --color-bg-light: #f9fafb; - - /* Spacing */ - --spacing-xs: 8px; - --spacing-sm: 12px; - --spacing-md: 16px; - --spacing-lg: 24px; - --spacing-xl: 32px; - --spacing-2xl: 64px; - --spacing-section: 80px; - - /* Border Radius */ - --radius-sm: 8px; - --radius-md: 12px; - --radius-lg: 16px; - --radius-xl: 20px; - - /* Shadows */ - --shadow-light: 0 2px 8px rgba(0, 0, 0, 0.08); - --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.1); - --shadow-heavy: 0 4px 16px rgba(0, 0, 0, 0.12); - - /* Typography */ - --font-family: - -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", - Arial, sans-serif; -} - -/* ============================================ - RESET & BASE STYLES - ============================================ */ -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -html { - scroll-behavior: smooth; -} - -body { - font-family: var(--font-family); - color: var(--color-black); - background-color: var(--color-white); - line-height: 1.6; -} - -.container { - max-width: 1280px; - margin: 0 auto; - padding: 0 var(--spacing-lg); -} - -/* ============================================ - HEADER / NAVIGATION - ============================================ */ -.header { - position: sticky; - top: 0; - z-index: 100; - background-color: var(--color-primary-darker); - box-shadow: var(--shadow-light); - height: 70px; - display: flex; - align-items: center; - padding: 0 var(--spacing-lg); -} - -.header-content { - display: flex; - align-items: center; - width: 100%; - gap: var(--spacing-lg); -} - -.logo { - display: flex; - align-items: center; - gap: var(--spacing-sm); - font-size: 24px; - font-weight: 700; - color: var(--color-white); - text-decoration: none; - cursor: pointer; - transition: opacity 0.3s ease; -} - -.logo:hover { - opacity: 0.8; -} - -.logo-icon { - height: 40px; - width: auto; - object-fit: contain; -} - -.nav-menu { - display: flex; - align-items: center; - gap: var(--spacing-md); - margin-left: auto; -} - -.nav-item { - color: var(--color-white); - text-decoration: none; - font-size: 14px; - transition: opacity 0.3s ease; -} - -.nav-item:hover { - opacity: 0.8; -} - -.nav-separator { - color: var(--color-white); - opacity: 0.5; -} - -.btn-login { - background-color: var(--color-primary); - color: var(--color-white); - border: none; - padding: 10px 24px; - border-radius: var(--radius-sm); - font-size: 14px; - font-weight: 600; - cursor: pointer; - transition: background-color 0.3s ease; -} - -.btn-login:hover { - background-color: var(--color-primary-dark); -} - -/* ============================================ - HERO SECTION - ============================================ */ -.hero { - padding: var(--spacing-section) 0; - background-color: var(--color-white); -} - -.hero-content { - display: grid; - grid-template-columns: 1fr 1fr; - gap: var(--spacing-2xl); - align-items: center; -} - -.hero-left { - display: flex; - flex-direction: column; - gap: var(--spacing-lg); -} - -.hero-title { - font-size: 48px; - font-weight: 700; - color: var(--color-primary-darker); - line-height: 1.2; -} - -.hero-subtitle { - font-size: 20px; - color: var(--color-gray); - line-height: 1.5; -} - -.hero-buttons { - display: flex; - gap: var(--spacing-md); -} - -.btn { - padding: 14px 32px; - border-radius: var(--radius-lg); - font-size: 16px; - font-weight: 600; - cursor: pointer; - border: none; - transition: all 0.3s ease; -} - -.btn-primary { - background-color: var(--color-primary); - color: var(--color-white); -} - -.btn-primary:hover { - background-color: var(--color-primary-dark); - transform: translateY(-2px); - box-shadow: var(--shadow-md); -} - -.btn-secondary { - background-color: var(--color-white); - color: var(--color-primary); - border: 2px solid var(--color-primary); -} - -.btn-secondary:hover { - background-color: var(--color-gray-light); -} - -.hero-right { - display: flex; - justify-content: center; -} - -.video-container { - position: relative; - width: 100%; - aspect-ratio: 16 / 9; - border-radius: var(--radius-lg); - overflow: hidden; - box-shadow: var(--shadow-heavy); -} - -.video-container img { - width: 100%; - height: 100%; - object-fit: cover; -} - -.play-button { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 60px; - height: 60px; - background-color: var(--color-primary); - color: var(--color-white); - border: none; - border-radius: 50%; - font-size: 24px; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - transition: all 0.3s ease; -} - -.play-button:hover { - background-color: var(--color-primary-dark); - transform: translate(-50%, -50%) scale(1.1); -} - -/* ============================================ - LEARNING HUB SECTION - ============================================ */ -.learning-hub { - padding: var(--spacing-section) 0; - background-color: var(--color-gray-light); -} - -.learning-hub-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: var(--spacing-2xl); - gap: var(--spacing-lg); -} - -.section-title { - font-size: 25px; - font-weight: 600; - color: var(--color-black); - white-space: nowrap; -} - -.filters-search { - display: flex; - gap: var(--spacing-md); - align-items: center; -} - -/* Filter Dropdown */ -.filter-dropdown { - position: relative; -} - -.filter-btn { - padding: var(--spacing-sm) var(--spacing-md); - border: 1px solid var(--color-gray-border); - border-radius: var(--radius-sm); - font-size: 14px; - font-family: var(--font-family); - background-color: var(--color-white); - cursor: pointer; - white-space: nowrap; - text-align: left; - transition: background-color 0.3s ease; -} - -.filter-btn:hover { - background-color: var(--color-gray-light); -} - -.filter-menu { - position: absolute; - top: 100%; - left: 0; - background-color: var(--color-white); - border: 1px solid var(--color-gray-border); - border-radius: var(--radius-sm); - min-width: 140px; - display: none; - flex-direction: column; - z-index: 10; - box-shadow: var(--shadow-light); -} - -.filter-dropdown:hover .filter-menu { - display: flex; -} - -.filter-item { - padding: var(--spacing-sm) var(--spacing-md); - color: var(--color-black); - text-decoration: none; - font-size: 14px; - transition: background-color 0.2s ease; -} - -.filter-item:hover { - background-color: var(--color-gray-light); -} - -.search-box { - position: relative; - display: flex; - align-items: center; -} - -.search-box input { - width: 200px; - padding: var(--spacing-sm) var(--spacing-md); - padding-right: 32px; - border: 1px solid var(--color-gray-border); - border-radius: var(--radius-sm); - font-size: 14px; - font-family: var(--font-family); -} - -.search-box i { - position: absolute; - right: 10px; - font-size: 14px; - pointer-events: none; - color: var(--color-gray); -} - -.learning-hub-content { - display: grid; - grid-template-columns: 1.5fr 1fr; - gap: var(--spacing-2xl); - width: 100%; - overflow: hidden; -} - -.learning-hub-left { - width: 100%; - overflow: hidden; -} - -/* Carousel */ -.carousel-section { - position: relative; - margin-bottom: var(--spacing-2xl); - width: 100%; - overflow: hidden; -} - -.carousel-container { - overflow: hidden; - border-radius: var(--radius-md); - width: 100%; -} - -.carousel-track { - display: flex; - gap: var(--spacing-lg); - overflow-x: auto; - scroll-behavior: smooth; - padding-bottom: var(--spacing-md); - width: 100%; - flex-wrap: nowrap; - min-width: 0; -} - -.carousel-track::-webkit-scrollbar { - height: 6px; -} - -.carousel-track::-webkit-scrollbar-track { - background: var(--color-gray-border); - border-radius: 3px; -} - -.carousel-track::-webkit-scrollbar-thumb { - background: var(--color-primary); - border-radius: 3px; -} - -.course-card { - flex: 0 0 280px; - height: 200px; - border-radius: var(--radius-md); - overflow: hidden; - position: relative; - cursor: pointer; - transition: transform 0.3s ease; -} - -.course-card:hover { - transform: translateY(-4px); -} - -.course-card img { - width: 100%; - height: 100%; - object-fit: cover; -} - -.card-overlay { - position: absolute; - bottom: 0; - left: 0; - right: 0; - background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent); - color: var(--color-white); - padding: var(--spacing-lg); - display: flex; - flex-direction: column; - justify-content: flex-end; -} - -.card-overlay h3 { - font-size: 14px; - font-weight: 600; - margin-bottom: var(--spacing-xs); -} - -.card-overlay p { - font-size: 12px; - margin-bottom: var(--spacing-sm); - opacity: 0.9; -} - -.card-tags { - display: flex; - gap: var(--spacing-xs); - flex-wrap: wrap; -} - -.tag { - background-color: rgba(255, 255, 255, 0.2); - padding: 2px 8px; - border-radius: 4px; - font-size: 11px; -} - -.carousel-nav { - position: absolute; - top: 50%; - transform: translateY(-50%); - background-color: var(--color-primary); - color: var(--color-white); - border: none; - width: 40px; - height: 40px; - border-radius: 50%; - cursor: pointer; - font-size: 20px; - display: flex; - align-items: center; - justify-content: center; - transition: background-color 0.3s ease; - z-index: 10; -} - -.carousel-nav:hover { - background-color: var(--color-primary-dark); -} - -.carousel-prev { - left: -20px; -} - -.carousel-next { - right: -20px; -} - -/* About Section */ -.about-title { - font-size: 25px; - font-weight: 600; - color: var(--color-black); - margin-bottom: var(--spacing-lg); -} - -.about-card { - background-color: var(--color-white); - padding: var(--spacing-xl); - border-radius: var(--radius-md); - display: grid; - grid-template-columns: 1fr 1fr; - gap: var(--spacing-xl); -} - -.about-item { - display: flex; - gap: var(--spacing-md); -} - -.about-icon { - font-size: 32px; - flex-shrink: 0; - width: 60px; - height: 60px; - display: flex; - align-items: center; - justify-content: center; - background-color: rgba(59, 130, 246, 0.1); - border-radius: 50%; -} - -.about-content h4 { - font-size: 16px; - font-weight: 600; - margin-bottom: var(--spacing-sm); - color: var(--color-black); -} - -.about-card p { - font-size: 13px; - color: var(--color-gray); - line-height: 1.5; -} - -/* Upload Area */ -.learning-hub-right { - width: 100%; - overflow: hidden; - display: flex; - flex-direction: column; - gap: var(--spacing-lg); -} - -.upload-title { - font-size: 25px; - font-weight: 600; - color: var(--color-black); -} - -.upload-card { - background-color: var(--color-white); - border: 2px dashed var(--color-gray-border); - border-radius: var(--radius-lg); - padding: var(--spacing-xl); - display: flex; - flex-direction: column; - gap: var(--spacing-xl); -} - -.upload-section-title { - font-size: 16px; - font-weight: 600; - color: var(--color-black); - margin: 0; -} - -/* Options Container - 2 columns */ -.options-container { - display: grid; - grid-template-columns: 1fr 1fr; - gap: var(--spacing-lg); -} - -.options-left { - display: flex; - flex-direction: column; -} - -.options-right { - display: flex; - flex-direction: column; -} - -/* Upload Section - Tạo ký hiệu */ -.upload-section { - display: flex; - flex-direction: column; - gap: var(--spacing-xl); -} - -.symbol-top { - display: flex; - flex-direction: column; - gap: var(--spacing-md); -} - -/* Symbol Dividers */ -.symbol-divider { - width: 100%; - height: 1px; - background-color: var(--color-gray-border); -} - -.symbol-v-divider { - width: 1px; - height: 100%; - background-color: var(--color-gray-border); -} - -/* Create Symbol Button */ -.create-symbol-btn { - width: 100%; - border: none; - background-color: var(--color-primary); - cursor: pointer; - padding: var(--spacing-md); - border-radius: var(--radius-md); - transition: all 0.3s ease; -} - -.create-symbol-btn:hover { - background-color: var(--color-primary-dark); - transform: translateY(-2px); - box-shadow: var(--shadow-md); -} - -/* Symbol Bottom Section */ -.symbol-bottom { - display: grid; - grid-template-columns: 1fr 1fr; - gap: var(--spacing-lg); -} - -.symbol-left { - display: flex; - flex-direction: column; - gap: var(--spacing-md); - justify-content: flex-start; -} - -.youtube-title { - font-size: 16px; - font-weight: 600; - color: var(--color-black); - margin: 0; -} - -.youtube-progress { - width: 100%; - height: 6px; - background-color: var(--color-gray-light); - border-radius: 3px; - overflow: hidden; -} - -.symbol-right { - display: flex; - align-items: center; - justify-content: center; -} - -.symbol-video-preview { - position: relative; - width: 100%; - aspect-ratio: 16 / 9; - border-radius: var(--radius-md); - overflow: hidden; - background-color: var(--color-gray-light); -} - -.symbol-video-preview img { - width: 100%; - height: 100%; - object-fit: cover; -} - -.play-icon { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - font-size: 32px; - color: var(--color-white); - background-color: rgba(59, 130, 246, 0.8); - width: 50px; - height: 50px; - display: flex; - align-items: center; - justify-content: center; - border-radius: 50%; -} - -.symbol-progress { - width: 100%; - height: 6px; - background-color: var(--color-gray-light); - border-radius: 3px; - overflow: hidden; -} - -.progress-bar { - height: 100%; - width: 20%; - background-color: var(--color-primary); - border-radius: 3px; -} - -.symbol-label { - font-size: 16px; - font-weight: 600; - color: var(--color-white); -} - -.upload-buttons { - display: flex; - flex-direction: column; - gap: var(--spacing-sm); -} - -.upload-btn { - width: 100%; - text-align: left; - padding: var(--spacing-sm) var(--spacing-md); - border-radius: var(--radius-sm); - background-color: var(--color-gray-light); - border: none; - cursor: pointer; - font-size: 14px; - transition: background-color 0.3s ease; -} - -.upload-btn:hover { - background-color: var(--color-gray-border); -} - -.upload-toggles { - display: flex; - flex-direction: column; - gap: var(--spacing-md); -} - -.toggle-group { - display: flex; - justify-content: space-between; - align-items: center; -} - -.toggle-group label { - font-size: 14px; - font-weight: 500; - color: var(--color-black); -} - -.toggle-switch { - appearance: none; - width: 48px; - height: 24px; - background-color: var(--color-gray-border); - border-radius: 12px; - cursor: pointer; - position: relative; - transition: background-color 0.3s ease; -} - -.toggle-switch::before { - content: ""; - position: absolute; - width: 20px; - height: 20px; - background-color: var(--color-white); - border-radius: 50%; - top: 2px; - left: 2px; - transition: left 0.3s ease; -} - -.toggle-switch:checked { - background-color: var(--color-primary); -} - -.toggle-switch:checked::before { - left: 26px; -} - -.avatar-preview { - border-radius: var(--radius-md); - overflow: hidden; - box-shadow: var(--shadow-md); -} - -.avatar-preview img { - width: 100%; - height: auto; - display: block; -} - -.avatar-selection { - background-color: var(--color-white); - padding: var(--spacing-lg); - border-radius: var(--radius-md); -} - -.avatar-selection h4 { - font-size: 14px; - font-weight: 600; - margin-bottom: var(--spacing-md); - color: var(--color-black); -} - -.avatar-options { - display: flex; - flex-direction: column; - gap: var(--spacing-sm); -} - -.avatar-radio { - display: flex; - align-items: center; - gap: var(--spacing-sm); - cursor: pointer; - font-size: 13px; -} - -.avatar-radio input[type="radio"] { - cursor: pointer; - accent-color: var(--color-primary); -} - -.avatar-label { - color: var(--color-gray); -} - -/* ============================================ - TESTIMONIAL SECTION - ============================================ */ -.testimonial { - padding: var(--spacing-section) 0; - background-color: var(--color-white); -} - -.testimonial .section-title { - text-align: left; - margin-bottom: var(--spacing-2xl); - margin-left: var(--spacing-2xl); - margin-right: var(--spacing-2xl); - font-size: 28px; - font-weight: 700; - color: var(--color-primary-darker); - display: flex; - align-items: center; - gap: var(--spacing-lg); -} - -.testimonial .section-title::after { - content: ""; - flex: 1; - height: 2px; - background-color: var(--color-primary); -} - -.testimonial-content { - display: grid; - grid-template-columns: 1fr 1fr; - gap: var(--spacing-2xl); - align-items: start; -} - -.testimonial-left { - display: flex; - flex-direction: column; - gap: var(--spacing-lg); -} - -.quote-card { - background-color: transparent; - padding: 0; - border-radius: 0; -} - -/* Timeline Text Wrapper */ -.timeline-text-wrapper { - display: flex; - flex-direction: column; - align-items: center; - gap: var(--spacing-md); - margin-bottom: var(--spacing-lg); -} - -.timeline-divider { - width: 200px; - height: 12px; - background-color: transparent; - position: relative; - display: flex; - align-items: center; - justify-content: center; -} - -.timeline-divider::before { - content: ""; - position: absolute; - width: 200px; - height: 2px; - background-color: var(--color-primary); - top: 50%; - left: 0; -} - -.timeline-divider::after { - content: ""; - position: absolute; - width: 12px; - height: 12px; - background-color: var(--color-primary); - border-radius: 50%; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - z-index: 2; -} - -.timeline-dot { - position: absolute; - width: 12px; - height: 12px; - background-color: var(--color-primary); - border-radius: 50%; - top: 50%; - transform: translateY(-50%); -} - -.timeline-dot-left { - left: -18px; -} - -.timeline-dot-right { - right: -18px; -} - -.timeline-text { - font-size: 18px; - letter-spacing: 4px; - color: var(--color-gray); - text-align: center; - font-weight: 700; -} - -.quote-box { - background-color: var(--color-gray-light); - padding: var(--spacing-xl); - border-radius: var(--radius-sm); - margin: var(--spacing-lg) 0; - position: relative; -} - -.quote-mark { - font-size: 48px; - color: var(--color-primary); - position: absolute; - line-height: 1; -} - -.quote-start { - top: var(--spacing-md); - left: var(--spacing-md); -} - -.quote-end { - bottom: var(--spacing-md); - right: var(--spacing-md); -} - -.quote-text { - font-size: 24px; - font-style: italic; - color: var(--color-black); - line-height: 1.6; - margin: var(--spacing-lg) 0; -} - -.avatars-group { - display: flex; - justify-content: center; - align-items: center; - gap: var(--spacing-md); - margin: var(--spacing-lg) 0; -} - -.avatar-circle { - width: 64px; - height: 64px; - border-radius: 50%; - border: 2px solid var(--color-white); - object-fit: cover; - flex-shrink: 0; -} - -.avatar-circle:first-child { - margin-left: 0; -} - -.feedback-info { - display: flex; - align-items: center; - justify-content: center; - gap: var(--spacing-sm); - font-size: 13px; - color: var(--color-gray); - margin-top: var(--spacing-lg); -} - -.feedback-icon { - font-size: 16px; -} - -/* Demo Section */ -.testimonial-right { - display: flex; - flex-direction: column; - gap: var(--spacing-lg); -} - -/* Demo Card */ -.demo-card { - background-color: var(--color-primary-darkest); - border-radius: var(--radius-lg); - padding: var(--spacing-xl); - display: flex; - flex-direction: column; - gap: var(--spacing-lg); -} - -.demo-buttons { - display: flex; - gap: var(--spacing-md); - flex-wrap: wrap; - justify-content: center; -} - -.demo-btn { - padding: var(--spacing-sm) var(--spacing-lg); - background-color: transparent; - border: 2px solid var(--color-white); - border-radius: var(--radius-md); - font-size: 14px; - cursor: pointer; - color: var(--color-white); - font-weight: 500; - transition: all 0.3s ease; -} - -.demo-btn:hover { - background-color: var(--color-white); - color: var(--color-primary-darker); - border-color: var(--color-white); -} - -.demo-video { - position: relative; - width: 100%; - aspect-ratio: 16 / 9; - border-radius: var(--radius-md); - overflow: hidden; - box-shadow: var(--shadow-md); - border: 2px solid var(--color-white); -} - -.demo-video img { - width: 100%; - height: 100%; - object-fit: cover; -} - -.demo-caption { - font-size: 16px; - color: var(--color-white); - font-weight: 600; - text-align: center; - margin-top: var(--spacing-md); -} - -/* ============================================ - FOOTER - ============================================ */ -.footer { - background-color: var(--color-primary-darker); - color: var(--color-white); - padding: var(--spacing-xl) 0; -} - -.footer-content { - display: flex; - justify-content: center; - align-items: center; - gap: var(--spacing-2xl); - position: relative; -} - -.footer-copyright { - text-align: center; -} - -.footer-links { - position: absolute; - right: 0; -} - -.footer-copyright { - font-size: 14px; -} - -.footer-links { - display: flex; - gap: var(--spacing-lg); -} - -.footer-links a { - color: var(--color-white); - text-decoration: none; - font-size: 14px; - transition: all 0.3s ease; -} - -.footer-links a:hover { - opacity: 0.8; -} - -.footer-link-icon { - display: flex; - align-items: center; - justify-content: center; - width: 40px; - height: 40px; - border: 2px solid var(--color-white); - border-radius: 50%; - font-size: 18px; - transition: all 0.3s ease; -} - -.footer-link-icon:hover { - background-color: var(--color-white); - color: var(--color-primary-darker); - transform: scale(1.1); -} - -/* ============================================ - RESPONSIVE DESIGN - ============================================ */ -@media (max-width: 1024px) { - .learning-hub-content { - grid-template-columns: 1fr; - } - - .hero-content { - grid-template-columns: 1fr; - } - - .testimonial-content { - grid-template-columns: 1fr; - } - - .learning-hub-header { - flex-direction: column; - align-items: flex-start; - } - - .filters-search { - width: 100%; - flex-wrap: wrap; - } -} - -@media (max-width: 768px) { - .header-content { - flex-wrap: wrap; - gap: var(--spacing-md); - } - - .nav-menu { - order: 3; - width: 100%; - justify-content: flex-start; - font-size: 12px; - } - - .hero-title { - font-size: 32px; - } - - .hero-subtitle { - font-size: 16px; - } - - .hero-buttons { - flex-direction: column; - } - - .section-title { - font-size: 24px; - } - - .about-cards { - grid-template-columns: 1fr; - } - - .upload-card { - grid-template-columns: 1fr; - } - - .carousel-track { - gap: var(--spacing-md); - } - - .course-card { - flex: 0 0 240px; - height: 160px; - } - - .footer-content { - flex-direction: column; - gap: var(--spacing-lg); - text-align: center; - } -} diff --git a/app.py b/app.py index 86fb4c9..a4db065 100644 --- a/app.py +++ b/app.py @@ -1,3 +1,32 @@ +""" +SignBridge - Hệ thống dịch Tiếng Việt Nói → Ngôn Ngữ Ký Hiệu (VSL) + +Mô tả: +Ứng dụng Flask cho phép người dùng upload video tiếng Việt nói, +sau đó tự động dịch sang ngôn ngữ ký hiệu Việt Nam (VSL) và hiển thị +qua avatar 3D. + +AI Pipeline: +1. Speech-to-Text (STT): OpenAI Whisper → transcript +2. Text-to-Gloss: Vocabulary mapping → gloss notation +3. Gloss-to-SiGML: VSL Dictionary → SiGML XML +4. Avatar Rendering: CWASA/JASigning → 3D animation + +Kiến trúc: +- Frontend: HTML5/CSS3/JavaScript (CWASA avatar player) +- Backend: Flask + SQLAlchemy + PostgreSQL +- AI Models: Whisper (speech recognition) +- Rendering: CWASA (SiGML avatar engine) + +Database: +- videos: Metadata video + SiGML content +- processing_history: Lịch sử xử lý pipeline +- sign_vocabulary: Từ vựng ký hiệu + +Author: SignBridge Team +License: MIT +""" + import os import logging from datetime import datetime @@ -16,31 +45,53 @@ from src.config import AppConfig from src.services import FigmaService, ProcessingPipeline, FileService, VideoService -from src.repositories import ManifestRepository +from src.repositories.video_repository import VideoRepository +from src.repositories.vocabulary_repository import VocabularyRepository from src.models import Video from src.exceptions import ValidationError, SignBridgeError from src.utils import timed_execution, RequestValidator -# Configure logging +# ========== LOGGING CONFIGURATION ========== logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" ) logger = logging.getLogger(__name__) -# Initialize application configuration +# ========== APPLICATION CONFIGURATION ========== +# Load từ .env file hoặc environment variables config = AppConfig.from_env() -figma_service = FigmaService(config.figma) -pipeline_service = ProcessingPipeline(config) -file_service = FileService() -manifest_repository = ManifestRepository( - manifest_path=os.path.join(config.content_dir, "manifest.json") + +# ========== DATABASE CONNECTION ========== +# PostgreSQL connection string +# Format: postgresql://username:password@host:port/database +DATABASE_URL = os.getenv( + 'DATABASE_URL', + 'postgresql://HiepData:123456@localhost:5438/db_signbridge' ) + +# ========== INITIALIZE SERVICES & REPOSITORIES ========== +# Services: Business logic cho các chức năng chính +figma_service = FigmaService(config.figma) # Figma design integration +pipeline_service = ProcessingPipeline(config) # AI pipeline (STT → Gloss → SiGML) +file_service = FileService() # File I/O operations + +# Repositories: Data access layer (PostgreSQL) +try: + video_repository = VideoRepository(DATABASE_URL) + vocabulary_repository = VocabularyRepository(DATABASE_URL) + logger.info("✅ Database repositories initialized successfully") +except Exception as e: + logger.error(f"❌ Failed to initialize database repositories: {e}") + logger.error("⚠️ Application requires database connection to run") + raise + +# Video Service: Orchestrates upload, processing, và storage video_service = VideoService( config=config, pipeline_service=pipeline_service, file_service=file_service, - manifest_repository=manifest_repository, + video_repository=video_repository ) # Legacy compatibility - maintain these for existing code @@ -63,154 +114,28 @@ def get_figma_tokens() -> dict: return figma_service.get_design_tokens() -def write_hardcoded_sigml(output_sigml: str) -> None: - """Overwrite output_sigml with a fixed two-hand SiGML for demo sentence. - This guarantees the avatar will sign with both hands regardless of STT/Gloss. - """ - sigml_text = """ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -""" - with open(output_sigml, "w", encoding="utf-8") as f: - f.write(sigml_text) +# NOTE: write_hardcoded_sigml() function removed +# Demo SiGML is now stored in database and loaded from out/video1.sigml file @app.route("/") @timed_execution def index() -> str: - """Render main landing page with video list. - + """ + Route: Trang chủ (Landing page) + + Chức năng: + - Hiển thị danh sách video demo có sẵn + - Interactive demo section (upload + preview) + - Tích hợp Figma design tokens + Returns: - Rendered HTML template + HTML template với danh sách video published """ - videos = manifest_repository.get_all_videos() - # Convert to dict for template compatibility + # Lấy danh sách video đã published từ DB + videos = video_repository.get_published_videos() + + # Convert sang dict để compatible với template videos_data = [v.to_dict() for v in videos] return render_template( "index.html", @@ -242,6 +167,7 @@ def watch(vid: str) -> Union[str, Response]: "result.html", video=None, video_url=viewing_data.video_url, + video_id=vid, # NEW - Pass video_id to template sigml=viewing_data.sigml_filename, playlist=None, embed=is_embed, @@ -256,19 +182,6 @@ def watch(vid: str) -> Union[str, Response]: return redirect(url_for("index")) -@app.route("/hub") -def hub() -> str: - """Render learning hub page. - - Returns: - Rendered HTML template - """ - videos = manifest_repository.get_all_videos() - # Convert to dict for template compatibility - videos_data = [v.to_dict() for v in videos] - return render_template("hub.html", videos=videos_data) - - @app.route("/assets/") def serve_assets(filename: str) -> Response: """Serve static asset files. @@ -285,8 +198,17 @@ def serve_assets(filename: str) -> Response: @app.route("/upload", methods=["POST"]) @timed_execution def upload() -> Response: - """Handle video upload and processing. - + """ + Route: Upload video và xử lý qua AI pipeline + + Flow: + 1. Nhận video từ form upload + 2. Validate file (size, extension) + 3. Lưu file vào static/uploads/ + 4. Xử lý qua pipeline: STT → Text2Gloss → Gloss2SiGML + 5. Lưu kết quả vào DB (videos + processing_history) + 6. Redirect đến trang xem kết quả + Returns: Redirect response to preview page or index on error """ @@ -344,6 +266,11 @@ def preview() -> str: @app.route("/result") def result(): + """Preview result page (for uploaded videos via /preview redirect). + + Returns: + Rendered result.html template + """ video = request.args.get("video") sigml = request.args.get("sigml") playlist_name = request.args.get("playlist") @@ -352,37 +279,42 @@ def result(): ) -@app.route("/add_to_hub", methods=["POST"]) +@app.route("/result/") @timed_execution -def add_to_hub() -> Tuple[Dict[str, Any], int]: - """Add uploaded video to Learning Hub (manifest.json). - +def view_video(video_id: str) -> str: + """View video by ID (for Learning Hub videos). + + Args: + video_id: Video identifier from database + Returns: - Tuple of (JSON response, HTTP status code) + Rendered result.html template """ - video_filename = request.form.get("video") - sigml_filename = request.form.get("sigml") - title = request.form.get("title", "Video mới") - try: - # Validate filenames to prevent path traversal - RequestValidator.validate_filename(video_filename) - RequestValidator.validate_filename(sigml_filename) - # Add video through service - video_id = video_service.add_to_learning_hub( - video_filename=video_filename, sigml_filename=sigml_filename, title=title + # Get video data from service + video_data = video_service.get_video_for_viewing(video_id) + + logger.info(f"Viewing video {video_id}: video_url={video_data.video_url}, sigml={video_data.sigml_filename}") + + return render_template( + "result.html", + video=video_data.video_url, + video_id=video_id, # NEW - Pass video_id to template + sigml=video_data.sigml_filename, + playlist=None ) - - logger.info(f"Video added to hub: {video_id}") - return {"success": True, "videoId": video_id}, 200 - + except ValidationError as e: - logger.warning(f"Validation error in add_to_hub: {e}") - return {"success": False, "error": str(e)}, 400 + logger.warning(f"Video not found: {video_id}") + flash(f"Video không tồn tại: {video_id}") + return redirect(url_for("hub")) + + except Exception as e: + logger.error(f"Error viewing video {video_id}: {e}", exc_info=True) + flash(f"Lỗi khi xem video: {e}") + return redirect(url_for("hub")) + - except SignBridgeError as e: - logger.error(f"Error in add_to_hub: {e}", exc_info=True) - return {"success": False, "error": str(e)}, 500 @app.route("/static/uploads/") @@ -401,6 +333,9 @@ def serve_upload(filename: str) -> Response: @app.route("/out/") def serve_out(filename: str) -> Response: """Serve output files (transcripts, SiGML, etc.). + + DEPRECATED - This endpoint is kept for backward compatibility only. + New code should use /api/sigml/ instead. Args: filename: Output filename @@ -411,5 +346,46 @@ def serve_out(filename: str) -> Response: return send_from_directory(OUT_DIR, filename) +@app.route("/api/sigml/") +@timed_execution +def get_sigml_content(video_id: str) -> Union[Response, Tuple[str, int]]: + """Serve SiGML content from database. + + This is the NEW primary endpoint for SiGML content. + Content is stored in database, not filesystem. + + Args: + video_id: Video identifier + + Returns: + SiGML XML content or error response + """ + try: + video = video_repository.get_video_by_id(video_id) + + if not video: + logger.warning(f"SiGML requested for non-existent video: {video_id}") + return "Video not found", 404 + + if not video.sigml_content: + logger.warning(f"Video {video_id} has no SiGML content") + return "SiGML content not available", 404 + + logger.info(f"Serving SiGML for video {video_id} ({len(video.sigml_content)} bytes)") + + return Response( + video.sigml_content, + mimetype='application/xml', + headers={ + 'Content-Type': 'application/xml; charset=utf-8', + 'Cache-Control': 'public, max-age=3600', # Cache for 1 hour + } + ) + + except Exception as e: + logger.error(f"Error serving SiGML for {video_id}: {e}", exc_info=True) + return "Internal server error", 500 + + if __name__ == "__main__": app.run(host="0.0.0.0", port=5001, debug=True) diff --git a/assets/bak.png b/assets/bak.png deleted file mode 100644 index a3da839..0000000 Binary files a/assets/bak.png and /dev/null differ diff --git a/content/manifest.json b/content/manifest.json index 12fccd3..f7cf9b9 100644 --- a/content/manifest.json +++ b/content/manifest.json @@ -5,8 +5,7 @@ "title": "Xin chào – ý tưởng giáo dục (AI)", "desc": "Câu chào và giới thiệu dự án trợ năng cho người khiếm thính", "videoPath": "assets/video1.mp4", - "sigmlSource": "inline", - "sigmlText": " ", + "sigmlSource": "db", "thumbPath": "assets/thumbail.png", "playback": { "startDelayMs": 1500, @@ -21,35 +20,45 @@ "title": "Mục tiêu dự án – nền tảng realtime", "desc": "Chuyển lời nói giáo viên thành văn bản/ký hiệu", "videoPath": "assets/video2.mp4", - "sigmlSource": "inline", - "sigmlText": "\n\n \n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n\n \n \n \n \n \n\n \n \n \n \n \n\n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n\n \n \n \n \n \n\n \n \n \n \n \n\n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n\n \n \n \n \n \n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n", - "playlistPath": "", + "sigmlSource": "db", "thumbPath": "assets/thumbail.png", - "playback": { "startDelayMs": 1500, "interSegmentPauseMs": 500, "stretchPolicy": "segment", "baseSignDur": 0.8, "clamp": { "min": -5, "max": 1 } } + "playback": { + "startDelayMs": 1500, + "interSegmentPauseMs": 500, + "stretchPolicy": "segment", + "baseSignDur": 0.8, + "clamp": { "min": -5, "max": 1 } + } }, { "id": "video3", "title": "Công nghệ STT + AI dịch ký hiệu", "desc": "Thu hẹp khoảng cách giao tiếp giáo dục", "videoPath": "assets/video3.mp4", - "sigmlSource": "inline", - "sigmlText": " ", - "playlistPath": "", + "sigmlSource": "db", "thumbPath": "assets/thumbail.png", - "playback": { "startDelayMs": 1500, "interSegmentPauseMs": 500, "stretchPolicy": "segment", "baseSignDur": 0.8, "clamp": { "min": -5, "max": 1 } } + "playback": { + "startDelayMs": 1500, + "interSegmentPauseMs": 500, + "stretchPolicy": "segment", + "baseSignDur": 0.8, + "clamp": { "min": -5, "max": 1 } + } }, { "id": "video4", "title": "Python – biến và print", "desc": "Ví dụ x = 10 và in ra bằng print", "videoPath": "assets/video4.mp4", - "sigmlSource": "inline", - "sigmlText": " ", - "playlistPath": "", + "sigmlSource": "db", "thumbPath": "assets/thumbail.png", - "playback": { "startDelayMs": 1500, "interSegmentPauseMs": 500, "stretchPolicy": "segment", "baseSignDur": 0.8, "clamp": { "min": -5, "max": 1 } } + "playback": { + "startDelayMs": 1500, + "interSegmentPauseMs": 500, + "stretchPolicy": "segment", + "baseSignDur": 0.8, + "clamp": { "min": -5, "max": 1 } + } } ] } - - diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..2678198 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,19 @@ +version: "3.9" + +services: + postgres: + container_name: signbridge + image: postgres:latest + environment: + POSTGRES_USER: HiepData + POSTGRES_PASSWORD: 123456 + POSTGRES_DB: db_signbridge + PGDATA: /var/lib/postgresql/data + volumes: + - pgdata_signbridge:/var/lib/postgresql/data + ports: + - "5438:5432" + restart: unless-stopped + +volumes: + pgdata_signbridge: diff --git a/out/20251016_135816.gloss.txt b/out/20251016_135816.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_135816.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_135816.sigml b/out/20251016_135816.sigml deleted file mode 100644 index 0a1e03b..0000000 --- a/out/20251016_135816.sigml +++ /dev/null @@ -1,91 +0,0 @@ - - - - e_It_S,,,,AD,RB,BB,hamfinger2,hamthumbacrossmod,hambetween,hamfinger23,hamthumbacrossmod,hammiddlefinger,hamfingerstraightmod,hamextfingerur,hambetween,hamextfingeru,hampalmu,hamshoulders,hamlrat - - - - o,,,,AD,RB,BB,hampinchall,hamextfingeru,hampalml,hamshoulders,hamlrat,hamreplace,hamfinger23spread,hamfingerhookmod,hamthumbacrossmod,hamextfingeru,hampalmd - - - - ,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hamindexfinger,hamfingerbendmod,hammiddlefinger,hamfingerbendmod,hamringfinger,hamfingerbendmod,hamextfingero,hampalmd,hamshoulders,hamlrat - - - - en,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hamindexfinger,hamfingerbendmod,hammiddlefinger,hamfingerbendmod,hamextfingero,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger2,hampinky,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamceeall,hamthumbopenmod,hamextfingeru,hampalmdl,hamshoulders,hamlrat - - - - e_It_S,,,,AD,RB,BB,hamfinger2,hamthumbacrossmod,hambetween,hamfinger23,hamthumbacrossmod,hammiddlefinger,hamfingerstraightmod,hamextfingerur,hambetween,hamextfingeru,hampalmu,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger23,hamthumbacrossmod,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - en,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hamindexfinger,hamfingerbendmod,hammiddlefinger,hamfingerbendmod,hamextfingero,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger2,hamthumboutmod,hamextfingerur,hampalmul,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger2345,hamthumbopenmod,hamindexfinger,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfist,hamindexfinger,hamdoublebent,hammiddlefinger,hamdoublebent,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - hoc,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hambetween,hamflathand,hamextfingeru,hampalmu,hamforehead,hamlrat,hamseqbegin,hamtouch,hamfingertip,hammiddlefinger,hamseqend - - - - ,,,,AD,RB,BB,hamfinger2,hamthumbacrossmod,hamthumb,hamfingernail,hammiddlefinger,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfist,hamindexfinger,hamdoublebent,hammiddlefinger,hamdoublebent,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - en,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hamindexfinger,hamfingerbendmod,hammiddlefinger,hamfingerbendmod,hamextfingero,hampalmd,hamshoulders,hamlrat - - - - e_It_S,,,,AD,RB,BB,hamfinger2,hamthumbacrossmod,hambetween,hamfinger23,hamthumbacrossmod,hammiddlefinger,hamfingerstraightmod,hamextfingerur,hambetween,hamextfingeru,hampalmu,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamflathand,hamfingerhookmod,hamthumbacrossmod,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,amcee12,hambetween,hamfinger2,hamthumbopenmod,hamextfingerdr,hampalmd,hamstomach,hamlrbeside - - - - ,,,,AD,RB,BB,hamfinger23,hamthumbacrossmod,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfist,hamindexfinger,hamdoublebent,hammiddlefinger,hamdoublebent,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger2345,hamthumbopenmod,hamindexfinger,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - diff --git a/out/20251016_135816.sigml.report.txt b/out/20251016_135816.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_135816.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_135816.txt b/out/20251016_135816.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_135816.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_141732.gloss.txt b/out/20251016_141732.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_141732.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_141732.sigml b/out/20251016_141732.sigml deleted file mode 100644 index 0a1e03b..0000000 --- a/out/20251016_141732.sigml +++ /dev/null @@ -1,91 +0,0 @@ - - - - e_It_S,,,,AD,RB,BB,hamfinger2,hamthumbacrossmod,hambetween,hamfinger23,hamthumbacrossmod,hammiddlefinger,hamfingerstraightmod,hamextfingerur,hambetween,hamextfingeru,hampalmu,hamshoulders,hamlrat - - - - o,,,,AD,RB,BB,hampinchall,hamextfingeru,hampalml,hamshoulders,hamlrat,hamreplace,hamfinger23spread,hamfingerhookmod,hamthumbacrossmod,hamextfingeru,hampalmd - - - - ,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hamindexfinger,hamfingerbendmod,hammiddlefinger,hamfingerbendmod,hamringfinger,hamfingerbendmod,hamextfingero,hampalmd,hamshoulders,hamlrat - - - - en,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hamindexfinger,hamfingerbendmod,hammiddlefinger,hamfingerbendmod,hamextfingero,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger2,hampinky,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamceeall,hamthumbopenmod,hamextfingeru,hampalmdl,hamshoulders,hamlrat - - - - e_It_S,,,,AD,RB,BB,hamfinger2,hamthumbacrossmod,hambetween,hamfinger23,hamthumbacrossmod,hammiddlefinger,hamfingerstraightmod,hamextfingerur,hambetween,hamextfingeru,hampalmu,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger23,hamthumbacrossmod,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - en,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hamindexfinger,hamfingerbendmod,hammiddlefinger,hamfingerbendmod,hamextfingero,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger2,hamthumboutmod,hamextfingerur,hampalmul,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger2345,hamthumbopenmod,hamindexfinger,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfist,hamindexfinger,hamdoublebent,hammiddlefinger,hamdoublebent,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - hoc,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hambetween,hamflathand,hamextfingeru,hampalmu,hamforehead,hamlrat,hamseqbegin,hamtouch,hamfingertip,hammiddlefinger,hamseqend - - - - ,,,,AD,RB,BB,hamfinger2,hamthumbacrossmod,hamthumb,hamfingernail,hammiddlefinger,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfist,hamindexfinger,hamdoublebent,hammiddlefinger,hamdoublebent,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - en,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hamindexfinger,hamfingerbendmod,hammiddlefinger,hamfingerbendmod,hamextfingero,hampalmd,hamshoulders,hamlrat - - - - e_It_S,,,,AD,RB,BB,hamfinger2,hamthumbacrossmod,hambetween,hamfinger23,hamthumbacrossmod,hammiddlefinger,hamfingerstraightmod,hamextfingerur,hambetween,hamextfingeru,hampalmu,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamflathand,hamfingerhookmod,hamthumbacrossmod,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,amcee12,hambetween,hamfinger2,hamthumbopenmod,hamextfingerdr,hampalmd,hamstomach,hamlrbeside - - - - ,,,,AD,RB,BB,hamfinger23,hamthumbacrossmod,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfist,hamindexfinger,hamdoublebent,hammiddlefinger,hamdoublebent,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger2345,hamthumbopenmod,hamindexfinger,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - diff --git a/out/20251016_141732.sigml.report.txt b/out/20251016_141732.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_141732.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_141732.txt b/out/20251016_141732.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_141732.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_143535.gloss.txt b/out/20251016_143535.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_143535.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_143535.sigml b/out/20251016_143535.sigml deleted file mode 100644 index 0a1e03b..0000000 --- a/out/20251016_143535.sigml +++ /dev/null @@ -1,91 +0,0 @@ - - - - e_It_S,,,,AD,RB,BB,hamfinger2,hamthumbacrossmod,hambetween,hamfinger23,hamthumbacrossmod,hammiddlefinger,hamfingerstraightmod,hamextfingerur,hambetween,hamextfingeru,hampalmu,hamshoulders,hamlrat - - - - o,,,,AD,RB,BB,hampinchall,hamextfingeru,hampalml,hamshoulders,hamlrat,hamreplace,hamfinger23spread,hamfingerhookmod,hamthumbacrossmod,hamextfingeru,hampalmd - - - - ,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hamindexfinger,hamfingerbendmod,hammiddlefinger,hamfingerbendmod,hamringfinger,hamfingerbendmod,hamextfingero,hampalmd,hamshoulders,hamlrat - - - - en,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hamindexfinger,hamfingerbendmod,hammiddlefinger,hamfingerbendmod,hamextfingero,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger2,hampinky,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamceeall,hamthumbopenmod,hamextfingeru,hampalmdl,hamshoulders,hamlrat - - - - e_It_S,,,,AD,RB,BB,hamfinger2,hamthumbacrossmod,hambetween,hamfinger23,hamthumbacrossmod,hammiddlefinger,hamfingerstraightmod,hamextfingerur,hambetween,hamextfingeru,hampalmu,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger23,hamthumbacrossmod,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - en,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hamindexfinger,hamfingerbendmod,hammiddlefinger,hamfingerbendmod,hamextfingero,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger2,hamthumboutmod,hamextfingerur,hampalmul,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger2345,hamthumbopenmod,hamindexfinger,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfist,hamindexfinger,hamdoublebent,hammiddlefinger,hamdoublebent,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - hoc,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hambetween,hamflathand,hamextfingeru,hampalmu,hamforehead,hamlrat,hamseqbegin,hamtouch,hamfingertip,hammiddlefinger,hamseqend - - - - ,,,,AD,RB,BB,hamfinger2,hamthumbacrossmod,hamthumb,hamfingernail,hammiddlefinger,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfist,hamindexfinger,hamdoublebent,hammiddlefinger,hamdoublebent,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - en,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hamindexfinger,hamfingerbendmod,hammiddlefinger,hamfingerbendmod,hamextfingero,hampalmd,hamshoulders,hamlrat - - - - e_It_S,,,,AD,RB,BB,hamfinger2,hamthumbacrossmod,hambetween,hamfinger23,hamthumbacrossmod,hammiddlefinger,hamfingerstraightmod,hamextfingerur,hambetween,hamextfingeru,hampalmu,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamflathand,hamfingerhookmod,hamthumbacrossmod,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,amcee12,hambetween,hamfinger2,hamthumbopenmod,hamextfingerdr,hampalmd,hamstomach,hamlrbeside - - - - ,,,,AD,RB,BB,hamfinger23,hamthumbacrossmod,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfist,hamindexfinger,hamdoublebent,hammiddlefinger,hamdoublebent,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger2345,hamthumbopenmod,hamindexfinger,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - diff --git a/out/20251016_143535.sigml.report.txt b/out/20251016_143535.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_143535.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_143535.txt b/out/20251016_143535.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_143535.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_145712.gloss.txt b/out/20251016_145712.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_145712.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_145712.sigml b/out/20251016_145712.sigml deleted file mode 100644 index 0a1e03b..0000000 --- a/out/20251016_145712.sigml +++ /dev/null @@ -1,91 +0,0 @@ - - - - e_It_S,,,,AD,RB,BB,hamfinger2,hamthumbacrossmod,hambetween,hamfinger23,hamthumbacrossmod,hammiddlefinger,hamfingerstraightmod,hamextfingerur,hambetween,hamextfingeru,hampalmu,hamshoulders,hamlrat - - - - o,,,,AD,RB,BB,hampinchall,hamextfingeru,hampalml,hamshoulders,hamlrat,hamreplace,hamfinger23spread,hamfingerhookmod,hamthumbacrossmod,hamextfingeru,hampalmd - - - - ,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hamindexfinger,hamfingerbendmod,hammiddlefinger,hamfingerbendmod,hamringfinger,hamfingerbendmod,hamextfingero,hampalmd,hamshoulders,hamlrat - - - - en,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hamindexfinger,hamfingerbendmod,hammiddlefinger,hamfingerbendmod,hamextfingero,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger2,hampinky,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamceeall,hamthumbopenmod,hamextfingeru,hampalmdl,hamshoulders,hamlrat - - - - e_It_S,,,,AD,RB,BB,hamfinger2,hamthumbacrossmod,hambetween,hamfinger23,hamthumbacrossmod,hammiddlefinger,hamfingerstraightmod,hamextfingerur,hambetween,hamextfingeru,hampalmu,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger23,hamthumbacrossmod,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - en,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hamindexfinger,hamfingerbendmod,hammiddlefinger,hamfingerbendmod,hamextfingero,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger2,hamthumboutmod,hamextfingerur,hampalmul,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger2345,hamthumbopenmod,hamindexfinger,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfist,hamindexfinger,hamdoublebent,hammiddlefinger,hamdoublebent,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - hoc,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hambetween,hamflathand,hamextfingeru,hampalmu,hamforehead,hamlrat,hamseqbegin,hamtouch,hamfingertip,hammiddlefinger,hamseqend - - - - ,,,,AD,RB,BB,hamfinger2,hamthumbacrossmod,hamthumb,hamfingernail,hammiddlefinger,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfist,hamindexfinger,hamdoublebent,hammiddlefinger,hamdoublebent,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - en,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hamindexfinger,hamfingerbendmod,hammiddlefinger,hamfingerbendmod,hamextfingero,hampalmd,hamshoulders,hamlrat - - - - e_It_S,,,,AD,RB,BB,hamfinger2,hamthumbacrossmod,hambetween,hamfinger23,hamthumbacrossmod,hammiddlefinger,hamfingerstraightmod,hamextfingerur,hambetween,hamextfingeru,hampalmu,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamflathand,hamfingerhookmod,hamthumbacrossmod,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,amcee12,hambetween,hamfinger2,hamthumbopenmod,hamextfingerdr,hampalmd,hamstomach,hamlrbeside - - - - ,,,,AD,RB,BB,hamfinger23,hamthumbacrossmod,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfist,hamindexfinger,hamdoublebent,hammiddlefinger,hamdoublebent,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger2345,hamthumbopenmod,hamindexfinger,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - diff --git a/out/20251016_145712.sigml.report.txt b/out/20251016_145712.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_145712.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_145712.txt b/out/20251016_145712.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_145712.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_145741.gloss.txt b/out/20251016_145741.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_145741.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_145741.sigml b/out/20251016_145741.sigml deleted file mode 100644 index 0a1e03b..0000000 --- a/out/20251016_145741.sigml +++ /dev/null @@ -1,91 +0,0 @@ - - - - e_It_S,,,,AD,RB,BB,hamfinger2,hamthumbacrossmod,hambetween,hamfinger23,hamthumbacrossmod,hammiddlefinger,hamfingerstraightmod,hamextfingerur,hambetween,hamextfingeru,hampalmu,hamshoulders,hamlrat - - - - o,,,,AD,RB,BB,hampinchall,hamextfingeru,hampalml,hamshoulders,hamlrat,hamreplace,hamfinger23spread,hamfingerhookmod,hamthumbacrossmod,hamextfingeru,hampalmd - - - - ,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hamindexfinger,hamfingerbendmod,hammiddlefinger,hamfingerbendmod,hamringfinger,hamfingerbendmod,hamextfingero,hampalmd,hamshoulders,hamlrat - - - - en,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hamindexfinger,hamfingerbendmod,hammiddlefinger,hamfingerbendmod,hamextfingero,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger2,hampinky,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamceeall,hamthumbopenmod,hamextfingeru,hampalmdl,hamshoulders,hamlrat - - - - e_It_S,,,,AD,RB,BB,hamfinger2,hamthumbacrossmod,hambetween,hamfinger23,hamthumbacrossmod,hammiddlefinger,hamfingerstraightmod,hamextfingerur,hambetween,hamextfingeru,hampalmu,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger23,hamthumbacrossmod,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - en,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hamindexfinger,hamfingerbendmod,hammiddlefinger,hamfingerbendmod,hamextfingero,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger2,hamthumboutmod,hamextfingerur,hampalmul,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger2345,hamthumbopenmod,hamindexfinger,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfist,hamindexfinger,hamdoublebent,hammiddlefinger,hamdoublebent,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - hoc,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hambetween,hamflathand,hamextfingeru,hampalmu,hamforehead,hamlrat,hamseqbegin,hamtouch,hamfingertip,hammiddlefinger,hamseqend - - - - ,,,,AD,RB,BB,hamfinger2,hamthumbacrossmod,hamthumb,hamfingernail,hammiddlefinger,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfist,hamindexfinger,hamdoublebent,hammiddlefinger,hamdoublebent,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - en,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hamindexfinger,hamfingerbendmod,hammiddlefinger,hamfingerbendmod,hamextfingero,hampalmd,hamshoulders,hamlrat - - - - e_It_S,,,,AD,RB,BB,hamfinger2,hamthumbacrossmod,hambetween,hamfinger23,hamthumbacrossmod,hammiddlefinger,hamfingerstraightmod,hamextfingerur,hambetween,hamextfingeru,hampalmu,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamflathand,hamfingerhookmod,hamthumbacrossmod,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,amcee12,hambetween,hamfinger2,hamthumbopenmod,hamextfingerdr,hampalmd,hamstomach,hamlrbeside - - - - ,,,,AD,RB,BB,hamfinger23,hamthumbacrossmod,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfist,hamindexfinger,hamdoublebent,hammiddlefinger,hamdoublebent,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger2345,hamthumbopenmod,hamindexfinger,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - diff --git a/out/20251016_145741.sigml.report.txt b/out/20251016_145741.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_145741.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_145741.txt b/out/20251016_145741.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_145741.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_150450.gloss.txt b/out/20251016_150450.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_150450.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_150450.sigml b/out/20251016_150450.sigml deleted file mode 100644 index 9ff5b3d..0000000 --- a/out/20251016_150450.sigml +++ /dev/null @@ -1,312 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251016_150450.sigml.report.txt b/out/20251016_150450.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_150450.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_150450.txt b/out/20251016_150450.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_150450.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_151054.gloss.txt b/out/20251016_151054.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_151054.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_151054.txt b/out/20251016_151054.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_151054.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_151118.gloss.txt b/out/20251016_151118.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_151118.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_151118.txt b/out/20251016_151118.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_151118.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_151331.gloss.txt b/out/20251016_151331.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_151331.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_151331.sigml b/out/20251016_151331.sigml deleted file mode 100644 index 9ff5b3d..0000000 --- a/out/20251016_151331.sigml +++ /dev/null @@ -1,312 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251016_151331.sigml.report.txt b/out/20251016_151331.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_151331.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_151331.txt b/out/20251016_151331.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_151331.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_151658.gloss.txt b/out/20251016_151658.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_151658.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_151658.sigml b/out/20251016_151658.sigml deleted file mode 100644 index 9ff5b3d..0000000 --- a/out/20251016_151658.sigml +++ /dev/null @@ -1,312 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251016_151658.sigml.report.txt b/out/20251016_151658.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_151658.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_151658.txt b/out/20251016_151658.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_151658.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_152357.gloss.txt b/out/20251016_152357.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_152357.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_152357.sigml b/out/20251016_152357.sigml deleted file mode 100644 index 9ff5b3d..0000000 --- a/out/20251016_152357.sigml +++ /dev/null @@ -1,312 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251016_152357.sigml.report.txt b/out/20251016_152357.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_152357.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_152357.txt b/out/20251016_152357.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_152357.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_152540.gloss.txt b/out/20251016_152540.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_152540.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_152540.sigml b/out/20251016_152540.sigml deleted file mode 100644 index 9ff5b3d..0000000 --- a/out/20251016_152540.sigml +++ /dev/null @@ -1,312 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251016_152540.sigml.report.txt b/out/20251016_152540.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_152540.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_152540.txt b/out/20251016_152540.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_152540.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_152834.gloss.txt b/out/20251016_152834.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_152834.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_152834.sigml b/out/20251016_152834.sigml deleted file mode 100644 index 9ff5b3d..0000000 --- a/out/20251016_152834.sigml +++ /dev/null @@ -1,312 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251016_152834.sigml.report.txt b/out/20251016_152834.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_152834.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_152834.txt b/out/20251016_152834.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_152834.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_153057.gloss.txt b/out/20251016_153057.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_153057.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_153057.sigml b/out/20251016_153057.sigml deleted file mode 100644 index 2f7ba6d..0000000 --- a/out/20251016_153057.sigml +++ /dev/null @@ -1,330 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251016_153057.sigml.report.txt b/out/20251016_153057.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_153057.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_153057.txt b/out/20251016_153057.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_153057.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_153510.gloss.txt b/out/20251016_153510.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_153510.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_153510.sigml b/out/20251016_153510.sigml deleted file mode 100644 index 2f7ba6d..0000000 --- a/out/20251016_153510.sigml +++ /dev/null @@ -1,330 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251016_153510.sigml.report.txt b/out/20251016_153510.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_153510.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_153510.txt b/out/20251016_153510.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_153510.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_153708.gloss.txt b/out/20251016_153708.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_153708.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_153708.sigml b/out/20251016_153708.sigml deleted file mode 100644 index 2f7ba6d..0000000 --- a/out/20251016_153708.sigml +++ /dev/null @@ -1,330 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251016_153708.sigml.report.txt b/out/20251016_153708.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_153708.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_153708.txt b/out/20251016_153708.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_153708.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_154825.gloss.txt b/out/20251016_154825.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_154825.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_154825.sigml b/out/20251016_154825.sigml deleted file mode 100644 index 44bfe7d..0000000 --- a/out/20251016_154825.sigml +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251016_154825.sigml.report.txt b/out/20251016_154825.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_154825.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_154825.txt b/out/20251016_154825.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_154825.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_155229.gloss.txt b/out/20251016_155229.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_155229.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_155229.sigml b/out/20251016_155229.sigml deleted file mode 100644 index e1fe7cb..0000000 --- a/out/20251016_155229.sigml +++ /dev/null @@ -1,132 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251016_155229.sigml.report.txt b/out/20251016_155229.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_155229.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_155229.txt b/out/20251016_155229.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_155229.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_160118.gloss.txt b/out/20251016_160118.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_160118.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_160118.txt b/out/20251016_160118.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_160118.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_160129.gloss.txt b/out/20251016_160129.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_160129.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_160129.sigml b/out/20251016_160129.sigml deleted file mode 100644 index 318c8b2..0000000 --- a/out/20251016_160129.sigml +++ /dev/null @@ -1,133 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251016_160129.sigml.report.txt b/out/20251016_160129.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_160129.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_160129.txt b/out/20251016_160129.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_160129.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_160617.gloss.txt b/out/20251016_160617.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_160617.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_160617.sigml b/out/20251016_160617.sigml deleted file mode 100644 index 318c8b2..0000000 --- a/out/20251016_160617.sigml +++ /dev/null @@ -1,133 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251016_160617.sigml.report.txt b/out/20251016_160617.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_160617.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_160617.txt b/out/20251016_160617.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_160617.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_160709.gloss.txt b/out/20251016_160709.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_160709.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_160709.sigml b/out/20251016_160709.sigml deleted file mode 100644 index 318c8b2..0000000 --- a/out/20251016_160709.sigml +++ /dev/null @@ -1,133 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251016_160709.sigml.report.txt b/out/20251016_160709.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_160709.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_160709.txt b/out/20251016_160709.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_160709.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_160846.gloss.txt b/out/20251016_160846.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_160846.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_160846.sigml b/out/20251016_160846.sigml deleted file mode 100644 index 318c8b2..0000000 --- a/out/20251016_160846.sigml +++ /dev/null @@ -1,133 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251016_160846.sigml.report.txt b/out/20251016_160846.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_160846.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_160846.txt b/out/20251016_160846.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_160846.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_161150.gloss.txt b/out/20251016_161150.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_161150.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_161150.sigml b/out/20251016_161150.sigml deleted file mode 100644 index f153472..0000000 --- a/out/20251016_161150.sigml +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/out/20251016_161150.sigml.report.txt b/out/20251016_161150.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_161150.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_161150.txt b/out/20251016_161150.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_161150.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_161228.gloss.txt b/out/20251016_161228.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_161228.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_161228.sigml b/out/20251016_161228.sigml deleted file mode 100644 index f153472..0000000 --- a/out/20251016_161228.sigml +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/out/20251016_161228.sigml.report.txt b/out/20251016_161228.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_161228.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_161228.txt b/out/20251016_161228.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_161228.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_161519.gloss.txt b/out/20251016_161519.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_161519.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_161519.sigml b/out/20251016_161519.sigml deleted file mode 100644 index f153472..0000000 --- a/out/20251016_161519.sigml +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/out/20251016_161519.sigml.report.txt b/out/20251016_161519.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_161519.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_161519.txt b/out/20251016_161519.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_161519.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_161900.gloss.txt b/out/20251016_161900.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_161900.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_161900.sigml b/out/20251016_161900.sigml deleted file mode 100644 index f153472..0000000 --- a/out/20251016_161900.sigml +++ /dev/null @@ -1,131 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/out/20251016_161900.sigml.report.txt b/out/20251016_161900.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_161900.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_161900.txt b/out/20251016_161900.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_161900.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_162133.gloss.txt b/out/20251016_162133.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_162133.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_162133.sigml b/out/20251016_162133.sigml deleted file mode 100644 index 44bfe7d..0000000 --- a/out/20251016_162133.sigml +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251016_162133.sigml.report.txt b/out/20251016_162133.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_162133.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_162133.txt b/out/20251016_162133.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_162133.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_162745.gloss.txt b/out/20251016_162745.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_162745.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_162745.sigml b/out/20251016_162745.sigml deleted file mode 100644 index 8b6253b..0000000 --- a/out/20251016_162745.sigml +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251016_162745.sigml.report.txt b/out/20251016_162745.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_162745.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_162745.txt b/out/20251016_162745.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_162745.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_163021.gloss.txt b/out/20251016_163021.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_163021.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_163021.sigml b/out/20251016_163021.sigml deleted file mode 100644 index 8b6253b..0000000 --- a/out/20251016_163021.sigml +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251016_163021.sigml.report.txt b/out/20251016_163021.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_163021.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_163021.txt b/out/20251016_163021.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_163021.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_163248.gloss.txt b/out/20251016_163248.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_163248.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_163248.sigml b/out/20251016_163248.sigml deleted file mode 100644 index 761b973..0000000 --- a/out/20251016_163248.sigml +++ /dev/null @@ -1,153 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251016_163248.sigml.report.txt b/out/20251016_163248.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_163248.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_163248.txt b/out/20251016_163248.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_163248.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_163347.gloss.txt b/out/20251016_163347.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_163347.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_163347.sigml b/out/20251016_163347.sigml deleted file mode 100644 index 761b973..0000000 --- a/out/20251016_163347.sigml +++ /dev/null @@ -1,153 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251016_163347.sigml.report.txt b/out/20251016_163347.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_163347.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_163347.txt b/out/20251016_163347.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_163347.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_163748.gloss.txt b/out/20251016_163748.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_163748.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_163748.sigml b/out/20251016_163748.sigml deleted file mode 100644 index 44bfe7d..0000000 --- a/out/20251016_163748.sigml +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251016_163748.sigml.report.txt b/out/20251016_163748.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_163748.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_163748.txt b/out/20251016_163748.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_163748.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_165823.gloss.txt b/out/20251016_165823.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_165823.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_165823.sigml b/out/20251016_165823.sigml deleted file mode 100644 index 1fd6b03..0000000 --- a/out/20251016_165823.sigml +++ /dev/null @@ -1,207 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251016_165823.sigml.report.txt b/out/20251016_165823.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_165823.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_165823.txt b/out/20251016_165823.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_165823.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_170055.gloss.txt b/out/20251016_170055.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_170055.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_170055.sigml b/out/20251016_170055.sigml deleted file mode 100644 index 6d04823..0000000 --- a/out/20251016_170055.sigml +++ /dev/null @@ -1,213 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251016_170055.sigml.report.txt b/out/20251016_170055.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_170055.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_170055.txt b/out/20251016_170055.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_170055.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_170237.gloss.txt b/out/20251016_170237.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_170237.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_170237.txt b/out/20251016_170237.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_170237.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251016_170248.gloss.txt b/out/20251016_170248.gloss.txt deleted file mode 100644 index 0329bc3..0000000 --- a/out/20251016_170248.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm ni chúng ta học dận hễ quật. diff --git a/out/20251016_170248.sigml b/out/20251016_170248.sigml deleted file mode 100644 index e28d5c2..0000000 --- a/out/20251016_170248.sigml +++ /dev/null @@ -1,225 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251016_170248.sigml.report.txt b/out/20251016_170248.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251016_170248.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251016_170248.txt b/out/20251016_170248.txt deleted file mode 100644 index c2efc75..0000000 --- a/out/20251016_170248.txt +++ /dev/null @@ -1 +0,0 @@ -Hôm nay chúng ta học về động vật. diff --git a/out/20251018_105148.segments.json b/out/20251018_105148.segments.json deleted file mode 100644 index b8dae49..0000000 --- a/out/20251018_105148.segments.json +++ /dev/null @@ -1 +0,0 @@ -{"segments": [{"start": 0.0, "end": 14.0, "text": "Trong bài thần, một biến được dùng để lưu trữ dư liệu, ví dụ, ta có thể gán x vàng 10 rồi in ra giá trị đó băng harm print, cách này giúp chương trình dễ hiểu và dễ sửa đối hơn"}]} \ No newline at end of file diff --git a/out/20251018_105148.txt b/out/20251018_105148.txt deleted file mode 100644 index 1f6b4a5..0000000 --- a/out/20251018_105148.txt +++ /dev/null @@ -1 +0,0 @@ -Trong bài thần, một biến được dùng để lưu trữ dư liệu, ví dụ, ta có thể gán x vàng 10 rồi in ra giá trị đó băng harm print, cách này giúp chương trình dễ hiểu và dễ sửa đối hơn diff --git a/out/20251018_105157.segments.json b/out/20251018_105157.segments.json deleted file mode 100644 index b8dae49..0000000 --- a/out/20251018_105157.segments.json +++ /dev/null @@ -1 +0,0 @@ -{"segments": [{"start": 0.0, "end": 14.0, "text": "Trong bài thần, một biến được dùng để lưu trữ dư liệu, ví dụ, ta có thể gán x vàng 10 rồi in ra giá trị đó băng harm print, cách này giúp chương trình dễ hiểu và dễ sửa đối hơn"}]} \ No newline at end of file diff --git a/out/20251018_105157.txt b/out/20251018_105157.txt deleted file mode 100644 index 1f6b4a5..0000000 --- a/out/20251018_105157.txt +++ /dev/null @@ -1 +0,0 @@ -Trong bài thần, một biến được dùng để lưu trữ dư liệu, ví dụ, ta có thể gán x vàng 10 rồi in ra giá trị đó băng harm print, cách này giúp chương trình dễ hiểu và dễ sửa đối hơn diff --git a/out/20251018_105300.gloss.txt b/out/20251018_105300.gloss.txt deleted file mode 100644 index 4ef9ea7..0000000 --- a/out/20251018_105300.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -trong_suốt bài_bác thần, kép lưu trữ giá trị xuể dùng đặng lưu tàng_trữ dư_thừa liệu, giá dụ, ta chớ dạng gán_ghép x vàng 10 rồi in ra giá trừng_phạt đó băng harm print, cách nè giúp chương thưa giàu hiểu và giàu chữa đối_đãi lợi diff --git a/out/20251018_105300.segments.json b/out/20251018_105300.segments.json deleted file mode 100644 index b8dae49..0000000 --- a/out/20251018_105300.segments.json +++ /dev/null @@ -1 +0,0 @@ -{"segments": [{"start": 0.0, "end": 14.0, "text": "Trong bài thần, một biến được dùng để lưu trữ dư liệu, ví dụ, ta có thể gán x vàng 10 rồi in ra giá trị đó băng harm print, cách này giúp chương trình dễ hiểu và dễ sửa đối hơn"}]} \ No newline at end of file diff --git a/out/20251018_105300.txt b/out/20251018_105300.txt deleted file mode 100644 index 1f6b4a5..0000000 --- a/out/20251018_105300.txt +++ /dev/null @@ -1 +0,0 @@ -Trong bài thần, một biến được dùng để lưu trữ dư liệu, ví dụ, ta có thể gán x vàng 10 rồi in ra giá trị đó băng harm print, cách này giúp chương trình dễ hiểu và dễ sửa đối hơn diff --git a/out/20251018_105829.segments.json b/out/20251018_105829.segments.json deleted file mode 100644 index b8dae49..0000000 --- a/out/20251018_105829.segments.json +++ /dev/null @@ -1 +0,0 @@ -{"segments": [{"start": 0.0, "end": 14.0, "text": "Trong bài thần, một biến được dùng để lưu trữ dư liệu, ví dụ, ta có thể gán x vàng 10 rồi in ra giá trị đó băng harm print, cách này giúp chương trình dễ hiểu và dễ sửa đối hơn"}]} \ No newline at end of file diff --git a/out/20251018_105829.txt b/out/20251018_105829.txt deleted file mode 100644 index 1f6b4a5..0000000 --- a/out/20251018_105829.txt +++ /dev/null @@ -1 +0,0 @@ -Trong bài thần, một biến được dùng để lưu trữ dư liệu, ví dụ, ta có thể gán x vàng 10 rồi in ra giá trị đó băng harm print, cách này giúp chương trình dễ hiểu và dễ sửa đối hơn diff --git a/out/20251018_105853.gloss.txt b/out/20251018_105853.gloss.txt deleted file mode 100644 index 4ef9ea7..0000000 --- a/out/20251018_105853.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -trong_suốt bài_bác thần, kép lưu trữ giá trị xuể dùng đặng lưu tàng_trữ dư_thừa liệu, giá dụ, ta chớ dạng gán_ghép x vàng 10 rồi in ra giá trừng_phạt đó băng harm print, cách nè giúp chương thưa giàu hiểu và giàu chữa đối_đãi lợi diff --git a/out/20251018_105853.playlist.json b/out/20251018_105853.playlist.json deleted file mode 100644 index 3d34fb2..0000000 --- a/out/20251018_105853.playlist.json +++ /dev/null @@ -1 +0,0 @@ -{"playlist": [{"start": 0.0, "end": 14.0, "text": "Trong bài thần, một biến được dùng để lưu trữ dư liệu, ví dụ, ta có thể gán x vàng 10 rồi in ra giá trị đó băng harm print, cách này giúp chương trình dễ hiểu và dễ sửa đối hơn", "gloss": "trong_suốt bài_bác thần, kép lưu trữ giá trị xuể dùng đặng lưu tàng_trữ dư_thừa liệu, giá dụ, ta chớ dạng gán_ghép x vàng 10 rồi in ra giá trừng_phạt đó băng harm print, cách nè giúp chương thưa giàu hiểu và giàu chữa đối_đãi lợi", "sigml": "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n a\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n u\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n e\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n a\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n u\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n u\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n e\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n u\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n u\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n"}]} \ No newline at end of file diff --git a/out/20251018_105853.segments.json b/out/20251018_105853.segments.json deleted file mode 100644 index b8dae49..0000000 --- a/out/20251018_105853.segments.json +++ /dev/null @@ -1 +0,0 @@ -{"segments": [{"start": 0.0, "end": 14.0, "text": "Trong bài thần, một biến được dùng để lưu trữ dư liệu, ví dụ, ta có thể gán x vàng 10 rồi in ra giá trị đó băng harm print, cách này giúp chương trình dễ hiểu và dễ sửa đối hơn"}]} \ No newline at end of file diff --git a/out/20251018_105853.sigml b/out/20251018_105853.sigml deleted file mode 100644 index b4ea1a5..0000000 --- a/out/20251018_105853.sigml +++ /dev/null @@ -1,2398 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251018_105853.sigml.report.txt b/out/20251018_105853.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251018_105853.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251018_105853.txt b/out/20251018_105853.txt deleted file mode 100644 index 1f6b4a5..0000000 --- a/out/20251018_105853.txt +++ /dev/null @@ -1 +0,0 @@ -Trong bài thần, một biến được dùng để lưu trữ dư liệu, ví dụ, ta có thể gán x vàng 10 rồi in ra giá trị đó băng harm print, cách này giúp chương trình dễ hiểu và dễ sửa đối hơn diff --git a/out/20251018_110507.segments.json b/out/20251018_110507.segments.json deleted file mode 100644 index b8dae49..0000000 --- a/out/20251018_110507.segments.json +++ /dev/null @@ -1 +0,0 @@ -{"segments": [{"start": 0.0, "end": 14.0, "text": "Trong bài thần, một biến được dùng để lưu trữ dư liệu, ví dụ, ta có thể gán x vàng 10 rồi in ra giá trị đó băng harm print, cách này giúp chương trình dễ hiểu và dễ sửa đối hơn"}]} \ No newline at end of file diff --git a/out/20251018_110507.txt b/out/20251018_110507.txt deleted file mode 100644 index 1f6b4a5..0000000 --- a/out/20251018_110507.txt +++ /dev/null @@ -1 +0,0 @@ -Trong bài thần, một biến được dùng để lưu trữ dư liệu, ví dụ, ta có thể gán x vàng 10 rồi in ra giá trị đó băng harm print, cách này giúp chương trình dễ hiểu và dễ sửa đối hơn diff --git a/out/20251018_110630.gloss.txt b/out/20251018_110630.gloss.txt deleted file mode 100644 index 4ef9ea7..0000000 --- a/out/20251018_110630.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -trong_suốt bài_bác thần, kép lưu trữ giá trị xuể dùng đặng lưu tàng_trữ dư_thừa liệu, giá dụ, ta chớ dạng gán_ghép x vàng 10 rồi in ra giá trừng_phạt đó băng harm print, cách nè giúp chương thưa giàu hiểu và giàu chữa đối_đãi lợi diff --git a/out/20251018_110630.playlist.json b/out/20251018_110630.playlist.json deleted file mode 100644 index 3d34fb2..0000000 --- a/out/20251018_110630.playlist.json +++ /dev/null @@ -1 +0,0 @@ -{"playlist": [{"start": 0.0, "end": 14.0, "text": "Trong bài thần, một biến được dùng để lưu trữ dư liệu, ví dụ, ta có thể gán x vàng 10 rồi in ra giá trị đó băng harm print, cách này giúp chương trình dễ hiểu và dễ sửa đối hơn", "gloss": "trong_suốt bài_bác thần, kép lưu trữ giá trị xuể dùng đặng lưu tàng_trữ dư_thừa liệu, giá dụ, ta chớ dạng gán_ghép x vàng 10 rồi in ra giá trừng_phạt đó băng harm print, cách nè giúp chương thưa giàu hiểu và giàu chữa đối_đãi lợi", "sigml": "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n a\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n u\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n e\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n a\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n u\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n u\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n e\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n u\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n u\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n"}]} \ No newline at end of file diff --git a/out/20251018_110630.segments.json b/out/20251018_110630.segments.json deleted file mode 100644 index b8dae49..0000000 --- a/out/20251018_110630.segments.json +++ /dev/null @@ -1 +0,0 @@ -{"segments": [{"start": 0.0, "end": 14.0, "text": "Trong bài thần, một biến được dùng để lưu trữ dư liệu, ví dụ, ta có thể gán x vàng 10 rồi in ra giá trị đó băng harm print, cách này giúp chương trình dễ hiểu và dễ sửa đối hơn"}]} \ No newline at end of file diff --git a/out/20251018_110630.sigml b/out/20251018_110630.sigml deleted file mode 100644 index b4ea1a5..0000000 --- a/out/20251018_110630.sigml +++ /dev/null @@ -1,2398 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251018_110630.sigml.report.txt b/out/20251018_110630.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251018_110630.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251018_110630.txt b/out/20251018_110630.txt deleted file mode 100644 index 1f6b4a5..0000000 --- a/out/20251018_110630.txt +++ /dev/null @@ -1 +0,0 @@ -Trong bài thần, một biến được dùng để lưu trữ dư liệu, ví dụ, ta có thể gán x vàng 10 rồi in ra giá trị đó băng harm print, cách này giúp chương trình dễ hiểu và dễ sửa đối hơn diff --git a/out/20251018_110641.gloss.txt b/out/20251018_110641.gloss.txt deleted file mode 100644 index c77dc68..0000000 --- a/out/20251018_110641.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Xin chào hôm ni, tui muốn chia sẻ dận ý thiết_tưởng giáo dục kín biệt, đó là giữ án sử dụng trí tuệ nhân tạo đặng giúp khó_tính khiếm thính, chớ dạng tiếp cận bài_bác giảng và nội dung học xấp giàu dàng lợi diff --git a/out/20251018_110641.playlist.json b/out/20251018_110641.playlist.json deleted file mode 100644 index e7cb349..0000000 --- a/out/20251018_110641.playlist.json +++ /dev/null @@ -1 +0,0 @@ -{"playlist": [{"start": 0.0, "end": 16.0, "text": "Xin chào hôm nay, tôi muốn chia sẻ về ý tưởng giáo dục đặc biệt, đó là giữ án sử dụng trí tuệ nhân tạo để giúp người khiếm thính, có thể tiếp cận bài giảng và nội dung học tập dễ dàng hơn", "gloss": "Xin chào hôm ni, tui muốn chia sẻ dận ý thiết_tưởng giáo dục kín biệt, đó là giữ án sử dụng trí tuệ nhân tạo đặng giúp khó_tính khiếm thính, chớ dạng tiếp cận bài_bác giảng và nội dung học xấp giàu dàng lợi", "sigml": "\n x\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n a\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n e\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n e\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n u\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n u\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n e\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n a\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n e\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n e\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n a\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n a\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n"}]} \ No newline at end of file diff --git a/out/20251018_110641.segments.json b/out/20251018_110641.segments.json deleted file mode 100644 index 4c20d1f..0000000 --- a/out/20251018_110641.segments.json +++ /dev/null @@ -1 +0,0 @@ -{"segments": [{"start": 0.0, "end": 16.0, "text": "Xin chào hôm nay, tôi muốn chia sẻ về ý tưởng giáo dục đặc biệt, đó là giữ án sử dụng trí tuệ nhân tạo để giúp người khiếm thính, có thể tiếp cận bài giảng và nội dung học tập dễ dàng hơn"}]} \ No newline at end of file diff --git a/out/20251018_110641.sigml b/out/20251018_110641.sigml deleted file mode 100644 index e477cc3..0000000 --- a/out/20251018_110641.sigml +++ /dev/null @@ -1,2105 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251018_110641.sigml.report.txt b/out/20251018_110641.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251018_110641.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251018_110641.txt b/out/20251018_110641.txt deleted file mode 100644 index 3ac67ed..0000000 --- a/out/20251018_110641.txt +++ /dev/null @@ -1 +0,0 @@ -Xin chào hôm nay, tôi muốn chia sẻ về ý tưởng giáo dục đặc biệt, đó là giữ án sử dụng trí tuệ nhân tạo để giúp người khiếm thính, có thể tiếp cận bài giảng và nội dung học tập dễ dàng hơn diff --git a/out/20251018_110948.gloss.txt b/out/20251018_110948.gloss.txt deleted file mode 100644 index 1c60e93..0000000 --- a/out/20251018_110948.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Cảm ơn bạn hẵng lắng nghe, hẵng thử coi hệ thống chớ dạng ghi loại tuyền bộ nội dung nè kép cách chính tử_thi chớ nhớ, đây là phần chót cụm_từ thử nghiệm diff --git a/out/20251018_110948.playlist.json b/out/20251018_110948.playlist.json deleted file mode 100644 index 29569df..0000000 --- a/out/20251018_110948.playlist.json +++ /dev/null @@ -1 +0,0 @@ -{"playlist": [{"start": 0.0, "end": 10.0, "text": "Cảm ơn bạn đã lắng nghe, hãy thử xem hệ thống có thể ghi loại toàn bộ nội dung này một cách chính xác không nhé, đây là phần cuối của thử nghiệm", "gloss": "Cảm ơn bạn hẵng lắng nghe, hẵng thử coi hệ thống chớ dạng ghi loại tuyền bộ nội dung nè kép cách chính tử_thi chớ nhớ, đây là phần chót cụm_từ thử nghiệm", "sigml": "\n c\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n a\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n a\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n a\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n e\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n e\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n u\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n a\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n u\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n e\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n"}]} \ No newline at end of file diff --git a/out/20251018_110948.segments.json b/out/20251018_110948.segments.json deleted file mode 100644 index 5df3a87..0000000 --- a/out/20251018_110948.segments.json +++ /dev/null @@ -1 +0,0 @@ -{"segments": [{"start": 0.0, "end": 10.0, "text": "Cảm ơn bạn đã lắng nghe, hãy thử xem hệ thống có thể ghi loại toàn bộ nội dung này một cách chính xác không nhé, đây là phần cuối của thử nghiệm"}]} \ No newline at end of file diff --git a/out/20251018_110948.sigml b/out/20251018_110948.sigml deleted file mode 100644 index 2c12937..0000000 --- a/out/20251018_110948.sigml +++ /dev/null @@ -1,1657 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251018_110948.sigml.report.txt b/out/20251018_110948.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251018_110948.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251018_110948.txt b/out/20251018_110948.txt deleted file mode 100644 index 05f4b18..0000000 --- a/out/20251018_110948.txt +++ /dev/null @@ -1 +0,0 @@ -Cảm ơn bạn đã lắng nghe, hãy thử xem hệ thống có thể ghi loại toàn bộ nội dung này một cách chính xác không nhé, đây là phần cuối của thử nghiệm diff --git a/out/20251018_111344.gloss.txt b/out/20251018_111344.gloss.txt deleted file mode 100644 index 1c60e93..0000000 --- a/out/20251018_111344.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Cảm ơn bạn hẵng lắng nghe, hẵng thử coi hệ thống chớ dạng ghi loại tuyền bộ nội dung nè kép cách chính tử_thi chớ nhớ, đây là phần chót cụm_từ thử nghiệm diff --git a/out/20251018_111344.playlist.json b/out/20251018_111344.playlist.json deleted file mode 100644 index 29569df..0000000 --- a/out/20251018_111344.playlist.json +++ /dev/null @@ -1 +0,0 @@ -{"playlist": [{"start": 0.0, "end": 10.0, "text": "Cảm ơn bạn đã lắng nghe, hãy thử xem hệ thống có thể ghi loại toàn bộ nội dung này một cách chính xác không nhé, đây là phần cuối của thử nghiệm", "gloss": "Cảm ơn bạn hẵng lắng nghe, hẵng thử coi hệ thống chớ dạng ghi loại tuyền bộ nội dung nè kép cách chính tử_thi chớ nhớ, đây là phần chót cụm_từ thử nghiệm", "sigml": "\n c\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n a\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n a\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n a\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n e\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n e\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n u\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n a\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n u\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n e\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n"}]} \ No newline at end of file diff --git a/out/20251018_111344.segments.json b/out/20251018_111344.segments.json deleted file mode 100644 index 5df3a87..0000000 --- a/out/20251018_111344.segments.json +++ /dev/null @@ -1 +0,0 @@ -{"segments": [{"start": 0.0, "end": 10.0, "text": "Cảm ơn bạn đã lắng nghe, hãy thử xem hệ thống có thể ghi loại toàn bộ nội dung này một cách chính xác không nhé, đây là phần cuối của thử nghiệm"}]} \ No newline at end of file diff --git a/out/20251018_111344.sigml b/out/20251018_111344.sigml deleted file mode 100644 index 2c12937..0000000 --- a/out/20251018_111344.sigml +++ /dev/null @@ -1,1657 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251018_111344.sigml.report.txt b/out/20251018_111344.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251018_111344.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251018_111344.txt b/out/20251018_111344.txt deleted file mode 100644 index 05f4b18..0000000 --- a/out/20251018_111344.txt +++ /dev/null @@ -1 +0,0 @@ -Cảm ơn bạn đã lắng nghe, hãy thử xem hệ thống có thể ghi loại toàn bộ nội dung này một cách chính xác không nhé, đây là phần cuối của thử nghiệm diff --git a/out/20251018_111705.gloss.txt b/out/20251018_111705.gloss.txt deleted file mode 100644 index 1c60e93..0000000 --- a/out/20251018_111705.gloss.txt +++ /dev/null @@ -1 +0,0 @@ -Cảm ơn bạn hẵng lắng nghe, hẵng thử coi hệ thống chớ dạng ghi loại tuyền bộ nội dung nè kép cách chính tử_thi chớ nhớ, đây là phần chót cụm_từ thử nghiệm diff --git a/out/20251018_111705.playlist.json b/out/20251018_111705.playlist.json deleted file mode 100644 index 29569df..0000000 --- a/out/20251018_111705.playlist.json +++ /dev/null @@ -1 +0,0 @@ -{"playlist": [{"start": 0.0, "end": 10.0, "text": "Cảm ơn bạn đã lắng nghe, hãy thử xem hệ thống có thể ghi loại toàn bộ nội dung này một cách chính xác không nhé, đây là phần cuối của thử nghiệm", "gloss": "Cảm ơn bạn hẵng lắng nghe, hẵng thử coi hệ thống chớ dạng ghi loại tuyền bộ nội dung nè kép cách chính tử_thi chớ nhớ, đây là phần chót cụm_từ thử nghiệm", "sigml": "\n c\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n a\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n a\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n a\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n e\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n e\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n u\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n o\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n a\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n u\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n e\">\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n"}]} \ No newline at end of file diff --git a/out/20251018_111705.segments.json b/out/20251018_111705.segments.json deleted file mode 100644 index 5df3a87..0000000 --- a/out/20251018_111705.segments.json +++ /dev/null @@ -1 +0,0 @@ -{"segments": [{"start": 0.0, "end": 10.0, "text": "Cảm ơn bạn đã lắng nghe, hãy thử xem hệ thống có thể ghi loại toàn bộ nội dung này một cách chính xác không nhé, đây là phần cuối của thử nghiệm"}]} \ No newline at end of file diff --git a/out/20251018_111705.sigml b/out/20251018_111705.sigml deleted file mode 100644 index 2c12937..0000000 --- a/out/20251018_111705.sigml +++ /dev/null @@ -1,1657 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/out/20251018_111705.sigml.report.txt b/out/20251018_111705.sigml.report.txt deleted file mode 100644 index ad9cadc..0000000 --- a/out/20251018_111705.sigml.report.txt +++ /dev/null @@ -1 +0,0 @@ -No missing characters. diff --git a/out/20251018_111705.txt b/out/20251018_111705.txt deleted file mode 100644 index 05f4b18..0000000 --- a/out/20251018_111705.txt +++ /dev/null @@ -1 +0,0 @@ -Cảm ơn bạn đã lắng nghe, hãy thử xem hệ thống có thể ghi loại toàn bộ nội dung này một cách chính xác không nhé, đây là phần cuối của thử nghiệm diff --git a/out/demo.sigml b/out/demo.sigml deleted file mode 100644 index e9b03b9..0000000 --- a/out/demo.sigml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - ,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hamindexfinger,hamfingerbendmod,hammiddlefinger,hamfingerbendmod,hamringfinger,hamfingerbendmod,hamextfingero,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamflathand,hamfingerhookmod,hamthumbacrossmod,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamceeall,hamthumbopenmod,hamextfingeru,hampalmdl,hamshoulders,hamlrat - - - - e_It_S,,,,AD,RB,BB,hamfinger2,hamthumbacrossmod,hambetween,hamfinger23,hamthumbacrossmod,hammiddlefinger,hamfingerstraightmod,hamextfingerur,hambetween,hamextfingeru,hampalmu,hamshoulders,hamlrat - - - - u,,,,AD,RB,BB,hamfinger23,hamthumbacrossmod,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat,hamreplace,hampinch12open,hammiddlefinger,hamfingerbendmod,hamringfinger,hamfingerbendmod,hampalml - - - - en,,,,AD,RB,BB,hamfist,hamthumbacrossmod,hamindexfinger,hamfingerbendmod,hammiddlefinger,hamfingerbendmod,hamextfingero,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger2,hamthumboutmod,hamextfingerur,hampalmul,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfist,hamindexfinger,hamdoublebent,hammiddlefinger,hamdoublebent,hamringfinger,hamdoublebent,hampinky,hamdoublebent,hamextfingeru,hampalmd,hamshoulders,hamlrat - - - - ,,,,AD,RB,BB,hamfinger2,hamthumboutmod,hampinky,hamindexfinger,hamdoublebent,hammiddlefinger,hamdoublebent,hamringfinger,hamdoublebent,hamextfingeru,hambetween,hamextfingerur,hampalmul,hambetween,hampalmd,hamshoulders,hamlrbeside - - diff --git a/out/demo.sigml.report.txt b/out/demo.sigml.report.txt deleted file mode 100644 index 0918bb9..0000000 --- a/out/demo.sigml.report.txt +++ /dev/null @@ -1,2 +0,0 @@ -Missing characters (char count): - 1 diff --git a/out/gloss.txt b/out/gloss.txt deleted file mode 100644 index ee037b4..0000000 --- a/out/gloss.txt +++ /dev/null @@ -1 +0,0 @@ -mẹ chưng ấy diff --git a/out/manual.txt b/out/manual.txt deleted file mode 100644 index aeeabc4..0000000 --- a/out/manual.txt +++ /dev/null @@ -1 +0,0 @@ -mẹ cô ấy diff --git a/out/video1.sigml b/out/video1.sigml deleted file mode 100644 index d6c9486..0000000 --- a/out/video1.sigml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/out/video1.v0.sigml b/out/video1.v0.sigml deleted file mode 100644 index 2546e5e..0000000 --- a/out/video1.v0.sigml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/out/video1.v1.sigml b/out/video1.v1.sigml deleted file mode 100644 index 9874e6f..0000000 --- a/out/video1.v1.sigml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/out/video1.v2.sigml b/out/video1.v2.sigml deleted file mode 100644 index d65d210..0000000 --- a/out/video1.v2.sigml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/out/video2.sigml b/out/video2.sigml deleted file mode 100644 index bbd2bb6..0000000 --- a/out/video2.sigml +++ /dev/null @@ -1,160 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/out/video3.sigml b/out/video3.sigml deleted file mode 100644 index a1c6aed..0000000 --- a/out/video3.sigml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/out/video4.sigml b/out/video4.sigml deleted file mode 100644 index de3e5e6..0000000 --- a/out/video4.sigml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 82e89bd..64df57f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,16 +1,18 @@ # Core Web Framework -Flask>=2.3.0,<3.0.0 +Flask>=2.3.0,<4.0.0 +Werkzeug>=2.3.0,<4.0.0 -# AI/ML Dependencies +# AI/ML Dependencies (Speech-to-Text) openai-whisper>=20231117 torch>=2.0.0,<3.0.0 -torchaudio>=2.0.0 +torchaudio>=2.0.0,<3.0.0 + +numpy>=1.20.0,<2.0.0 +numba>=0.57.0 # Audio/Video Processing ffmpeg-python>=0.2.0 -# Optional: Faster Whisper (uncomment for improved performance) -# faster-whisper>=0.9.0 - -# Standard Library Type Hints (Python <3.9 compatibility) -typing-extensions>=4.5.0 +# Database +psycopg2-binary>=2.9.9 +SQLAlchemy>=2.0.23 diff --git a/scripts/1_stt_whisper.py b/scripts/1_stt_whisper.py deleted file mode 100644 index 9c9a232..0000000 --- a/scripts/1_stt_whisper.py +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/env python3 -""" -Simple STT script for Vietnamese using openai-whisper (CPU-friendly baseline). - -Usage: - python scripts/1_stt_whisper.py --input path/to/input.(mp4|wav|m4a|mp3) \ - --output out/transcript.txt --model small - -Notes: - - Requires: pip install openai-whisper ffmpeg-python - - You should have FFmpeg installed and on PATH. - - Defaults: language="vi"; on CPU we disable fp16 automatically. -""" - -import argparse -import os -import sys -import json -from typing import Optional, List, Dict - - -def ensure_dependencies() -> None: - try: - import whisper # noqa: F401 - except Exception as exc: # pragma: no cover - print( - "[ERROR] Missing dependency: openai-whisper.\n" - "Run: pip install openai-whisper ffmpeg-python\n" - f"Details: {exc}", - file=sys.stderr, - ) - sys.exit(1) - - -def transcribe( - input_path: str, - output_path: Optional[str] = None, - model_size: str = "small", - language: str = "vi", - beam_size: int = 5, - initial_prompt: Optional[str] = None, -) -> Dict[str, str]: - import torch - import whisper - - # Force CPU by default; openai-whisper auto-detects but we ensure compatibility - device = "cuda" if torch.cuda.is_available() else "cpu" - model = whisper.load_model(model_size, device=device) - - # For CPU, set fp16 to False to avoid errors; enable word_timestamps if needed later - result = model.transcribe( - input_path, - language=language, - fp16=False if device == "cpu" else True, - verbose=False, - task="transcribe", - temperature=0.0, - condition_on_previous_text=False, - initial_prompt=initial_prompt, - ) - - # Collect plain text and timestamps - lines: List[str] = [] - seg_items: List[Dict[str, float | str]] = [] - for seg in result.get("segments", []) or []: - t = str(seg.get("text", "")).strip() - if not t: - continue - lines.append(t) - seg_items.append( - { - "start": float(seg.get("start", 0.0)), - "end": float(seg.get("end", 0.0)), - "text": t, - } - ) - text = "\n".join(lines) - - if not output_path: - base, _ = os.path.splitext(input_path) - output_path = base + ".transcript.txt" - - os.makedirs(os.path.dirname(output_path) or ".", exist_ok=True) - with open(output_path, "w", encoding="utf-8") as f: - f.write(text + "\n") - seg_out = os.path.splitext(output_path)[0] + ".segments.json" - with open(seg_out, "w", encoding="utf-8") as jf: - json.dump({"segments": seg_items}, jf, ensure_ascii=False) - - return {"transcript": output_path, "segments": seg_out} - - -def main() -> None: - parser = argparse.ArgumentParser(description="Vietnamese STT using openai-whisper") - parser.add_argument("--input", required=True, help="Path to input audio/video file") - parser.add_argument("--output", default=None, help="Path to output transcript .txt") - parser.add_argument( - "--model", - default="small", - help="Whisper model size (e.g., tiny, base, small, medium, large-v3)", - ) - parser.add_argument("--language", default="vi", help="Language code (default: vi)") - parser.add_argument("--beam", type=int, default=5, help="Beam size (default: 5)") - parser.add_argument( - "--prompt", - default=None, - help="Initial prompt (domain keywords) to bias transcription", - ) - args = parser.parse_args() - - if not os.path.isfile(args.input): - print(f"[ERROR] Input not found: {args.input}", file=sys.stderr) - sys.exit(2) - - ensure_dependencies() - - # Default Vietnamese education-domain prompt to stabilize vocabulary for demo - default_prompt = ( - "Xin chào hôm nay, giáo dục, ý tưởng, trí tuệ nhân tạo, AI, người khiếm thính, " - "bài giảng, nội dung học tập, dự án, tiếp cận, chia sẻ" - ) - - out = transcribe( - input_path=args.input, - output_path=args.output, - model_size=args.model, - language=args.language, - beam_size=args.beam, - initial_prompt=args.prompt or default_prompt, - ) - print(f"[OK] Transcript written: {out['transcript']}") - print(f"[OK] Segments JSON written: {out['segments']}") - - -if __name__ == "__main__": - main() diff --git a/scripts/2_text2gloss.py b/scripts/2_text2gloss.py deleted file mode 100644 index 538c220..0000000 --- a/scripts/2_text2gloss.py +++ /dev/null @@ -1,214 +0,0 @@ -#!/usr/bin/env python3 -""" -Greedy phrase-table converter: Vietnamese text -> gloss-like output - -Data sources: - - VSL/DataTrain1.txt (with diacritics) or VSL/DataTrain2.txt (ASCII) - Each line: \t - - Optional synonyms list: VSL/Synonyms.txt (format: one pair per line, or tab-separated; non-fatal if format varies) - - Optional seed vocabulary JSON (preferred): seed_vocabulary.json with fields - [{ "word": "...", "gloss": "...", "synonyms": ["..."] }] - -Usage: - python scripts/2_text2gloss.py --input transcript.txt --output gloss.txt \ - --pairs VSL/DataTrain1.txt --synonyms VSL/Synonyms.txt \ - --seed_json seed_vocabulary.json - -Strategy: - - Merge phrase pairs and seed vocabulary (prefer longer sources, JSON wins on conflicts) - - Apply synonyms normalization, then greedy replacement (longest match first) - - Fallback: keep original token if no match -""" - -import argparse -import os -import re -import json -from typing import Dict, List, Tuple - - -ENCODINGS_TRY_ORDER = [ - "utf-8", - "utf-8-sig", - "cp1258", # Vietnamese Windows - "cp1252", - "latin1", -] - - -def read_text_lines(path: str) -> List[str]: - last_err: Exception | None = None - for enc in ENCODINGS_TRY_ORDER: - try: - with open(path, "r", encoding=enc) as f: - return [ln.rstrip("\n") for ln in f] - except Exception as e: # keep trying next encoding - last_err = e - continue - # Fallback: ignore errors to ensure demo keeps going - try: - with open(path, "r", encoding="utf-8", errors="ignore") as f: - return [ln.rstrip("\n") for ln in f] - except Exception as e: - raise e if last_err is None else last_err - - -def load_pairs(path: str) -> List[Tuple[str, str]]: - pairs: List[Tuple[str, str]] = [] - lines = read_text_lines(path) - for line in lines: - line = line.strip() - if not line: - continue - if "\t" in line: - src, tgt = line.split("\t", 1) - else: - parts = line.split() - if len(parts) < 2: - continue - src = parts[0] - tgt = " ".join(parts[1:]) - pairs.append((src.strip(), tgt.strip())) - # Sort by length of src desc to prefer longest matches - pairs.sort(key=lambda p: len(p[0]), reverse=True) - return pairs - - -def try_load_synonyms(path: str) -> Dict[str, str]: - mapping: Dict[str, str] = {} - if not path or not os.path.isfile(path): - return mapping - lines = read_text_lines(path) - for line in lines: - line = line.strip() - if not line: - continue - if "\t" in line: - a, b = line.split("\t", 1) - else: - parts = line.split() - if len(parts) < 2: - continue - a, b = parts[0], " ".join(parts[1:]) - a = a.strip() - b = b.strip() - if a and b: - mapping[a] = b - return mapping - - -def try_load_seed_json(path: str) -> List[Tuple[str, str]]: - """Load seed_vocabulary.json if present, returning list of (src, tgt_gloss). - We include both the canonical word and its synonyms as sources. - """ - pairs: List[Tuple[str, str]] = [] - if not path or not os.path.isfile(path): - return pairs - try: - with open(path, "r", encoding="utf-8") as f: - data = json.load(f) - if isinstance(data, list): - for item in data: - if not isinstance(item, dict): - continue - word = str(item.get("word", "")).strip() - gloss = str(item.get("gloss", "")).strip() - syns = item.get("synonyms", []) or [] - if word and gloss: - pairs.append((word, gloss)) - for s in syns: - s = str(s or "").strip() - if s and gloss: - pairs.append((s, gloss)) - except Exception: - # Best-effort; ignore malformed seed json - return pairs - # Prefer longest first - pairs.sort(key=lambda p: len(p[0]), reverse=True) - return pairs - - -def greedy_replace(text: str, pairs: List[Tuple[str, str]]) -> str: - # Replace using regex with word-boundary-ish handling; Vietnamese spacing preserved - out = text - for src, tgt in pairs: - if not src: - continue - # Use simple boundaries: match src as standalone token or phrase boundaries - pattern = r"(? List[str]: - results: List[str] = [] - for line in lines: - line = line.strip() - if not line: - results.append("") - continue - # apply synonyms first (normalize text) - if synonyms: - for a, b in synonyms.items(): - if not a: - continue - pattern = r"(? None: - parser = argparse.ArgumentParser( - description="Vietnamese Text -> gloss-like via phrase table" - ) - parser.add_argument( - "--input", required=True, help="Input transcript .txt (one or many sentences)" - ) - parser.add_argument("--output", required=True, help="Output gloss .txt") - parser.add_argument( - "--pairs", - default="VSL/DataTrain1.txt", - help="Path to DataTrain1/2 mapping file", - ) - parser.add_argument( - "--synonyms", default="VSL/Synonyms.txt", help="Optional synonyms file" - ) - parser.add_argument( - "--seed_json", - default="seed_vocabulary.json", - help="Optional seed_vocabulary JSON (preferred)", - ) - args = parser.parse_args() - - if not os.path.isfile(args.input): - raise FileNotFoundError(args.input) - if not os.path.isfile(args.pairs): - raise FileNotFoundError(args.pairs) - - pairs = load_pairs(args.pairs) - seed_pairs = try_load_seed_json(args.seed_json) - # Merge with seed, seed first to win on conflicts (later regex passes override earlier if same span) - if seed_pairs: - pairs = seed_pairs + [ - p for p in pairs if p[0].lower() not in {s[0].lower() for s in seed_pairs} - ] - synonyms = try_load_synonyms(args.synonyms) - - lines = read_text_lines(args.input) - - results = process_lines(lines, pairs, synonyms) - os.makedirs(os.path.dirname(args.output) or ".", exist_ok=True) - with open(args.output, "w", encoding="utf-8") as f: - for r in results: - f.write(r + "\n") - - print(f"[OK] Gloss written: {args.output}") - - -if __name__ == "__main__": - main() diff --git a/scripts/3_gloss2sigml.py b/scripts/3_gloss2sigml.py deleted file mode 100644 index 5966aa7..0000000 --- a/scripts/3_gloss2sigml.py +++ /dev/null @@ -1,466 +0,0 @@ -#!/usr/bin/env python3 -""" -Gloss -> SiGML concatenator (demo) - -This script reads a gloss text file (one sentence per line), looks up each token -in the VSL HamNoSys/SiGML dictionary, and concatenates them into a single SiGML -sequence with fixed durations. If a token is missing, it attempts fallback -fingerspelling by spelling characters (a..z, ă, â, ê, ô, ơ, ư, đ) via entries -in the dictionary if present. Otherwise, it comments the token. - -Input: - - gloss.txt (from 2_text2gloss.py) - - VSL/Dictionary VSL HamNoSys (TSV-like with headers: Word ... Hand) - -Output: - - demo.sigml (rough, for MVP demo purposes) - -Usage: - python scripts/3_gloss2sigml.py --input gloss.txt --dict "VSL/Dictionary VSL HamNoSys" --output out/demo.sigml -""" - -import argparse -import csv -import os -import unicodedata -from typing import Dict, List, Tuple - -# Bimanual mode: 'auto' | 'always' | 'never' (set in main) -BIMANUAL_MODE: str = "auto" - - -def load_dictionary(path: str) -> Dict[str, str]: - """Load a very large TSV-like dictionary file. - We consider the first column 'Word' as key and the rest of columns joined - as a pseudo-HamNoSys/SiGML body. This is heuristic for demo. - """ - mapping: Dict[str, str] = {} - with open(path, "r", encoding="utf-8", errors="ignore") as f: - reader = csv.reader(f, delimiter="\t") - header = None - for row in reader: - if not row: - continue - if header is None: - header = row - # Ensure first column named Word if possible - # Not strictly required for demo - continue - key = row[0].strip() - if not key: - continue - # Join remaining columns to a single string as placeholder body - body = ",".join(col.strip() for col in row[1:] if col is not None) - mapping[key] = body - return mapping - - -def tokenize_gloss(line: str) -> List[str]: - return [tok for tok in line.strip().split() if tok] - - -def wrap_sigml_sequence(segments: List[str]) -> str: - """Wrap concatenated segments into SiGML root.""" - content = "\n".join(segments) - return "\n" f"{content}\n" "\n" - - -def strip_diacritics(ch: str) -> str: - # Normalize Vietnamese letters to base ASCII; special-case đ/Đ - if ch == "đ": - return "d" - if ch == "Đ": - return "D" - decomp = unicodedata.normalize("NFD", ch) - base = "".join(c for c in decomp if not unicodedata.combining(c)) - return base - - -def sanitize_ascii(text: str) -> str: - """Return ASCII-only variant of text (strip diacritics and non-ascii).""" - if not text: - return "" - norm = unicodedata.normalize("NFKD", text) - return norm.encode("ascii", "ignore").decode("ascii") - - -def html_escape(text: str) -> str: - return ( - text.replace("&", "&") - .replace('"', """) - .replace("<", "<") - .replace(">", ">") - ) - - -def _parse_tokens(body_csv: str) -> List[str]: - tokens = [t.strip() for t in (body_csv or "").split(",")] - out: List[str] = [] - for tok in tokens: - if not tok: - continue - tok_ascii = sanitize_ascii(tok) - if not tok_ascii: - continue - if tok_ascii.startswith("ham") or tok_ascii.startswith("hnm_"): - out.append(tok_ascii) - return out - - -def _render_elements(tokens: List[str]) -> str: - if not tokens: - return " " - return "\n".join((f" <{t}/>" for t in tokens)) - - -def _mirror_token(tok: str) -> str: - """Heuristic mirror for left/right orientation tokens. - This is best-effort for demo only. - """ - # Common right/left suffix flips - suffix_map = [ - ("ur", "ul"), - ("or", "ol"), - ("dr", "dl"), - ("ir", "il"), - ("r", "l"), - ("palmr", "palml"), - ("palmdr", "palmdl"), - ("palmur", "palmul"), - ] - for a, b in suffix_map: - if tok.endswith(a): - return tok[: -len(a)] + b - return tok - - -def _prefer_bimanual(gloss: str, tokens: List[str]) -> bool: - if BIMANUAL_MODE == "always": - return True - if BIMANUAL_MODE == "never": - return False - g = (gloss or "").upper() - if g.startswith("SPELL:"): - return False - if g in { - "XIN_CHAO", - "CHAO", - "CHAO_MUNG", - "HOM_NAY", - "GIAO_DUC", - "DU_AN", - "AI", - "CHIA_SE", - "NOI_DUNG", - "BAI_GIANG", - "TIEP_CAN", - }: - return True - # Heuristic: flat/cee/finger2345 are often symmetric gestures in demo - hint = {"hamflathand", "hamceeall", "hamfinger2345", "hamfinger23spread"} - if any(t in tokens for t in hint): - return True - return False - - -def tokens_to_hamnosys_manual(body_csv: str) -> str: - """Convert comma-separated mnemonic tokens into XML. - We keep only tokens that look like HamNoSys element names (prefix 'ham' or 'hnm_'). - """ - tokens = _parse_tokens(body_csv) - parts = _render_elements(tokens) - return " \n" f"{parts}\n" " " - - -def build_segment_for_token( - token: str, - dict_map: Dict[str, str], - letter_map: Dict[str, str], - miss_chars: Dict[str, int], -) -> str: - # Treat special underscores as short pause between parts - if token == "_": - return " " - - if token in dict_map and dict_map[token]: - body_raw = dict_map[token] - # If gloss is known to be bimanual, synthesize symmetric pair using hampar blocks - tokens = _parse_tokens(body_raw) - g = html_escape(sanitize_ascii(token).replace(" ", "_")) - prefer_bi = _prefer_bimanual(g, tokens) or any( - t in {"hamsymmlr", "hamsymmpar", "hamparbegin"} for t in tokens - ) - if prefer_bi and tokens: - right = _render_elements(tokens) - left_tokens = [_mirror_token(t) for t in tokens] - left = _render_elements(left_tokens) - manual = ( - " \n" - " \n" - " \n" - f"{right}\n" - " \n" - " \n" - f"{left}\n" - " \n" - " " - ) - else: - manual = tokens_to_hamnosys_manual(body_raw) - return f' \n' f"{manual}\n" f" " - - # fallback: fingerspelling per character (each as a sign) - segs: List[str] = [] - for ch in token: - # treat punctuation as pause (skip missing) - if unicodedata.category(ch).startswith("P") or ch in { - "?", - "!", - ",", - ".", - ":", - ";", - "…", - "—", - "–", - "-", - '"', - "'", - "(", - ")", - "[", - "]", - "/", - "\\", - }: - segs.append(" ") - continue - if ch == "_": - segs.append(" ") - continue - key = ch - g = html_escape(sanitize_ascii(key)) - if key in letter_map and letter_map[key]: - manual = tokens_to_hamnosys_manual(letter_map[key]) - segs.append( - f' \n' f"{manual}\n" f" " - ) - continue - base = strip_diacritics(key).lower() - if base in letter_map and letter_map[base]: - manual = tokens_to_hamnosys_manual(letter_map[base]) - segs.append( - f' \n' - f"{manual}\n" - f" " - ) - continue - miss_chars[key] = miss_chars.get(key, 0) + 1 - segs.append(f" ") - return "\n".join(segs) - - -def extract_letter_map(dict_map: Dict[str, str]) -> Dict[str, str]: - """Build simple char->hamnosys map from dictionary for base letters and common Vietnamese chars.""" - candidates = [ - "a", - "b", - "c", - "d", - "e", - "f", - "g", - "h", - "i", - "j", - "k", - "l", - "m", - "n", - "o", - "p", - "q", - "r", - "s", - "t", - "u", - "v", - "w", - "x", - "y", - "z", - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - "I", - "J", - "K", - "L", - "M", - "N", - "O", - "P", - "Q", - "R", - "S", - "T", - "U", - "V", - "W", - "X", - "Y", - "Z", - "đ", - "Đ", - "ă", - "â", - "ê", - "ô", - "ơ", - "ư", - "Á", - "À", - "Ả", - "Ã", - "Ạ", - "á", - "à", - "ả", - "ã", - "ạ", - "É", - "È", - "Ẻ", - "Ẽ", - "Ẹ", - "é", - "è", - "ẻ", - "ẽ", - "ẹ", - "Í", - "Ì", - "Ỉ", - "Ĩ", - "Ị", - "í", - "ì", - "ỉ", - "ĩ", - "ị", - "Ó", - "Ò", - "Ỏ", - "Õ", - "Ọ", - "ó", - "ò", - "ỏ", - "õ", - "ọ", - "Ú", - "Ù", - "Ủ", - "Ũ", - "Ụ", - "ú", - "ù", - "ủ", - "ũ", - "ụ", - "Ý", - "Ỳ", - "Ỷ", - "Ỹ", - "Ỵ", - "ý", - "ỳ", - "ỷ", - "ỹ", - "ỵ", - ] - out: Dict[str, str] = {} - for ch in candidates: - if ch in dict_map and dict_map[ch]: - out[ch] = dict_map[ch] - # Also map stripped diacritics if present only in base form - for ch in candidates: - base = strip_diacritics(ch) - if ch not in out and base in dict_map and dict_map[base]: - out[ch] = dict_map[base] - return out - - -def main() -> None: - parser = argparse.ArgumentParser(description="Gloss -> SiGML concatenator (demo)") - parser.add_argument( - "--input", required=True, help="gloss.txt (one sentence per line)" - ) - parser.add_argument( - "--dict", - dest="dict_path", - required=True, - help="Path to 'Dictionary VSL HamNoSys'", - ) - parser.add_argument("--output", required=True, help="Output .sigml path") - parser.add_argument( - "--report", default=None, help="Optional report.txt for missing chars/tokens" - ) - parser.add_argument( - "--bimanual", - choices=["auto", "always", "never"], - default="auto", - help="Force two-hand composition policy", - ) - args = parser.parse_args() - - if not os.path.isfile(args.input): - raise FileNotFoundError(args.input) - if not os.path.isfile(args.dict_path): - raise FileNotFoundError(args.dict_path) - - dict_map = load_dictionary(args.dict_path) - global BIMANUAL_MODE - BIMANUAL_MODE = args.bimanual - letter_map = extract_letter_map(dict_map) - - with open(args.input, "r", encoding="utf-8") as f: - lines = [ln.rstrip("\n") for ln in f] - - segments: List[str] = [] - missing_chars: Dict[str, int] = {} - for line in lines: - tokens = tokenize_gloss(line) - for tok in tokens: - seg = build_segment_for_token(tok, dict_map, letter_map, missing_chars) - segments.append(seg) - - sigml = wrap_sigml_sequence(segments) - os.makedirs(os.path.dirname(args.output) or ".", exist_ok=True) - with open(args.output, "w", encoding="utf-8") as f: - f.write(sigml) - - print(f"[OK] SiGML written: {args.output}") - - # Optional report - report_path = args.report or (args.output + ".report.txt") - try: - with open(report_path, "w", encoding="utf-8") as rf: - if not missing_chars: - rf.write("No missing characters.\n") - else: - rf.write("Missing characters (char\tcount):\n") - for ch, cnt in sorted(missing_chars.items(), key=lambda x: -x[1]): - rf.write(f"{ch}\t{cnt}\n") - print(f"[OK] Report written: {report_path}") - except Exception: - pass - - -if __name__ == "__main__": - main() diff --git a/scripts/3b_segments_to_playlist.py b/scripts/3b_segments_to_playlist.py deleted file mode 100644 index f7ae7c3..0000000 --- a/scripts/3b_segments_to_playlist.py +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env python3 -""" -Build a per-segment SiGML playlist from Whisper segments. - -Inputs: - --segments out/.segments.json (from scripts/1_stt_whisper.py) - --pairs VSL/DataTrain1.txt - --synonyms VSL/Synonyms.txt - --dict "VSL/Dictionary VSL HamNoSys" - -Outputs: - --output out/.playlist.json - -Each playlist item: - { start: number, end: number, text: string, gloss: string, sigml: string } - -Note: For simplicity, this script invokes the existing CLI scripts 2 and 3 -to transform text->gloss and gloss->sigml per segment. -""" - -import argparse -import json -import os -import subprocess -import tempfile -from typing import List, Dict - - -def run_text2gloss(text: str, pairs: str, synonyms: str) -> str: - with tempfile.NamedTemporaryFile( - "w", delete=False, encoding="utf-8", suffix=".txt" - ) as tin: - tin.write(text + "\n") - tin_path = tin.name - gout = tin_path + ".gloss.txt" - cmd = [ - "python", - "scripts/2_text2gloss.py", - "--input", - tin_path, - "--output", - gout, - "--pairs", - pairs, - "--synonyms", - synonyms, - ] - subprocess.check_call(cmd) - with open(gout, "r", encoding="utf-8") as f: - line = f.readline().rstrip("\n") - try: - os.remove(tin_path) - os.remove(gout) - except Exception: - pass - return line - - -def run_gloss2sigml_from_text(gloss_line: str, dict_path: str) -> str: - # write temp gloss file - with tempfile.NamedTemporaryFile( - "w", delete=False, encoding="utf-8", suffix=".txt" - ) as g: - g.write(gloss_line + "\n") - gpath = g.name - sout = gpath + ".sigml" - cmd = [ - "python", - "scripts/3_gloss2sigml.py", - "--input", - gpath, - "--dict", - dict_path, - "--output", - sout, - ] - subprocess.check_call(cmd) - with open(sout, "r", encoding="utf-8") as f: - sigml = f.read() - try: - os.remove(gpath) - os.remove(sout) - except Exception: - pass - return sigml - - -def main() -> None: - p = argparse.ArgumentParser() - p.add_argument("--segments", required=True) - p.add_argument("--pairs", required=True) - p.add_argument("--synonyms", required=True) - p.add_argument("--dict", dest="dict_path", required=True) - p.add_argument("--output", required=True) - args = p.parse_args() - - with open(args.segments, "r", encoding="utf-8") as jf: - segdata = json.load(jf) - segments: List[Dict] = segdata.get("segments", []) - - playlist: List[Dict] = [] - for seg in segments: - text = str(seg.get("text", "")).strip() - if not text: - continue - gloss = run_text2gloss(text, args.pairs, args.synonyms) - sigml = run_gloss2sigml_from_text(gloss, args.dict_path) - playlist.append( - { - "start": float(seg.get("start", 0.0)), - "end": float(seg.get("end", 0.0)), - "text": text, - "gloss": gloss, - "sigml": sigml, - } - ) - - os.makedirs(os.path.dirname(args.output) or ".", exist_ok=True) - with open(args.output, "w", encoding="utf-8") as pf: - json.dump({"playlist": playlist}, pf, ensure_ascii=False) - - print(f"[OK] Playlist written: {args.output} ({len(playlist)} items)") - - -if __name__ == "__main__": - main() diff --git a/scripts/4_preview.html b/scripts/4_preview.html deleted file mode 100644 index 2947a93..0000000 --- a/scripts/4_preview.html +++ /dev/null @@ -1,215 +0,0 @@ - - - - - - SignBridge Demo Preview - - - -

SignBridge Demo Preview

-

- Chọn file .sigml (tạo bởi script 3) để xem nội dung. Đây chỉ - là xem văn bản SiGML; không render 3D. -

- -
- - - -
- -
- -
-

-        
-
-
- - - - diff --git a/seed_vocabulary.csv b/seed_vocabulary.csv deleted file mode 100644 index 8557266..0000000 --- a/seed_vocabulary.csv +++ /dev/null @@ -1,11 +0,0 @@ -word,gloss,synonyms -biến,lưu trữ giá trị,variable -hàm,khối lệnh có tên,"function, method" -mô hình ngôn ngữ lớn,model học hiểu ngôn ngữ tự nhiên,"LLM, large language model" -dữ liệu,thông tin đầu vào,"data, dataset" -học viên,người học trong lớp,"student, learner" -giảng viên,"người dạy, hướng dẫn học viên","teacher, instructor" -thực hành,làm bài tập trên máy,"practice, exercise" -ví dụ,minh họa cho lý thuyết,"example, demo" -thử lại,khuyến khích học viên làm lại,"retry, try again" -tốt lắm,lời khen khi học viên làm đúng,"good job, well done" diff --git a/seed_vocabulary.json b/seed_vocabulary.json deleted file mode 100644 index c5d69a3..0000000 --- a/seed_vocabulary.json +++ /dev/null @@ -1,81 +0,0 @@ -[ - { - "word": "biến", - "gloss": "lưu trữ giá trị", - "synonyms": [ - "variable" - ] - }, - { - "word": "hàm", - "gloss": "khối lệnh có tên", - "synonyms": [ - "function", - "method" - ] - }, - { - "word": "mô hình ngôn ngữ lớn", - "gloss": "model học hiểu ngôn ngữ tự nhiên", - "synonyms": [ - "LLM", - "large language model" - ] - }, - { - "word": "dữ liệu", - "gloss": "thông tin đầu vào", - "synonyms": [ - "data", - "dataset" - ] - }, - { - "word": "học viên", - "gloss": "người học trong lớp", - "synonyms": [ - "student", - "learner" - ] - }, - { - "word": "giảng viên", - "gloss": "người dạy, hướng dẫn học viên", - "synonyms": [ - "teacher", - "instructor" - ] - }, - { - "word": "thực hành", - "gloss": "làm bài tập trên máy", - "synonyms": [ - "practice", - "exercise" - ] - }, - { - "word": "ví dụ", - "gloss": "minh họa cho lý thuyết", - "synonyms": [ - "example", - "demo" - ] - }, - { - "word": "thử lại", - "gloss": "khuyến khích học viên làm lại", - "synonyms": [ - "retry", - "try again" - ] - }, - { - "word": "tốt lắm", - "gloss": "lời khen khi học viên làm đúng", - "synonyms": [ - "good job", - "well done" - ] - } -] \ No newline at end of file diff --git a/src/models/db_models.py b/src/models/db_models.py new file mode 100644 index 0000000..e5ef55a --- /dev/null +++ b/src/models/db_models.py @@ -0,0 +1,210 @@ +""" +SQLAlchemy database models cho SignBridge. + +Module này định nghĩa các bảng cơ sở dữ liệu PostgreSQL: +- videos: Lưu trữ metadata video (demo + upload) +- processing_history: Lịch sử xử lý video qua pipeline +- sign_vocabulary: Từ vựng ngôn ngữ ký hiệu Việt Nam +- vsl_dictionary_cache: Cache từ điển VSL HamNoSys +- analytics_events: Ghi nhận sự kiện người dùng + +Kiến trúc: SQLAlchemy ORM với PostgreSQL +""" + +from datetime import datetime +from typing import Optional, List +from sqlalchemy import ( + Column, Integer, String, Text, Boolean, DECIMAL, TIMESTAMP, + ForeignKey, ARRAY, Index +) +from sqlalchemy.dialects.postgresql import JSONB +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import relationship +from sqlalchemy.sql import func + +Base = declarative_base() + + +class Video(Base): + """ + Bảng videos: Lưu trữ thông tin video (demo + upload) + + Mục đích: + - Quản lý metadata của video demo và video người dùng upload + - Lưu trữ nội dung SiGML đã xử lý (không phụ thuộc file) + - Hỗ trợ Learning Hub với trạng thái is_published + + Quan hệ: 1 video -> N processing_history (one-to-many) + """ + + __tablename__ = 'videos' + + # Primary key + id = Column(Integer, primary_key=True) + + # Identifiers + video_id = Column(String(50), unique=True, nullable=False, index=True) + + # Basic info + title = Column(String(255), nullable=False) + description = Column(Text) + + # File paths + video_path = Column(String(500), nullable=False) + thumbnail_path = Column(String(500)) + duration_seconds = Column(DECIMAL(10, 2)) + + # SiGML storage - Lưu trữ file SiGML (XML ký hiệu ngôn ngữ ký hiệu) + sigml_path = Column(String(500)) # DEPRECATED - đường dẫn file cũ (giữ để tương thích) + sigml_content = Column(Text) # PRIMARY - nội dung SiGML lưu trực tiếp trong DB + has_sigml = Column(Boolean, default=False) # Flag: video đã có SiGML chưa + + # Metadata + source = Column(String(50), default='upload') # 'demo' or 'upload' + is_demo = Column(Boolean, default=False) + is_published = Column(Boolean, default=False, index=True) + + # Timestamps + created_at = Column(TIMESTAMP, server_default=func.now()) + updated_at = Column(TIMESTAMP, server_default=func.now(), onupdate=func.now()) + + # Relationships + processing_records = relationship( + "ProcessingHistory", + back_populates="video", + cascade="all, delete-orphan" + ) + + def __repr__(self) -> str: + return f"" + + def to_dict(self) -> dict: + """Convert to dictionary for JSON serialization.""" + return { + 'id': self.video_id, + 'title': self.title, + 'desc': self.description or '', + 'videoPath': self.video_path, + 'thumbPath': self.thumbnail_path or 'assets/thumbail.png', + 'sigmlPath': self.sigml_path, + 'hasSigml': self.has_sigml, + 'source': self.source, + 'isDemo': self.is_demo, + 'isPublished': self.is_published, + 'createdAt': self.created_at.isoformat() if self.created_at else None, + } + + +class ProcessingHistory(Base): + """ + Bảng processing_history: Lịch sử xử lý video qua pipeline + + Mục đích: + - Ghi lại quá trình: Speech-to-Text → Text-to-Gloss → Gloss-to-SiGML + - Lưu trữ nội dung đầu ra từng bước (transcript, gloss, SiGML, segments) + - Theo dõi performance metrics (thời gian, độ dài, số lượng ký hiệu) + - Ghi nhận lỗi nếu pipeline fail + + Quan hệ: N processing_history -> 1 video (many-to-one) + """ + + __tablename__ = 'processing_history' + + # Primary key + id = Column(Integer, primary_key=True) + + # Foreign key to videos + video_id = Column(Integer, ForeignKey('videos.id', ondelete='CASCADE'), nullable=False, index=True) + + # Generated file paths (DEPRECATED - kept for backward compatibility) + transcript_path = Column(String(500)) + gloss_path = Column(String(500)) + sigml_path = Column(String(500)) + segments_path = Column(String(500)) + + # Content storage (NEW - Primary source) + transcript_content = Column(Text) + gloss_content = Column(Text) + segments_json = Column(JSONB) + + # Processing metrics (milliseconds) + stt_duration_ms = Column(Integer) + text2gloss_duration_ms = Column(Integer) + gloss2sigml_duration_ms = Column(Integer) + total_duration_ms = Column(Integer) + + # Processing status + status = Column(String(50), default='completed', index=True) + error_message = Column(Text) + + # Content statistics + transcript_length = Column(Integer) + gloss_token_count = Column(Integer) + sigml_sign_count = Column(Integer) + missing_token_count = Column(Integer) + + # Timestamps + started_at = Column(TIMESTAMP, server_default=func.now(), index=True) + completed_at = Column(TIMESTAMP) + + # Relationships + video = relationship("Video", back_populates="processing_records") + + def __repr__(self) -> str: + return f"" + + +class SignVocabulary(Base): + """ + Bảng sign_vocabulary: Từ vựng ngôn ngữ ký hiệu Việt Nam + + Mục đích: + - Lưu trữ ánh xạ từ tiếng Việt → Gloss (ký hiệu chuẩn) + - Hỗ trợ từ đồng nghĩa (synonyms) + - Theo dõi mức độ sử dụng (usage_count) để tối ưu hóa + + Nguồn: Thay thế file seed_vocabulary.json + """ + + __tablename__ = 'sign_vocabulary' + + # Primary key + id = Column(Integer, primary_key=True) + + # Vocabulary data + word = Column(String(255), nullable=False, index=True) + gloss = Column(Text, nullable=False) + category = Column(String(100), index=True) + + # Synonyms as PostgreSQL array + synonyms = Column(ARRAY(Text)) + + # Usage tracking + usage_count = Column(Integer, default=0, index=True) + last_used_at = Column(TIMESTAMP) + + # Source tracking + source = Column(String(50), default='manual') + + # Timestamps + created_at = Column(TIMESTAMP, server_default=func.now()) + updated_at = Column(TIMESTAMP, server_default=func.now(), onupdate=func.now()) + + __table_args__ = ( + Index('idx_vocab_word', 'word'), + Index('idx_vocab_synonyms', 'synonyms', postgresql_using='gin'), + ) + + def __repr__(self) -> str: + return f"" + + def to_dict(self) -> dict: + """Convert to dictionary for JSON serialization.""" + return { + 'word': self.word, + 'gloss': self.gloss, + 'synonyms': self.synonyms or [], + 'category': self.category, + 'usageCount': self.usage_count, + } + diff --git a/src/models/video.py b/src/models/video.py index 7aa5440..d2d55b6 100644 --- a/src/models/video.py +++ b/src/models/video.py @@ -15,8 +15,10 @@ class Video: id: str title: str video_path: str - sigml_source: str = "inline" - sigml_text: str = "" + sigml_source: str = "db" # Changed from "inline" to "db" for database content + sigml_text: str = "" # DEPRECATED - kept for backward compatibility + sigml_content: str = "" # NEW - Primary source for SiGML XML content from DB + sigml_path: str = "" # DEPRECATED - Path to SiGML file (for backward compatibility) duration: str = "00:00" thumbnail: str = "assets/thumbail.png" @@ -34,8 +36,10 @@ def from_dict(cls, data: Dict[str, Any]) -> "Video": id=data.get("id", ""), title=data.get("title", ""), video_path=data.get("videoPath", ""), - sigml_source=data.get("sigmlSource", "inline"), - sigml_text=data.get("sigmlText", ""), + sigml_source=data.get("sigmlSource", "db"), + sigml_text=data.get("sigmlText", ""), # DEPRECATED + sigml_content=data.get("sigmlContent", ""), + sigml_path=data.get("sigmlPath", ""), # DEPRECATED duration=data.get("duration", "00:00"), thumbnail=data.get("thumbnail", "assets/thumbail.png") ) @@ -53,7 +57,9 @@ def to_dict(self) -> Dict[str, Any]: "thumbnail": self.thumbnail, "videoPath": self.video_path, "sigmlSource": self.sigml_source, - "sigmlText": self.sigml_text + "sigmlText": self.sigml_text, # DEPRECATED + "sigmlContent": self.sigml_content, + "sigmlPath": self.sigml_path # DEPRECATED } diff --git a/src/processors/gloss2sigml_processor.py b/src/processors/gloss2sigml_processor.py index ab5273f..ee27353 100644 --- a/src/processors/gloss2sigml_processor.py +++ b/src/processors/gloss2sigml_processor.py @@ -1,8 +1,23 @@ """ -Gloss-to-SiGML processor. - -Extracts core logic from scripts/3_gloss2sigml.py for library use. -Generates SiGML (Signing Gesture Markup Language) from gloss notation. +Gloss2SiGML Processor: Chuyển đổi Gloss → SiGML (XML ngôn ngữ ký hiệu) + +Chức năng: +- Convert gloss notation → HamNoSys notation (từ VSL Dictionary) +- Generate SiGML XML để điều khiển avatar 3D ký hiệu +- Hỗ trợ bimanual signs (ký hiệu 2 tay) với auto-enhancement +- Fingerspelling cho từ không có trong từ điển + +Flow: +1. Đọc gloss.txt (ví dụ: "XIN CHÀO TÊN TÔI LÀ") +2. Tra từ điển VSL HamNoSys → lấy HamNoSys notation +3. Enhance bimanual signs (thêm hamsymmlr, hamplus nếu cần) +4. Generate SiGML XML với structure: → tokens +5. Output: file .sigml để CWASA avatar render + +Tech stack: +- HamNoSys: Notation system cho ngôn ngữ ký hiệu +- SiGML: XML markup language cho avatar +- CWASA/JASigning: Avatar rendering engine """ import os @@ -28,14 +43,27 @@ class SiGMLResult: class Gloss2SigMLProcessor: - """Generates SiGML markup from gloss notation.""" + """ + Processor chuyển đổi Gloss → SiGML + + Nhiệm vụ: + - Tra cứu HamNoSys notation từ VSL Dictionary + - Auto-detect và enhance bimanual signs (ký hiệu 2 tay) + - Generate SiGML XML hợp lệ cho CWASA avatar + - Fingerspelling cho từ không có trong từ điển + """ def __init__(self, dictionary_path: str, bimanual_mode: str = "auto"): - """Initialize gloss-to-SiGML processor. - + """ + Khởi tạo Gloss2SiGML processor + Args: - dictionary_path: Path to VSL HamNoSys dictionary - bimanual_mode: Two-hand composition policy (auto/always/never) + dictionary_path: Đường dẫn file VSL HamNoSys dictionary + (ví dụ: "VSL/Dictionary VSL HamNoSys") + bimanual_mode: Chính sách xử lý ký hiệu 2 tay + - "auto": Tự động detect và enhance (mặc định) + - "always": Luôn áp dụng bimanual + - "never": Không dùng bimanual """ self.dictionary_path = dictionary_path self.bimanual_mode = bimanual_mode @@ -75,8 +103,17 @@ def _load_dictionary(self) -> Dict[str, str]: if not key: continue - # Join remaining columns as notation body - body = ",".join(col.strip() for col in row[1:] if col is not None) + # Dictionary format: Word | Mouth | Body | Head | Shoulder | Eyegaze | Eyebrow | Eyelids | Hand + # CRITICAL FIX: Only use column 8 (Hand) which contains HamNoSys notation + # Other columns contain annotations (AD, RB, BB) and pronunciation marks + # that crash the CWASA parser + if len(row) >= 9: + body = row[8].strip() # Column 8 = Hand column (0-indexed) + elif len(row) > 1: + body = row[-1].strip() # Fallback: use last column + else: + body = "" + mapping[key] = body self._dictionary = mapping @@ -174,17 +211,93 @@ def _tokens_to_hamnosys(self, body_csv: str) -> str: """ tokens = [t.strip() for t in (body_csv or "").split(",") if t.strip()] - # Filter for valid HamNoSys tokens - valid_tokens = [ - t for t in tokens if t.startswith("ham") or t.startswith("hnm_") - ] + # Filter for valid HamNoSys tokens with enhanced validation + valid_tokens = [] + for t in tokens: + # Must start with ham or hnm_ + if not (t.startswith("ham") or t.startswith("hnm_")): + continue + + # Must be longer than 3 chars (avoid bare "ham") + if len(t) <= 3: + continue + + # First 4 chars should not contain digits (avoid contamination like "ham123") + if any(c.isdigit() for c in t[:min(4, len(t))]): + continue + + # Should not contain special chars that indicate annotations + if any(c in t for c in ['@', ':', '?', '.', '!', '~', '^', '`']): + continue + + valid_tokens.append(t) if not valid_tokens: return " \n \n " + # ✨ BIMANUAL DETECTION & ENHANCEMENT + # Detect if this is a bimanual sign (uses both hands) + is_bimanual = "hamparbegin" in valid_tokens + has_symmetry = "hamsymmlr" in valid_tokens + + if is_bimanual and self.bimanual_mode != "never": + # Check if hamparbegin is at the beginning (valid position for hamsymmlr) + # HamNoSys grammar: hamsymmlr must be immediately followed by hamparbegin + try: + begin_idx = valid_tokens.index("hamparbegin") + # Only add hamsymmlr if hamparbegin is at position 0 or 1 (after hamsymmlr) + if begin_idx == 0 and not has_symmetry: + # Insert symmetry tag at the beginning + valid_tokens.insert(0, "hamsymmlr") + logger.debug("Added hamsymmlr tag for bimanual sign") + elif begin_idx > 1: + # Invalid structure: hand config before hamparbegin + # This means it's not a proper bimanual sign, skip enhancement + logger.warning(f"Skipping bimanual enhancement: hamparbegin at position {begin_idx} (expected 0)") + is_bimanual = False + except ValueError: + pass + + # Ensure there's a hand separator (hamplus) between hands + # This is typically between hamparbegin and hamparend + # Only do this if we have a valid bimanual structure + if is_bimanual and "hamplus" not in valid_tokens: + # Find position to insert hamplus (after first hand configuration) + # Look for hamparbegin, then find a good split point + try: + begin_idx = valid_tokens.index("hamparbegin") + end_idx = valid_tokens.index("hamparend") if "hamparend" in valid_tokens else len(valid_tokens) + + # Find midpoint between begin and end + # Insert hamplus roughly in the middle of the parallel section + mid_idx = begin_idx + (end_idx - begin_idx) // 2 + if mid_idx > begin_idx + 1: + valid_tokens.insert(mid_idx, "hamplus") + logger.debug("Added hamplus separator for bimanual sign") + except (ValueError, IndexError): + # If structure is unexpected, skip hamplus insertion + logger.warning("Could not insert hamplus: unexpected bimanual structure") + elements = "\n".join(f" <{tok}/>" for tok in valid_tokens) return f" \n{elements}\n " + def _escape_xml_attr(self, text: str) -> str: + """Escape special characters for XML attributes. + + Args: + text: Text to escape + + Returns: + Escaped text safe for XML attributes + """ + return (text + .replace("&", "&") + .replace("<", "<") + .replace(">", ">") + .replace('"', """) + .replace("'", "'") + .replace(" ", "_")) + def _build_sign_segment( self, token: str, @@ -211,7 +324,13 @@ def _build_sign_segment( if token in dict_map and dict_map[token]: body = dict_map[token] manual = self._tokens_to_hamnosys(body) - gloss_attr = token.replace(" ", "_") + + # Check if manual is empty (all tokens filtered out) + if "" in manual: + logger.warning(f"All tokens filtered out for '{token}': {body}") + return f" " + + gloss_attr = self._escape_xml_attr(token) return f' \n{manual}\n ' # Fallback: Fingerspelling @@ -230,9 +349,15 @@ def _build_sign_segment( char_lower = char.lower() if char_lower in letter_map and letter_map[char_lower]: manual = self._tokens_to_hamnosys(letter_map[char_lower]) - segments.append( - f' \n{manual}\n ' - ) + # Skip if manual is empty + if "" not in manual: + char_escaped = self._escape_xml_attr(char_lower) + segments.append( + f' \n{manual}\n ' + ) + else: + missing[char] = missing.get(char, 0) + 1 + segments.append(f" ") else: # Track missing character missing[char] = missing.get(char, 0) + 1 diff --git a/src/repositories/__init__.py b/src/repositories/__init__.py index 6bbab44..7d4fa2e 100644 --- a/src/repositories/__init__.py +++ b/src/repositories/__init__.py @@ -1,4 +1,7 @@ -"""Repository modules for data access.""" -from .manifest_repository import ManifestRepository +"""Repository layer for data access.""" + +from .video_repository import VideoRepository +from .vocabulary_repository import VocabularyRepository + +__all__ = ['VideoRepository', 'VocabularyRepository'] -__all__ = ["ManifestRepository"] diff --git a/src/repositories/manifest_repository.py b/src/repositories/manifest_repository.py deleted file mode 100644 index 58c87f8..0000000 --- a/src/repositories/manifest_repository.py +++ /dev/null @@ -1,162 +0,0 @@ -""" -Manifest repository for managing video metadata. - -Provides data access layer with caching and atomic writes. -""" - -import os -import json -import logging -import threading -from typing import List, Optional -from pathlib import Path - -from ..models import Video, Manifest -from ..exceptions import SignBridgeError - - -logger = logging.getLogger(__name__) - - -class ManifestRepository: - """Repository for manifest.json operations with caching.""" - - def __init__(self, manifest_path: str): - """Initialize manifest repository. - - Args: - manifest_path: Path to manifest.json file - """ - self.manifest_path = manifest_path - self._cache: Optional[Manifest] = None - self._lock = threading.RLock() # For thread-safe cache operations - - def get_manifest(self) -> Manifest: - """Get manifest with caching. - - Returns: - Manifest instance - - Raises: - SignBridgeError: If manifest loading fails - """ - with self._lock: - if self._cache is None: - self._cache = self._load_manifest() - return self._cache - - def get_all_videos(self) -> List[Video]: - """Get all videos from manifest. - - Returns: - List of Video objects - """ - manifest = self.get_manifest() - return manifest.videos - - def get_video_by_id(self, video_id: str) -> Optional[Video]: - """Find video by ID. - - Args: - video_id: Video identifier - - Returns: - Video if found, None otherwise - """ - manifest = self.get_manifest() - return manifest.get_video_by_id(video_id) - - def add_video(self, video: Video) -> None: - """Add video to manifest and save. - - Args: - video: Video to add - - Raises: - SignBridgeError: If save operation fails - """ - with self._lock: - manifest = self.get_manifest() - manifest.add_video(video) - self._save_manifest(manifest) - # Invalidate cache to force reload on next access - self._cache = manifest - logger.info(f"Video added to manifest: {video.id}") - - def generate_video_id(self) -> str: - """Generate unique video ID. - - Returns: - New video ID (e.g., "video1", "video2", ...) - """ - manifest = self.get_manifest() - return manifest.generate_video_id() - - def invalidate_cache(self) -> None: - """Invalidate cached manifest, forcing reload on next access.""" - with self._lock: - self._cache = None - logger.debug("Manifest cache invalidated") - - def _load_manifest(self) -> Manifest: - """Load manifest from file. - - Returns: - Manifest instance - - Raises: - SignBridgeError: If loading fails - """ - try: - if os.path.isfile(self.manifest_path): - logger.debug(f"Loading manifest from: {self.manifest_path}") - with open(self.manifest_path, "r", encoding="utf-8") as f: - data = json.load(f) - manifest = Manifest.from_dict(data) - logger.info(f"Manifest loaded: {len(manifest.videos)} videos") - return manifest - else: - logger.warning(f"Manifest file not found, creating empty: {self.manifest_path}") - return Manifest(videos=[]) - - except json.JSONDecodeError as e: - logger.error(f"Invalid JSON in manifest: {e}") - raise SignBridgeError(f"Manifest JSON is invalid: {e}") from e - - except Exception as e: - logger.error(f"Failed to load manifest: {e}") - raise SignBridgeError(f"Failed to load manifest: {e}") from e - - def _save_manifest(self, manifest: Manifest) -> None: - """Save manifest to file atomically. - - Args: - manifest: Manifest to save - - Raises: - SignBridgeError: If save operation fails - """ - try: - # Ensure directory exists - os.makedirs(os.path.dirname(self.manifest_path), exist_ok=True) - - # Atomic write: write to temp file first, then rename - temp_path = f"{self.manifest_path}.tmp" - - with open(temp_path, "w", encoding="utf-8") as f: - json.dump(manifest.to_dict(), f, ensure_ascii=False, indent=2) - - # Atomic rename (overwrites existing file) - os.replace(temp_path, self.manifest_path) - - logger.info(f"Manifest saved: {len(manifest.videos)} videos") - - except Exception as e: - logger.error(f"Failed to save manifest: {e}") - # Clean up temp file if it exists - if os.path.exists(temp_path): - try: - os.remove(temp_path) - except: - pass - raise SignBridgeError(f"Failed to save manifest: {e}") from e diff --git a/src/repositories/video_repository.py b/src/repositories/video_repository.py new file mode 100644 index 0000000..9921f40 --- /dev/null +++ b/src/repositories/video_repository.py @@ -0,0 +1,342 @@ +""" +Video Repository: Quản lý video trong database PostgreSQL + +Thay thế: ManifestRepository (file-based) → VideoRepository (database-based) + +Chức năng chính: +- CRUD operations cho video (create, read, update, delete) +- Lưu/đọc nội dung SiGML trực tiếp từ DB (không phụ thuộc file) +- Ghi nhận lịch sử processing qua pipeline +- Hỗ trợ Learning Hub với filter is_published + +Kiến trúc: Repository Pattern với SQLAlchemy ORM +""" + +import logging +from typing import List, Optional +from datetime import datetime +from sqlalchemy import create_engine, desc +from sqlalchemy.orm import sessionmaker, Session +from sqlalchemy.exc import SQLAlchemyError + +from src.models.db_models import Base, Video as VideoModel, ProcessingHistory +from src.models.video import Video + +logger = logging.getLogger(__name__) + + +class VideoRepository: + """ + Repository cho video CRUD operations sử dụng PostgreSQL + + Chức năng: + - Quản lý metadata video (title, path, thumbnail, timestamps) + - Lưu/đọc nội dung SiGML (XML ký hiệu) trực tiếp từ DB + - Ghi nhận lịch sử xử lý qua pipeline (ProcessingHistory) + - Hỗ trợ publish/unpublish video cho Learning Hub + """ + + def __init__(self, database_url: str): + """ + Khởi tạo kết nối database + + Args: + database_url: Chuỗi kết nối PostgreSQL + Ví dụ: "postgresql://user:password@localhost:5432/dbname" + """ + self.database_url = database_url + self.engine = create_engine(database_url, echo=False) + self.SessionLocal = sessionmaker(bind=self.engine) + + logger.info(f"VideoRepository initialized with database") + + def get_session(self) -> Session: + """Get a new database session.""" + return self.SessionLocal() + + def create_tables(self): + """Create all database tables (for initial setup).""" + Base.metadata.create_all(self.engine) + logger.info("Database tables created successfully") + + def get_all_videos(self) -> List[Video]: + """Get all videos from database. + + Returns: + List of Video objects + """ + session = self.get_session() + try: + db_videos = session.query(VideoModel).order_by(desc(VideoModel.created_at)).all() + return [self._db_to_domain(v) for v in db_videos] + except SQLAlchemyError as e: + logger.error(f"Error fetching all videos: {e}") + return [] + finally: + session.close() + + def get_published_videos(self) -> List[Video]: + """Get all published videos (for Learning Hub). + + Returns: + List of published Video objects + """ + session = self.get_session() + try: + db_videos = ( + session.query(VideoModel) + .filter(VideoModel.is_published == True) + .order_by(desc(VideoModel.created_at)) + .all() + ) + return [self._db_to_domain(v) for v in db_videos] + except SQLAlchemyError as e: + logger.error(f"Error fetching published videos: {e}") + return [] + finally: + session.close() + + def get_video_by_id(self, video_id: str) -> Optional[Video]: + """Get video by video_id. + + Args: + video_id: Unique video identifier (e.g., 'video1', '20251021_083858') + + Returns: + Video object if found, None otherwise + """ + session = self.get_session() + try: + db_video = session.query(VideoModel).filter(VideoModel.video_id == video_id).first() + if db_video: + return self._db_to_domain(db_video) + return None + except SQLAlchemyError as e: + logger.error(f"Error fetching video {video_id}: {e}") + return None + finally: + session.close() + + def create_video( + self, + video_id: str, + title: str, + video_path: str, + description: str = "", + thumbnail_path: str = "assets/thumbail.png", + sigml_content: str = "", # NEW - Primary source + source: str = "upload", + is_demo: bool = False, + is_published: bool = False, + sigml_path: Optional[str] = None # DEPRECATED + ) -> Optional[int]: + """Create a new video record. + + Args: + video_id: Unique identifier + title: Video title + video_path: Path to video file + description: Video description + thumbnail_path: Path to thumbnail + sigml_content: SiGML XML content (NEW - stored in DB) + source: 'demo' or 'upload' + is_demo: Whether this is a demo video + is_published: Whether to show in hub + sigml_path: Optional path to SiGML file (DEPRECATED) + + Returns: + Database ID of created video, or None if failed + """ + session = self.get_session() + try: + new_video = VideoModel( + video_id=video_id, + title=title, + description=description, + video_path=video_path, + thumbnail_path=thumbnail_path, + sigml_content=sigml_content, # NEW + sigml_path=sigml_path, # DEPRECATED - kept for backward compatibility + has_sigml=bool(sigml_content or sigml_path), + source=source, + is_demo=is_demo, + is_published=is_published + ) + session.add(new_video) + session.commit() + video_db_id = new_video.id + logger.info(f"Video created: {video_id} (DB ID: {video_db_id})") + return video_db_id + except SQLAlchemyError as e: + session.rollback() + logger.error(f"Error creating video {video_id}: {e}") + return None + finally: + session.close() + + def update_video_sigml(self, video_id: str, sigml_path: str) -> bool: + """Update SiGML path for a video. + + Args: + video_id: Video identifier + sigml_path: Path to SiGML file + + Returns: + True if updated successfully, False otherwise + """ + session = self.get_session() + try: + video = session.query(VideoModel).filter(VideoModel.video_id == video_id).first() + if video: + video.sigml_path = sigml_path + video.has_sigml = True + session.commit() + logger.info(f"Updated SiGML path for video {video_id}") + return True + return False + except SQLAlchemyError as e: + session.rollback() + logger.error(f"Error updating SiGML for video {video_id}: {e}") + return False + finally: + session.close() + + def update_video_published(self, video_id: str, is_published: bool) -> bool: + """Update published status of a video. + + Args: + video_id: Video identifier + is_published: Whether to publish + + Returns: + True if updated successfully, False otherwise + """ + session = self.get_session() + try: + video = session.query(VideoModel).filter(VideoModel.video_id == video_id).first() + if video: + video.is_published = is_published + session.commit() + logger.info(f"Updated published status for video {video_id}: {is_published}") + return True + return False + except SQLAlchemyError as e: + session.rollback() + logger.error(f"Error updating published status for video {video_id}: {e}") + return False + finally: + session.close() + + def get_db_id_by_video_id(self, video_id: str) -> Optional[int]: + """Get database primary key ID by video_id. + + Args: + video_id: Video identifier + + Returns: + Database ID or None if not found + """ + session = self.get_session() + try: + video = session.query(VideoModel).filter(VideoModel.video_id == video_id).first() + return video.id if video else None + except SQLAlchemyError as e: + logger.error(f"Error fetching DB ID for video {video_id}: {e}") + return None + finally: + session.close() + + def add_processing_history( + self, + video_db_id: int, + transcript_content: str = "", # NEW - Primary source + gloss_content: str = "", # NEW - Primary source + segments_json: Optional[dict] = None, # NEW - Primary source + transcript_path: str = "", # DEPRECATED + gloss_path: str = "", # DEPRECATED + sigml_path: str = "", # DEPRECATED + segments_path: Optional[str] = None, # DEPRECATED + total_duration_ms: Optional[int] = None, + transcript_length: Optional[int] = None, + sigml_sign_count: Optional[int] = None, + missing_token_count: Optional[int] = None, + status: str = "completed", + error_message: Optional[str] = None + ) -> bool: + """Add processing history record. + + Args: + video_db_id: Database ID of video + transcript_content: Transcript text content (NEW) + gloss_content: Gloss text content (NEW) + segments_json: Segments as JSON dict (NEW) + transcript_path: Path to transcript file (DEPRECATED) + gloss_path: Path to gloss file (DEPRECATED) + sigml_path: Path to SiGML file (DEPRECATED) + segments_path: Optional path to segments JSON (DEPRECATED) + total_duration_ms: Total processing time + transcript_length: Character count + sigml_sign_count: Number of signs generated + missing_token_count: Number of missing tokens + status: Processing status + error_message: Error message if failed + + Returns: + True if successful, False otherwise + """ + session = self.get_session() + try: + history = ProcessingHistory( + video_id=video_db_id, + transcript_content=transcript_content, # NEW + gloss_content=gloss_content, # NEW + segments_json=segments_json, # NEW + transcript_path=transcript_path, # DEPRECATED + gloss_path=gloss_path, # DEPRECATED + sigml_path=sigml_path, # DEPRECATED + segments_path=segments_path, # DEPRECATED + total_duration_ms=total_duration_ms, + transcript_length=transcript_length, + sigml_sign_count=sigml_sign_count, + missing_token_count=missing_token_count, + status=status, + error_message=error_message, + completed_at=datetime.now() + ) + session.add(history) + session.commit() + logger.info(f"Processing history added for video ID {video_db_id}") + return True + except SQLAlchemyError as e: + session.rollback() + logger.error(f"Error adding processing history: {e}") + return False + finally: + session.close() + + def _db_to_domain(self, db_video: VideoModel) -> Video: + """Convert database model to domain model. + + Args: + db_video: SQLAlchemy Video model + + Returns: + Domain Video model + """ + return Video( + id=db_video.video_id, + title=db_video.title, + video_path=db_video.video_path, + sigml_source="db", # Changed from "file" to "db" + sigml_text="", # DEPRECATED + sigml_content=db_video.sigml_content or "", # NEW - Primary source + sigml_path=db_video.sigml_path or "", # DEPRECATED - Path to SiGML file + duration="00:00", # Can be computed if needed + thumbnail=db_video.thumbnail_path or "assets/thumbail.png" + ) + + def close(self): + """Close database connection.""" + self.engine.dispose() + logger.info("VideoRepository connection closed") + diff --git a/src/repositories/vocabulary_repository.py b/src/repositories/vocabulary_repository.py new file mode 100644 index 0000000..81a007e --- /dev/null +++ b/src/repositories/vocabulary_repository.py @@ -0,0 +1,258 @@ +""" +Vocabulary Repository: Quản lý từ vựng ký hiệu trong database + +Thay thế: seed_vocabulary.json (file-based) → VocabularyRepository (database-based) + +Chức năng chính: +- Lưu trữ ánh xạ từ tiếng Việt → Gloss (ký hiệu chuẩn) +- Hỗ trợ từ đồng nghĩa (synonyms array) +- Theo dõi mức độ sử dụng để tối ưu hóa +- Cache trong memory để tăng tốc độ tra cứu + +Sử dụng bởi: Text2GlossProcessor để convert text → gloss +""" + +import logging +from typing import List, Dict, Optional +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker, Session +from sqlalchemy.exc import SQLAlchemyError +from datetime import datetime + +from src.models.db_models import Base, SignVocabulary + +logger = logging.getLogger(__name__) + + +class VocabularyRepository: + """ + Repository cho từ vựng ngôn ngữ ký hiệu Việt Nam + + Chức năng: + - CRUD operations cho từ vựng (create, read, update, delete) + - Cache trong memory để tăng tốc độ tra cứu + - Hỗ trợ bulk import từ file CSV/JSON + - Theo dõi usage_count cho analytics + """ + + def __init__(self, database_url: str): + """ + Khởi tạo kết nối database và cache + + Args: + database_url: Chuỗi kết nối PostgreSQL + """ + self.database_url = database_url + self.engine = create_engine(database_url, echo=False) + self.SessionLocal = sessionmaker(bind=self.engine) + self._cache: Optional[List[Dict]] = None + + logger.info(f"VocabularyRepository initialized") + + def get_session(self) -> Session: + """Get a new database session.""" + return self.SessionLocal() + + def get_all(self, use_cache: bool = True) -> List[Dict]: + """Get all vocabulary entries. + + Args: + use_cache: Whether to use in-memory cache + + Returns: + List of vocabulary dictionaries + """ + if use_cache and self._cache is not None: + return self._cache + + session = self.get_session() + try: + entries = session.query(SignVocabulary).all() + result = [self._db_to_dict(e) for e in entries] + + if use_cache: + self._cache = result + logger.info(f"Vocabulary cache loaded: {len(result)} entries") + + return result + except SQLAlchemyError as e: + logger.error(f"Error fetching vocabulary: {e}") + return [] + finally: + session.close() + + def get_by_word(self, word: str) -> Optional[Dict]: + """Get vocabulary entry by word. + + Args: + word: Word to look up + + Returns: + Vocabulary dictionary or None + """ + session = self.get_session() + try: + entry = session.query(SignVocabulary).filter(SignVocabulary.word == word).first() + return self._db_to_dict(entry) if entry else None + except SQLAlchemyError as e: + logger.error(f"Error fetching word '{word}': {e}") + return None + finally: + session.close() + + def search_by_synonym(self, synonym: str) -> List[Dict]: + """Search vocabulary by synonym. + + Args: + synonym: Synonym to search for + + Returns: + List of matching vocabulary entries + """ + session = self.get_session() + try: + # PostgreSQL array contains operator + entries = session.query(SignVocabulary).filter( + SignVocabulary.synonyms.contains([synonym]) + ).all() + return [self._db_to_dict(e) for e in entries] + except SQLAlchemyError as e: + logger.error(f"Error searching synonym '{synonym}': {e}") + return [] + finally: + session.close() + + def create_entry( + self, + word: str, + gloss: str, + synonyms: Optional[List[str]] = None, + category: Optional[str] = None, + source: str = "manual" + ) -> bool: + """Create a new vocabulary entry. + + Args: + word: Word/phrase + gloss: Gloss translation + synonyms: List of synonyms + category: Optional category + source: Source of entry ('manual', 'seed', 'imported') + + Returns: + True if successful, False otherwise + """ + session = self.get_session() + try: + entry = SignVocabulary( + word=word, + gloss=gloss, + synonyms=synonyms or [], + category=category, + source=source + ) + session.add(entry) + session.commit() + + # Invalidate cache + self._cache = None + + logger.info(f"Vocabulary entry created: {word}") + return True + except SQLAlchemyError as e: + session.rollback() + logger.error(f"Error creating vocabulary entry '{word}': {e}") + return False + finally: + session.close() + + def increment_usage(self, word: str) -> bool: + """Increment usage count for a vocabulary entry. + + Args: + word: Word to update + + Returns: + True if successful, False otherwise + """ + session = self.get_session() + try: + entry = session.query(SignVocabulary).filter(SignVocabulary.word == word).first() + if entry: + entry.usage_count += 1 + entry.last_used_at = datetime.now() + session.commit() + return True + return False + except SQLAlchemyError as e: + session.rollback() + logger.error(f"Error incrementing usage for '{word}': {e}") + return False + finally: + session.close() + + def bulk_create(self, entries: List[Dict]) -> int: + """Bulk create vocabulary entries. + + Args: + entries: List of vocabulary dictionaries + Each dict should have: word, gloss, synonyms (optional) + + Returns: + Number of entries created successfully + """ + session = self.get_session() + count = 0 + try: + for entry_data in entries: + entry = SignVocabulary( + word=entry_data['word'], + gloss=entry_data['gloss'], + synonyms=entry_data.get('synonyms', []), + category=entry_data.get('category'), + source=entry_data.get('source', 'seed') + ) + session.add(entry) + count += 1 + + session.commit() + + # Invalidate cache + self._cache = None + + logger.info(f"Bulk created {count} vocabulary entries") + return count + except SQLAlchemyError as e: + session.rollback() + logger.error(f"Error in bulk create: {e}") + return count + finally: + session.close() + + def invalidate_cache(self): + """Invalidate the in-memory cache.""" + self._cache = None + logger.info("Vocabulary cache invalidated") + + def _db_to_dict(self, entry: SignVocabulary) -> Dict: + """Convert database model to dictionary. + + Args: + entry: SQLAlchemy SignVocabulary model + + Returns: + Dictionary representation + """ + return { + 'word': entry.word, + 'gloss': entry.gloss, + 'synonyms': entry.synonyms or [], + 'category': entry.category, + 'usage_count': entry.usage_count + } + + def close(self): + """Close database connection.""" + self.engine.dispose() + logger.info("VocabularyRepository connection closed") + diff --git a/src/services/pipeline_service.py b/src/services/pipeline_service.py index 29245b8..d4f0a26 100644 --- a/src/services/pipeline_service.py +++ b/src/services/pipeline_service.py @@ -31,6 +31,17 @@ class PipelineResult: gloss_path: str sigml_path: str segments_path: Optional[str] = None + + # NEW: Content fields (for database storage) + transcript_text: Optional[str] = None + gloss_text: Optional[str] = None + sigml_content: Optional[str] = None + segments_json: Optional[dict] = None + + # Processing metadata + processing_time: Optional[float] = None + missing_tokens: Optional[list] = None + error_message: Optional[str] = None @@ -150,6 +161,32 @@ def process_video( raise PipelineError(f"Gloss-to-SiGML generation failed: {e}") from e logger.info("Pipeline completed successfully") + + # Read generated content for database storage + transcript_text = "" + gloss_text = "" + sigml_content = "" + segments_json = None + + try: + if os.path.exists(transcript_path): + with open(transcript_path, 'r', encoding='utf-8') as f: + transcript_text = f.read() + + if os.path.exists(gloss_path): + with open(gloss_path, 'r', encoding='utf-8') as f: + gloss_text = f.read() + + if os.path.exists(sigml_path): + with open(sigml_path, 'r', encoding='utf-8') as f: + sigml_content = f.read() + + if os.path.exists(segments_path): + import json + with open(segments_path, 'r', encoding='utf-8') as f: + segments_json = json.load(f) + except Exception as e: + logger.warning(f"Failed to read generated content for DB: {e}") return PipelineResult( success=True, @@ -157,6 +194,10 @@ def process_video( gloss_path=gloss_path, sigml_path=sigml_path, segments_path=segments_path, + transcript_text=transcript_text, # NEW + gloss_text=gloss_text, # NEW + sigml_content=sigml_content, # NEW + segments_json=segments_json, # NEW error_message=None, ) diff --git a/src/services/video_service.py b/src/services/video_service.py index 6695750..3776add 100644 --- a/src/services/video_service.py +++ b/src/services/video_service.py @@ -1,7 +1,19 @@ """ -Video service for video processing and management. +Video Service: Business logic cho xử lý và quản lý video -Extracts business logic from Flask routes, providing reusable video operations. +Vai trò: Tách logic nghiệp vụ ra khỏi Flask routes (theo nguyên tắc Separation of Concerns) + +Chức năng chính: +- Upload video và xử lý qua AI pipeline (STT → Text2Gloss → Gloss2SiGML) +- Thêm video vào Learning Hub (publish/unpublish) +- Chuẩn bị dữ liệu để hiển thị video + avatar +- Tương tác với VideoRepository để lưu/đọc DB + +Flow: +1. User upload video → save file +2. Tạo record trong DB (videos table) +3. Xử lý qua pipeline → lưu SiGML content vào DB +4. Ghi lại processing_history """ import os @@ -13,7 +25,7 @@ from ..config import AppConfig from ..models import Video -from ..repositories import ManifestRepository +from ..repositories.video_repository import VideoRepository from ..services.pipeline_service import ProcessingPipeline, PipelineResult from ..services.file_service import FileService from ..exceptions import SignBridgeError, ValidationError @@ -41,40 +53,62 @@ class VideoViewingData: class VideoService: - """Service for video processing and management business logic.""" + """ + Service cho xử lý video và quản lý business logic + + Nhiệm vụ: + - Xử lý video upload: validate → save file → run pipeline → lưu DB + - Publish video lên Learning Hub + - Chuẩn bị dữ liệu để render video + avatar SiGML + + Dependencies: + - VideoRepository: CRUD operations với DB + - ProcessingPipeline: AI pipeline (STT → Gloss → SiGML) + - FileService: Lưu/đọc file an toàn + """ def __init__( self, config: AppConfig, pipeline_service: ProcessingPipeline, file_service: FileService, - manifest_repository: ManifestRepository + video_repository: VideoRepository ): - """Initialize video service. + """ + Khởi tạo VideoService với các dependencies cần thiết Args: - config: Application configuration - pipeline_service: Processing pipeline service - file_service: File operations service - manifest_repository: Manifest repository + config: Cấu hình ứng dụng (paths, settings) + pipeline_service: Service xử lý AI pipeline + file_service: Service thao tác file + video_repository: Repository tương tác DB """ self.config = config self.pipeline_service = pipeline_service self.file_service = file_service - self.manifest_repository = manifest_repository + self.video_repository = video_repository def upload_and_process(self, video_file: FileStorage) -> VideoUploadResult: - """Upload video file and process through pipeline. + """ + Upload video và xử lý qua AI pipeline + + Flow: + 1. Validate file (size, extension) + 2. Lưu file vào static/uploads/ + 3. Tạo record trong DB (videos table) + 4. Xử lý qua pipeline: STT → Text2Gloss → Gloss2SiGML + 5. Lưu nội dung SiGML vào DB + 6. Ghi lại processing_history Args: - video_file: Uploaded video file from Flask request + video_file: File video từ Flask request (form upload) Returns: - VideoUploadResult with processing results + VideoUploadResult chứa kết quả xử lý Raises: - ValidationError: If video file is invalid - SignBridgeError: If processing fails + ValidationError: File không hợp lệ (size, extension) + SignBridgeError: Pipeline xử lý thất bại """ # Validate video file if not video_file or video_file.filename == "": @@ -90,14 +124,45 @@ def upload_and_process(self, video_file: FileStorage) -> VideoUploadResult: video_file.save(save_path) logger.info(f"Video uploaded: {video_filename}") + # Create video record in database + video_id = timestamp # Use timestamp as video_id + relative_video_path = f"static/uploads/{video_filename}" + + db_id = self.video_repository.create_video( + video_id=video_id, + title=f"Uploaded Video {timestamp[:8]}", + description=f"Uploaded on {datetime.now().strftime('%Y-%m-%d %H:%M')}", + video_path=relative_video_path, + sigml_content="", # Will be updated after processing + source='upload', + is_demo=False, + is_published=False + ) + + if not db_id: + logger.warning(f"Failed to create video record in DB for {video_id}") + else: + logger.info(f"Video record created in DB with ID: {db_id}") + # Process through pipeline result = self.pipeline_service.process_video( video_path=save_path, timestamp=timestamp, - fallback_on_error=True # Backward compatibility + fallback_on_error=False ) if not result.success: + # Update video record with error + if db_id: + self.video_repository.add_processing_history( + video_db_id=db_id, + transcript_path="", + gloss_path="", + sigml_path="", + status='failed', + error_message=result.error_message + ) + return VideoUploadResult( success=False, video_filename=video_filename, @@ -108,13 +173,49 @@ def upload_and_process(self, video_file: FileStorage) -> VideoUploadResult: # Extract filenames from paths sigml_filename = os.path.basename(result.sigml_path) + # Update video record with SiGML content (NEW - Primary source) + if db_id and result.sigml_content: + # Update videos table with SiGML content + session = self.video_repository.get_session() + try: + from sqlalchemy import text + session.execute( + text("UPDATE videos SET sigml_content = :content, has_sigml = TRUE WHERE video_id = :vid"), + {"content": result.sigml_content, "vid": video_id} + ) + session.commit() + logger.info(f"SiGML content saved to DB for video {video_id} ({len(result.sigml_content)} bytes)") + except Exception as e: + session.rollback() + logger.error(f"Failed to save SiGML content to DB: {e}") + finally: + session.close() + + # Add processing history with content (NEW) + self.video_repository.add_processing_history( + video_db_id=db_id, + transcript_content=result.transcript_text or "", # NEW + gloss_content=result.gloss_text or "", # NEW + segments_json=result.segments_json, # NEW + transcript_path=result.transcript_path, # DEPRECATED + gloss_path=result.gloss_path, # DEPRECATED + sigml_path=result.sigml_path, # DEPRECATED + segments_path=result.segments_path, # DEPRECATED + total_duration_ms=int(result.processing_time * 1000) if result.processing_time else None, + transcript_length=len(result.transcript_text) if result.transcript_text else None, + sigml_sign_count=result.sigml_content.count(' VideoUploadResult: logger.error(f"Video upload and processing failed: {e}") raise SignBridgeError(f"Failed to process video: {e}") from e - def add_to_learning_hub( - self, - video_filename: str, - sigml_filename: str, - title: str = "Video mới" - ) -> str: - """Add processed video to learning hub. - - Args: - video_filename: Video file name in uploads directory - sigml_filename: SiGML file name in out directory - title: Video title - - Returns: - Generated video ID - - Raises: - ValidationError: If required files are missing - SignBridgeError: If operation fails - """ - if not video_filename or not sigml_filename: - raise ValidationError("Missing video or SiGML filename") - - try: - # Copy video from uploads to assets - upload_path = os.path.join(self.config.upload_dir, video_filename) - asset_path = os.path.join(self.config.assets_dir, video_filename) - - if not os.path.isfile(upload_path): - raise ValidationError(f"Video file not found: {video_filename}") - - self.file_service.copy_file(upload_path, asset_path) - - # Read SiGML content - sigml_path = os.path.join(self.config.out_dir, sigml_filename) - sigml_content = "" - if os.path.isfile(sigml_path): - sigml_content = self.file_service.read_file(sigml_path) - - # Generate video ID - video_id = self.manifest_repository.generate_video_id() - - # Create video model - new_video = Video( - id=video_id, - title=title, - video_path=f"assets/{video_filename}", - sigml_source="inline", - sigml_text=sigml_content, - duration="00:00", - thumbnail="assets/thumbail.png" - ) - - # Add to manifest - self.manifest_repository.add_video(new_video) - - logger.info(f"Video added to learning hub: {video_id}") - return video_id - - except Exception as e: - logger.error(f"Failed to add video to learning hub: {e}") - raise SignBridgeError(f"Failed to add video to hub: {e}") from e - def get_video_for_viewing(self, video_id: str) -> VideoViewingData: """Get video data for viewing. @@ -199,31 +237,51 @@ def get_video_for_viewing(self, video_id: str) -> VideoViewingData: SignBridgeError: If operation fails """ try: - # Get video from repository - video = self.manifest_repository.get_video_by_id(video_id) + # Get video from database + video = self.video_repository.get_video_by_id(video_id) if not video: raise ValidationError(f"Video not found: {video_id}") # Determine video URL if video.video_path: - video_rel_path = video.video_path.split('assets/')[-1] - video_url = f"/assets/{video_rel_path}" + if 'assets/' in video.video_path: + video_rel_path = video.video_path.split('assets/')[-1] + video_url = f"/assets/{video_rel_path}" + elif 'static/uploads/' in video.video_path: + video_filename = video.video_path.split('static/uploads/')[-1] + video_url = f"/static/uploads/{video_filename}" + else: + video_url = video.video_path else: video_url = "" - # Prepare SiGML file - sigml_filename = f"{video_id}.sigml" + # SiGML filename - use from DB if available, otherwise default + if hasattr(video, 'sigml_path') and video.sigml_path: + # Database has sigml_path (e.g., "out/video1.sigml") + if video.sigml_path.startswith('out/'): + sigml_filename = video.sigml_path.split('out/')[-1] + else: + sigml_filename = os.path.basename(video.sigml_path) + else: + # Fallback to default naming + sigml_filename = f"{video_id}.sigml" + sigml_path = os.path.join(self.config.out_dir, sigml_filename) - # Write inline SiGML to file if present - if video.sigml_source == "inline" and video.sigml_text: + # For backward compatibility: write inline SiGML to file if present + if hasattr(video, 'sigml_text') and video.sigml_text: try: with open(sigml_path, "w", encoding="utf-8") as f: f.write(video.sigml_text) + logger.info(f"Wrote inline SiGML to file: {sigml_path}") except Exception as e: logger.warning(f"Failed to write SiGML file: {e}") + # Verify SiGML file exists + if not os.path.exists(sigml_path): + logger.warning(f"SiGML file not found: {sigml_path}") + logger.info(f"Video prepared for viewing: {video_id}") return VideoViewingData( diff --git a/static/uploads/vid_20251015_234315.mp4 b/static/uploads/vid_20251015_234315.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251015_234315.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251015_234317.mp4 b/static/uploads/vid_20251015_234317.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251015_234317.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251015_234443.mp4 b/static/uploads/vid_20251015_234443.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251015_234443.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251015_234445.mp4 b/static/uploads/vid_20251015_234445.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251015_234445.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251015_234506.mp4 b/static/uploads/vid_20251015_234506.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251015_234506.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251015_235333.mp4 b/static/uploads/vid_20251015_235333.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251015_235333.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_002018.mp4 b/static/uploads/vid_20251016_002018.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251016_002018.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_002019.mp4 b/static/uploads/vid_20251016_002019.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251016_002019.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_002137.mp4 b/static/uploads/vid_20251016_002137.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251016_002137.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_004118.mp4 b/static/uploads/vid_20251016_004118.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251016_004118.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_004436.mp4 b/static/uploads/vid_20251016_004436.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251016_004436.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_004918.mp4 b/static/uploads/vid_20251016_004918.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251016_004918.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_005419.mp4 b/static/uploads/vid_20251016_005419.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251016_005419.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_005421.mp4 b/static/uploads/vid_20251016_005421.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251016_005421.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_005425.mp4 b/static/uploads/vid_20251016_005425.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251016_005425.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_005426.mp4 b/static/uploads/vid_20251016_005426.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251016_005426.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_005433.mp4 b/static/uploads/vid_20251016_005433.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251016_005433.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_005803.mp4 b/static/uploads/vid_20251016_005803.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251016_005803.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_010243.mp4 b/static/uploads/vid_20251016_010243.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251016_010243.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_010643.mp4 b/static/uploads/vid_20251016_010643.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251016_010643.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_011344.mp4 b/static/uploads/vid_20251016_011344.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251016_011344.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_012117.mp4 b/static/uploads/vid_20251016_012117.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251016_012117.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_013020.mp4 b/static/uploads/vid_20251016_013020.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251016_013020.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_013159.mp4 b/static/uploads/vid_20251016_013159.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251016_013159.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_014053.mp4 b/static/uploads/vid_20251016_014053.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251016_014053.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_014129.mp4 b/static/uploads/vid_20251016_014129.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251016_014129.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_014230.mp4 b/static/uploads/vid_20251016_014230.mp4 deleted file mode 100644 index 988d325..0000000 Binary files a/static/uploads/vid_20251016_014230.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_123412.mp4 b/static/uploads/vid_20251016_123412.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251016_123412.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_123413.mp4 b/static/uploads/vid_20251016_123413.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251016_123413.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_123843.mp4 b/static/uploads/vid_20251016_123843.mp4 deleted file mode 100644 index 418ef09..0000000 Binary files a/static/uploads/vid_20251016_123843.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_134212.mp4 b/static/uploads/vid_20251016_134212.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_134212.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_134214.mp4 b/static/uploads/vid_20251016_134214.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_134214.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_134222.mp4 b/static/uploads/vid_20251016_134222.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_134222.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_134229.mp4 b/static/uploads/vid_20251016_134229.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_134229.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_135126.mp4 b/static/uploads/vid_20251016_135126.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_135126.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_135816.mp4 b/static/uploads/vid_20251016_135816.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_135816.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_141732.mp4 b/static/uploads/vid_20251016_141732.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_141732.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_143517.mp4 b/static/uploads/vid_20251016_143517.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_143517.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_143519.mp4 b/static/uploads/vid_20251016_143519.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_143519.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_143528.mp4 b/static/uploads/vid_20251016_143528.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_143528.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_143535.mp4 b/static/uploads/vid_20251016_143535.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_143535.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_145706.mp4 b/static/uploads/vid_20251016_145706.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_145706.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_145708.mp4 b/static/uploads/vid_20251016_145708.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_145708.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_145712.mp4 b/static/uploads/vid_20251016_145712.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_145712.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_145741.mp4 b/static/uploads/vid_20251016_145741.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_145741.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_150450.mp4 b/static/uploads/vid_20251016_150450.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_150450.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_151054.mp4 b/static/uploads/vid_20251016_151054.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_151054.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_151118.mp4 b/static/uploads/vid_20251016_151118.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_151118.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_151331.mp4 b/static/uploads/vid_20251016_151331.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_151331.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_151647.mp4 b/static/uploads/vid_20251016_151647.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_151647.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_151658.mp4 b/static/uploads/vid_20251016_151658.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_151658.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_152357.mp4 b/static/uploads/vid_20251016_152357.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_152357.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_152540.mp4 b/static/uploads/vid_20251016_152540.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_152540.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_152834.mp4 b/static/uploads/vid_20251016_152834.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_152834.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_153057.mp4 b/static/uploads/vid_20251016_153057.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_153057.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_153507.mp4 b/static/uploads/vid_20251016_153507.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_153507.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_153510.mp4 b/static/uploads/vid_20251016_153510.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_153510.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_153700.mp4 b/static/uploads/vid_20251016_153700.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_153700.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_153701.mp4 b/static/uploads/vid_20251016_153701.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_153701.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_153705.mp4 b/static/uploads/vid_20251016_153705.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_153705.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_153708.mp4 b/static/uploads/vid_20251016_153708.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_153708.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_154825.mp4 b/static/uploads/vid_20251016_154825.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_154825.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_155229.mp4 b/static/uploads/vid_20251016_155229.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_155229.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_160110.mp4 b/static/uploads/vid_20251016_160110.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_160110.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_160112.mp4 b/static/uploads/vid_20251016_160112.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_160112.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_160118.mp4 b/static/uploads/vid_20251016_160118.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_160118.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_160129.mp4 b/static/uploads/vid_20251016_160129.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_160129.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_160617.mp4 b/static/uploads/vid_20251016_160617.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_160617.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_160709.mp4 b/static/uploads/vid_20251016_160709.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_160709.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_160846.mp4 b/static/uploads/vid_20251016_160846.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_160846.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_161150.mp4 b/static/uploads/vid_20251016_161150.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_161150.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_161228.mp4 b/static/uploads/vid_20251016_161228.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_161228.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_161519.mp4 b/static/uploads/vid_20251016_161519.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_161519.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_161900.mp4 b/static/uploads/vid_20251016_161900.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_161900.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_162133.mp4 b/static/uploads/vid_20251016_162133.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_162133.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_162745.mp4 b/static/uploads/vid_20251016_162745.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_162745.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_163021.mp4 b/static/uploads/vid_20251016_163021.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_163021.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_163248.mp4 b/static/uploads/vid_20251016_163248.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_163248.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_163347.mp4 b/static/uploads/vid_20251016_163347.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_163347.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_163725.mp4 b/static/uploads/vid_20251016_163725.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_163725.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_163727.mp4 b/static/uploads/vid_20251016_163727.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_163727.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_163748.mp4 b/static/uploads/vid_20251016_163748.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_163748.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_165823.mp4 b/static/uploads/vid_20251016_165823.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_165823.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_170055.mp4 b/static/uploads/vid_20251016_170055.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_170055.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_170231.mp4 b/static/uploads/vid_20251016_170231.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_170231.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_170233.mp4 b/static/uploads/vid_20251016_170233.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_170233.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_170237.mp4 b/static/uploads/vid_20251016_170237.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_170237.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251016_170248.mp4 b/static/uploads/vid_20251016_170248.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251016_170248.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251018_105148.mp4 b/static/uploads/vid_20251018_105148.mp4 deleted file mode 100644 index 6d1ca13..0000000 Binary files a/static/uploads/vid_20251018_105148.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251018_105157.mp4 b/static/uploads/vid_20251018_105157.mp4 deleted file mode 100644 index 6d1ca13..0000000 Binary files a/static/uploads/vid_20251018_105157.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251018_105300.mp4 b/static/uploads/vid_20251018_105300.mp4 deleted file mode 100644 index 6d1ca13..0000000 Binary files a/static/uploads/vid_20251018_105300.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251018_105829.mp4 b/static/uploads/vid_20251018_105829.mp4 deleted file mode 100644 index 6d1ca13..0000000 Binary files a/static/uploads/vid_20251018_105829.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251018_105853.mp4 b/static/uploads/vid_20251018_105853.mp4 deleted file mode 100644 index 6d1ca13..0000000 Binary files a/static/uploads/vid_20251018_105853.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251018_110507.mp4 b/static/uploads/vid_20251018_110507.mp4 deleted file mode 100644 index 6d1ca13..0000000 Binary files a/static/uploads/vid_20251018_110507.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251018_110630.mp4 b/static/uploads/vid_20251018_110630.mp4 deleted file mode 100644 index 6d1ca13..0000000 Binary files a/static/uploads/vid_20251018_110630.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251018_110641.mp4 b/static/uploads/vid_20251018_110641.mp4 deleted file mode 100644 index 2680d5c..0000000 Binary files a/static/uploads/vid_20251018_110641.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251018_110948.mp4 b/static/uploads/vid_20251018_110948.mp4 deleted file mode 100644 index 88eb70e..0000000 Binary files a/static/uploads/vid_20251018_110948.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251018_111344.mp4 b/static/uploads/vid_20251018_111344.mp4 deleted file mode 100644 index 88eb70e..0000000 Binary files a/static/uploads/vid_20251018_111344.mp4 and /dev/null differ diff --git a/static/uploads/vid_20251018_111705.mp4 b/static/uploads/vid_20251018_111705.mp4 deleted file mode 100644 index 88eb70e..0000000 Binary files a/static/uploads/vid_20251018_111705.mp4 and /dev/null differ diff --git a/templates/hub.html b/templates/hub.html deleted file mode 100644 index da97089..0000000 --- a/templates/hub.html +++ /dev/null @@ -1,236 +0,0 @@ - - - - - - SignBridge | Learning Hub - - - - - -
-
-

AI cho giáo dục hòa nhập

-

Chuyển giọng nói thành ký hiệu, mở cánh cửa tri thức.

- -
-
- -
-
- -
-

Kho học tập chính (Learning Hub)

-
- {% for v in videos %} -
-
- {{ loop.index }} • {{ v.title[:24] }}{% if v.title|length > 24 %}…{% - endif %} -
-
-
{{ v.title }}
-
{{ v.desc }}
-
-
VSL
-
Avatar 3D
-
Demo
-
-
- Xem - Mở tab -
-
-
- {% endfor %} -
-
- - - - - diff --git a/templates/index.html b/templates/index.html index 4b65ced..5124ff5 100644 --- a/templates/index.html +++ b/templates/index.html @@ -58,7 +58,7 @@

AI cho giáo dục hòa nhập

target="_blank" >Watch Demo - Try Now @@ -334,15 +334,7 @@

Interactive Demo Section

- +

Hôm nay chưa học

[Hôm nay] Chúng ta học...

@@ -715,8 +707,6 @@

try { const uploadInput = document.getElementById("uploadVideo"); const uploadForm = document.getElementById("uploadForm"); - const previewOverlay = document.getElementById("previewOverlay"); - const btnAddHub = document.getElementById("btnAddHub"); const interactiveFrame = document.getElementById("interactiveFrame"); let currentVideo = null; @@ -740,76 +730,40 @@

}); } - // Listen for iframe load to show "Add to Hub" button + // Listen for iframe load if (interactiveFrame) { interactiveFrame.addEventListener("load", function () { try { const src = interactiveFrame.src || ""; - if (src.includes("/preview?")) { - // Hide loading indicator with a small delay - setTimeout(() => { - if (loadingIndicator) { - loadingIndicator.style.display = "none"; - console.log("Loading indicator hidden"); - } - }, 500); + console.log("[DEBUG] Iframe loaded with src:", src); + + // Always hide loading indicator when iframe loads ANY content + setTimeout(() => { + if (loadingIndicator) { + loadingIndicator.style.display = "none"; + console.log("Loading indicator hidden"); + } + }, 500); + // Check if it's a preview page (has video + sigml) + if (src.includes("/preview")) { // Extract video and sigml from URL const url = new URL(src, window.location.origin); currentVideo = url.searchParams.get("video"); currentSigml = url.searchParams.get("sigml"); - if (currentVideo && currentSigml && previewOverlay) { - previewOverlay.style.display = "flex"; - } - } - } catch (_) {} - }); - } - - // Handle "Add to Hub" button click - if (btnAddHub) { - btnAddHub.addEventListener("click", async function () { - if (!currentVideo || !currentSigml) { - alert("Không có video để thêm"); - return; - } - - const title = prompt("Nhập tiêu đề cho video:", "Video mới"); - if (!title) return; - - try { - btnAddHub.disabled = true; - btnAddHub.textContent = "Đang thêm..."; - - const formData = new FormData(); - formData.append("video", currentVideo); - formData.append("sigml", currentSigml); - formData.append("title", title); - - const response = await fetch("/add_to_hub", { - method: "POST", - body: formData, - }); - - const result = await response.json(); - - if (result.success) { - alert("Đã thêm vào Learning Hub!"); - previewOverlay.style.display = "none"; - location.reload(); // Reload to show new video in hub - } else { - alert("Lỗi: " + (result.error || "Unknown error")); - btnAddHub.disabled = false; - btnAddHub.textContent = "+ Add to Learning Hub"; } } catch (e) { - alert("Lỗi kết nối: " + e.message); - btnAddHub.disabled = false; - btnAddHub.textContent = "+ Add to Learning Hub"; + console.error("[DEBUG] Error in iframe load handler:", e); + // Hide loading even on error + if (loadingIndicator) { + loadingIndicator.style.display = "none"; + } } }); } + + // Add to Hub feature removed - videos now auto-saved to database } catch (_) {} })(); diff --git a/templates/result.html b/templates/result.html index 4d7fbd4..c63fabf 100644 --- a/templates/result.html +++ b/templates/result.html @@ -178,7 +178,13 @@ if (data.type === 'host-exit') { try { document.body.classList.remove('is-fs'); } catch(e){} } }); } catch(e){} + + // NEW: Use API endpoint if video_id is available (database-backed), otherwise fallback to file + {% if video_id %} + const sigmlUrl = "{{ url_for('get_sigml_content', video_id=video_id) }}"; + {% else %} const sigmlUrl = "{{ url_for('serve_out', filename=sigml) }}"; + {% endif %} const absSigmlUrl = window.location.origin + sigmlUrl; document.getElementById('copyUrl').addEventListener('click', async () => { try { @@ -196,10 +202,10 @@ let currentIdx = -1; let hasStartedOnce = false; let pendingTimer = null; - const START_DELAY_MS = 1500; // trễ trước khi avatar bắt đầu - const INTER_SEGMENT_DELAY_MS = 500; // dừng 0.5s giữa các từ/segment - const BASE_SIGN_DUR = 0.8; // ước lượng 0.8s mỗi ký hiệu - const INTER_SIGN_PAUSE = 0.5; // 0.5s giữa ký hiệu + const START_DELAY_MS = 800; // trễ trước khi avatar bắt đầu + const INTER_SEGMENT_DELAY_MS = 100; // dừng 0.1s giữa các từ/segment + const BASE_SIGN_DUR = 0.3; // ước lượng 0.3s mỗi ký hiệu + const INTER_SIGN_PAUSE = 0.2; // 0.2s giữa ký hiệu const MIN_SEG_DUR = 0.5; // tối thiểu const SPEED_MIN = -5.0, SPEED_MAX = 1.0; // clamp tốc độ // Loop whole-file playback (embed) @@ -238,12 +244,20 @@ const out = []; for (let i=0;i\n${segs[i]}\n` }); + // Skip comment-only segments + if (segs[i].includes('') || segs[i].includes('