How to Make a Personal Question and Answer Search Engine in HTML & Javascript

Updated on April 3, 2019
mikejhca profile image

I started making games and other programs in JavaScript because it is easy to add the code to websites.

Personal Question and Answer Search Engine

Search engines are great for finding lots of useful information but they often provide you with too much information. It can take time to sort through it to find what you need. Most people end up doing the same search over again because they don't remember everything. I started adding useful information to a file so it would be easy to find but it became harder and harder to find what I was looking for.

A personal question and answer search engine makes it easier to find what you are looking for. Type a question. If the answer you want is not there find it. Then add it so it will be there next time. I made a simple question and answer search engine because I don't have a photographic memory. Computers don't forget. They can remember everything you add to them and my computer program makes it easy to find the information I am looking for.

If you don't remember everything then get your computer to remember for you.

Knowledge Base

A knowledge base is a collection of knowledge stored in a file. They can be used to store lots of useful information including answers to frequently asked questions. While taking notes you may type or paste information into a text editor like Notepad or Wordpad. For this program you ask a question then you add the answer to a text box. Instead of just taking notes you are adding content to the search engine so it is easier to find.

After adding some recipes to a knowledge base. I could type 'How to make chicken and rice?' and it would give me the recipe. Using my JavaScript and HTML knowledge base I could ask "How to save and load data to local storage?" and it would give me code that I could copy and paste into an HTML page.

Ideas for a Knowledge Base

computer code
general knowledge
how to
expert systems
recipes
troubleshooting
AI computer players
facts and trivia
technical questions
chat bot
frequently asked questions
manuals
game bot
identification
guides
virtual you
help center
tips

HTML Page with Buttons

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta content="keyword1,keyword2,keyword3,etc." name="keywords">
<meta content="A short description." name="description">
<title>Title of the Page</title>
</head>
<body onload="OnLoad()">
<a style="font-weight:bold;font-size: 120%;">Personal Question & Answer Search Engine</a> <input id="KBName" type="text" placeholder="Name of Knowledge Base">
<div class="autocomplete" id="autocomplete" style="width:300px;">
   <input id="myQuestion" type="text" name="myQuestion" placeholder="Question">
</div>
<br><br><br><textarea style="width:100%;height:50px;border-width: 0;" id="text1" placeholder="Answer will appear here."></textarea>
<button onclick="SetAnswer()">Answer</button> <button onclick="RemoveQuestion()">Remove Question</button> <button onclick="RemoveQuestions()">Clear questions.</button> &nbsp <button id="Backup">Backup</button> <a download="MyQnAFile.txt" id="downloadlink" style="display: none;">Download</a> <button style="display:initial;" onclick="document.getElementById('getFile').click()">Restore</button>
<textarea id="Text2" style="display:none;">Used while sending data to text file.</textarea>
<input type='file' id="getFile" style="display:none;" accept='text/plain' onchange='openFile(event)'>

<script>
//Put the JavaScript below between the script tags.
</script>

</body>
</html>

Autocomplete

Autocomplete gives the user the option of completing words or sentences. You need it so you can match new questions with ones that have already been asked. It saves time and shows the user a list of similar question that have already been asked. The autocomplete function is the main function. If I start typing "How to" it would give me a list of questions that contain the words "how to".

var KBName=document.getElementById("KBName");
var myQuestion=document.getElementById("myQuestion"); //input for Questions
var Text1=document.getElementById("text1");    //TextBox for showing answers
var Text2 = document.getElementById('Text2'); //textbox for saving to text file
var Complete=document.getElementById("autocomplete"); //div
var Backup = document.getElementById('Backup'); //button

var QuestionL=[],AnswerL=[],OnQuestion=-1;
var ScreenRatio=Math.ceil(window.devicePixelRatio);
var ScreenHeight=Math.floor(window.innerHeight*ScreenRatio-6*ScreenRatio);
var ScreenWidth=Math.floor(window.innerWidth*ScreenRatio);

Text1.style.width=Math.floor(ScreenWidth*.98)+"px";
myQuestion.style.width=Text1.style.width; myQuestion.style.maxWidth = "600px";

