Spaces:
Running
Running
Commit History
25 days ago
-
fix(dub): Edge bị chặn 403 không còn kéo VieNeu và cả tool câm theo
Claude +1: Claude Opus 5.5Unverified signatureLỗi trên Space: Microsoft trả 403 khi bắt tay WebSocket với Edge (edge-tts đã là bản mới nhất, nên không phải do thư viện cũ). Tiếng Việt cũng câm vì VieNeu từng nạp hỏng một lần và load_engine gán luôn Edge vào chỗ VieNeu tới lần restart. - load_engine: nạp hỏng thì Edge chỉ đứng TẠM, sau 5 phút nạp lại; nạp model trong khoá để job và việc làm sẵn giọng thử lúc khởi động không nạp song song. - synth_line: Edge cũng hỏng -> en/fil đọc bằng OmniVoice (local), giọng cùng giới tính với giọng Edge đang chọn. - Thêm env EDGE_TTS_PROXY để Edge đi qua proxy khi IP máy chủ bị chặn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RwiJZLUb773B8NwksxfTU98b45574 -
fix(dub): gen voice từ text báo lỗi thật thay vì trả audio câm
Claude +1: Claude Opus 5.5Unverified signatureEngine TTS hỏng (VieNeu nạp lỗi, Edge không gọi được) thì run_tts trả clip lặng 0.4s và job vẫn "xong" -> người dùng chỉ thấy audio 0 giây, không biết vì sao. - /api/dub/tts: clip ra lặng -> báo lỗi kèm nguyên nhân của từng engine. - Giao diện: job không có kết quả thì hiện thông báo lỗi. - synth_line: lỗi của Edge (khi đứng thay engine nạp hỏng) ghi dưới tên "edge", không đè mất lỗi nạp thật của engine gốc. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RwiJZLUb773B8NwksxfTU9bb75713
-
fix(down list): /api/download/start tải song song — chỗ người dùng thật sự chạm
Commit trước song song hoá `download_many`, nhưng api/download.py KHÔNG gọi hàm đó: nó có vòng lặp tuần tự riêng. Nên tối ưu không chạm tới người dùng. Nay `work()` tải nhiều link cùng lúc (trần 4, đổi bằng DOWNLOAD_WORKERS). Giữ nguyên: thứ tự kết quả theo thứ tự link nhập, huỷ giữa chừng, log/tiến độ từng link; thêm: 1 link ném exception không còn giết cả mẻ. Test mới bắt đúng lỗi này (4 link x 0.4s phải xong dưới 1.2s). 119/119 PASS. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>8ae4ca6 -
fix(cut): cắt 2+ video không còn 500; tách khúc tự động nhanh gấp ~3 lần
Lỗi: thả nhiều video một lượt lúc chưa có video nào -> `cur` là biến chụp lúc render nên mọi lần upload đều gửi session rỗng -> backend tạo mỗi video một phiên riêng. Lúc cắt, FE chỉ gửi phiên của video đầu nên video thứ 2 trở đi không tìm thấy file, ffprobe chết, cả request 500 "Internal Server Error". Một video thì không bao giờ dính. Sửa lỗi: - FE giữ sid chạy theo vòng lặp upload -> mọi video vào cùng một phiên; và gửi kèm session của TỪNG video khi cắt để các phiên cũ đã lỡ tách vẫn chạy. - resolve_src() chặn thoát thư mục phiên; probe() báo lý do đọc được thay vì CalledProcessError trống trơn. - execute-batch đưa việc nặng vào job: 1 video hỏng chỉ hỏng phần của nó, hỏng hết thì job báo lỗi thật. - Khúc end <= start trước đây bị ffmpeg nuốt im lặng (-frames:v âm = không giới hạn) và xuất ra clip dài tới hết video -> nay chặn. - alert hiện `detail` thay vì nguyên cục JSON. Tăng tốc (đo thật, video QC 1080x1920 30s): - Tách khúc tự động 11.9s -> 3.9s/video. PySceneDetect …07d3e14
-
fix(báo cáo): ô "Số tài khoản được cấp" đếm nhầm bảng; buộc tải video qua relay trên Space
Ô "Số tài khoản được cấp" hiện 4 trong khi thực tế đã cấp hơn 80. Nó đang đếm bảng mã U00N, mà mã chỉ sinh khi người đó ĐĂNG NHẬP lần đầu hoặc khi quản trị tự tay thêm — duyệt từ hàng chờ thì không cấp mã. Đổi sang đếm bảng tài khoản đã duyệt, đúng bằng số dòng tab "Quản lý người dùng". Kèm nhóm sửa relay/HF đang làm dở: - Trên Space, tikwm/iesdouyin/Piped BẮT BUỘC đi qua TIKTOK_RELAY_URL; thiếu relay thì nêu lỗi rõ ràng thay vì gọi thẳng từ IP datacenter (hay bị chặn). Dev local vẫn gọi trực tiếp như cũ. - Worker relay đặt Referer theo đúng nguồn: CDN Douyin chống hotlink, sai Referer là 403. - CI loại thư mục deploy/ khỏi bản đẩy lên Space (commit tạm trong runner, main trên GitHub giữ nguyên). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>9dbe21e
-
Merge PR #3: nhan log tu 3 app desktop vao tab Quan ly thoi luong
huytran049Unverified signaturefeat(báo cáo): nhận log từ 3 app desktop vào tab "Quản lý thời lượng"8ed38c8 -
feat(báo cáo): nhận log từ 3 app desktop vào tab "Quản lý thời lượng"
Ba tool đóng gói cho Windows/Mac (down_ads, remove_subtitle, listing_image) nay bắn log về chung `POST /api/events`. Chúng dùng đúng schema và từ điển event của bản web nên ETL không phải sửa gì; ở đây chỉ thêm phần còn thiếu: - FEATURE_LABELS: 3 khoá mới, ĐỂ RIÊNG chứ không dùng lại khoá của bản web. Gộp chung thì bảng "Chi tiết theo tool" cộng số hai bản làm một, không còn biết bản nào chạy tốt. Muốn xem gộp thì lọc theo properties.client. - PHASE_LABELS: các pha máy chạy của bản app (tải video, xoá phụ đề, SEO, sửa ảnh hàng loạt...). - VALUE_LABELS: win/mac/linux, để cột "Thiết bị" đọc được thay vì mã thô. GIỮ ĐÚNG NGÀY CHO LÔ GỬI BÙ (sửa /api/events): App desktop có hàng đợi lưu đĩa — mất mạng thì gom lại, mở lần sau gửi bù. Trước đây mốc chỉnh lệch đồng hồ lấy theo event MỚI NHẤT trong lô, nên cả lô cũ bị kéo về hiện tại: việc làm tối qua bị đếm sang hôm nay. Nay lô nào có `sent_at` (giờ máy khách lúc bấm gửi) thì lấy nó làm mốc, và kéo luôn `server_ts` về đúng lúc việc …ea44972 -
fix(core): mọi tool đều giữ chỗ phiên khi chạy, thêm lớp chặn cho việc chạy đồng bộ
Nối tiếp 20e69c0 (mới bọc riêng Dịch/đổi giọng). Cut video, Xào video và Down list dùng chung cơ chế phiên nên vẫn dính: bộ dọn phiên quá hạn có thể xoá trúng thư mục job đang ghi. - Chuyển hàm bọc thành submit_for_session() dùng chung trong core/jobs.py; cả 4 tool (11 chỗ tạo job) đi qua đó, không còn jobs.submit trần. - Listing ảnh chạy THẲNG TRONG REQUEST, không qua job nên không đăng ký được vào sổ phiên-đang-bận. Thêm lớp chặn thứ hai ngay trong cleanup_old: quét sâu tìm dấu vết ghi mới, thấy là bỏ qua. Dừng sớm khi gặp file mới và có trần số mục để phiên vài trăm video không làm chậm đợt dọn. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>c8ce1a0 -
fix(dub): dọn phiên quá hạn xoá trúng phiên đang chạy -> job chết, trả video gốc
Lỗi người dùng gặp: Không tổng hợp giọng được nên trả video gốc: ffmpeg ... anullsrc ... line_0000.wav returned non-zero exit status 254 và last_error trên Space: FileNotFoundError: '/data/tnt_work/dub_.../work/tts/line_0000.wav.mp3' Cả engine chính, Edge đọc đỡ, lẫn bước tạo file lặng đều không ghi nổi file -> thư mục làm việc đã BIẾN MẤT giữa job. Thủ phạm là cleanup_old: nó xét tuổi bằng mtime của THƯ MỤC PHIÊN, mà mtime thư mục chỉ đổi khi thêm/bớt mục con TRỰC TIẾP. Job ghi sâu bên trong (out/<video>/work/tts/...) không hề chạm tới mtime đó, nên phiên đang xử lý vẫn bị tính là quá hạn và bị rmtree ngay giữa chừng (sweep chạy ké mỗi lần có người mở phiên mới). - Đếm job đang chạy theo phiên (session_in_use); cleanup_old bỏ qua phiên bận. - cleanup_old cũng thôi đụng thư mục dùng chung (voice_previews) — không phải phiên thì không có "hạn". - Mọi bước ghi file TTS tự dựng lại thư mục nếu mất, để một sự cố tương tự chỉ làm chậm chứ không giết cả job. Co-Authored-By: Clau…20e69c0 -
feat(báo cáo): dựng lại tab thời lượng theo mẫu, CSV đọc được bằng tiếng Việt
Bảng nhân sự: cột "Xong" chỉ in SỐ việc xong, bỏ phần trăm đi kèm — cột này đứng cạnh cột "Số task" nên tỷ lệ tự đọc ra được, in thêm % chỉ làm ô chật. Thêm cột Team/BU tách từ tên đăng nhập kiểu "họ tên - team - bu". Giao diện dựng theo hai file mẫu đã chốt form: tiêu đề + thanh lọc (người dùng / công cụ / từ ngày / đến ngày) + ba nhóm ô chỉ số có gạch phân cách, rồi tới các card nội dung. Bật lại bảng "Tốc độ máy mỗi bước (B2)". Chỉ số mới trong ETL: số user đã dùng thật (không tính người chỉ ngó trang), dùng hàng tuần/hàng ngày — đếm theo mốc MỚI NHẤT trong khoảng lọc chứ không so với hôm nay, để xem lại báo cáo cũ vẫn đúng. CSV tải về: mỗi cột là một câu tiếng Việt, cục properties_json được bung thành "Bước máy: Bóc lời & dịch · Lần bấm chạy thứ: 1". Cột mã và JSON gốc dồn về cuối để vẫn dò ngược được. `?raw=1` giữ nguyên 11 cột schema v2 cho bên nào cần nạp vào công cụ khác. Bảng dịch để một chỗ ở labels.py, màn "Nhật ký chi tiết" đọc chung nên không lệch với file tải về; khoá …4ffa05a
-
fix(dub): cache giọng thử đặt tên theo ĐỊNH NGHĨA giọng, không chỉ theo id
Bản instruct đã sửa lên Space rồi (nhãn giọng mới, last_error rỗng) nhưng /voice-preview vẫn trả y nguyên 220110 byte suốt 19 phút: đó là bản do Edge đọc đỡ hồi OmniVoice còn hỏng, đã nằm trong cache. Nó NGHE RA TIẾNG nên phép kiểm "file câm" thêm hôm trước không bắt được, mà STORAGE_DIR thì sống qua cả lần build lại -> nghe giọng Edge mãi dù model đã chạy đúng. Tên file cache nay kèm VÂN TAY của định nghĩa giọng (engine + chuỗi instruct thật): đổi engine hoặc sửa preset là bản cũ tự hết hiệu lực. Ghi bản mới thì xoá luôn bản cũ cùng giọng cho khỏi đọng rác. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>92f69cd -
fix(dub): bỏ bản giọng thử CÂM đã nằm trong cache
Đo trên Space: /voice-preview trả đúng 19278 byte lặng ở MỌI lần gọi, thời gian 1.3s, mà `last_error` vẫn rỗng -> không hề có lần tổng hợp nào chạy. Bản lặng do lần TTS hỏng trước ghi ra đã nằm trong STORAGE_DIR và sống qua cả lần build lại, nên phép thử cũ ("có file và > 44 byte") luôn đúng và đường đi không bao giờ chạm tới engine — vừa câm vừa không ghi nổi lỗi. Nay cache chỉ tính là dùng được khi file KHÔNG câm; câm thì xoá, làm lại. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>268fabb -
fix(dub): TTS hỏng thì đọc bằng Edge, không trả cả video tiếng lặng
Test thật trên Space: /voice-preview trả về ĐÚNG 0.4s im lặng tuyệt đối — là nhánh _silence(0.4) của synth_line, tức OmniVoice ném lỗi ở MỌI câu. Hai lỗi lộ ra: 1. synth_line nuốt lỗi thành khoảng lặng và KHÔNG log gì. Hỏng 1 câu thì không sao, nhưng engine hỏng hệ thống (model chưa tải xong, thiếu RAM) thì cả video câm mà chẳng báo gì. Nay hỏng -> đọc lại bằng Edge TTS (online, gần như luôn có); chỉ khi Edge cũng hỏng mới trả khoảng lặng. 2. _ensure_preview cache luôn bản câm đó -> giọng thử câm vĩnh viễn kể cả sau khi model đã chạy được. Nay phát hiện file câm thì xoá + báo lỗi. Thêm đường chẩn đoán TỪ XA: ghi lỗi gần nhất của từng engine và trả qua /api/dub/voices (`last_error`) — trên Space không xem log tiện, mà triệu chứng thì chỉ là "nghe không thấy gì". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>35076e5 -
feat(dub): thêm OmniVoice (k2-fsa) làm engine TTS cho tiếng Anh & Filipino
en/fil trước chỉ có Edge TTS: giọng dựng sẵn, KHÔNG clone được. Nay chạy OmniVoice (k2-fsa/OmniVoice, 0.6B, 646 ngôn ngữ, ra 24 kHz) với 2 chế độ: - CLONE : có mẫu giọng (từ video hoặc file tải lên) -> ref_audio. - DESIGN : không mẫu -> "instruct" tả giọng bằng chữ. Gói sẵn 6 giọng en + 4 giọng fil (nam/nữ, Mỹ/Anh), ghép thêm ngữ điệu đang chọn (tự nhiên / quảng cáo / đọc tin / kể chuyện). CHƯA CÀI GÓI thì en/fil tự chạy Edge TTS y như cũ — quyết định lấy engine nào làm TRƯỚC bằng find_spec (không import torch trong request /voices), nên /voices trả đúng danh sách giọng của engine sẽ thật sự chạy. /api/dub/voices trả thêm engine + model_label + can_clone; giao diện bỏ hàm đoán isEdge(lang) — clone được hay không là do ENGINE quyết, không phải do tiếng gì. Edge chặn id giọng lạ (vd "omni:*" còn kẹt trong state trình duyệt) để không lỗi cả câu. Chỉnh bằng env: OMNI_DEVICE (cpu|cuda:0|mps), OMNI_STEPS (16), OMNI_ENABLED=0. Co-Authored-By: Claude Opus 5 <…6f5141d
-
feat(analytics): mã người dùng U00N + task_id/session_id đọc-được + source/parent_task
Theo góp ý chốt với team về 2 cột task_id/session_id trong bản log: - user_id đổi từ tên tự do sang mã U00N cấp tuần tự khi tạo tài khoản. Mã lưu bảng/file RIÊNG (user_codes), KHÔNG đụng bảng phân quyền: cấp mã lỗi thì đăng nhập vẫn chạy (lùi về username). login trả code; admin thêm user cấp mã ngay. - task_id = <tool>_<user>_<YYYYMMDD>_<HHMMSS>_<rand4>, session_id = s_<user>_<YYYYMMDD>_<HHMMSS>_<rand4> — đọc được, tự sắp theo thời gian, dùng giờ+random thay số thứ tự trong ngày nên mở 2 tab/2 máy không đụng ID. - task mới sinh từ task cũ ghi source + parent_task: rerun (nút Làm mới) và forward (chuyển sang tool khác, mang "cha" qua sessionStorage). - dashboard hiện TÊN cạnh mã (map U00N -> username) để quản trị vẫn biết ai. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>5edb87f -
feat(analytics): tab "Quản lý thời lượng" theo dõi người dùng cho quản trị
Ghi log thô raw_events rồi suy ra 9 chỉ số (A1-A5, B1-B4) bằng ETL, không lưu sẵn chỉ số. Lưu Postgres nếu có DATABASE_URL, không thì SQLite trong STORAGE_DIR (giữ 90 ngày, tự dọn). - backend: services/analytics (storage + etl + track), api/analytics (POST /api/events + các endpoint quản trị), middleware reqctx đọc header X-TNT-* để dòng log máy chạy gắn đúng task; JobManager tự phát job_queued/started/done kèm latency_ms (đã trừ thời gian chờ hàng đợi). - frontend: lib/track.js (đồng hồ người), nút 👍/👎 (ThumbsFeedback) cho B3, dashboard SVG thuần trong tab Quản lý thời lượng; gắn điểm đo vào 8 tool. Kèm sửa lỗi phát hiện khi test: - khôi phục core.files.rel_path() + gom mọi đường dẫn phiên ở cut/dub/shuffle/ download về "/" (trước nối "\" của Windows làm hỏng URL). - get_file trả 404 khi trỏ vào thư mục (thay vì 500). - run_tests.py cô lập STORAGE_DIR sang temp (trước dọn nhầm phiên thật). - cập nhật test_cut/test_dub theo API hiện hành + thêm test_analytics (14 test). …00d2c12
-
fix(dub): caption chứa "#" làm hỏng URL tải video/audio/srt (500)
Tên thư mục output ở luồng dịch/đổi giọng lấy thẳng caption video; caption TikTok chứa "#" -> "#" trong URL bị coi là fragment -> file endpoint nhận nhầm thư mục -> 500, video đen + không tải được. - Làm sạch tên thư mục output (bỏ #, [], dấu cách...) + hash tránh đè, giống luồng "Chèn phụ đề" vốn đã đúng; giữ caption để hiển thị. - Sửa kèm auto-save: bỏ đúng tiền tố /api/files/{session}/ nên trước đây dựng sai path -> không backup được file lên History/Drive. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>1d527a5
-
feat(text): thêm tab "Chèn chữ vào video" (nhiều video) + nhận dạng lời (ASR)
- Tab mới /chen-chu: vào 1..N video, chèn chữ hard-sub, ra N video tương ứng. - Dùng lại SubtitleEditor (đủ phông/màu/11 kiểu nền/3 kiểu hiển thị/kéo thả) qua props tùy chọn initialSegs/initialMode/onChange/headerExtra/onFetchLines (mặc định null -> tab Dịch/đổi giọng không đổi). - Lấy text: nút "Tự lấy lời từ video (nhận dạng)" -> ASR Whisper (Groq) không dịch, đổ lời + mốc vào editor để sửa; hoặc gõ tay. - Áp form giữa các video: "Áp cả lời + kiểu" (cùng nội dung) và "Áp kiểu (giữ lời riêng)" (mỗi video tự nhận dạng lời khác nhau). - Backend: endpoint /api/dub/subtitle/transcribe (extract_tracks + asr, nhẹ); burn + preview-frame ra thư mục RIÊNG theo từng video (hash) -> burn nhiều video 1 phiên không đè nhau. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>788bc93
-
feat(shuffle): bảng tổ hợp mirror video_cook — ảo hoá 300k + lọc bằng nút (JS)
Làm phần hiển thị list combo giống tool video_cook: - Thứ tự combo: tuần tự từ điển nếu ≤ trần, LẤY MẪU ĐA DẠNG nếu vượt (bỏ cách cũ chỉ lấy N cái đầu theo product). /plan trả sequences + clip_names (payload gọn). - Trần 300.000 combo. Bảng FE ẢO HOÁ (chỉ vẽ dòng đang thấy) -> không treo dù hàng trăm nghìn dòng. Hiển thị "tên + tên + tên" + cột 🎵 Source (xoay vòng theo thứ hạng trong tập đang chọn) + STT + ✓, giống combo_model.py. - Bộ lọc bằng NÚT nối chuỗi trên tập ĐANG CHỌN (giống tab2_output.py): Đặt lại / Chọn hết / Bỏ hết / Lọc ngẫu nhiên % / Lọc tương đồng % + "Ưu tiên khúc khác hoàn toàn". Lọc tương đồng port Y HỆT SimilarityWorker (greedy keep-first + nén, 0%=khác hoàn toàn), chạy Web Worker -> UI không đơ. Đã cross-check 40 case khớp 100% với bản Python. Component mới: ComboTable.jsx, worker: simFilter.js. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>824497d -
feat(dub): mục "Nâng cao (ASR)" cho user chỉnh ngưỡng lọc Whisper (ẩn, mặc định như cũ)
Thêm chỗ tinh chỉnh 2 ngưỡng quyết định giữ nhiều/ít lời khi Whisper bỏ sót (video nói nhỏ / lẫn nhạc): no_speech_max (0.6) và logprob_min (-1.0). Ẩn trong mục thu gọn "⚙ Nâng cao — nhận dạng lời (ASR)" vì đa số không cần; MẶC ĐỊNH giữ đúng giá trị hiện tại nên hành vi không đổi trừ khi user tự chỉnh. Có nút "Bắt nhiều lời hơn" (0.85/-1.6) và "Về mặc định". Nối: FE DubVideo -> dubPrepare -> DubReq -> DubOptions -> pipeline -> asr.transcribe -> _filter_speech. Đã verify: default bỏ đoạn ranh giới, nới thì giữ. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>aab8e67
-
feat(sub+shuffle): tay kéo giãn ô phụ đề + giữ/tắt tiếng gốc khi xào
Phụ đề: thêm 4 tay kéo cạnh cho ô đang chọn — trái/phải đổi BỀ RỘNG vùng (w), trên/dưới GIÃN cỡ chữ (fontSize theo khoảng cách con trỏ tới tâm ô, con trỏ bám cạnh). Bỏ tay kéo góc cũ. Xào video: thêm tùy chọn "Giữ âm thanh gốc" (mặc định BẬT) — ghép nối tiếng gốc các khúc theo đúng thứ tự xào; nếu có lồng track thì TRỘN track lên tiếng gốc. Tắt -> video câm (như cũ) / chỉ còn track. Mô hình theo tool video_cook: - normalize_clip(with_audio): giữ tiếng gốc (aac 44100 stereo), clip câm chèn im lặng để concat copy đồng nhất; cache key riêng theo chế độ audio. - attach_audio(keep_original): amix track lên tiếng gốc (normalize=0) thay vì thay hẳn. Đã verify render thật: giữ/tắt/trộn đều đúng, tiếng gốc đúng vị trí từng khúc. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>ad3a570 -
fix(sub): preview khớp 100% burn bằng render server (bỏ libass-wasm)
libass-wasm và ffmpeg dùng 2 BẢN libass khác phiên bản -> render KHÁC nhau (chữ bị rớt do bug fallback libass #460, khác font-hinting...). Không thể đảm bảo giống hệt bằng bộ vẽ thứ 2 trong trình duyệt. Cách chắc chắn = dùng CHÍNH ffmpeg/libass của bản burn để xem trước: - Bỏ hẳn libass-wasm (gỡ package + public/libass + endpoint /subtitle/ass). - Khi BẬT "Xem trước khớp 100%" + video TẠM DỪNG + không gõ/kéo -> tự gọi /subtitle/preview-frame render đúng khung tại thời điểm hiện tại (server ffmpeg) rồi đè ảnh lên video. Ảnh này = ĐÚNG video sẽ xuất. - Đang phát/gõ/kéo -> hiện CSS nhanh (mượt); dừng lại tự cập nhật khung chuẩn (debounce 350ms, chống race bằng frameSeq). - Giữ fix cỡ video = nội dung thật (bỏ letterbox) để ảnh đè khớp vùng video. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>4f9859d -
feat(sub): xem trước phụ đề KHỚP 100% bản burn (libass-wasm + render khung server)
Preview CSS chỉ 'bắt chước' libass -> không bao giờ giống hệt. Nay preview dùng CHÍNH libass, cùng ASS + font như bản burn: - Backend: tách build_ass_str (1 nguồn ASS cho burn/preview), thêm render_frame (render đúng 1 khung), 2 endpoint: /subtitle/ass (ASS cho libass-wasm), /subtitle/preview-frame (ảnh khớp 100% để đối chiếu). - FE (A) libass-wasm (SubtitlesOctopus): vẽ phụ đề THẬT đè video, real-time; nạp ASS từ backend (debounce), font từ /fonts. Toggle "Xem trước khớp 100%"; lỗi -> tự lùi về CSS. Ẩn lớp CSS khi libass bật (tránh chồng đôi); ẩn canvas khi đang gõ. - FE (B) nút "Xem trước chuẩn (ảnh)" -> gọi render 1 khung server. - Sửa lệch hình học gốc: cỡ hiển thị video = nội dung THẬT (bỏ letterbox ngang) nên overlay ánh xạ đúng toạ độ video (trước tính theo khung thẻ kèm viền đen). - worker/wasm libass để LFS (khớp *.wasm), HF chấp nhận. Đã kiểm: build FE pass; backend build_ass_str/render_frame ra ASS+khung đúng (highlight đúng thời điểm); libass-wasm nạp worker+was…d908e31
-
feat(dub): prompt dịch persona 20 năm + xưng hô nhất quán; nạp SRT tự tải
- Prompt dịch (Gemini + Groq dùng chung): đóng vai chuyên gia dịch <gốc>→<đích> 20 năm KN, ép xưng hô nhất quán theo nhân vật/hoàn cảnh. Ngôn ngữ gốc lấy tự động từ ASR (pipeline truyền source_lang xuống translate_all). - Nạp SRT tự tải: endpoint /api/dub/subtitle/import parse SRT + BỎ nhãn trong [] (giữ mốc + nội dung); nút "Dùng file SRT khác" ở khu xem/sửa bản dịch để thay bản dịch tự động khi user không ưng. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>ab852b0
-
feat(dub): giọng mẫu tự giới thiệu tên + tạo SẴN lúc khởi động
- Câu mẫu cá nhân hoá: "Xin chào, tôi tên là {tên}, đây là giọng đọc của tôi" (vi) / "Hello, my name is {name}. This is my voice." (en) / bản fil. Tên lấy từ label giọng (vd 'Aria', 'Ngọc Lan'). - warm_voice_previews(): tạo sẵn TẤT CẢ giọng preset lúc khởi động (chạy nền, daemon thread từ startup) -> user bấm Nghe thử là phát ngay, khỏi chờ. Edge (en/fil) làm trước, VieNeu (vi) sau; best-effort, lỗi 1 giọng không sao. Tắt bằng env WARM_VOICE_PREVIEWS=0. - Tách _ensure_preview dùng chung endpoint + warm-up. Test: tên 'en-US-AriaNeural'->'Aria'; warm-up tạo 9 giọng en+fil trong 8s; bấm nghe lấy cache 0.001s. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>dfad780 -
feat(dub): nút "Nghe thử" giọng trước khi chọn (vi/en/fil)
- api/dub.py: GET /api/dub/voice-preview?lang=&voice= — server đọc 1 câu mẫu bằng giọng chọn, CACHE dùng chung mọi user (VieNeu vi chậm nên chỉ chạy 1 lần/giọng, sau đó tức thì). Khoá tránh 2 request cùng tạo 1 giọng. - DubVideo.jsx: component VoicePreview (nút "▶ Nghe thử" + <audio>), gắn cạnh cả 3 ô chọn giọng: Edge (en/fil), VieNeu preset (vi), và khu tạo giọng từ text. VieNeu lần đầu hiện "Đang tạo…" trong lúc server dựng. Test: en/fil qua Edge OK (~2s lần đầu, cache 0.000s); vi cùng code path. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>2b1978a -
feat(cut): tách video thành video không lời + MP3, tải cái nào tuỳ ý
Thêm tính năng trong tool Cut: user tải/kéo thả video -> tách thành 1 video KHÔNG lời (mp4) và 1 file âm thanh (mp3), cho tải riêng từng cái. - services/cutter/cut.py: split_audio() — video không lời (copy luồng hình, lỗi thì re-encode H.264) + mp3 (libmp3lame). has_audio_stream() để bỏ qua mp3 khi video vốn không có tiếng. Trả SplitResult. - api/cut.py: POST /api/cut/split-audio (chạy job) trả URL 2 file + has_audio; auto-save vào lịch sử/Drive nếu có username. - api.js: cutSplitAudio(). - CutVideo.jsx: card "🔊 Tách âm thanh" (dùng video đang chọn) + 2 nút tải; báo rõ khi video gốc không có tiếng. Test: video có tiếng -> video không lời (hết audio) + mp3 hợp lệ; video không tiếng -> chỉ video không lời; endpoint end-to-end OK. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>b7ce941
-
fix(shuffle): báo rõ khi clip đã bị xoá khỏi vùng tạm, thay vì ffmpeg exit 254
Clip nằm ở STORAGE_DIR=/tmp; trên HF Space /tmp BỊ XOÁ mỗi lần server khởi động lại/deploy -> file clip biến mất trong khi trình duyệt vẫn nhớ danh sách -> ffmpeg chết với "exit status 254" (ENOENT: no such file) và MỌI biến thể fail, thông báo FE lại đoán sai là "clip khác kích thước". Kiểm tra tồn tại file ngay ở /generate -> trả 400 kèm thông báo tiếng Việt rõ: "N clip không còn trên máy chủ ... hãy TẢI LẠI clip rồi xào lại" + tên clip thiếu. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>54b9540
-
feat: dịch dự phòng deep-translator + lọc ảo giác ASR + xào render tới 10k
Dịch (translate.py, asr.py): - Nối deep-translator (Google free, không cần key) làm dự phòng cuối: khi Gemini + Groq lỗi/thiếu key vẫn dịch được từ tiếng bất kỳ trong video sang vi/en/fil (source auto-detect), thay vì trả câu gốc. - Bắt cả trường hợp dịch ra y hệt câu gốc -> vẫn chạy deep-translator. - Log rõ khi Gemini/Groq lỗi (soi HF Logs ra ngay thủ phạm). - Parser batch bền hơn (1. 2) **3.** 4: markdown). - Lọc ảo giác Whisper: bỏ câu dài mà đọc quá chậm + cụm bịa quen ("đăng ký kênh", "cảm ơn đã xem"...) khi tốc độ đọc bất thường. Xào (shuffle.py, ShuffleVideo.jsx): - MAX_RENDER 150 -> 10000 (env SHUFFLE_MAX_RENDER); PLAN_CAP 3000 -> 5000 (env SHUFFLE_PLAN_CAP). FE lấy max_render từ backend nên luôn khớp env. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>3d2064d
-
perf: queue theo loại + code-split FE + streaming upload cho nhiều user
Backend: - Viết lại JobManager thành hàng đợi theo loại tác vụ (heavy/io), có vị trí hàng đợi (queue_pos/total) và tự dọn job cũ để không rò rỉ RAM. Cấu hình qua env JOB_HEAVY_WORKERS/JOB_IO_WORKERS/JOB_HISTORY_MAX. - core/bg.py: pool nền có giới hạn (BG_WORKERS) thay raw thread không giới hạn ở listing/listing_free/flux2. - Đưa OpenAI blocking ra khỏi event loop (listing analyze/create_session, listing_free analyze/auto-generate: async def -> def). - Streaming upload (save_upload_stream) thay vì đọc cả file vào RAM; enforce MAX_UPLOAD_MB. Áp cho dub/cut/shuffle. - Cache: Demucs model, ffprobe theo (path,mtime), client Groq. - thumbnail_strip gộp 40 lần ffmpeg -> 1 pass (fallback chậm khi lỗi). - Endpoint GET /api/queue/stats. Frontend: - Sửa bug double <Outlet> trong Layout (mọi trang mount 2 lần -> chạy đôi upload/poll/API). - Code-split các page bằng React.lazy + Suspense; tách react-vendor chunk. - pollJob nhận AbortSignal; hủy poll khi rời trang (chống rò rỉ setTimeou…3370310 -
update cut, guide, dub
c55c292
-
update downvideo
91f1a3a
-
fix: restore Flux 9B defaults, dual-mode client (simple + multi-step)
d025c22 -
refactor: dynamic Gradio API endpoint detection + flexible params
56cb772 -
fix: Wan2GP model options (t2v, moviigen, t2v_fusionix, t2v_sf)
46472f9 -
fix: also limit count in auto-generate endpoint + slice custom items
db37cfa -
fix: Wan2GP compatible resolutions (720x720) and default model
40fb7c0 -
fix: GPT now generates exactly N prompts (respect count), not always 9
5dd1ef4 -
fix: correct Wangp URL param mapping (url vs wangp_url), pass autoPrompts as items + respect count
114f8a6 -
feat: add Gradio URL test/connect button with status indicator
6d566e0 -
feat: full pipeline GPT->Wangp->Design with config params (API key, model, resolution, steps, guidance, etc.)
0458580 -
feat: add Listing anh Free tool (Pillow design + Wangp background, web UI)
643d3ab
-
Merge branch 'main' of https://github.com/Digital-Transformation-TNT/website_content_tnt
c04ebb3 -
feat: add Flux2 image generation (backend api + frontend page)
77cfd71 -
update
30b7d3a -
fix: add missing Request import for gradio-proxy endpoint (422 error)
02b2548
-
Merge branch 'main' of https://github.com/Digital-Transformation-TNT/website_content_tnt
4134d02 -
update add subtitle
c55989f -
fix download race: use tempfile + BackgroundTasks, tránh Response content shorter than Content-Length
e47be4d -
person types: composite person+SP ko mask, giữ face+SP, đổi tư thế
1bab57c