Introduction
Either you are a fresher or an experienced developer, you need a project that shines out of the crowd. Today we will build one such project. This is an excellent project to have it on your resume with latest technology. Stay tuned for this 2 parts article and add this feather 🪶 in your cap ! 🧢
Learn from the detailed step-by-step video below –
The Project 🗒️
Today we will “build our own Text-To-Speech application” which will take following input on a web page
- Text – to generate the speech.
- Source Language – of the input text.
- Target Language – in which the audio (speech) is required to generate.
and display the audio file on the web page as response.
The Preparation ✍🏻
In this project we will
- Create a simple nodejs package which will have a frontend html page having an Input form for Text and Two drop-downs to select Source Language and Target Language.
- Integrate a Text Translator (Google Translate API or some other public API) using Rapid API.
- Integrate Open AI API to generate Audio file for the input text. Read API documentation here.
- Upload the playable audio file on web page.
The Pre-Requirements 🛠️
- None. We will setup everything from scratch.
Technology & APIs used 🕹️
- Text Translator from RapidAPI. Read the documentation from here.
- Open AI public audio speech API. Read the documentation from here.
- Node Js – Open-source Javascript run-time platform available for Mac, Windows, Linux etc.
- Express Js – Node.js web application framework to develop RESTful APIs with Node.js. Read here
- Axios – Node.js library that allows making HTTP requests from web browser or Node.js
- Postman – Postman is an application used for API Testing. This application allows to test HTTP or HTTPS requests.
Don’t worry, we will setup all of it in our project.
All Set, Let’s Go ! 🚤
Setup 🌱
- Download Postman application for testing your application (Recommended but you can skip the steps involving postman testing).
- Create a free account in Rapid API (Rapid API is an API marketplace that allows developers to create, test and connect to APIs).
- Now let’s setup Node.js on our computer. To do that, you can download Node.js from the main website – https://nodejs.org/en
- Go to desktop and create a folder with your project name. I am naming this application – Techshshila Translator.
- Open any IDE (vscode, intellij etc.) and open the folder we created above.
- We will now initialise node modules by running the command in the terminal –
~ % npm init
- Once you have run the above command, you will see a package.json file.
- Now we will create a new javascript file and call it – index.js
- We will also create a new html file and call it – index.html
- We will then install few important packages which will be required through our development. These packages are –
- Run the following commands to install the above packages
~ % npm i express
~ % npm i axios
- Once these packages are installed we are good to go.
Coding – Getting the basics right !
- Let’s add some basic code in the index.js file.
// import express and axios
const express = require('express');
const app = express();
const axios = require('axios');
// define the local port 8000 or use the port number setup as the environment variable
const PORT = process.env.PORT || 8000;
// open the listener to our PORT. Any activity at PORT will now be detected
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
// application logic to be added
- Now our objective is to take the inputs from the HTML page and use that input to call the translate and audio generator APIs. So let’s create an HTML page with input text fields.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div id="mainContent">
<div id="card">
<h1>Techshshila Translator</h1>
<!-- Creat an input form -->
<form id="translationForm">
<!-- Creat an input field to take input - Text-->
<label for="textInput">Text:</label>
<div id="textInputContainer">
<textarea id="textInput" name="text" placeholder="Enter Text To Translate"></textarea>
</div>
<!-- Creat an empty drop-down field to select Source Language -->
<label for="sourceSelect">Source:</label>
<select id="sourceSelect" name="source" required>
</select>
<!-- Creat an empty drop-down field to select Target Language -->
<label for="targetSelect">Target:</label>
<select id="targetSelect" name="source" required>
</select>
<!-- Add a button to click to generate audio file-->
<button id= "translateButton" type="button">Generate Translated Audio</button>
</form>
</div>
</div>
</body>
</html>
- The above html page generates a simple form without styling. Let’s add styling to it. Create a new css file – styles.css
Keep it in style – 🎨
Show File
html,body {
font-family: 'Roboto', sans-serif; /* Use Roboto or another modern font */
background-color: #f4f4f4;
text-align: center;
margin: 0;
padding: 0;
height: 100%;
}
#mainContent {
width: 50%;
display: flex;
flex-direction: column;
height: 70%;
justify-content: center;
position: absolute;
margin-left: 15%;
}
/* Add a loading class */
#translationForm.loading button {
position: relative;
}
#card {
float: left;
background-color: #2f1a6e;
padding-top: 30px;
padding-bottom: 120px;
padding-left: 60px;
padding-right: 60px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
text-align: center;
font-family: 'Playfair Display', serif;
color: #ef0ec5;
font-size: 18px;
width: 50%;
height: 64.5%;
position: absolute;
right: 0;
top: 10%;
}
#translationForm.loading button::after {
content: "";
position: absolute;
top: 30%;
right: 20px; /* Adjust the distance from the right side of the button */
transform: translateY(-50%);
border: 3px solid #ffffff;
border-radius: 50%;
border-top: 3px solid transparent;
border-bottom: 3px solid transparent;
width: 14px;
height: 14px;
animation: spin 1s linear infinite;
}
/* Add this style for the textarea with character count */
#textInputContainer {
position: relative;
}
#textInput {
width: 100%;
padding: 10px;
margin-bottom: 15px;
box-sizing: border-box;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 16px;
background-color: #ffffff;
}
#translationForm.loading button::after {
content: "";
position: absolute;
top: 30%;
right: 20px; /* Adjust the distance from the right side of the button */
transform: translateY(-50%);
border: 3px solid #ffffff;
border-radius: 50%;
border-top: 3px solid transparent;
border-bottom: 3px solid transparent;
width: 14px;
height: 14px;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
input, select {
width: 100%;
padding: 10px;
margin-bottom: 15px;
box-sizing: border-box;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 16px; /* Increased font size */
font-family: 'Playfair Display', serif;
}
/* Style the dropdowns */
select {
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
padding: 10px;
background-color: #ffffff;
background-image: linear-gradient(45deg, transparent 50%, #555 50%), linear-gradient(135deg, #555 50%, transparent 50%);
background-position: calc(100% - 20px) calc(1em + 2px), calc(100% - 15px) calc(1em + 2px);
background-size: 5px 5px, 5px 5px;
background-repeat: no-repeat;
border: 1px solid #ccc;
border-radius: 4px;
color: #555;
font-size: 16px; /* Increased font size */
font-family: 'Playfair Display', serif;
}
/* Style the hover and focus state of the dropdown */
select:hover, select:focus {
border-color: #666;
}
/* Updated label styles with a stylish font */
label {
display: block;
margin-bottom: 8px;
color: #ffffff;
font-family: 'Playfair Display', serif; /* Use the Playfair Display font */
font-weight: bold; /* Make the label text bold */
font-size: 16px; /* Adjust the font size */
text-align: left; /* Align the text to the left */
}
button {
background-color: #9f0d85;
color: #fff;
padding: 14px 20px;
border: none;
width: 15rem;
border-radius: 25px;
cursor: pointer;
font-size: 17px;
font-family: 'Playfair Display', serif;
margin-top: 1rem;
margin-bottom: 1rem;
}
button:hover {
background-color: #45a049;
}
- Let’s link this css to our index.html like below –
<!DOCTYPE html>
<html lang="en">
<head>
...
<link rel="stylesheet" href="./styles.css">
</head>
...
- Now this will style input form but our drop-downs are still empty. Let’s add languages to our source and target drop-downs.
Adding the languages for selection !
- To do that we will create a new javascript file and call it – constants.js
- Before we add languages we must know which languages our TextTranslator API supports. We will be using Text Translator API present in Rapid API – here. I have that information, so i will add it in the constants file, you can copy it.
- Let’s update the constants file –
Show constants file
// constants
export const languageData = {
"data": {
"languages": [
{
"code": "en",
"name": "English"
},
{
"code": "hi",
"name": "Hindi"
},
{
"code": "it",
"name": "Italian"
},
{
"code": "af",
"name": "Afrikaans"
},
{
"code": "sq",
"name": "Albanian"
},
{
"code": "am",
"name": "Amharic"
},
{
"code": "ar",
"name": "Arabic"
},
{
"code": "hy",
"name": "Armenian"
},
{
"code": "az",
"name": "Azerbaijani"
},
{
"code": "eu",
"name": "Basque"
},
{
"code": "be",
"name": "Belarusian"
},
{
"code": "bn",
"name": "Bengali"
},
{
"code": "bs",
"name": "Bosnian"
},
{
"code": "bg",
"name": "Bulgarian"
},
{
"code": "ca",
"name": "Catalan"
},
{
"code": "ceb",
"name": "Cebuano"
},
{
"code": "ny",
"name": "Chichewa"
},
{
"code": "zh-CN",
"name": "Chinese (Simplified)"
},
{
"code": "zh-TW",
"name": "Chinese (Traditional)"
},
{
"code": "co",
"name": "Corsican"
},
{
"code": "hr",
"name": "Croatian"
},
{
"code": "cs",
"name": "Czech"
},
{
"code": "da",
"name": "Danish"
},
{
"code": "nl",
"name": "Dutch"
},
{
"code": "eo",
"name": "Esperanto"
},
{
"code": "et",
"name": "Estonian"
},
{
"code": "tl",
"name": "Filipino"
},
{
"code": "fi",
"name": "Finnish"
},
{
"code": "fr",
"name": "French"
},
{
"code": "fy",
"name": "Frisian"
},
{
"code": "gl",
"name": "Galician"
},
{
"code": "ka",
"name": "Georgian"
},
{
"code": "de",
"name": "German"
},
{
"code": "el",
"name": "Greek"
},
{
"code": "gu",
"name": "Gujarati"
},
{
"code": "ht",
"name": "Haitian Creole"
},
{
"code": "ha",
"name": "Hausa"
},
{
"code": "haw",
"name": "Hawaiian"
},
{
"code": "iw",
"name": "Hebrew"
},
{
"code": "hmn",
"name": "Hmong"
},
{
"code": "hu",
"name": "Hungarian"
},
{
"code": "is",
"name": "Icelandic"
},
{
"code": "ig",
"name": "Igbo"
},
{
"code": "id",
"name": "Indonesian"
},
{
"code": "ga",
"name": "Irish"
},
{
"code": "ja",
"name": "Japanese"
},
{
"code": "jw",
"name": "Javanese"
},
{
"code": "kn",
"name": "Kannada"
},
{
"code": "kk",
"name": "Kazakh"
},
{
"code": "km",
"name": "Khmer"
},
{
"code": "rw",
"name": "Kinyarwanda"
},
{
"code": "ko",
"name": "Korean"
},
{
"code": "ku",
"name": "Kurdish (Kurmanji)"
},
{
"code": "ky",
"name": "Kyrgyz"
},
{
"code": "lo",
"name": "Lao"
},
{
"code": "la",
"name": "Latin"
},
{
"code": "lv",
"name": "Latvian"
},
{
"code": "lt",
"name": "Lithuanian"
},
{
"code": "lb",
"name": "Luxembourgish"
},
{
"code": "mk",
"name": "Macedonian"
},
{
"code": "mg",
"name": "Malagasy"
},
{
"code": "ms",
"name": "Malay"
},
{
"code": "ml",
"name": "Malayalam"
},
{
"code": "mt",
"name": "Maltese"
},
{
"code": "mi",
"name": "Maori"
},
{
"code": "mr",
"name": "Marathi"
},
{
"code": "mn",
"name": "Mongolian"
},
{
"code": "my",
"name": "Myanmar (Burmese)"
},
{
"code": "ne",
"name": "Nepali"
},
{
"code": "no",
"name": "Norwegian"
},
{
"code": "or",
"name": "Odia (Oriya)"
},
{
"code": "ps",
"name": "Pashto"
},
{
"code": "fa",
"name": "Persian"
},
{
"code": "pl",
"name": "Polish"
},
{
"code": "pt",
"name": "Portuguese"
},
{
"code": "pa",
"name": "Punjabi"
},
{
"code": "ro",
"name": "Romanian"
},
{
"code": "ru",
"name": "Russian"
},
{
"code": "sm",
"name": "Samoan"
},
{
"code": "gd",
"name": "Scots Gaelic"
},
{
"code": "sr",
"name": "Serbian"
},
{
"code": "st",
"name": "Sesotho"
},
{
"code": "sn",
"name": "Shona"
},
{
"code": "sd",
"name": "Sindhi"
},
{
"code": "si",
"name": "Sinhala"
},
{
"code": "sk",
"name": "Slovak"
},
{
"code": "sl",
"name": "Slovenian"
},
{
"code": "so",
"name": "Somali"
},
{
"code": "es",
"name": "Spanish"
},
{
"code": "su",
"name": "Sundanese"
},
{
"code": "sw",
"name": "Swahili"
},
{
"code": "sv",
"name": "Swedish"
},
{
"code": "tg",
"name": "Tajik"
},
{
"code": "ta",
"name": "Tamil"
},
{
"code": "tt",
"name": "Tatar"
},
{
"code": "te",
"name": "Telugu"
},
{
"code": "th",
"name": "Thai"
},
{
"code": "tr",
"name": "Turkish"
},
{
"code": "tk",
"name": "Turkmen"
},
{
"code": "uk",
"name": "Ukrainian"
},
{
"code": "ur",
"name": "Urdu"
},
{
"code": "ug",
"name": "Uyghur"
},
{
"code": "uz",
"name": "Uzbek"
},
{
"code": "vi",
"name": "Vietnamese"
},
{
"code": "cy",
"name": "Welsh"
},
{
"code": "xh",
"name": "Xhosa"
},
{
"code": "yi",
"name": "Yiddish"
},
{
"code": "yo",
"name": "Yoruba"
},
{
"code": "zu",
"name": "Zulu"
},
{
"code": "he",
"name": "Hebrew"
},
{
"code": "zh",
"name": "Chinese (Simplified)"
}
]
}
};
- We will import this constants file in our index.html file and add it to our drop-downs using a function. Naturally we would not want to add them one by one ! 😁
- Let’s see the modified index.html code –
Show File
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./check.css">
</head>
<body>
<div id="mainContent">
<div id="card">
<h1>Techshshila Translator</h1>
<!-- Creat an input form -->
<form id="translationForm">
<!-- Creat an input field to take input - Text-->
<label for="textInput">Text:</label>
<div id="textInputContainer">
<textarea id="textInput" name="text" placeholder="Enter Text To Translate"></textarea>
</div>
<!-- Creat an empty drop-down field to select Source Language -->
<label for="sourceSelect">Source:</label>
<select id="sourceSelect" name="source" required>
</select>
<!-- Creat an empty drop-down field to select Target Language -->
<label for="targetSelect">Target:</label>
<select id="targetSelect" name="source" required>
</select>
<script type = "module">
// Get the select element
import {languageData} from "./constants.js";
let sourceSelect = document.getElementById("sourceSelect");
let targetSelect = document.getElementById("targetSelect");
// Populate the select options using the array
languageData.data.languages.map(language => {
let sourceOption = document.createElement("option");
sourceOption.value = language.code;
sourceOption.text = language.name;
let targetOption = document.createElement("option");
targetOption.value = language.code;
targetOption.text = language.name;
sourceSelect.appendChild(sourceOption);
targetSelect.appendChild(targetOption);
})
</script>
<!-- Add a button to click to generate audio file-->
<button id= "translateButton" type="button">Generate Translated Audio</button>
</form>
</div>
</div>
</body>
</html>
- Tadaaaa !! 🎉 We have the successfully created an input form for our application. Now this input will be passed on to the back-end logic which we will use to call our translation and audio generation API.
Application Logic 💡
- Now its time to add our application logic.
Step 1 – Adding Text Translation API
If you read the Text Translator document, you will see how to call the API. We will copy the header, URL and method options for the API and use it in our application. Here is how we will change our index.js file.
Show File
// import express and axios
const express = require('express');
const app = express();
const axios = require('axios');
// define the local port 8000 or use the port number setup as the environment variable
const PORT = 8000;
// open the listener to our PORT. Any activity at PORT will now be detected
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
app.use(express.json());
// text translate POST API call options. [from Rapid API]
const textTranslatorTranslateOptions = {
method: 'POST',
url: 'https://text-translator2.p.rapidapi.com/translate',
headers: {
'content-type': 'application/x-www-form-urlencoded',
// Your rapid API key will automatically be populated below.
'X-RapidAPI-Key': {YOUR_RAPID_API_KEY},
'X-RapidAPI-Host': 'text-translator2.p.rapidapi.com'
}
};
// map to store POST API request body parameters as key-value pair
const textTranslatorTranslateAPIRequestBodyParams = {};
// POST API call which will take input parameters from the form created
// in index.html
app.post("/", async function (req, res) {
try {
console.log("request = ", req);
const reqBody = req.body;
console.log("Req body : ",reqBody);
// read the input from the user input
const text = reqBody.text;
const sourceLanguage = reqBody.source;
const targetLanguage = reqBody.target;
// handling error case when fields are null
if (text == null || sourceLanguage == null || targetLanguage == null) {
return res.status(400).json({
error: "Bad Request: Text, Source Language, and Target Language are required" });
}
// initialising the POST API parameters before calling the
// Text Translator APIs
textTranslatorTranslateAPIRequestBodyParams['text'] = text;
textTranslatorTranslateAPIRequestBodyParams['source_language'] = sourceLanguage;
textTranslatorTranslateAPIRequestBodyParams['target_language'] = targetLanguage;
// call the Text Translator API
const responseTranslate = await axios.request({
...textTranslatorTranslateOptions,
data: textTranslatorTranslateAPIRequestBodyParams
});
// log the API response in console.
console.log('API Response', responseTranslate.data);
const translatedText = responseTranslate.data.data.translatedText;
if (translatedText.length === 0) {
return res.status(500).json({ error: 'Internal Error: Translated text is empty.' });
}
// log the translated text in console.
console.log('Translated Text in Target language = ',translatedText);
// return the 200 response
res.status(200).json(
{
text: text,
sourceLanguage: sourceLanguage,
targetLanguage: targetLanguage,
translatedText: translatedText
});
} catch (err) {
// log the axios error if occurred
console.error("Error occurred:", err);
res.status(500).json({ error: "Internal Error: " + err.message });
}
});
Let’s test the above –
- First, let’s call run our service, by running the command
~ % npm start
- Now Open Postman Application and create a POST request –
- URL : http://localhost:8000/
- Body :
The source language is english and target language is hindi. (💡Tip: Try yourself with your favourite 🤩 target language.)
{
"text": "I love programming !",
"source" : "en",
"target" : "hi"
}
- You should get a response:
{
"text": "I love programming !",
"sourceLanguage": "en",
"targetLanguage": "hi",
"translatedText": "मुझे प्रोग्रामिंग बहुत पसंद है!"
}
Congratulations ! 🎉 We have successfully translated our source language. Kudos for stretching this far, we are almost there. In the next part, we will generate the speech for the translated text too and display it on our website !