Complete.style.width=Text1.style.width;
Complete.style.maxWidth = "600px";

myQuestion.focus(); 
Text1.style.height=ScreenHeight*.5+"px";

Complete.style.position = "fixed";

var input = myQuestion;
input.addEventListener("keyup", function(event) { event.preventDefault(); if (event.keyCode === 13) AddNewQuestion(); });


function autocomplete(TxtInp, AutoLst,Lst2)  //(input object,array,array)
{
   var BestMatch=0,Matches=[];
   TxtInp.addEventListener("input", function(e) { //Runs when user writes in the text field.

      var Div1, Div2, val = this.value;
      Text1.value="";

      closeAllLists(); //close open lists
      if (!val) { Text1.placeholder="Answer will appear here.";return false;}
      Text1.placeholder=""; //so do not see placeholder under auto complete text
      Div1 = document.createElement("DIV"); //create Div to contain values
      Div1.setAttribute("id", this.id + "autocomplete-list");
      Div1.setAttribute("class", "autocomplete-items");      
      this.parentNode.appendChild(Div1); //add DIV child of autocomplete element

      var Srt=SortMatches(AutoLst,Lst2,val);

      BestMatch=Srt[0];Matches=Srt[1];

      for (var i = 0; i < AutoLst.length; i++) {       //main loop
         //step 1. break AutoLst[i] & val into words
         var Q=AutoLst[i]; //Q from questions list, U users question
         var Q2="",U=val,U2="",Max=15;

         for(var loo=0;loo<Q.length-1;loo++) {Q2=Q2+Q[loo];} 
         Q2 = Q2.replace(/,/g, ", ");Q2 = Q2.replace(/ +/g, " "); //make sure space after comma & remove extra spaces
         Q3 = Q2.replace(/,/g, "");  //remove commas from Q3
         var Qwords = Q3.split(" "); //turn sentence into array of words
         var Qwords2 = Q2.split(" "); //turn sentence into array of words

         for(var loo=0;loo<U.length;loo++) if(U[loo]!="?" & U[loo]!=".") {U2=U2+U[loo].toLowerCase()}
         U3 = U2.replace(/,/g, " ");U3 = U3.replace(/ +/g, " "); //remove commas & extra spaces
         var Uwords = U3.split(" ");  //Seperate users sentence into words

         for(var j=0;j<Uwords.length;j++) Uwords[j]=Uwords[j].toLowerCase();
         MatchCount=Matches[i]; //values from sorting       

         if (MatchCount>0 & i<Max) {  //could use  MatchCount==BestMatch
            Div2 = document.createElement("DIV");             //Make Div element for each match
            for(var L=0;L<Qwords.length;L++) // make matching words bold 
            { 
               if(Uwords.indexOf(Qwords[L].toLowerCase())>-1) if(L<Qwords.length-1) { if( Qwords2[L].indexOf(",")==-1) { Div2.innerHTML+="<strong>"+Qwords2[L]+" </strong>"; } else Div2.innerHTML+="<strong>"+Qwords2[L].substring(0, Qwords2[L].length-1)+"</strong>, ";  } else {Div2.innerHTML+="<strong>"+Qwords2[L]+"</strong>?";}
               else if(L<Qwords.length-1) {Div2.innerHTML+=Qwords2[L]+" ";} else Div2.innerHTML+=Qwords2[L]+"?";
            }

            Div2.innerHTML += "<input type='hidden' value='" + AutoLst[i] + "'>"; //holds current array's value
            Div2.addEventListener("click", function(e) { //run when Div element is clicked
              TxtInp.value = this.getElementsByTagName("input")[0].value;   
              closeAllLists(); //close  autocomplete values,
              GetAnswer();
            });
            Div1.appendChild(Div2); //adds div2 to Div1
         }
     
      } //end of loop
   }); //end of TxtInp.addEventListener


  TxtInp.addEventListener("keydown", function(e) {
     //could add arrow keys
      if(e.keyCode == 13) { //enter key
        e.preventDefault();
         closeAllLists();
      }
  });
  

  function closeAllLists(elmnt) { 
    var ACI = document.getElementsByClassName("autocomplete-items"); //close autocomplete lists
    for (var i = 0; i < ACI.length; i++) ACI[i].parentNode.removeChild(ACI[i]); 
  }
  document.addEventListener("click", function (e) { //when click on page.
      closeAllLists(e.target);
  });
}

