commit 18/12/2025

This commit is contained in:
2025-12-18 16:56:48 +07:00
parent bdb24a7c03
commit 8e2d529a9e
7 changed files with 226 additions and 159 deletions

View File

@@ -0,0 +1,54 @@
function cleartext() {
$('#usernametext').val('');
$('#passwordtext').val('');
}
function validstring(str) {
if (str !== null && str.length > 0) {
return true;
}
return false;
}
$(document).ready(function () {
console.log("Login page is ready.");
cleartext();
$('#loginbtn').off('click').on('click', function () {
var username = $('#usernametext').val();
var password = $('#passwordtext').val();
if (!validstring(username) || !validstring(password)) {
alert("Please enter both username and password.");
cleartext();
return;
}
fetch('/login.html', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
username: username,
password: password
})
})
.then(response => {
//console.log("Received response from server : " + response.status + " " + response.statusText+" is redirected: "+response.redirected);
if (response.redirected) {
//alert("Login successful, will redirect now.");
//console.log("Redirecting to: " + response.url);
window.location.href = response.url;
return;
}
if (response.status === 400 || response.status === 401) {
alert("Login failed");
cleartext();
}
})
.catch(error => {
console.error('Error:', error);
alert("An error occurred during login.");
cleartext();
});
});
});

View File

