thảo luận [FREE] Tool dịch truyện TXT/EPUB bằng AI + nghe audio liền mạch

  • Người tạo chủ đề Người tạo chủ đề manhvu81
  • Ngày bắt đầu Ngày bắt đầu
khoảng 400 chương nếu bác muốn chất lượng dịch tốt (dùng model 3.5 flash và 3 flash). nếu là tk free thì cứ tạo full 10 key để tool tự đổi key và đổi model khi hết quota nhé bác
sao 10 key của tôi dịch dc có tầm 100 chap nhỉ
 
sao 10 key của tôi dịch dc có tầm 100 chap nhỉ
bác tạo project rồi mới tạo key nhé, chứ nếu tạo 1 project thì có tạo bao nhiêu key từ project đó thì lượng quota giới hạn ngày vẫn không đổi. bác vào mục rate limit trên trang goolge studio xem còn RPD không
 
lỗi tắt Cuộn bị mất hightlight, với cả thay button Lên đầu chương bằng Quay về dòng đang đọc đi thớt , kiểu next đi vài chương vẫn quay về đúng vị trí dòng đang hightlight í

1788945691283.webp
1788949474005.webp
 
lỗi tắt Cuộn bị mất hightlight, với cả thay button Lên đầu chương bằng Quay về dòng đang đọc đi thớt , kiểu next đi vài chương vẫn quay về đúng vị trí dòng đang hightlight í

Xem tệp đính kèm 3789543Xem tệp đính kèm 3789612
thực ra là bác đang muốn đánh dấu đoạn đang đọc dở kiểu như thay vì bookmark chương thì bookmark đoạn đó thì đúng hơn. cái này dạo gần đây mình đã có ý tưởng rồi nhưng chưa cụ thể, để từ từ mình nghĩ đã nhé :go:
 
No no, ý tớ đúng là quay về dòng đang đọc á, không phải bookmark đâu bro. tớ có thói quen vừa nghe vừa back về các chương cũ để sửa lỗi text. Phiên bản cũ không có hightlight rất khó tìm về dòng đang đọc, bản mới đỡ hơn nhiều nhưng có thêm nút comeback như Readest thì càng tốt :D

Screenshot_20260909-175925.webp
 
No no, ý tớ đúng là quay về dòng đang đọc á, không phải bookmark đâu bro. tớ có thói quen vừa nghe vừa back về các chương cũ để sửa lỗi text. Phiên bản cũ không có hightlight rất khó tìm về dòng đang đọc, bản mới đỡ hơn nhiều nhưng có thêm nút comeback như Readest thì càng tốt :D

Xem tệp đính kèm 3789657
éc. nhưng mình bỏ nút Stop rồi bác. do đó mình buộc phải dừng audio khi người dùng chuyển chương/đổi truyện, nếu khi chuyển chương mà cứ tiếp tục phát audio như bản cũ thì sẽ không còn nút Stop để dừng rồi phát audio chương mới nữa :smile:
Hơn nữa bình thường người ta chỉ nghe hoặc đọc, chứ mấy ai nghe 1 chương, đọc 1 chương khác như bác chứ :ops:
 
bác tạo dự án rồi mới tạo key nhé, chứ nếu tạo 1 dự án thì có tạo bao nhiêu key từ dự án đó thì số lượng giới hạn ngày vẫn không thay đổi. bác vào giới hạn tốc độ mục trên trang goolge studio xem còn RPD thì không
key tạo mỗi ngày có số lượng cố định à bác, có thể dùng trong bao lâu
 