Functions autocomplete needs

function SortMatches(AutoLst,Lst2,val)
{
   var BestMatch=0,Matches=[],Srt=[];
   //Count number of matches   
   for(var i=0;i<AutoLst.length;i++) //loop through all the possible questions
   {  //Q from question list, U from user's question
      Matches[i]=0;
      var Q=AutoLst[i],Q2="",U=val,U2="";

      Q2 = Q.replace(/\?/g,""); //remove ?
      Q2 = Q2.replace(/,/g," "); //replace commas with space.
      Q2 = Q2.replace(/ +/g, " "); //remove double spaces
      var Qwords = Q2.split(" "); //turn string into an array

      U2 = U.replace(/\?|\./g," "); // replace ? & . Need \ before speicial characters
      U2 = U2.replace(/,/g," "); // replace commas
      U2 = U2.replace(/ +/g, " "); //remove double spaces
      if(U2[U2.length-1]==" " & i==0) { U2=U2.slice(0, -1);} //if last is space remove it
      var Uwords = U2.split(" ");

      for(var j=0;j<Uwords.length;j++)
         for(var loo=0;loo<Qwords.length;loo++) if(Uwords[j].toUpperCase()==Qwords[loo].toUpperCase()) {Matches[i]++;break;}      
   } //end of i loop

   //Sort according to Matches
   for(var j=0;j<AutoLst.length-1;j++) //loop through all question words
      for(var i=0;i<AutoLst.length-1;i++) //loop through words user entered
      {
         if(Matches[i]>BestMatch) BestMatch=Matches[i];
         if(Matches[i]<Matches[i+1])
         {
            var AutoLstT=AutoLst[i];AutoLst[i]=AutoLst[i+1];AutoLst[i+1]=AutoLstT; //switch questions
            var Lst2T=Lst2[i];Lst2[i]=Lst2[i+1];Lst2[i+1]=Lst2T;   //switch answers
            var MatchesT=Matches[i];Matches[i]=Matches[i+1];Matches[i+1]=MatchesT; //switch matches
         }
   }
   Srt[0]=BestMatch;Srt[1]=Matches;
   return Srt;
}


function LowerArray() //make Question Array all lower case
{
  var LowerQuestions=[];
  for(var i=0;i<QuestionL.length;i++) LowerQuestions[i]=QuestionL[i].toLowerCase();
  return LowerQuestions; 
}

function FilterQuestion(TempValue,Mark) //pass value when not using Question input, Mark true to add Question mark
{
  var CanChange=false;
  if(TempValue==undefined || TempValue==null) {TempValue=myQuestion.value;CanChange=true;}
  var value=""
  TempValue = TempValue.replace(/ +/g, " "); //replace double spaces with single spaces
  if(TempValue.length==0) {return value;}

  for(var i=0;i<TempValue.length;i++) if(TempValue[i]!="." & TempValue[i]!=":" & TempValue[i]!=";") value=value+TempValue[i]; 
  if(value[value.length-1]!="?" & Mark!=false) {value=value+"?";}

   value = value.replace(/ \?/g,"?"); //handle blank space at end of question

  if(value.length>0) value=value[0].toUpperCase()+value.substring(1, value.length); //make sure 1st letter of question is capitalized
  if(CanChange & value.length>5) { myQuestion.value=value; } //change question asked to match filter

  return value;
}

function FilterAllQuestions() {  for(var i=0;i<QuestionL.length;i++) QuestionL[i]=FilterQuestion(QuestionL[i]); }

function AddNewQuestion(K)
{
  var value=FilterQuestion();if(value.length<6)  {return;}
  FilterAllQuestions(); //double check to make sure questions asked match new question format
  
  OnQuestion= FindQ()
  if(OnQuestion>-1) GetAnswer(); //Asked before
  else {OnQuestion=QuestionL.length;QuestionL[QuestionL.length]=value;AnswerL[AnswerL.length]="";if(K!=true) Text1.value="";if(K!=true) SaveQuestions("AddNewQuestion"); } //new
}