@@ -44,6 +44,77 @@ function fill_messagebanktablebody(vv) {
$('#tablesize').text("Table Size: " + vv.length); $('#tablesize').text("Table Size: " + vv.length);
} }
/**
* @typedef {Object} MessageBank
* @property {string} Description - Description of the messagebank entry
* @property {string} Language - Language code
* @property {number} ANN_ID - ANN ID (1-100)
* @property {string} Voice_Type - Voice type
* @property {string} Message_Detail - Detailed message constructed from categories and phrases
* @property {string} Message_TAGS - Tags associated with the message
*/
/**
* Get data from modal inputs and return as MessageBank object
* @returns {MessageBank} messagebank object or null if validation fails
*/
function GetDataFromModal() {
let description = $messagedescription.val().trim();
let language = $messagelanguage.val();
let annid = parseInt($messageannid.val());
let voicetype = $messagevoicetype.val();
let messagedetail = "";
let messagetags = "";
// iterate messageselectedvariables children
$messageselectedvariables.children().each(function () {
let text = $(this).text().trim();
let value = $(this).val().trim();
console.log('selected text:' + text + ', value:' + value);
if (text.length > 0) {
k
if (value.length > 0) {
messagetags += (messagetags.length > 0 ? " " : "") + value;
messagedetail += (messagedetail.length > 0 ? " " : "") + text;
}
}
});
console.log(`Constructed Message_Detail: ${messagedetail}`);
console.log(`Constructed Message_TAGS: ${messagetags}`);
if (description.length === 0) {
alert("Description cannot be empty");
return null;
}
if (!language) {
alert("Language cannot be empty");
return null;
}
if (isNaN(annid) || annid < 1 || annid > 100) {
alert("ANN_ID must be a number between 1 and 100");
return null;
}
if (!voicetype) {
alert("Voice Type cannot be empty");
return null;
}
if (messagedetail.length === 0 || messagetags.length === 0) {
alert("Message haven't been constructed, please add categories and phrases");
return null;
}
let mb = {
Description: description,
Language: language,
ANN_ID: annid,
Voice_Type: voicetype,
Message_Detail: messagedetail,
Message_TAGS: messagetags
};
return mb;
}
$(document).ready(function () { $(document).ready(function () {
@@ -91,22 +162,24 @@ $(document).ready(function () {
function refill_messageavailablevariables() { function refill_messageavailablevariables() {
$messageavailablevariables.empty(); $messageavailablevariables.empty();
categories.forEach(cat => { categories.forEach(cat => {
$messageavailablevariables.append(ListItem(`[${cat}]`)); if ("Phrase" === cat) return; // skip Phrase category
let displayCat = `[${cat}]`;
$messageavailablevariables.append(new Option(displayCat, displayCat));
}); });
let lang = $messagelanguage.val(); let lang = $messagelanguage.val();
let vt = $messagevoicetype.val(); let vt = $messagevoicetype.val();
if (lang && lang.length > 0){ if (lang && lang.length > 0) {
console.log("Selected Language:", lang); //console.log("Selected Language:", lang);
if (vt && vt.length > 0){ if (vt && vt.length > 0) {
console.log("Selected Voice Type:", vt); //console.log("Selected Voice Type:", vt);
fetchAPI(`SoundBank/GetPhrases/${lang}/${vt}`, "GET", {}, null, (okdata) => { fetchAPI(`SoundBank/GetPhrases/${lang}/${vt}`, "GET", {}, null, (okdata) => {
if (Array.isArray(okdata) && okdata.length > 0) { if (Array.isArray(okdata) && okdata.length > 0) {
console.log(`Loaded ${okdata.length} phrases from soundbank for language=${lang} and voiceType=${vt}`); console.log(`Loaded ${okdata.length} phrases from soundbank for language=${lang} and voiceType=${vt}`);
console.log(JSON.stringify(okdata)); //console.log(JSON.stringify(okdata));
okdata.forEach(sb => { okdata.forEach(sb => {
if (sb.description && sb.description.length > 0) { if (sb.description && sb.description.length > 0) {
$messageavailablevariables.append(ListItem(`${sb.description} [${sb.TAG}]`)); $messageavailablevariables.append($('<option>', { value: sb.tag, text: sb.description, title: sb.description }));
} }
}); });
} }
@@ -196,83 +269,32 @@ $(document).ready(function () {
reloadMessageBank(APIURL, () => fill_messagebanktablebody(window.messagebankdata)); reloadMessageBank(APIURL, () => fill_messagebanktablebody(window.messagebankdata));
$btnClear.click(() => { $btnClear.click(() => {
DoClear(APIURL, "Messagebank", (okdata) => { DoClear(APIURL, "Messagebank", (okdata) => {
reloadMessageBank(APIURL, () => fill_messagebanktablebody(window.messagebankdata) ); reloadMessageBank(APIURL, () => fill_messagebanktablebody(window.messagebankdata));
alert("Success clear messagebank : " + okdata.message); alert("Success clear messagebank : " + okdata.message);
}, (errdata) => { }, (errdata) => {
alert("Error clear messagebank : " + errdata.message); alert("Error clear messagebank : " + errdata.message);
}); });
}); });
$btnAdd.click(() => { $btnAdd.click(() => {
$modal.modal('show'); $modal.modal('show');
clearMessageModal(); clearMessageModal();
$('#closemodalbutton').off('click').on('click', function () {
// event on Click save button console.log('Close button clicked')
$modal.off('click.messagebanksave').on('click.messagebanksave', '#messagebanksave', function () { $modal.modal('hide');
let description = $messagedescription.val().trim(); });
let language = $messagelanguage.val(); $('#savemodalbutton').off('click').on('click', function () {
let annid = parseInt($messageannid.val()); console.log('Save button clicked')
let voicetype = $messagevoicetype.val(); let mb = GetDataFromModal();
let messagedetail = ""; if (!mb) {
let messagetags = "";
// iterate messageselectedvariables children
$messageselectedvariables.children().each(function () {
let val = $(this).text().trim();
if (val.length > 0) {
if (val.startsWith('[') && val.endsWith(']')) {
// categories
messagetags += (messagetags.length > 0 ? " " : "") + val;
messagedetail += (messagedetail.length > 0 ? " " : "") + val;
} else {
// phrases
// find in soundbankdata by description with specified language and voicetype
let sb = soundbankdata
.filter(sb => sb.language.toLowerCase() === language.toLowerCase())
.filter(sb => sb.voiceType.toLowerCase() === voicetype.toLowerCase())
.find(sb => sb.Description.toLowerCase() === val.toLowerCase());
if (sb) {
messagedetail += (messagedetail.length > 0 ? " " : "") + sb.Description;
messagetags += (messagetags.length > 0 ? " " : "") + sb.tag;
}
}
}
});
if (description.length === 0) {
alert("Description cannot be empty");
return; return;
} }
if (!language) {
alert("Language cannot be empty");
return;
}
if (isNaN(annid) || annid < 1 || annid > 100) {
alert("ANN_ID must be a number between 1 and 100");
return;
}
if (!voicetype) {
alert("Voice Type cannot be empty");
return;
}
if (messagedetail.length === 0 || messagetags.length === 0) {
alert("Message haven't been constructed, please add categories and phrases");
return;
}
let mb = {
Description: description,
Language: language,
ANN_ID: annid,
Voice_Type: voicetype,
Message_Detail: messagedetail,
Message_TAGS: messagetags
};
// send to server using fetchAPI // send to server using fetchAPI
fetchAPI(APIURL + "Add", "POST", mb, null, (okdata) => { fetchAPI(APIURL + "Add", "POST", mb, null, (okdata) => {
reloadMessageBank(APIURL, () => fill_messagebanktablebody(window.messagebankdata) ); reloadMessageBank(APIURL, () => fill_messagebanktablebody(window.messagebankdata));
alert("Success add new messagebank : " + okdata.message); alert("Success add new messagebank : " + okdata.message);
}, (errdata) => { }, (errdata) => {
alert("Error add new messagebank : " + errdata.message); alert("Error add new messagebank : " + errdata.message);
@@ -280,10 +302,7 @@ $(document).ready(function () {
$modal.modal('hide'); $modal.modal('hide');
}); });
// event on Click close button
$modal.off('click.messagebankclose').on('click.messagebankclose', '#messagebankclose', function () {
$modal.modal('hide');
});
}); });
$btnRemove.click(() => { $btnRemove.click(() => {
if (window.selectedmessagerow) { if (window.selectedmessagerow) {
@@ -301,7 +320,7 @@ $(document).ready(function () {
if (confirm(`Are you sure to delete messagebank [${mb.index}] Description=${mb.description}? ANN_ID=${mb.aNN_ID} Language=${mb.language} Voice_Type=${mb.voice_Type} `)) { if (confirm(`Are you sure to delete messagebank [${mb.index}] Description=${mb.description}? ANN_ID=${mb.aNN_ID} Language=${mb.language} Voice_Type=${mb.voice_Type} `)) {
fetchAPI(APIURL + "DeleteByIndex/" + mb.index, "DELETE", {}, null, (okdata) => { fetchAPI(APIURL + "DeleteByIndex/" + mb.index, "DELETE", {}, null, (okdata) => {
reloadMessageBank(APIURL, () => fill_messagebanktablebody(window.messagebankdata) ); reloadMessageBank(APIURL, () => fill_messagebanktablebody(window.messagebankdata));
alert("Success delete messagebank : " + okdata.message); alert("Success delete messagebank : " + okdata.message);
}, (errdata) => { }, (errdata) => {
alert("Error delete messagebank : " + errdata.message); alert("Error delete messagebank : " + errdata.message);
@@ -336,76 +355,42 @@ $(document).ready(function () {
refill_messageavailablevariables(); refill_messageavailablevariables();
// Fill messageselectedvariables from message_Detail and message_TAGS // Fill messageselectedvariables from message_Detail and message_TAGS
$messageselectedvariables.empty(); $messageselectedvariables.empty();
if (mb.message_Detail) { if (mb.message_Detail && mb.message_Detail.length > 0) {
mb.message_Detail.split(' ').forEach(val => { if (mb.message_TAGS && mb.message_TAGS.length > 0) {
$messageselectedvariables.append(ListItem(val)); let tags = mb.message_TAGS.split(" ");
}); tags.forEach((tag, idx) => {
console.log(`Restoring tag[${idx}]: ${tag}`);
let tagLower = tag.toLowerCase();
// find <option> in messageavailablevariables with value=tag
$messageavailablevariables.find('option').each(function () {
let val = $(this).val().toLowerCase();
console.log(`Available option value: ${val}`);
if (val === tagLower) {
console.log(`Found matching option for tag: ${tag}`);
$messageselectedvariables.append($(this).clone());
}
});
});
}
} }
// Save button event // Save button event
$modal.off('click.messagebanksave').on('click.messagebanksave', '#messagebanksave', function () { $('#savemodalbutton').off('click').on('click', function () {
let description = $messagedescription.val().trim(); console.log('Save button clicked')
let language = $messagelanguage.val(); let mbUpdate = GetDataFromModal();
let annid = parseInt($messageannid.val()); if (!mbUpdate) {
let voicetype = $messagevoicetype.val();
let messagedetail = "";
let messagetags = "";
$messageselectedvariables.children().each(function () {
let val = $(this).text().trim();
if (val.length > 0) {
if (val.startsWith('[') && val.endsWith(']')) {
messagetags += (messagetags.length > 0 ? " " : "") + val;
messagedetail += (messagedetail.length > 0 ? " " : "") + val;
} else {
let sb = soundbankdata
.filter(sb => sb.language.toLowerCase() === language.toLowerCase())
.filter(sb => sb.voiceType.toLowerCase() === voicetype.toLowerCase())
.find(sb => sb.Description && sb.Description.toLowerCase() === val.toLowerCase());
if (sb) {
messagedetail += (messagedetail.length > 0 ? " " : "") + sb.Description;
messagetags += (messagetags.length > 0 ? " " : "") + sb.tag;
}
}
}
});
if (description.length === 0) {
alert("Description cannot be empty");
return; return;
} }
if (!language) {
alert("Language cannot be empty");
return;
}
if (isNaN(annid) || annid < 1 || annid > 100) {
alert("ANN_ID must be a number between 1 and 100");
return;
}
if (!voicetype) {
alert("Voice Type cannot be empty");
return;
}
if (messagedetail.length === 0 || messagetags.length === 0) {
alert("Message haven't been constructed, please add categories and phrases");
return;
}
let mbUpdate = {
Description: description,
Language: language,
ANN_ID: annid,
Voice_Type: voicetype,
Message_Detail: messagedetail,
Message_TAGS: messagetags
};
fetchAPI(APIURL + "UpdateByIndex/" + mb.index, "PATCH", mbUpdate, null, (okdata) => { fetchAPI(APIURL + "UpdateByIndex/" + mb.index, "PATCH", mbUpdate, null, (okdata) => {
reloadMessageBank(APIURL, () => fill_messagebanktablebody(window.messagebankdata) ); reloadMessageBank(APIURL, () => fill_messagebanktablebody(window.messagebankdata));
alert("Success edit messagebank : " + okdata.message); alert("Success edit messagebank : " + okdata.message);
}, (errdata) => { }, (errdata) => {
alert("Error edit messagebank : " + errdata.message); alert("Error edit messagebank : " + errdata.message);
}); });
$modal.modal('hide'); $modal.modal('hide');
}); });
// Close button event $('#closemodalbutton').off('click').on('click', function () {
$modal.off('click.messagebankclose').on('click.messagebankclose', '#messagebankclose', function () { console.log('Close button clicked')
$modal.modal('hide'); $modal.modal('hide');
}); });
@@ -417,7 +402,7 @@ $(document).ready(function () {
}); });
$btnImport.click(() => { $btnImport.click(() => {
DoImport(APIURL, (okdata) => { DoImport(APIURL, (okdata) => {
reloadMessageBank(APIURL, () => fill_messagebanktablebody(window.messagebankdata) ); reloadMessageBank(APIURL, () => fill_messagebanktablebody(window.messagebankdata));
alert("Success import messagebank : " + okdata.message); alert("Success import messagebank : " + okdata.message);
}, (errdata) => { }, (errdata) => {
alert("Error importing messagebank from XLSX : " + errdata.message); alert("Error importing messagebank from XLSX : " + errdata.message);

View File

@@ -30,12 +30,12 @@
<path d="M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6m2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0m4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4m-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664z"></path> <path d="M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6m2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0m4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4m-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664z"></path>
</svg></div> </svg></div>
<h2 class="mb-3 h-login">Login</h2> <h2 class="mb-3 h-login">Login</h2>
<form class="text-center py-2 bottom-signin" method="post"> <form class="text-center py-2">
<p class="p-login">Username</p> <p class="p-login">Username</p>
<div class="mb-3"><input class="form-control input-login" type="text" name="username" placeholder="Enter your username"></div> <div class="mb-3"><input class="form-control" type="text" id="usernametext" name="username" placeholder="Enter your username"></div>
<p class="p-login">Password</p> <p class="p-login">Password</p>
<div class="mb-3"><input class="form-control input-login" type="password" name="password" placeholder="Enter your password"></div> <div class="mb-3"><input class="form-control" type="password" id="passwordtext" name="password" placeholder="Enter your password"></div>
<div class="mb-3 py-2"><button class="btn btn-primary d-block w-100 btn-login" type="submit">Login</button></div> <div class="mb-3 py-2"><button class="btn btn-primary d-block w-100" id="loginbtn" type="button">Login</button></div>
</form> </form>
</div> </div>
</div> </div>
@@ -45,6 +45,8 @@
</section> </section>
<script src="assets/bootstrap/js/bootstrap.min.js"></script> <script src="assets/bootstrap/js/bootstrap.min.js"></script>
<script src="assets/js/bs-init.js"></script> <script src="assets/js/bs-init.js"></script>
<script src="assets/js/jquery-3.7.1.min.js"></script>
<script src="assets/js/login.js"></script>
</body> </body>
</html> </html>

View File

@@ -111,9 +111,7 @@
</select></div> </select></div>
</div> </div>
<div class="row"> <div class="row">
<div class="col bg-light"> <div class="col bg-light"><select class="w-100 h-100" id="messageavailablevariables" size="10"></select></div>
<ul class="list-unstyled w-100 h-100" id="messageavailablevariables"></ul>
</div>
<div class="col-3 col-sm-3 col-md-3 col-lg-2 col-xl-2"> <div class="col-3 col-sm-3 col-md-3 col-lg-2 col-xl-2">
<div class="row pad-row-btn"><button class="btn btn-round-basic color-remove" data-bs-toggle="tooltip" data-bss-tooltip="" id="btnclearlist" type="button" title="Clear List"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="1em" height="1em" fill="currentColor" style="font-size: 32;"> <div class="row pad-row-btn"><button class="btn btn-round-basic color-remove" data-bs-toggle="tooltip" data-bss-tooltip="" id="btnclearlist" type="button" title="Clear List"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="1em" height="1em" fill="currentColor" style="font-size: 32;">
<!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. --> <!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. -->
@@ -128,12 +126,10 @@
<path d="M464 256A208 208 0 1 1 48 256a208 208 0 1 1 416 0zM0 256a256 256 0 1 0 512 0A256 256 0 1 0 0 256zM294.6 135.1c-4.2-4.5-10.1-7.1-16.3-7.1C266 128 256 138 256 150.3V208H160c-17.7 0-32 14.3-32 32v32c0 17.7 14.3 32 32 32h96v57.7c0 12.3 10 22.3 22.3 22.3c6.2 0 12.1-2.6 16.3-7.1l99.9-107.1c3.5-3.8 5.5-8.7 5.5-13.8s-2-10.1-5.5-13.8L294.6 135.1z"></path> <path d="M464 256A208 208 0 1 1 48 256a208 208 0 1 1 416 0zM0 256a256 256 0 1 0 512 0A256 256 0 1 0 0 256zM294.6 135.1c-4.2-4.5-10.1-7.1-16.3-7.1C266 128 256 138 256 150.3V208H160c-17.7 0-32 14.3-32 32v32c0 17.7 14.3 32 32 32h96v57.7c0 12.3 10 22.3 22.3 22.3c6.2 0 12.1-2.6 16.3-7.1l99.9-107.1c3.5-3.8 5.5-8.7 5.5-13.8s-2-10.1-5.5-13.8L294.6 135.1z"></path>
</svg></button></div> </svg></button></div>
</div> </div>
<div class="col bg-light"> <div class="col bg-light"><select class="w-100 h-100" id="messageselectedvariables" size="10"></select></div>
<ul class="list-unstyled w-100 h-100" id="messageselectedvariables"></ul>
</div>
</div> </div>
</div> </div>
<div class="modal-footer"><button class="btn btn-round-basic color-edit class25" type="button" data-bs-dismiss="modal">Close</button><button class="btn btn-round-basic color-add class25" type="button">Save</button></div> <div class="modal-footer"><button class="btn btn-round-basic color-edit class25" id="closemodalbutton" type="button" data-bs-dismiss="modal">Close</button><button class="btn btn-round-basic color-add class25" id="savemodalbutton" type="button">Save</button></div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -635,7 +635,7 @@ class MainExtension01 {
val list = db.queuepagingDB.List val list = db.queuepagingDB.List
.filter { it.Type=="SHALAT" } .filter { it.Type=="SHALAT" }
list.forEach { qp -> list.forEach { qp ->
println("Processing $qp") //println("Processing $qp")
if (qp.BroadcastZones.isNotBlank()){ if (qp.BroadcastZones.isNotBlank()){
val zz = qp.BroadcastZones.split(";") val zz = qp.BroadcastZones.split(";")
if (AllBroadcastZonesValid(zz)){ if (AllBroadcastZonesValid(zz)){
@@ -749,7 +749,7 @@ class MainExtension01 {
db.queuetableDB.Get() db.queuetableDB.Get()
val list = db.queuetableDB.List.filter { it.Type=="TIMER" } val list = db.queuetableDB.List.filter { it.Type=="TIMER" }
list.forEach { qa -> list.forEach { qa ->
println("Processing $qa") //println("Processing $qa")
if (qa.BroadcastZones.isNotEmpty()){ if (qa.BroadcastZones.isNotEmpty()){
val zz = qa.BroadcastZones.split(";") val zz = qa.BroadcastZones.split(";")
if (AllBroadcastZonesValid(zz)){ if (AllBroadcastZonesValid(zz)){

View File

@@ -15,7 +15,6 @@ import java.nio.file.Files
import java.util.function.BiConsumer import java.util.function.BiConsumer
import kotlin.io.path.Path import kotlin.io.path.Path
import db import db
import java.nio.file.Paths
import kotlin.io.path.absolutePathString import kotlin.io.path.absolutePathString
@Suppress("unused") @Suppress("unused")
@@ -81,18 +80,22 @@ class GoogleTTS(credentialJson: String = "c:/googlettsapi/gtc-cloud-aas-ae23c955
// file not exists, or overwrite // file not exists, or overwrite
if (targetrow!=null){ if (targetrow!=null){
// ada // ada
targetrow.Path = fullpath.absolutePathString()
Speak( Speak(
text = s.Description, text = s.Description,
language = GoogleTTSLanguage.fromLanguage(Language.valueOf(s.Language)), language = GoogleTTSLanguage.fromLanguage(Language.valueOf(s.Language)),
voicetype = GoogleTTSVoiceType.valueOf(voicetype), voicetype = GoogleTTSVoiceType.valueOf(voicetype),
targetfilename = fullpath.absolutePathString() target = targetrow
){ ){
success, message -> success, rst ->
if (success){ if (success){
Logger.info { "Generated sound for TAG ${rst.TAG} Category ${rst.Category}, saved to ${rst.Path}" }
progress.accept(index , "Generated sound for TAG ${rst.TAG} Category ${rst.Category}")
// update path di database
db.soundDB.UpdateByIndex(rst.index.toInt(), rst)
} else { } else {
Logger.error { "Failed to generate sound for TAG ${s.TAG} Category ${s.Category}, message : $message" } Logger.error { "Failed to generate sound for TAG ${rst.TAG} Category ${rst.Category}" }
progress.accept(index , "Failed to generate sound for TAG ${s.TAG} Category ${s.Category}, message : $message") progress.accept(index , "Failed to generate sound for TAG ${rst.TAG} Category ${rst.Category}")
} }
} }
@@ -120,7 +123,32 @@ class GoogleTTS(credentialJson: String = "c:/googlettsapi/gtc-cloud-aas-ae23c955
isGeneratingSoundbank = false isGeneratingSoundbank = false
} }
fun Speak(text: String, language : GoogleTTSLanguage, voicetype: GoogleTTSVoiceType, targetfilename: String, event: BiConsumer<Boolean, String>? = null){ fun Speak(text: String, language: GoogleTTSLanguage, voicetype: GoogleTTSVoiceType, target: Soundbank, event: BiConsumer<Boolean, Soundbank>){
TextToSpeechClient.create().use { client ->
try{
val input = SynthesisInput.newBuilder().setText(text).build()
val voice = VoiceSelectionParams.newBuilder()
.setLanguageCode(language.name)
.setName(String.format("%s-%s", language.name, voicetype.name))
.build()
val audioconfig = AudioConfig.newBuilder()
.setAudioEncoding(AudioEncoding.LINEAR16)
.setSampleRateHertz(44100)
.build()
val response = client.synthesizeSpeech(input, voice, audioconfig)
val bytes = response.audioContent.toByteArray()
val fs = Path(target.Path)
Files.write(fs, bytes)
Logger.info { "Speak success, file saved to : ${fs.absolutePathString()}" }
event.accept(true, target)
} catch (e : Exception){
Logger.error { "Speak failed, message : ${e.message}" }
event.accept(false, target)
}
}
}
fun Speak(text: String, language : GoogleTTSLanguage, voicetype: GoogleTTSVoiceType, targetfilename: String, event: BiConsumer<Boolean, String>){
TextToSpeechClient.create().use { client -> TextToSpeechClient.create().use { client ->
try{ try{
val input = SynthesisInput.newBuilder().setText(text).build() val input = SynthesisInput.newBuilder().setText(text).build()
@@ -137,10 +165,10 @@ class GoogleTTS(credentialJson: String = "c:/googlettsapi/gtc-cloud-aas-ae23c955
val target = Path(targetfilename) val target = Path(targetfilename)
Files.write(target, bytes) Files.write(target, bytes)
Logger.info { "Speak success, file saved to : $targetfilename" } Logger.info { "Speak success, file saved to : $targetfilename" }
event?.accept(true, targetfilename) event.accept(true, targetfilename)
} catch (e : Exception){ } catch (e : Exception){
Logger.error { "Speak failed, message : ${e.message}" } Logger.error { "Speak failed, message : ${e.message}" }
event?.accept(false, e.message ?: "Unknown error") event.accept(false, e.message ?: "Unknown error")
} }
} }

View File

@@ -125,8 +125,10 @@ class WebApp(val listenPort: Int, var userlist: List<Pair<String, String>>, val
// Redirect to home page // Redirect to home page
if (user.first== GetAdminUserFromConfig()){ if (user.first== GetAdminUserFromConfig()){
it.redirect("homeadmin.html") it.redirect("homeadmin.html")
println("User ${user.first} redirected to homeadmin.html")
} else { } else {
it.redirect("homeviewer.html") it.redirect("homeviewer.html")
println("User ${user.first} redirected to homeviewer.html")
} }
} }
} }