Ặc giờ mới để ý bản mới chuyển chương mất voice >"<
Nhiều khi name lỗi nằm tít cuối chương (hoặc lười chưa fix), muốn tìm fix phải back về chương trước hoặc trước trước nữa. Bro cấu hình như zị thì tớ phải nghe lại chương đã nghe hoặc tắt voice, ko vừa nghe vừa sửa được nữa =((

Còn vụ phát audio có nhiều cách mà nhẩy, bôi đen từ hoặc tắt mở lại voice..., cần gì nút stop đâu :oops:

P/s: bro tham khảo UI của Readest (web.readest.com) thử, tớ test qua rất nhiều app, đánh giá UI của thằng này tối ưu cực kỳ, lại còn mã nguồn mở nữa :sexy_girl:
 
Ặc giờ mới để ý bản mới chuyển chương mất voice >"<
Nhiều khi name lỗi nằm tít cuối chương (hoặc lười chưa fix), muốn tìm fix phải back về chương trước hoặc trước trước nữa. Bro cấu hình như zị thì tớ phải nghe lại chương đã nghe hoặc tắt voice, ko vừa nghe vừa sửa được nữa =((

Còn vụ phát audio có nhiều cách mà nhẩy, bôi đen từ hoặc tắt mở lại voice..., cần gì nút stop đâu :oops:

P/s: bro tham khảo UI của Readest (web.readest.com) thử, tớ test qua rất nhiều app, đánh giá UI của thằng này tối ưu cực kỳ, lại còn mã nguồn mở nữa :sexy_girl:
bác reload lại nhé. mình mới có ý tưởng mới nên fix lại rồi
 
bác tạo dự án rồi mới tạo key nhé, chứ nếu tạo 1 dự án thì có tạo bao nhiêu key từ dự án đó thì số lượng giới hạn ngày vẫn không thay đổi. bác vào mục giới hạn tốc độ trên trang goolge studio xem còn RPD thì không
còn RPG nhưng vẫn báo lỗi không dịch được, vs reset key không hay chỉ dịch số lượng nhất định thôi b
 
bác reload lại nhé. mình mới có ý tưởng mới nên fix lại rồi
UI mới ngon quá thớt, thớt chịu khó fix nốt tính năng sửa lỗi là best luôn :beauty:

thực sự kiểu sửa đơn lẻ từng từ bất tiện kinh khủng, cop sang truyện mới siêu thốn, thống khổ không thể tả T_T

1789091660185.webp

(Nội dung demo tớ cop tạm từ bộ data sửa lỗi VietPhrase mà ae converter dùng trên EmEditor.)

Mã:
// AutoCorrect.jsee

// macro AutoCorrect dành cho EmEditor dùng để sửa lỗi hàng loạt dựa theo danh sách có sẵn
// gọi là file mẫu sửa lỗi

// File mẫu sửa lỗi là file text, gồm các dòng trống, dòng sửa lỗi và dòng comment.
// các dòng trống để tách các dòng / khối cho dễ đọc.
//
// Các dòng comment chỉ dùng để giải thích, chúng bắt đầu bằng _COMMENT_
// Ví dụ: _COMMENT_: các dòng dưới đây sửa các lỗi đánh máy thường gặp
//
// Các dòng sửa lỗi có dạng:
// <lỗi>=<sửa>=<option1>=<option2>
// option1: 0 = normal; 1 = extended; 2 = regex
// option2: 512 = normal; 514 = match case; 513 = whole word; 515 = match case + whole word
// ví dụ: alf=là=0=3


// Cách dùng:
// 1. Đóng tất cả các file đang mở
// 2. Mở file mẫu sửa lỗi và file text cần sửa lỗi, file mẫu sửa lỗi ở trước file text cần sửa lỗi.
// 3. Chọn file mẫu sửa lỗi là Active Document
// 4. Chạy macro AutoCorrect.jsee

// Chú ý: trong thời gian chạy máy macro AutoCorrect tắt Undo để tăng tốc
// chức năng tắt Undo chỉ có ở những version tương đối mới (14.6 trở lên)

function getFmtTimeStr(dt)
{
    return dt.getHours().toString() + ":" + ("0" + dt.getMinutes().toString()).slice(-2) + ":" + ("0" + dt.getSeconds().toString()).slice(-2) + " " + dt.getDate().toString() + "-" + (dt.getMonth() + 1).toString() + "-" + dt.getFullYear().toString();
}

function stringFromMilisec(nMilisec)
{
    return Math.floor(nMilisec    / 3600000).toString() + ":" + ("0" + Math.floor(nMilisec % 3600000 / 60000).toString()).slice(-2) + ":" + ("0" + Math.floor(nMilisec % 60000 / 1000)).slice(-2);
}

// Constants
var frOpt1 = new Array();
frOpt1[0] = eeFindNext | eeFindReplaceQuiet | eeReplaceAll;
frOpt1[1] = eeFindNext | eeFindReplaceQuiet | eeReplaceAll | eeFindReplaceEscSeq;
frOpt1[2] = eeFindNext | eeFindReplaceQuiet | eeReplaceAll | eeFindReplaceRegExp;

var frOpt2 = new Array();
frOpt2[0] = 0;
frOpt2[1] = eeFindReplaceOnlyWord;
frOpt2[2] = eeFindReplaceCase;
frOpt2[3] = eeFindReplaceCase | eeFindReplaceOnlyWord;

var str, i, res;
var fndStrings = new Array();
var replStrings = new Array();
var replOpts = new Array();

var corSel = editor.ActiveDocument.selection;

// thời gian bắt đầu
var dtStart = new Date();
OutputBar.Clear();
OutputBar.writeln("Sửa lỗi theo danh sách có sẵn. Xin chờ trong ít phút ...");
OutputBar.Visible = true;


// Nạp danh sách sửa lỗi:
DiscardUndo = true;
corSel.Collapse();
corSel.StartOfDocument();
corSel.NewLine();
corSel.EndOfDocument();
corSel.NewLine();
corSel.StartOfDocument();
corSel.Replace("^_COMMENT_[^\\r\\n]*","", eeFindNext | eeFindReplaceQuiet | eeReplaceAll | eeFindReplaceRegExp);
corSel.StartOfDocument();
corSel.Replace("(\\r\\n){2,}", "\\r\\n", eeFindNext | eeFindReplaceQuiet | eeReplaceAll | eeFindReplaceRegExp);
corSel.StartOfDocument();
corSel.Delete();
corSel.EndOfDocument();
var maxLineNum = corSel.GetActivePointY(eePosLogical) - 1;

corSel.StartOfDocument();
i = 0;
while (i < maxLineNum)
{
    corSel.StartOfLine(false, eeLineLogical);
    corSel.EndOfLine(true, eeLineLogical);
    str = corSel.Text;
    res = str.split("=");
    fndStrings[i] = res[0];
    replStrings[i] = res[1];
    replOpts[i] = frOpt1[parseInt(res[2], 10)] | frOpt2[parseInt(res[3], 10) - 512];
    corSel.LineDown();
    i++;
}

// close without save
editor.ExecuteCommandByID(4120);

// Sửa lỗi theo danh sách
var txtSel = editor.ActiveDocument.selection;
txtSel.Collapse();
for (i = 0; i < maxLineNum; i++)
{
    txtSel.StartOfDocument();
    txtSel.Replace(fndStrings[i], replStrings[i], replOpts[i]);
}
DiscardUndo = false;
editor.ActiveDocument.Saved = false;

dtEnd = new Date();
OutputBar.writeln("Thời gian bắt đầu: " + getFmtTimeStr(dtStart));
OutputBar.writeln("Thời gian kết thúc: " + getFmtTimeStr(dtEnd));
OutputBar.writeln("Thời gian chạy: " + stringFromMilisec(dtEnd.getTime() - dtStart.getTime()));
 
UI mới ngon quá thớt, thớt chịu khó fix nốt tính năng sửa lỗi là best luôn :beauty:

thực sự kiểu sửa đơn lẻ từng từ bất tiện kinh khủng, cop sang truyện mới siêu thốn, thống khổ không thể tả T_T

Xem tệp đính kèm 3791808
(Nội dung demo tớ cop tạm từ bộ data sửa lỗi VietPhrase mà ae converter dùng trên EmEditor.)

Mã:
// AutoCorrect.jsee

// macro AutoCorrect dành cho EmEditor dùng để sửa lỗi hàng loạt dựa theo danh sách có sẵn
// gọi là file mẫu sửa lỗi

// File mẫu sửa lỗi là file text, gồm các dòng trống, dòng sửa lỗi và dòng comment.
// các dòng trống để tách các dòng / khối cho dễ đọc.
//
// Các dòng comment chỉ dùng để giải thích, chúng bắt đầu bằng _COMMENT_
// Ví dụ: _COMMENT_: các dòng dưới đây sửa các lỗi đánh máy thường gặp
//
// Các dòng sửa lỗi có dạng:
// <lỗi>=<sửa>=<option1>=<option2>
// option1: 0 = normal; 1 = extended; 2 = regex
// option2: 512 = normal; 514 = match case; 513 = whole word; 515 = match case + whole word
// ví dụ: alf=là=0=3


// Cách dùng:
// 1. Đóng tất cả các file đang mở
// 2. Mở file mẫu sửa lỗi và file text cần sửa lỗi, file mẫu sửa lỗi ở trước file text cần sửa lỗi.
// 3. Chọn file mẫu sửa lỗi là Active Document
// 4. Chạy macro AutoCorrect.jsee

// Chú ý: trong thời gian chạy máy macro AutoCorrect tắt Undo để tăng tốc
// chức năng tắt Undo chỉ có ở những version tương đối mới (14.6 trở lên)

function getFmtTimeStr(dt)
{
    return dt.getHours().toString() + ":" + ("0" + dt.getMinutes().toString()).slice(-2) + ":" + ("0" + dt.getSeconds().toString()).slice(-2) + " " + dt.getDate().toString() + "-" + (dt.getMonth() + 1).toString() + "-" + dt.getFullYear().toString();
}

function stringFromMilisec(nMilisec)
{
    return Math.floor(nMilisec    / 3600000).toString() + ":" + ("0" + Math.floor(nMilisec % 3600000 / 60000).toString()).slice(-2) + ":" + ("0" + Math.floor(nMilisec % 60000 / 1000)).slice(-2);
}

// Constants
var frOpt1 = new Array();
frOpt1[0] = eeFindNext | eeFindReplaceQuiet | eeReplaceAll;
frOpt1[1] = eeFindNext | eeFindReplaceQuiet | eeReplaceAll | eeFindReplaceEscSeq;
frOpt1[2] = eeFindNext | eeFindReplaceQuiet | eeReplaceAll | eeFindReplaceRegExp;

var frOpt2 = new Array();
frOpt2[0] = 0;
frOpt2[1] = eeFindReplaceOnlyWord;
frOpt2[2] = eeFindReplaceCase;
frOpt2[3] = eeFindReplaceCase | eeFindReplaceOnlyWord;

var str, i, res;
var fndStrings = new Array();
var replStrings = new Array();
var replOpts = new Array();

var corSel = editor.ActiveDocument.selection;

// thời gian bắt đầu
var dtStart = new Date();
OutputBar.Clear();
OutputBar.writeln("Sửa lỗi theo danh sách có sẵn. Xin chờ trong ít phút ...");
OutputBar.Visible = true;


// Nạp danh sách sửa lỗi:
DiscardUndo = true;
corSel.Collapse();
corSel.StartOfDocument();
corSel.NewLine();
corSel.EndOfDocument();
corSel.NewLine();
corSel.StartOfDocument();
corSel.Replace("^_COMMENT_[^\\r\\n]*","", eeFindNext | eeFindReplaceQuiet | eeReplaceAll | eeFindReplaceRegExp);
corSel.StartOfDocument();
corSel.Replace("(\\r\\n){2,}", "\\r\\n", eeFindNext | eeFindReplaceQuiet | eeReplaceAll | eeFindReplaceRegExp);
corSel.StartOfDocument();
corSel.Delete();
corSel.EndOfDocument();
var maxLineNum = corSel.GetActivePointY(eePosLogical) - 1;

corSel.StartOfDocument();
i = 0;
while (i < maxLineNum)
{
    corSel.StartOfLine(false, eeLineLogical);
    corSel.EndOfLine(true, eeLineLogical);
    str = corSel.Text;
    res = str.split("=");
    fndStrings[i] = res[0];
    replStrings[i] = res[1];
    replOpts[i] = frOpt1[parseInt(res[2], 10)] | frOpt2[parseInt(res[3], 10) - 512];
    corSel.LineDown();
    i++;
}

// close without save
editor.ExecuteCommandByID(4120);

// Sửa lỗi theo danh sách
var txtSel = editor.ActiveDocument.selection;
txtSel.Collapse();
for (i = 0; i < maxLineNum; i++)
{
    txtSel.StartOfDocument();
    txtSel.Replace(fndStrings[i], replStrings[i], replOpts[i]);
}
DiscardUndo = false;
editor.ActiveDocument.Saved = false;

dtEnd = new Date();
OutputBar.writeln("Thời gian bắt đầu: " + getFmtTimeStr(dtStart));
OutputBar.writeln("Thời gian kết thúc: " + getFmtTimeStr(dtEnd));
OutputBar.writeln("Thời gian chạy: " + stringFromMilisec(dtEnd.getTime() - dtStart.getTime()));
để cuối tuần mình xem sao nhé. dạo này hơi bận nên sắp tới chắc mình sẽ ít update UI hơn :go:
 
Báo lỗi phiên bản mới: ban đầu tưởng mạng cùi lag nên app đọc vấp, bỏ đoạn nhưng tớ thử dis mạng thì phát hiện hightlight vẫn tiếp tục chạy thậm chí chạy sang chương tiếp theo luôn trong khi voice đã dừng từ lúc mất mạng
 
Báo lỗi phiên bản mới: ban đầu tưởng mạng cùi lag nên app đọc vấp, bỏ đoạn nhưng tớ thử dis mạng thì phát hiện hightlight vẫn tiếp tục chạy thậm chí chạy sang chương tiếp theo luôn trong khi voice đã dừng từ lúc mất mạng
đã fix nhé bác. ngoài ra mới thêm tính năng "Nghe tiếp đoạn dang dở" để ae khi nghe mà đột ngột tắt app, tắt audio hay sao đó thì không cần tìm lại đoạn đang nghe dở nữa.
Mình hay test tính năng nên mỗi lần muốn reload là lại phải đợi nghe hết chương mới dám reload, phiền quá nên làm ra cái tính năng này :shame:
 
[ Update ] Thêm 1 số tính năng nhỏ:
  • Cho phép sửa văn bản nâng cao hơn: Phân biệt hoa/thường, Khớp đúng từ (whole word), regex. Cho phép sao chép, dán, export danh sách từ khoá.
  • Nghe tiếp đoạn dang dở: Cho phép nghe tiếp từ đoạn đang nghe dở trước đó thay thì phải ngồi lục tìm xem trước đó đang nghe tới đoạn nào.
  • Đánh dấu đoạn văn: Bây giờ ngoài đánh dấu chương thì có thể đánh dấu riêng 1 đoạn văn trên chương đó, khỏi phải tìm lại đoạn đang đọc dở trước đó.
  • Giảm gap khi nghe giọng Tiktok
Mỗi lần sửa UI là giống như vẽ nháp lên giấy ấy. Không biết bao giờ mới vẽ lại hoàn chỉnh cho đẹp được :burn_joss_stick:
 
Sửa lần cuối:
Bác thêm 1 tính năng split chương theo nhu cầu được ko? Hiện tại đang thấy có 1 trường hợp là import truyện, tool có gặp chương dài thì có chia ra nhiều phần rồi, nhưng mà có vẻ độ dài một số vẫn còn dài quá limit, nên có thay key api mới cũng ko thể dịch đc, mình thử tách cái chương bị stuck bằng tay ở file txt trước rồi import lại thì dịch khá êm. Nên nếu bác thêm cái nút "Chia nhỏ" ở giao diện đọc, khi tới chương mà bị stuck ko dịch đc, bấm cái nút đó nó chia thành 2 chương rời và đánh index lại mấy chương phía sau thì ngon quá :D
 
Bác thêm 1 tính năng split chương theo nhu cầu được ko? Hiện tại đang thấy có 1 trường hợp là import truyện, tool có gặp chương dài thì có chia ra nhiều phần rồi, nhưng mà có vẻ độ dài một số vẫn còn dài quá limit, nên có thay key api mới cũng ko thể dịch đc, mình thử tách cái chương bị stuck bằng tay ở file txt trước rồi import lại thì dịch khá êm. Nên nếu bác thêm cái nút "Chia nhỏ" ở giao diện đọc, khi tới chương mà bị stuck ko dịch đc, bấm cái nút đó nó chia thành 2 chương rời và đánh index lại mấy chương phía sau thì ngon quá :D
Thêm tính năng ngách nhức đầu lắm bác ạ :oops: Mình muốn giảm tối đa số nút bấm trên màn hình thay vì cố nhồi nhét nhiều chức năng phụ gây rối mắt.
Trước đó giới hạn ký tự mỗi chương là 12k, giờ mình mới giảm xuống 10k rồi nhé, chất lượng dịch sẽ ok hơn với chương dài, cũng đỡ lỗi khi dịch hơn. Để tránh ảnh hưởng tới bản dịch cũ của mọi người nên mình chỉ áp dụng cách chia mới cho truyện mới thôi, bác xoá truyện cũ đi rồi import lại xem thử ok chưa nhé :D
 
Thêm tính năng ngách nhức đầu lắm bác ạ :oops: Mình muốn giảm tối đa số nút bấm trên màn hình thay vì cố nhồi nhét nhiều chức năng phụ gây rối mắt.
Trước đó giới hạn ký tự mỗi chương là 12k, giờ mình mới giảm xuống 10k rồi nhé, chất lượng dịch sẽ ok hơn với chương dài, cũng đỡ lỗi khi dịch hơn. Để tránh ảnh hưởng tới bản dịch cũ của mọi người nên mình chỉ áp dụng cách chia mới cho truyện mới thôi, bác xoá truyện cũ đi rồi import lại xem thử ok chưa nhé :D
Ngon rồi bác :D Mà cái này bác thêm thành 1 option trong setting thì cũng hay
 
Sửa lần cuối:
Hiện tại tất cả các khóa mô hình đều bị lỗi b, đã thử lại bằng khóa của các tài khoản khác nhưng vẫn lỗi
mình vẫn dùng bình thường mà? :v
bác có đang dịch truyện cấm gì không thế? :shame: Nếu vi phạm chính sách của Gemini thì nó sẽ hay lỗi lắm bác.

Nếu bác lấy đúng 10 API key (10 project Gemini) thì nó sẽ tương tự như ảnh mình đính kèm đây (mỗi project có 1 tên riêng, tương ứng 1 API key).

Trường hợp của bác thì có lẽ có 3 khả năng:
  • Truyện bị vi phạm chính sách nào đó nên Gemini không dịch
  • Bác tạo nhiều API trên cùng 1 project nên hết RPD (request per day) nhanh quá
  • Gemini đang quá tải
Tóm lại là bác cứ phải gửi ảnh lỗi + cài đặt (có thể che API Keys đi) cho mình xem mình mới biết vấn đề ở đâu được nhé :D

Bác check Rate Limit ở link này nhé: Sign in - Google Accounts (https://aistudio.google.com/u/3/rate-limit?timeRange=last-1-day)
 

Tệp đính kèm

  • 1789310432980.webp
    1789310432980.webp
    69,4 KB · Lượt xem: 2
  • 1789310474982.webp
    1789310474982.webp
    40,8 KB · Lượt xem: 2
Sửa lần cuối:

Thống kê chủ đề

Ngày tạo
manhvu81,
Người trả lời cuối
manhvu81,
Trả lời
155
Lượt xem
7.578
Quay lại
Lên đầu trang