function GetAnswer() //display answer to the question if there is one
{
  OnQuestion=FindQ(); 
  if(OnQuestion>-1) { if(AnswerL[OnQuestion]==undefined || AnswerL[OnQuestion]==null) AnswerL[OnQuestion]=""; Text1.value=AnswerL[OnQuestion];}
  else {Text1.value="";OnQuestion=QuestionL.length; AddNewQuestion(); }
}


function FindQ(Q) //look for index of question
{
   var CanChange=false;
   if(Q==undefined) {Q=myQuestion.value;CanChange=true;}
   Q=FilterQuestion(Q);
   if(CanChange) myQuestion.value=Q;
   var InputLower=Q.toLowerCase();
   var LowerQuestions=LowerArray(QuestionL);
   var index=LowerQuestions.indexOf(InputLower);
   return index;
}

function SetAnswer() //when user answers a question
{
  if(myQuestion.value.length<6) return; //return if question length is too short
  OnQuestion=FindQ();
  if(OnQuestion<0) AddNewQuestion(true);
  else {var value=FilterQuestion(); QuestionL[OnQuestion]=value;AnswerL[OnQuestion]=Text1.value;SaveQuestions("SetAnswer");}
}

Saving the Knowledge

When you ask and answer questions the information is saved automatically using 'localStorage'. It stores the information for the current knowledge base on your computer. Only the current browser can access it. So if you made the knowledge base in Chrome you can't access it in Firefox. You can also save and load using text files. Saving and loading text files is done manually with the 'Backup' and 'Restore' buttons.

A knowledge base that is saved to a text file can be accessed by different browsers. You could even e-mail it to someone that has this program on their computer.

Save & Load Local

function SaveQuestions(Where)
{
   for(var i=0;i<AnswerL.length;i++) if(AnswerL[i]==undefined) {AnswerL[i]="";alert("Found undefined");}  //make sure no undefined answers
   FilterAllQuestions(); //make sure Question has ? at the end of it

   var Answers2="",Questions2="";
   //add ~~ as a sperator
   for(var i=0;i<QuestionL.length;i++) if(i<QuestionL.length-1) Questions2=Questions2+""+QuestionL[i]+"~~"; else Questions2=Questions2+""+QuestionL[i]; 
   for(var i=0;i<AnswerL.length;i++) if(i<AnswerL.length-1) Answers2=Answers2+""+AnswerL[i]+"~~"; else Answers2=Answers2+""+AnswerL[i];

   var Title=FilterQuestion(KBName.value,false);
   localStorage.setItem("mikesQuestions", Title+"~~"+Questions2);
   localStorage.setItem("mikesAnswers", Answers2); 
}

function LoadQuestions()
{
   var GQ,GA;
   if (localStorage.mikesAnswers) {GQ=localStorage.getItem("mikesQuestions");GA=localStorage.getItem("mikesAnswers");}
   else {QuestionL=[];AnswerL=[];return;}

   QuestionL=GQ.split("~~"); KBName.value=QuestionL[0]; //Title;
   QuestionL.splice(0,1); //remove the title
   AnswerL=GA.split("~~"); //separate text into an array
}

Save & Load to text files

   var textFile = null;
   function makeTextFile(text) //makes a url with the data so it can be downloaded
   {
      var data = new Blob([text], {type: 'text/plain'});
      if (textFile !== null)  window.URL.revokeObjectURL(textFile);  //If replacing previous revoke to free memory   
      textFile = window.URL.createObjectURL(data);
      return textFile; //needs this for download button click to work
   }; 

   Backup.addEventListener('click', function () { //When click 'Backup' button 
      var link = document.getElementById('downloadlink');
      var Title=FilterQuestion(KBName.value,false);

      var Questions2="",Answers2="";
      for(var i=0;i<QuestionL.length;i++) Questions2=Questions2+QuestionL[i]+"~~";
      for(var i=0;i<AnswerL.length;i++) if(i<AnswerL.length-2) Answers2=Answers2+AnswerL[i]+"~~"; else Answers2=Answers2+AnswerL[i];
      Text2.value=Title+"~~"+QuestionL.length+"~~"+Questions2+Answers2; 

      link.href = makeTextFile(Text2.value); //if want to see add link.style.display = 'block';
      link.click();  //so user does not need to click.
   }, false);


