I am using the p5.js library, and I am working on a speech recognition - text to speech project. Kind of a chatbot.
Input is voice input which becomes a string.
I am outputting the result from a txt file, using a markov chain. Output is a string contained in a div.
My question is:
Is there a way to hide/show the div containing my input/output (.myMessage and .robotMessage) in intervals?
I want the whole screen first showing only the input when I am talking, then input disappears and only output showing, then when the computer voice finishes speaking my input is shown in the screen and so on...
Here some parts of the code, let me know if it is clear enough.
//bot
function setup() {
noCanvas();
//reads and checks into the text file
for (var j = 0; j < names.length; j++) {
var txt = names[j];
for (var i = 0; i <= txt.length - order; i++) {
var gram = txt.substring(i, i + order);
if (i == 0) {
beginnings.push(gram);
}
if (!ngrams[gram]) {
ngrams[gram] = [];
}
ngrams[gram].push(txt.charAt(i + order));
}
}
//voice recognition
let lang = 'en-US';
let speechRec = new p5.SpeechRec(lang, gotSpeech);
let continuous = true;
let interim = false;
speechRec.start(continuous, interim);
//text-to-speach
speech = new p5.Speech();
speech.onLoad = voiceReady;
function voiceReady() {
console.log('voice ready');
}
//input-ouput
function gotSpeech() {
if (speechRec.resultValue) {
var p = createP(speechRec.resultString);
p.class('myMessage');
}
markovIt();
chooseVoice();
speech.speak(answer);
}
}
and
function markovIt() {
var currentGram = random(beginnings);
var result = currentGram;
for (var i = 0; i < 100; i++) {
var possibilities = ngrams[currentGram];
if (!possibilities) {
break;
}
var next = random(possibilities);
result += next;
var len = result.length;
currentGram = result.substring(len - order, len);
}
var answer = result;
window.answer = answer;
var p2 = createP(answer);
p2.class('robotMessage');
}
how the HTML looks
<div class="container">
<div class="myMessage"></div>
<div class="robotMessage"></div>
</div>
Use select() to get a document element by its id, class, or tag name. e.g:
let my_div = select("myMessage");
Change the style of an element by style().
e.g hide:
my_div.style("display", "none");
e.g. show:
my_div.style("display", "block");
See also Toggle Hide and Show
I'm currently trying to pass an array of values from a Google Sheet to the HtmlService where I will have the user choose an option and eventually pass it back to the .gs script. I have been using these two links as references:
1. Google Documentation
2. Stack Overflow example
When running the code, I looked at my console and noticed this error:
VM3051:4 Uncaught TypeError: google.script.run.withSuccessHandler(...).getVersionArray is not a function
It appears that getVersionArray() is not being passed correctly. When removing this function from the rest of that google.script.run call, the error goes away.
Also, per link two, I tried that code with the template and never even got a window to pop up, so I have been using the HtmlOutput example from the Google documentation link as a starting point. I have also tried the code with and without the SandboxMode declaration.
gs code:
function bugPieChart() {
getVersionArray();
openDialog();
function getVersionArray() {
var ss = SpreadsheetApp.getActive();
var valuesR = ss.getSheetByName("report").getRange('R1:R').getValues();
var valuesS = ss.getSheetByName("report").getRange('S1:S').getValues();
var versionRSArray = [];
for (var i = 0; i < valuesR.length; i++) {
versionRSArray.push(valuesR[i][0]);
}
for (var i = 0; i < valuesS.length; i++) {
versionRSArray.push(valuesS[i][0]);
}
versionRSArray.sort();
var uniqueArray = [];
uniqueArray.push(versionRSArray[0]);
for (var i in versionRSArray ) {
if((uniqueArray[uniqueArray.length-1]!=versionRSArray[i]) && (versionRSArray[i] !== "")) {
uniqueArray.push(versionRSArray[i]);
}
}
return uniqueArray;
}
function openDialog() {
var html = HtmlService.createHtmlOutputFromFile('index');
SpreadsheetApp.getUi().showModalDialog(html, 'Dialog title');
var htmlOutput = html.setSandboxMode(HtmlService.SandboxMode.NATIVE);
return htmlOutput;
}
}
index.html:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script>
$(function() {
google.script.run.withSuccessHandler(buildOptionsList)
.getVersionArray();
});
function buildOptionsList(uniqueArray) {
var list = $('#optionList');
list.empty();
for (var i = 0; i < uniqueArray.length; i++) {
list.append('<option value="' + uniqueArray[i].toLowerCase() + '">' + uniqueArray[i] + '</option>');
}
}
</script>
</head>
<body>
<select id="optionList">
<option>Loading...</option>
</select>
<input type="button" value="Close" onclick="google.script.host.close()" />
</body>
</html>
I think your just missing a closing bracket on the function above it.
function bugPieChart() {
getVersionArray();
openDialog();
}
function getVersionArray() {
var ss = SpreadsheetApp.getActive();
var valuesR = ss.getSheetByName("report").getRange('R1:R').getValues();
var valuesS = ss.getSheetByName("report").getRange('S1:S').getValues();
var versionRSArray = [];
for (var i = 0; i < valuesR.length; i++) {
versionRSArray.push(valuesR[i][0]);
}
for (var i = 0; i < valuesS.length; i++) {
versionRSArray.push(valuesS[i][0]);
}
versionRSArray.sort();
var uniqueArray = [];
uniqueArray.push(versionRSArray[0]);
for (var i in versionRSArray ) {
if((uniqueArray[uniqueArray.length-1]!=versionRSArray[i]) && (versionRSArray[i] !== "")) {
uniqueArray.push(versionRSArray[i]);
}
}
return uniqueArray;
}
function openDialog() {
var html = HtmlService.createHtmlOutputFromFile('index');
SpreadsheetApp.getUi().showModalDialog(html, 'Dialog title');
var htmlOutput = html.setSandboxMode(HtmlService.SandboxMode.NATIVE);
return htmlOutput;
}
So I was able to find an specific table and I need to get no the text that's into the <b></b> of this table. Can't figure out how.
I'm using the following to test if I'm seeing my table correct:
var a = document.getElementsByTagName('table').length;
for (var i=0; i < a; i++)
{
b = document.getElementsByTagName("table")[i];
if (b.getAttribute("background") != null && b.getAttribute("background") == 'common/imgs/tabfade1.gif' ) { console.log(b.getAttribute("background")); }
}
result = true;
Any leads into how set my result as the text I need? Thanks in advance.
EDIT:
Image of the table.
Table Sample
document.querySelectorAll("table b")
Should give you a list of all <b> elements in all of the table elements.
Then you can peform your regular operations on them.
Well, in case someone else needs what I needed, here's what I've found as the solution:
var tables = document.getElementsByTagName('table');
var container = -1;
for (var i = 0; i < tables.length-1; i++) {
if (tables[i].background == "tabfade1.gif") {
container = i;
}
}
if (container > -1) {
result = tables[container].rows[0].cells[0].innerText.trim();
} else {
result = "";
}
I searched but I didn't find the answer.
I have a code that change the color of my wordpress template blocks and posts randomly. Actually it changes the classes of these blocks and so the colors. You can see the code here:
function inArray(array , exist) {
var rslt = false;
for (var j = 0; j < array.length; j++)
{
if (array[j] == exist)
{
rslt = true;
}
}
return rslt;
}
var colored = Array();
function changeColor(target) {
var blocks = document.getElementsByClassName(target);
var blockLength = blocks.length;
for (var i = 0; i < blockLength; i++)
{
if (colored.length >= 9)
{
colored = [];
}
var rand = 0;
while (rand == 0 || inArray(colored , rand))
{
rand = Math.floor(Math.random()*10)%10;
}
colored.push(rand);
blocks[i].className = target+' color'+rand ;
}
}
window.onload = function() {
changeColor('block');
changeColor('post');
}
the code you seen placed in an external file named 'colors.js' and included by:
<script src="<?php bloginfo('template_url'); ?>/scripts/colors.js"></script>
in my wordpress template.
the code works correctly til I add another code like this:
<script>var _mxvtmw_position = 'left', _mxvtmw_domain = 'icomp.ir'</script>
<script src="http://iwfcdn.iranwebfestival.com/js/mx.vtmw.min.js?12688" async="async"></script>
Why? And how can i fix this problem?
Thank you.
EDIT:
DEMO: http://tuts.icomp.ir/
IN CASE blocks.length IS 1 YOU HAVE TO ADD ONE MORE IF CONDITION
if (blocks.length==undefined){
//code
}
What I'm trying to accomplish with this code is to output the array alphabet as a series of list items into an existing unordered list in the actual markup. I've got the array into list items, but I can't figure out how to tell it to append itself to an existing unordered list <ul id="itemList"></ul>.
var itemsExist = true;
var indexNum = 0;
var unorderedList = document.getElementById('itemList');
var alphabet= new Array("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");
function write_letters(){
for (i = 0; i < alphabet.length; i++ ) {
document.write('<li>' + alphabet[indexNum++] + '</li>');
}
}
if (itemsExist){
write_letters();
} else {
document.write("error!");
}
Don't use document.write to do it. You should act like this:
function write_letters(){
var letters = "";
for (var i = 0; i < alphabet.length; i++ ) {
//Also I don't understand the purpose of the indexNum variable.
//letters += "<li>" + alphabet[indexNum++] + "</li>";
letters += "<li>" + alphabet[i] + "</li>";
}
document.getElementById("itemList").innerHTML = letters;
}
More proper way is to use DOM (in case you want full control of what's coming on):
function write_letters(){
var items = document.getElementById("itemList");
for (var i = 0; i < alphabet.length; i++ ) {
var item = document.createElement("li");
item.innerHTML = alphabet[i];
items.appendChild(item);
}
}
You can use a combination of createElement() and appendChild() to add new HTML elements within another HTML element. The code below should work for you:
<html>
<head>
<title>Script Test</title>
</head>
<body>
<ul id="itemList"></ul>
</body>
<script>
var itemsExist = true;
var indexNum = 0;
var unorderedList = document.getElementById('itemList');
var alphabet= new Array("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");
var myElement;
function write_letters(){
for (i = 0; i < alphabet.length; i++ ) {
// Create the <LI> element
myElement = document.createElement("LI");
// Add the letter between the <LI> tags
myElement.innerHTML = alphabet[indexNum++];
// Append the <LI> to the bottom of the <UL> element
unorderedList.appendChild(myElement);
}
}
if (itemsExist){
write_letters();
} else {
document.write("error!");
}
</script>
</html>
Note how the script exists below the body tag. This is important if you want your script to work the way you wrote it. Otherwise document.getElementById('itemList') will not find the 'itemList' ID.
Try to reduce the actions on the DOM as much as possible. Every appendChild on unorderedList forces the browser to re-render the complete page. Use documentFragement for that sort of action.
var frag = document.createDocumentFragment();
for (var i = alphabet.length; i--; ) {
var li = document.createElement("li");
li.appendChild(document.createTextNode(alphabet[indexNum++]));
frag.appendChild(li);
}
unorderedList.appendChild(frag);
So there will be only one DOM action which forces a complete redraw instead of alphabet.length redraws