Initial commit
This commit is contained in:
commit
4dcd202425
|
@ -0,0 +1,7 @@
|
||||||
|
node_modules/
|
||||||
|
._.DS_Store
|
||||||
|
.DS_Store
|
||||||
|
.history/
|
||||||
|
package-lock.json
|
||||||
|
*.mp3
|
||||||
|
._*
|
|
@ -0,0 +1,49 @@
|
||||||
|
# Sanskrit TTS
|
||||||
|
## Info
|
||||||
|
A text to speech web-app for the ancient language Sanskrit, using [https://github.com/SameeraMurthy/sanskrit-tts](https://github.com/SameeraMurthy/sanskrit-tts) npm library.
|
||||||
|
|
||||||
|
### Writing Scripts
|
||||||
|
All scripts supported by the `sanskrit-tts` library are supported.
|
||||||
|
- bengali
|
||||||
|
- devanagari
|
||||||
|
- gujarati
|
||||||
|
- gurmukhi
|
||||||
|
- kannada
|
||||||
|
- malayalam
|
||||||
|
- oriya
|
||||||
|
- tamil
|
||||||
|
- telugu
|
||||||
|
- grantha
|
||||||
|
- grantamil
|
||||||
|
- hk (Harvard-Kyoto)
|
||||||
|
- iast (International Alphabet of Sanskrit Transliteration)
|
||||||
|
- iso15919 (ISO 15919)
|
||||||
|
- itrans (ITRANS)
|
||||||
|
- slp1 (Sanskrit Library Phonetic Basic)
|
||||||
|
- velthuis (Velthuis)
|
||||||
|
- wx (WX)
|
||||||
|
|
||||||
|
## Instances
|
||||||
|
| **URL** | **Country** | **Status** | **Hosted By** |
|
||||||
|
|----------------------------------------------------------------|-------------|------------|---------------|
|
||||||
|
| [sanskrit.winsdominoes.net](https://sanskrit.winsdominoes.net) | 🇹🇭 | Up | @WinsDominoes |
|
||||||
|
|
||||||
|
## Quick Setup
|
||||||
|
Wanna try this out? Here's what you need to do
|
||||||
|
#### Clone this repo
|
||||||
|
```
|
||||||
|
git clone https://github.com/WinsDominoes/sanskrit-tts
|
||||||
|
```
|
||||||
|
#### Install packages
|
||||||
|
```
|
||||||
|
npm install -y
|
||||||
|
```
|
||||||
|
#### Run the application
|
||||||
|
```
|
||||||
|
node .
|
||||||
|
```
|
||||||
|
The frontend endpoint will be at `http://localhost:3000` and the API endpoint will be at `http://localhost:3000/api/tts`
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
- `sanskrit-tts` library by [https://github.com/SameeraMurthy/sanskrit-tts](https://github.com/SameeraMurthy/sanskrit-tts)
|
||||||
|
- Material Design Theme by [daemonite.github.io](https://daemonite.github.io/material/)
|
|
@ -0,0 +1,78 @@
|
||||||
|
const express = require('express');
|
||||||
|
const app = express();
|
||||||
|
const port = process.env.PORT || 3000;
|
||||||
|
|
||||||
|
const tts = require("sanskrit-tts")
|
||||||
|
const { v4: uuidv4 } = require('uuid');
|
||||||
|
|
||||||
|
const bodyParser = require('body-parser');
|
||||||
|
const cors = require('cors');
|
||||||
|
|
||||||
|
app.use(cors({
|
||||||
|
origin: '*'
|
||||||
|
}))
|
||||||
|
|
||||||
|
app.set('view engine', 'ejs');
|
||||||
|
app.use(express.static(__dirname + '/public'))
|
||||||
|
|
||||||
|
app.use(bodyParser.json());
|
||||||
|
app.use(bodyParser.urlencoded());
|
||||||
|
app.use(bodyParser.urlencoded({ extended: true }));
|
||||||
|
|
||||||
|
app.get('/', (req, res) => {
|
||||||
|
res.render('pages/home.ejs')
|
||||||
|
})
|
||||||
|
|
||||||
|
app.post('/api/tts', (req, res) => {
|
||||||
|
console.log("TTS Request")
|
||||||
|
|
||||||
|
const body = req.body;
|
||||||
|
let text = body.text;
|
||||||
|
let script = body.script;
|
||||||
|
|
||||||
|
if(body) {
|
||||||
|
if(script) {
|
||||||
|
if(text) {
|
||||||
|
console.log("Request Body");
|
||||||
|
console.log("Text: " + text)
|
||||||
|
console.log("Script: " + script)
|
||||||
|
|
||||||
|
let fileName = "audio/" + uuidv4() + ".mp3";
|
||||||
|
console.log("File Path: " + fileName)
|
||||||
|
|
||||||
|
tts.saveFile(text, {
|
||||||
|
script: script,
|
||||||
|
slow: true,
|
||||||
|
fileName: "public/" + fileName
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(200).send({
|
||||||
|
"response": true,
|
||||||
|
"message": "TTS request successful!",
|
||||||
|
"url": "/" + fileName
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
res.status(403).send({
|
||||||
|
"response": false,
|
||||||
|
"message": "Text cannot be empty!"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.status(403).send({
|
||||||
|
"response": false,
|
||||||
|
"message": "Writing script cannot be empty!"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.status(403).send({
|
||||||
|
"response": false,
|
||||||
|
"message": "Request body cannot be empty!"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(port, () =>
|
||||||
|
console.log(`App is listening on port ${port}.`) // this is where the node app will be started
|
||||||
|
)
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"body-parser": "^1.20.2",
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"ejs": "^3.1.9",
|
||||||
|
"express": "^4.18.2",
|
||||||
|
"sanskrit-tts": "^1.0.0",
|
||||||
|
"uuid": "^9.0.0"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
body{
|
||||||
|
margin:0;
|
||||||
|
padding:0
|
||||||
|
}
|
||||||
|
button{
|
||||||
|
border:none;
|
||||||
|
border-radius:2px;
|
||||||
|
padding:12px 18px;
|
||||||
|
font-size:16px;
|
||||||
|
text-transform:uppercase;
|
||||||
|
cursor:pointer;
|
||||||
|
color:#fff;
|
||||||
|
background-color:#2196f3;
|
||||||
|
box-shadow:0 0 4px #999;
|
||||||
|
outline:none
|
||||||
|
}
|
||||||
|
pre{
|
||||||
|
white-space:pre-line
|
||||||
|
}
|
||||||
|
form, input, textarea, label, p, select, option{
|
||||||
|
color: #fff !important
|
||||||
|
}
|
||||||
|
#icon{
|
||||||
|
max-width:45px;
|
||||||
|
height:auto;
|
||||||
|
border-radius:50%
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
var options = [
|
||||||
|
"bengali",
|
||||||
|
"devanagari",
|
||||||
|
"gujarati",
|
||||||
|
"gurmukhi",
|
||||||
|
"kannada",
|
||||||
|
"malayalam",
|
||||||
|
"oriya",
|
||||||
|
"tamil",
|
||||||
|
"telugu",
|
||||||
|
"grantha",
|
||||||
|
"grantamil",
|
||||||
|
"hk",
|
||||||
|
"iast",
|
||||||
|
"iso15919",
|
||||||
|
"itrans",
|
||||||
|
"slp1",
|
||||||
|
"velthuis",
|
||||||
|
"wx"
|
||||||
|
];
|
||||||
|
|
||||||
|
$('#script').empty();
|
||||||
|
$.each(options, function(i, p) {
|
||||||
|
$('#script').append($('<option></option>').val(p).html(p));
|
||||||
|
});
|
|
@ -0,0 +1,62 @@
|
||||||
|
$('#formSubmit').click(function () {
|
||||||
|
|
||||||
|
const text = $('#textInput').val();
|
||||||
|
const script = $('#script').val();
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
"script": script,
|
||||||
|
"text": text
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleFormData = async () => {
|
||||||
|
const sent = await fetch('/api/tts', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(data)
|
||||||
|
})
|
||||||
|
|
||||||
|
try {
|
||||||
|
const body = await sent.json()
|
||||||
|
console.log(body)
|
||||||
|
|
||||||
|
let response = body.response;
|
||||||
|
if(response) {
|
||||||
|
const url = body.url;
|
||||||
|
|
||||||
|
$('#audioContainer').css("display", "block");
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
|
||||||
|
var audio = $('#audioPlayer').get(0);
|
||||||
|
audio.pause();
|
||||||
|
|
||||||
|
$("#ttsAudio").prop('src', url);
|
||||||
|
|
||||||
|
audio.load();
|
||||||
|
audio.play();
|
||||||
|
}, 2000)
|
||||||
|
} else {
|
||||||
|
$('#resultContainer').html = `
|
||||||
|
<div class="errorContainer">
|
||||||
|
<div class="alert alert-danger" role="alert">
|
||||||
|
Something went wrong!
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="errorMessage">
|
||||||
|
<pre>
|
||||||
|
${res.body}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleFormData()
|
||||||
|
|
||||||
|
})
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,41 @@
|
||||||
|
<%- include('../partials/header'); %>
|
||||||
|
|
||||||
|
<div class="column shadow-sm p-3 m-4 bg-dark-3 text-light">
|
||||||
|
<div align="left">
|
||||||
|
<h1>Sanskrit TTS</h1>
|
||||||
|
<p>Enter your text below to convert to speech.</p>
|
||||||
|
|
||||||
|
<form>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="script">Writing Script</label>
|
||||||
|
<select name="script" id="script" class="custom-select" required></select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="textInput">Text Input</label>
|
||||||
|
<textarea class="form-control" id="textInput" placeholder="Enter your Sanskrit..." rows="3" name="text" required></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<button type="button" class="btn btn-dark" id="formSubmit" name="formSubmit">Submit</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h3>Result</h3>
|
||||||
|
<div id="resultContainer">
|
||||||
|
<div id="audioContainer" style="display: none;">
|
||||||
|
<div class="gapContainer">
|
||||||
|
<audio controls id="audioPlayer">
|
||||||
|
<source src="" id="ttsAudio">
|
||||||
|
Your browser does not support the audio element.
|
||||||
|
</audio>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%- include('../partials/footer'); %>
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
<p class="text-center text-light">Source Code: <a href="">Github</a> - Made by <a href="https://github.com/WinsDominoes">Win</a> - Material Theme Library by <a href="https://daemonite.github.io/material/">daemonite.github.io</a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Optional JavaScript -->
|
||||||
|
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
|
||||||
|
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"></script>
|
||||||
|
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script>
|
||||||
|
|
||||||
|
<script src="/assets/js/fetch.js"></script>
|
||||||
|
<script src="/assets/js/dropdown.js"></script>
|
||||||
|
|
||||||
|
<!-- Then Material JavaScript on top of Bootstrap JavaScript -->
|
||||||
|
<script src="/assets/material/material.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,32 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
|
<!-- CSS -->
|
||||||
|
<link rel="stylesheet" href="/assets/css/style.css">
|
||||||
|
|
||||||
|
<!-- Add Material font (Roboto) and Material icon as needed -->
|
||||||
|
<link href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,500,500i,700,700i|Roboto+Mono:300,400,700|Roboto+Slab:300,400,700"
|
||||||
|
rel="stylesheet">
|
||||||
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- Add Material CSS, replace Bootstrap CSS -->
|
||||||
|
<link href="/assets/material/material.min.css" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- GOOGLE ICONS -->
|
||||||
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@48,400,0,0"/>
|
||||||
|
<title>Sanskrit TTS</title>
|
||||||
|
</head>
|
||||||
|
<body class="bg-dark-2">
|
||||||
|
<header>
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-dark bg-info">
|
||||||
|
<a class="navbar-brand" href="/"></a>
|
||||||
|
<span>Sanskrit TTS</span>
|
||||||
|
</a>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div align="center">
|
Loading…
Reference in New Issue