function openFile(event) {  //When click 'Restore'
   var input = event.target;
   var reader = new FileReader();
   reader.onload = function()
   {
      if(document.getElementById("getFile").value=="") return;
      var text = reader.result;
      var textArray=text.split("~~"); //turn text into an array
      KBName.value=textArray[0];  
      NumberOfQuestions=parseInt(textArray[1]); //change from string to number
      QuestionL=textArray.slice(2, NumberOfQuestions+2);
      AnswerL=textArray.slice(NumberOfQuestions+2);
      autocomplete(myQuestion, QuestionL,AnswerL); //call again so updates autocomplete
      SaveQuestions("from loaded text restoring"); //write over the previous local questions
      document.getElementById("getFile").value=""; //so it can load the same file twice
   };
   reader.readAsText(input.files[0]);
};

Functions to Remove Questions

function RemoveQuestion() //when user chooses to remove an answer from local
{
   OnQuestion = FindQ();
   if (OnQuestion > -1) {
      QuestionL.splice(OnQuestion, 1);
      AnswerL.splice(OnQuestion, 1);
      myQuestion.value="";
      Text1.value="";
      SaveQuestions("RemoveQuestion")
      autocomplete(myQuestion, QuestionL,AnswerL);
   }
}

function RemoveQuestions() //only removes local, txt files need to be deleted by user
{
   if(confirm("Clear all questions & answers.") )
   {
      localStorage.removeItem('mikesQuestions'); 
      localStorage.removeItem('mikesAnswers'); 
      myQuestion.value="";Text1.value="";
      QuestionL=[];AnswerL=[]; 
      autocomplete(myQuestion, QuestionL,AnswerL);
   }
}

Runs When Page Finishes Loading

function OnLoad() 
{
  LoadQuestions();
  autocomplete(myQuestion, QuestionL,AnswerL);
}

How to Copy and Paste Code

Open a text editor like Notepad or Wordpad. Copy and paste the html code with buttons. Then copy the javascript in order, pasting it between the script tags. Save the file with a name like QnASearch.htm so you can open it in a browser. Make sure you pay attention to file's location. View your computer files and find the folder. Then double click to open the file.

You should see the question and answer search engine. The knowledge base will be empty. So you will need to fill it by asking and answering questions. It is intended to be used as an offline webpage. You open it in a web browser but you don't need to be online.

Load data from a text file online.

//fetches a file named KB that was uploaded with your HTML file
fetch('KB.txt')
   .then(response => response.text())
   .then((data) => {
      alert(data); //to see that it worked
     //move the data to variables
   })

Sharing & Using Your Knowledge Base

This program is good for getting your computer to remember things for you. You can also share your knowledge or get other people to share information by sharing the text files created with the "Backup" button. The easiest way would be to email the file. Another way to share a knowledge base is to load it into a web page. Upload a text file with the questions and answers. Then get a web page to load the information using the onload function and fetch code shown above.

After creating a knowledge base you can get other web pages and programs to load and use the data. You could use it for games, chat bots, a FAQ page, help pages, expert systems, etc. Instead of just answering questions you ask the program could fill in for you in your absence. A computer program could make decisions based on your knowledge and respond the way you would.

This content is accurate and true to the best of the author’s knowledge and is not meant to substitute for formal and individualized advice from a qualified professional.

