karim23657's picture
Update templates/index.html
15b89d4 verified
<!DOCTYPE html>
<html lang="fa">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Karim23657</title>
<link rel="stylesheet" href="/static/bootstrap.min.css">
<script src="/static/jquery.min.js"></script>
<style>
@font-face {
font-family: 'Sahel';
src: url('/static/sahel.ttf') format('truetype');
font-weight: normal;
font-style: normal;
font-display: swap;
}
body {
font-family: Sahel, sans-serif;
background-color: #f4f4f9;
padding: 20px;
text-align: center;
direction: rtl; /* Right-to-left direction */
}
.content {
padding: 20px;
text-align: center;
}
.tab-pane {
display: none;
}
.tab-pane.active {
display: block;
}
.visualizer {
display: flex;
justify-content: center;
align-items: flex-end;
height: 30px;
gap: 3px;
margin: 20px 0;
}
.bar {
width: 3px;
background: #1db9b9;
border-radius: 3px;
animation: bounce 1s infinite;
}
@keyframes bounce {
0%,
100% {
height: 5px;
}
50% {
height: 20px;
}
}
</style>
</head>
<body>
<div class="container mt-5">
<!-- Tabs -->
<ul class="nav nav-tabs">
<li class="nav-item">
<a class="nav-link active" href="#" data-target="#home">متن به گفتار 🗣️</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" data-target="#menu1">ویرایش تلفظ</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" data-target="#menu2">واژه های اخیر</a>
</li>
</ul>
<!-- Tab Content -->
<div class="tab-content">
<div id="home" class="container tab-pane active content"><br>
<h3 class="mb-3">متن به گفتار 🗣️</h3>
<div class="mb-3"><a href="https://t.me/persian_tts" rel="nofollow" class="mt-3"><img src="https://camo.githubusercontent.com/5816246a32fe5752272b083398ef7ced06a11b0eb73d7c0bcefad490ba5f32b1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f54656c656772616d2d6368616e6e656c2d626c75653f7374796c653d666c61742d737175617265266c6f676f3d74656c656772616d" alt="Telegram channel" data-canonical-src="https://img.shields.io/badge/Telegram-channel-blue?style=flat-square&amp;logo=telegram" style="max-width: 100%;"></a>
</div>
<div class="row">
<form class="form col-md-6 input" dir="rtl" id="tts">
<input type="hidden" name="tab" value="tts">
<div class="form-group">
<div class="rounded p-2 border" style="background-color: #f8f9fa;">
<div class="form-group">
<label for="textarea" class="d-flex justify-content-start">متن:</label>
<textarea class="form-control" id="textarea" rows="3" name="text" required></textarea>
</div>
<div class="form-group">
<label class="d-flex justify-content-start">انتخاب صدا:</label>
{{ components|safe }}
</div>
</div>
</div>
<div class="form-group">
<div class="row mb-3">
<div class="col">
<button class="btn btn-light btn-outline-dark btn-block" type="submit" value="submit">بگو</button>
</div>
<div class="col">
<button class="btn btn-light btn-outline-dark btn-block" value="stop">توقف</button>
</div>
</div>
</div>
</form>
<div class="form-group col-md-6 output">
<div class="rounded p-2 border" style="background-color: #f8f9fa;">
<label for="tts-audio" class="d-flex justify-content-start">صوت:</label>
<audio controls id="tts-audio" class="col-12 result">Your browser does not support the audio element.</audio>
<label for="status" class="d-flex justify-content-start">وضعیت:</label>
<textarea class="form-control result" id="status" rows="2" disabled></textarea>
</div>
</div>
</div>
<div class="rounded p-2 border" dir="rtl" style="text-align: right;">
<p>اینجا می توانید مدل های فارسی را با کتابخانه <a href="https://github.com/k2-fsa/sherpa-onnx">sherpa-onnx</a> امتحان کنید</p>
<p>در صورت تلفظ اشتباه ، واژه را در سربرگ <span style="color:#2980b9"><span style="background-color:#bdc3c7">ویرایش تلفظ </span></span>&nbsp; ارسال کنید.</p>
<p>بروزرسانی ها را در کانال تلگرام&nbsp;<a href="https://t.me/persian_tts">persian_tts@</a> دنبال کنید .</p>
<p>نظراتتون رو برای بهتر شدن برنامه در گروه تلگرام <a href="https://t.me/persian_tts_chat">persian_tts_chat@</a>&nbsp; بگید</p>
<p>کانال تلگرام : <a href="https://t.me/persian_tts">https://t.me/persian_tts</a></p>
<p>گیتهاب : <a href="https://github.com/karim23657/Persian-tts-coqui">https://github.com/karim23657/Persian-tts-coqui</a></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
</div>
</div>
<div id="menu1" class="container tab-pane content">
<br>
<h3 class="mb-3">ویرایش تلفظ واژه</h3>
<div class="row">
<div class="form-group col-md-6">
<form dir="rtl" class="form-group " id="phonemize">
<input type="hidden" name="tab" value="phonemize">
<div class="rounded p-2 border mb-3" style="background-color: #f8f9fa;">
<div class="form-group row align-items-center">
<div class="col-2"><label for="input_word" class="col-form-label">واژه:</label></div>
<div class="col-10"><input type="text" class="form-control" id="input_word" name="word" placeholder="واژه را وارد کنید"></div>
</div>
<div class="form-group row align-items-center">
<div class="col-2"><label for="phonetics" class="d-flex justify-content-start">تلفظ:</label></div>
<div class="col-10"><input type="text" class="form-control result" id="phonetics" name="phonetic" placeholder="تلفظ را وارد کنید"></div>
</div>
</div>
<div class="form-group row align-items-center">
<div class="col"><button class="btn btn-light btn-outline-dark btn-block" type="submit" value="phonemize">آوانویسی</button></div>
<div class="col"><button class="btn btn-light btn-outline-dark btn-block" type="submit" value="say">بگو</button></div>
<div class="col"><button class="btn btn-light btn-outline-dark btn-block" type="submit" value="send">ارسال واژه</button></div>
</div>
</form>
</div>
<div class="form-group col-md-6">
<div class="rounded p-2 border" style="background-color: #f8f9fa;">
<label for="audio" class="d-flex justify-content-start">صوت:</label>
<audio controls id="audio" class="col-12 result">Your browser does not support the audio element.</audio>
<label for="status" class="d-flex justify-content-start">وضعیت:</label>
<textarea class="form-control result" id="status" rows="2" disabled></textarea>
</div>
</div>
</div>
</div>
<div id="menu2" class="container tab-pane content"><br>
<h3>واژه هایی که ثبت شده</h3>
<form dir="rtl" class="form-group " id="words">
<input type="hidden" name="tab" value="words">
<div class="form-group row align-items-center">
<div class="col-6"><button class="btn btn-light btn-outline-dark btn-block" type="submit" value="words">بروز رسانی</button></div>
<div class="col-3"><a class="btn btn-light btn-outline-dark btn-block" href="/download/fa_dict">dict ⇩</a></div>
<div class="col-3"><a class="btn btn-light btn-outline-dark btn-block" href="/download/fa_extra">list ⇩</a></div>
</div>
<table class="table table-bordered table-striped result">
<thead>
<tr>
<th>#</th>
<th>واژه</th>
<th>تلفظ</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</form>
</div>
</div>
</div>
<script>
$(document).ready(function() {
$('.nav-link').on('click', function(e) {
e.preventDefault();
$('.nav-link').removeClass('active');
$(this).addClass('active');
var target = $(this).data('target');
$('.tab-pane').removeClass('active');
$(target).addClass('active');
});
let currentTaskId = null;
let resultCheckInterval = null;
function createLoadingOverlay(element) {
const overlay = $("<div>", {
class: "loading-overlay position-absolute top-0 start-0 d-flex justify-content-center align-items-center bg-secondary bg-opacity-50",
css: {
zIndex: 1000,
fontFamily: 'sans-serif' // Or a suitable Persian font
}
});
// Use RTL layout for Persian text
overlay.html('<span class="spinner-border spinner-border-sm text-light ms-2" role="status"></span><span class="text-light mr-3" dir="rtl">در حال بارگذاری... <span id="loading-counter">0.00</span></span>');
$("body").append(overlay);
let counter = 0.00;
const counterInterval = setInterval(() => {
counter = parseFloat((counter + 0.01).toFixed(2));
$("#loading-counter", overlay).text(counter.toFixed(2));
}, 10);
overlay.data('counterInterval', counterInterval);
overlay.data('element', element);
updateOverlayPosition(overlay);
$(window).on("resize.overlay scroll.overlay", function() {
updateOverlayPosition(overlay);
});
return overlay;
}
function updateOverlayPosition(overlay) {
const element = overlay.data('element');
if (!element || !element.length) {
return;
}
const elementPosition = element.offset();
const elementWidth = element.outerWidth();
const elementHeight = element.outerHeight();
overlay.css({
top: elementPosition.top,
left: elementPosition.left,
width: elementWidth,
height: elementHeight
});
}
function destroyOverlayAll(elements) {
elements.each(function() {
const $this = $(this);
destroyOverlay($this);
});
}
function destroyOverlay(element) {
const overlay = $(".loading-overlay").filter(function() {
return $(this).data('element')[0] === element[0];
});
if (overlay.length) {
clearInterval(overlay.data('counterInterval'));
$(window).off("resize.overlay scroll.overlay");
overlay.remove();
}
}
$('#tts').on('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
$(this).parent().find('.result').each(function() {
const $this = $(this);
const overlay = createLoadingOverlay($this);
});
const clickedButton = $(e.originalEvent.submitter);
if(clickedButton.val()=='submit'){
clickedButton.prop('disabled',true)
$.ajax({
url: '/submit',
type: 'POST',
data: formData,
contentType: false,
processData: false,
success: function(data) {
currentTaskId = data.task_id;
const position = data.position;
//$('#queuePosition').html(`Your task is in position: ${position}`);
checkResult(currentTaskId);
},
error: function(xhr) {
destroyOverlayAll($('#tts').parent().find('.result'));
if (xhr.status === 429) {
//$('#queuePosition').html('Error: Task queue is full. Please try again later.');
clickedButton.prop('disabled',false)
}
}
});
}else if(clickedButton.val()=='stop'){
if (currentTaskId) {
$.post(`/stop/${currentTaskId}`, function(data) {
destroyOverlayAll($('#tts').parent().find('.result'));
clearInterval(resultCheckInterval);
}).fail(function() {
//$('#queuePosition').html('Error stopping the task. It may have already completed.');
});
}
}
function checkResult(taskId) {
resultCheckInterval = setInterval(function() {
$.get(`/result/${taskId}/tts`, function(data) {
if (data.status === "completed") {
clearInterval(resultCheckInterval);
$('#status').val(data.result.status);
$('#tts-audio').attr('src', data.result.audio); // Update audio source
destroyOverlayAll($('#tts').parent().find('.result'));
clickedButton.prop('disabled',false)
}
});
}, 1000); // Check every second for a faster response
}
});
$('#phonemize').on('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
let parentEl = $(this).parent().parent();
let result_holders = parentEl.find('.result');
result_holders.each(function() {
const $this = $(this);
const overlay = createLoadingOverlay($this);
});
const clickedButton = $(e.originalEvent.submitter);
console.log(clickedButton.val());
if(['say','phonemize','send'].includes(clickedButton.val())){
clickedButton.prop('disabled',true);
formData.append('task',clickedButton.val());
$.ajax({
url: '/submit',
type: 'POST',
data: formData,
contentType: false,
processData: false,
success: function(data) {
currentTaskId = data.task_id;
const position = data.position;
//$('#queuePosition').html(`Your task is in position: ${position}`);
checkResult(currentTaskId);
},
error: function(xhr) {
destroyOverlayAll(result_holders);
if (xhr.status === 429) {
//$('#queuePosition').html('Error: Task queue is full. Please try again later.');
clickedButton.prop('disabled',false)
}
}
});
}
function checkResult(taskId) {
resultCheckInterval = setInterval(function() {
$.get(`/result/${taskId}/phonemize`, function(data) {
if (data.status === "completed") {
clearInterval(resultCheckInterval);
parentEl.find('#phonetics').val(data.result.phonemes);
parentEl.find('#status').val(data.result.status);
parentEl.find('#audio').attr('src', data.result.audio); // Update audio source
destroyOverlayAll(result_holders);
clickedButton.prop('disabled',false)
}
});
}, 1000); // Check every second for a faster response
}
});
$('#words').on('submit', function(e) {
e.preventDefault();
let parentEl = $(this).parent();
let result_holders = parentEl.find('.result');
const formData = new FormData(this);
result_holders.each(function() {
const $this = $(this);
const overlay = createLoadingOverlay($this);
});
const clickedButton = $(e.originalEvent.submitter);
console.log(clickedButton.val());
clickedButton.prop('disabled',true);
formData.append('task',clickedButton.val());
$.ajax({
url: '/submit',
type: 'POST',
data: formData,
contentType: false,
processData: false,
success: function(data) {
currentTaskId = data.task_id;
const position = data.position;
//$('#queuePosition').html(`Your task is in position: ${position}`);
checkResult(currentTaskId);
},
error: function(xhr) {
destroyOverlayAll(result_holders);
if (xhr.status === 429) {
//$('#queuePosition').html('Error: Task queue is full. Please try again later.');
clickedButton.prop('disabled',false)
}
}
});
function checkResult(taskId) {
resultCheckInterval = setInterval(function() {
$.get(`/result/${taskId}/words`, function(data) {
if (data.status === "completed") {
clearInterval(resultCheckInterval);
let tbody = parentEl.find('tbody');
tbody.empty();
data.result.forEach(function(item, index) {
tbody.append(`<tr><td>${index + 1}</td><td>${item.word}</td><td>${item.phonetic}</td></tr>`);
});
destroyOverlayAll(result_holders);
clickedButton.prop('disabled',false)
}
});
}, 1000); // Check every second for a faster response
}
});
});
</script>
<script src="/static/iframeResizer.contentWindow.min.js"></script>
</body>
</html>