Questions & Answers

    © 2019 Michael H

    Comments

      0 of 8192 characters used
      Post Comment

      No comments yet.

      working

      This website uses cookies

      As a user in the EEA, your approval is needed on a few things. To provide a better website experience, owlcation.com uses cookies (and other similar technologies) and may collect, process, and share personal data. Please choose which areas of our service you consent to our doing so.

      For more information on managing or withdrawing consents and how we handle data, visit our Privacy Policy at: https://owlcation.com/privacy-policy#gdpr

      Show Details
      Necessary
      HubPages Device IDThis is used to identify particular browsers or devices when the access the service, and is used for security reasons.
      LoginThis is necessary to sign in to the HubPages Service.
      Google RecaptchaThis is used to prevent bots and spam. (Privacy Policy)
      AkismetThis is used to detect comment spam. (Privacy Policy)
      HubPages Google AnalyticsThis is used to provide data on traffic to our website, all personally identifyable data is anonymized. (Privacy Policy)
      HubPages Traffic PixelThis is used to collect data on traffic to articles and other pages on our site. Unless you are signed in to a HubPages account, all personally identifiable information is anonymized.
      Amazon Web ServicesThis is a cloud services platform that we used to host our service. (Privacy Policy)
      CloudflareThis is a cloud CDN service that we use to efficiently deliver files required for our service to operate such as javascript, cascading style sheets, images, and videos. (Privacy Policy)
      Google Hosted LibrariesJavascript software libraries such as jQuery are loaded at endpoints on the googleapis.com or gstatic.com domains, for performance and efficiency reasons. (Privacy Policy)
      Features
      Google Custom SearchThis is feature allows you to search the site. (Privacy Policy)
      Google MapsSome articles have Google Maps embedded in them. (Privacy Policy)
      Google ChartsThis is used to display charts and graphs on articles and the author center. (Privacy Policy)
      Google AdSense Host APIThis service allows you to sign up for or associate a Google AdSense account with HubPages, so that you can earn money from ads on your articles. No data is shared unless you engage with this feature. (Privacy Policy)
      Google YouTubeSome articles have YouTube videos embedded in them. (Privacy Policy)
      VimeoSome articles have Vimeo videos embedded in them. (Privacy Policy)
      PaypalThis is used for a registered author who enrolls in the HubPages Earnings program and requests to be paid via PayPal. No data is shared with Paypal unless you engage with this feature. (Privacy Policy)
      Facebook LoginYou can use this to streamline signing up for, or signing in to your Hubpages account. No data is shared with Facebook unless you engage with this feature. (Privacy Policy)
      MavenThis supports the Maven widget and search functionality. (Privacy Policy)
      Marketing
      Google AdSenseThis is an ad network. (Privacy Policy)
      Google DoubleClickGoogle provides ad serving technology and runs an ad network. (Privacy Policy)
      Index ExchangeThis is an ad network. (Privacy Policy)
      SovrnThis is an ad network. (Privacy Policy)
      Facebook AdsThis is an ad network. (Privacy Policy)
      Amazon Unified Ad MarketplaceThis is an ad network. (Privacy Policy)
      AppNexusThis is an ad network. (Privacy Policy)
      OpenxThis is an ad network. (Privacy Policy)
      Rubicon ProjectThis is an ad network. (Privacy Policy)
      TripleLiftThis is an ad network. (Privacy Policy)
      Say MediaWe partner with Say Media to deliver ad campaigns on our sites. (Privacy Policy)
      Remarketing PixelsWe may use remarketing pixels from advertising networks such as Google AdWords, Bing Ads, and Facebook in order to advertise the HubPages Service to people that have visited our sites.
      Conversion Tracking PixelsWe may use conversion tracking pixels from advertising networks such as Google AdWords, Bing Ads, and Facebook in order to identify when an advertisement has successfully resulted in the desired action, such as signing up for the HubPages Service or publishing an article on the HubPages Service.
      Statistics
      Author Google AnalyticsThis is used to provide traffic data and reports to the authors of articles on the HubPages Service. (Privacy Policy)
      ComscoreComScore is a media measurement and analytics company providing marketing data and analytics to enterprises, media and advertising agencies, and publishers. Non-consent will result in ComScore only processing obfuscated personal data. (Privacy Policy)
      Amazon Tracking PixelSome articles display amazon products as part of the Amazon Affiliate program, this pixel provides traffic statistics for those products (Privacy Policy)
      ClickscoThis is a data management platform studying reader behavior (Privacy Policy)