Spaces:
Runtime error
Runtime error
Upload 10 files
Browse files- README.md +28 -7
- about.html +99 -0
- app.js +131 -0
- app.py +29 -4
- index.html +224 -465
- privacy.html +121 -0
- style.css +448 -0
- terms.html +111 -0
README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
---
|
| 2 |
-
title: Myanmar Voice
|
| 3 |
emoji: 🔊
|
| 4 |
colorFrom: yellow
|
| 5 |
colorTo: green
|
|
@@ -8,14 +8,25 @@ app_port: 7860
|
|
| 8 |
pinned: false
|
| 9 |
---
|
| 10 |
|
| 11 |
-
# Myanmar Voice
|
| 12 |
|
| 13 |
-
|
|
|
|
|
|
|
| 14 |
|
| 15 |
## Voices
|
| 16 |
- `my-MM-NilarNeural` — Nilar (Female)
|
| 17 |
- `my-MM-ThihaNeural` — Thiha (Male)
|
| 18 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
## Local run
|
| 20 |
```bash
|
| 21 |
pip install -r requirements.txt
|
|
@@ -24,8 +35,18 @@ python app.py
|
|
| 24 |
|
| 25 |
## Deploy on Hugging Face Spaces
|
| 26 |
1. Create a new Space → SDK: **Docker**.
|
| 27 |
-
2. Upload `Dockerfile`, `requirements.txt`, `app.py`, `
|
| 28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
|
| 30 |
-
## AdSense
|
| 31 |
-
`templates/index.html` ထဲမှာ `ca-pub-XXXXXXXXXXXXXXXX` နှင့် `data-ad-slot` placeholder များကို သင့် AdSense client ID / slot ID များဖြင့် အစားထိုးပါ။
|
|
|
|
| 1 |
---
|
| 2 |
+
title: Myanmar Voice Studio
|
| 3 |
emoji: 🔊
|
| 4 |
colorFrom: yellow
|
| 5 |
colorTo: green
|
|
|
|
| 8 |
pinned: false
|
| 9 |
---
|
| 10 |
|
| 11 |
+
# Myanmar Voice Studio
|
| 12 |
|
| 13 |
+
A free Myanmar (Burmese) text-to-speech web app built on Edge TTS, with an
|
| 14 |
+
English-language marketing site (Home, About, Privacy, Terms) designed to be
|
| 15 |
+
AdSense-friendly.
|
| 16 |
|
| 17 |
## Voices
|
| 18 |
- `my-MM-NilarNeural` — Nilar (Female)
|
| 19 |
- `my-MM-ThihaNeural` — Thiha (Male)
|
| 20 |
|
| 21 |
+
## Pages
|
| 22 |
+
- `/` — Home: hero, TTS tool, How It Works, Features, Use Cases, FAQ
|
| 23 |
+
- `/about` — About the project
|
| 24 |
+
- `/privacy` — Privacy Policy (AdSense / cookies disclosure)
|
| 25 |
+
- `/terms` — Terms of Use
|
| 26 |
+
|
| 27 |
+
## Limits
|
| 28 |
+
- Maximum text length: **10,000 characters** per request.
|
| 29 |
+
|
| 30 |
## Local run
|
| 31 |
```bash
|
| 32 |
pip install -r requirements.txt
|
|
|
|
| 35 |
|
| 36 |
## Deploy on Hugging Face Spaces
|
| 37 |
1. Create a new Space → SDK: **Docker**.
|
| 38 |
+
2. Upload all files (`Dockerfile`, `requirements.txt`, `app.py`, `index.html`,
|
| 39 |
+
`about.html`, `privacy.html`, `terms.html`, `style.css`, `app.js`,
|
| 40 |
+
`README.md`) at the **root** of the repo — no subfolders.
|
| 41 |
+
3. Space builds and serves on port `7860` automatically.
|
| 42 |
+
|
| 43 |
+
## Before going live — replace these placeholders
|
| 44 |
+
- `ca-pub-XXXXXXXXXXXXXXXX` in `index.html`, `about.html`, `privacy.html`,
|
| 45 |
+
`terms.html` → your real AdSense publisher ID.
|
| 46 |
+
- `data-ad-slot="1111111111"` / `"2222222222"` in `index.html` → your real ad
|
| 47 |
+
unit slot IDs.
|
| 48 |
+
- `contact@example.com` in `privacy.html` / `terms.html` → a real contact
|
| 49 |
+
email.
|
| 50 |
+
- Add your Space's domain (`yourname-spacename.hf.space`) under AdSense → Sites
|
| 51 |
+
and wait for review/approval.
|
| 52 |
|
|
|
|
|
|
about.html
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>About — Myanmar Voice Studio</title>
|
| 7 |
+
<meta name="description" content="Learn about Myanmar Voice Studio, a free tool for converting Myanmar text into natural-sounding speech.">
|
| 8 |
+
|
| 9 |
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 10 |
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
| 11 |
+
<link href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,400..700;1,9..144,400..600&family=Inter:wght@400;500;600&family=Noto+Sans+Myanmar:wght@400;500;600;700&display=swap" rel="stylesheet">
|
| 12 |
+
<link rel="stylesheet" href="/style.css">
|
| 13 |
+
<script async src="https://pagead2.googleadsense.com/pagead/js/adsbygoogle.js?client=ca-pub-XXXXXXXXXXXXXXXX" crossorigin="anonymous"></script>
|
| 14 |
+
</head>
|
| 15 |
+
<body>
|
| 16 |
+
|
| 17 |
+
<nav class="nav">
|
| 18 |
+
<div class="wrap">
|
| 19 |
+
<a href="/" class="brand"><span class="dot"></span>Myanmar Voice Studio</a>
|
| 20 |
+
<div class="nav-links">
|
| 21 |
+
<a href="/">Home</a>
|
| 22 |
+
<a href="/#tool">Try It</a>
|
| 23 |
+
<a href="/#how-it-works">How It Works</a>
|
| 24 |
+
<a href="/#faq">FAQ</a>
|
| 25 |
+
<a href="/about" class="active">About</a>
|
| 26 |
+
</div>
|
| 27 |
+
</div>
|
| 28 |
+
</nav>
|
| 29 |
+
|
| 30 |
+
<div class="wrap prose">
|
| 31 |
+
<h1>About Myanmar Voice Studio</h1>
|
| 32 |
+
<p class="updated">Last updated: June 2026</p>
|
| 33 |
+
|
| 34 |
+
<p>Myanmar Voice Studio is a free online text-to-speech tool built for the
|
| 35 |
+
Myanmar-speaking community and for anyone working with the Burmese
|
| 36 |
+
language. It converts written Myanmar text into natural-sounding spoken
|
| 37 |
+
audio that can be downloaded and used right away.</p>
|
| 38 |
+
|
| 39 |
+
<h2>Why we built this</h2>
|
| 40 |
+
<p>High-quality voice technology for the Myanmar language has historically
|
| 41 |
+
been hard to find and often locked behind expensive software or
|
| 42 |
+
subscriptions. We wanted to make it simple: paste your text, choose a
|
| 43 |
+
voice, and get an audio file — no account, no installation, and no cost.</p>
|
| 44 |
+
|
| 45 |
+
<h2>What you can do here</h2>
|
| 46 |
+
<ul>
|
| 47 |
+
<li>Convert up to 10,000 characters of Myanmar text into speech.</li>
|
| 48 |
+
<li>Choose between a female voice (Nilar) and a male voice (Thiha).</li>
|
| 49 |
+
<li>Adjust speaking speed and pitch to match your project.</li>
|
| 50 |
+
<li>Download the result as an MP3 file for use in videos, lessons,
|
| 51 |
+
presentations, or apps.</li>
|
| 52 |
+
</ul>
|
| 53 |
+
|
| 54 |
+
<h2>The technology behind it</h2>
|
| 55 |
+
<p>Audio is generated using neural text-to-speech voices, the same family of
|
| 56 |
+
voice models used in modern screen readers and voice assistants. These
|
| 57 |
+
models are trained to produce natural intonation and pacing for Myanmar
|
| 58 |
+
script, including correct handling of tone marks and word boundaries.</p>
|
| 59 |
+
|
| 60 |
+
<h2>Who maintains this site</h2>
|
| 61 |
+
<p>Myanmar Voice Studio is built and maintained by an independent developer
|
| 62 |
+
focused on Myanmar-language content tools. If you have feedback, found a
|
| 63 |
+
bug, or have a feature request, feel free to reach out through the
|
| 64 |
+
contact details on our <a href="/privacy">Privacy Policy</a> page.</p>
|
| 65 |
+
|
| 66 |
+
<h2>Advertising</h2>
|
| 67 |
+
<p>This site is supported by advertising so that it can remain free to use.
|
| 68 |
+
Ads are served through Google AdSense. You can read more about how this
|
| 69 |
+
affects your data in our <a href="/privacy">Privacy Policy</a>.</p>
|
| 70 |
+
</div>
|
| 71 |
+
|
| 72 |
+
<footer>
|
| 73 |
+
<div class="wrap">
|
| 74 |
+
<div class="footer-grid">
|
| 75 |
+
<div class="footer-col">
|
| 76 |
+
<h4>Myanmar Voice Studio</h4>
|
| 77 |
+
<a href="/">Home</a>
|
| 78 |
+
<a href="/#tool">Text to Speech Tool</a>
|
| 79 |
+
<a href="/#how-it-works">How It Works</a>
|
| 80 |
+
</div>
|
| 81 |
+
<div class="footer-col">
|
| 82 |
+
<h4>Resources</h4>
|
| 83 |
+
<a href="/#faq">FAQ</a>
|
| 84 |
+
<a href="/about">About</a>
|
| 85 |
+
</div>
|
| 86 |
+
<div class="footer-col">
|
| 87 |
+
<h4>Legal</h4>
|
| 88 |
+
<a href="/privacy">Privacy Policy</a>
|
| 89 |
+
<a href="/terms">Terms of Use</a>
|
| 90 |
+
</div>
|
| 91 |
+
</div>
|
| 92 |
+
<div class="footer-bottom">
|
| 93 |
+
© 2026 Myanmar Voice Studio. Voices powered by neural text-to-speech technology.
|
| 94 |
+
</div>
|
| 95 |
+
</div>
|
| 96 |
+
</footer>
|
| 97 |
+
|
| 98 |
+
</body>
|
| 99 |
+
</html>
|
app.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// ---- Build signature waveform ----
|
| 2 |
+
const wave = document.getElementById('wave');
|
| 3 |
+
if (wave) {
|
| 4 |
+
const BAR_COUNT = 24;
|
| 5 |
+
for (let i = 0; i < BAR_COUNT; i++) {
|
| 6 |
+
const bar = document.createElement('div');
|
| 7 |
+
bar.className = 'bar';
|
| 8 |
+
bar.style.animationDelay = (i * 0.06) + 's';
|
| 9 |
+
wave.appendChild(bar);
|
| 10 |
+
}
|
| 11 |
+
}
|
| 12 |
+
const bars = wave ? wave.querySelectorAll('.bar') : [];
|
| 13 |
+
|
| 14 |
+
function setWaveActive(active) {
|
| 15 |
+
if (!wave) return;
|
| 16 |
+
wave.classList.toggle('is-active', active);
|
| 17 |
+
if (!active) bars.forEach(b => b.style.height = '');
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
let waveInterval = null;
|
| 21 |
+
function startWaveAnimation() {
|
| 22 |
+
setWaveActive(true);
|
| 23 |
+
waveInterval = setInterval(() => {
|
| 24 |
+
bars.forEach(b => b.style.height = (6 + Math.random() * 28) + 'px');
|
| 25 |
+
}, 110);
|
| 26 |
+
}
|
| 27 |
+
function stopWaveAnimation() {
|
| 28 |
+
if (waveInterval) clearInterval(waveInterval);
|
| 29 |
+
waveInterval = null;
|
| 30 |
+
setWaveActive(false);
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
// ---- Voice card selection ----
|
| 34 |
+
const voiceCards = document.querySelectorAll('.voice-card');
|
| 35 |
+
voiceCards.forEach(card => {
|
| 36 |
+
card.addEventListener('click', () => {
|
| 37 |
+
voiceCards.forEach(c => c.classList.remove('selected'));
|
| 38 |
+
card.classList.add('selected');
|
| 39 |
+
});
|
| 40 |
+
});
|
| 41 |
+
|
| 42 |
+
// ---- Sliders ----
|
| 43 |
+
const rate = document.getElementById('rate');
|
| 44 |
+
const pitch = document.getElementById('pitch');
|
| 45 |
+
const rateVal = document.getElementById('rateVal');
|
| 46 |
+
const pitchVal = document.getElementById('pitchVal');
|
| 47 |
+
|
| 48 |
+
function fmt(v, unit) {
|
| 49 |
+
const n = Number(v);
|
| 50 |
+
return (n >= 0 ? '+' : '') + n + unit;
|
| 51 |
+
}
|
| 52 |
+
if (rate) rate.addEventListener('input', () => rateVal.textContent = fmt(rate.value, '%'));
|
| 53 |
+
if (pitch) pitch.addEventListener('input', () => pitchVal.textContent = fmt(pitch.value, 'Hz'));
|
| 54 |
+
|
| 55 |
+
// ---- Character counter ----
|
| 56 |
+
const MAX_CHARS = 10000;
|
| 57 |
+
const text = document.getElementById('text');
|
| 58 |
+
const charCount = document.getElementById('charCount');
|
| 59 |
+
if (text) {
|
| 60 |
+
text.addEventListener('input', () => {
|
| 61 |
+
const len = text.value.length;
|
| 62 |
+
charCount.textContent = `${len} / ${MAX_CHARS}`;
|
| 63 |
+
charCount.classList.toggle('over', len > MAX_CHARS);
|
| 64 |
+
});
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
// ---- Generate ----
|
| 68 |
+
const generateBtn = document.getElementById('generateBtn');
|
| 69 |
+
const status = document.getElementById('status');
|
| 70 |
+
const output = document.getElementById('output');
|
| 71 |
+
const player = document.getElementById('player');
|
| 72 |
+
const downloadLink = document.getElementById('downloadLink');
|
| 73 |
+
|
| 74 |
+
let currentObjectUrl = null;
|
| 75 |
+
|
| 76 |
+
if (generateBtn) {
|
| 77 |
+
generateBtn.addEventListener('click', async () => {
|
| 78 |
+
const value = text.value.trim();
|
| 79 |
+
if (!value) {
|
| 80 |
+
status.textContent = 'Please enter some text first.';
|
| 81 |
+
status.classList.add('error');
|
| 82 |
+
return;
|
| 83 |
+
}
|
| 84 |
+
if (value.length > MAX_CHARS) {
|
| 85 |
+
status.textContent = `Text is too long. Maximum is ${MAX_CHARS} characters.`;
|
| 86 |
+
status.classList.add('error');
|
| 87 |
+
return;
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
const voice = document.querySelector('input[name="voice"]:checked').value;
|
| 91 |
+
|
| 92 |
+
status.classList.remove('error');
|
| 93 |
+
status.textContent = 'Generating audio...';
|
| 94 |
+
generateBtn.disabled = true;
|
| 95 |
+
startWaveAnimation();
|
| 96 |
+
|
| 97 |
+
try {
|
| 98 |
+
const res = await fetch('/api/tts', {
|
| 99 |
+
method: 'POST',
|
| 100 |
+
headers: { 'Content-Type': 'application/json' },
|
| 101 |
+
body: JSON.stringify({
|
| 102 |
+
text: value,
|
| 103 |
+
voice: voice,
|
| 104 |
+
rate: Number(rate.value),
|
| 105 |
+
pitch: Number(pitch.value)
|
| 106 |
+
})
|
| 107 |
+
});
|
| 108 |
+
|
| 109 |
+
if (!res.ok) {
|
| 110 |
+
const err = await res.json().catch(() => ({}));
|
| 111 |
+
throw new Error(err.error || 'Failed to generate audio.');
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
const blob = await res.blob();
|
| 115 |
+
if (currentObjectUrl) URL.revokeObjectURL(currentObjectUrl);
|
| 116 |
+
currentObjectUrl = URL.createObjectURL(blob);
|
| 117 |
+
|
| 118 |
+
player.src = currentObjectUrl;
|
| 119 |
+
downloadLink.href = currentObjectUrl;
|
| 120 |
+
output.classList.add('visible');
|
| 121 |
+
status.textContent = 'Done! Your audio is ready below.';
|
| 122 |
+
player.play().catch(() => {});
|
| 123 |
+
} catch (e) {
|
| 124 |
+
status.textContent = e.message;
|
| 125 |
+
status.classList.add('error');
|
| 126 |
+
} finally {
|
| 127 |
+
generateBtn.disabled = false;
|
| 128 |
+
stopWaveAnimation();
|
| 129 |
+
}
|
| 130 |
+
});
|
| 131 |
+
}
|
app.py
CHANGED
|
@@ -19,7 +19,7 @@ DEFAULT_VOICE = "my-MM-NilarNeural"
|
|
| 19 |
TMP_DIR = os.path.join(tempfile.gettempdir(), "mm_tts_outputs")
|
| 20 |
os.makedirs(TMP_DIR, exist_ok=True)
|
| 21 |
|
| 22 |
-
MAX_CHARS =
|
| 23 |
|
| 24 |
|
| 25 |
def clamp_pct(value, lo=-50, hi=50):
|
|
@@ -35,6 +35,31 @@ def index():
|
|
| 35 |
return send_file(os.path.join(BASE_DIR, "index.html"))
|
| 36 |
|
| 37 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
@app.route("/api/voices")
|
| 39 |
def get_voices():
|
| 40 |
return jsonify(VOICES)
|
|
@@ -50,10 +75,10 @@ def tts():
|
|
| 50 |
pitch = clamp_pct(data.get("pitch", 0))
|
| 51 |
|
| 52 |
if not text:
|
| 53 |
-
return jsonify({"error": "
|
| 54 |
|
| 55 |
if len(text) > MAX_CHARS:
|
| 56 |
-
return jsonify({"error": f"
|
| 57 |
|
| 58 |
if voice not in VOICES:
|
| 59 |
voice = DEFAULT_VOICE
|
|
@@ -74,7 +99,7 @@ def tts():
|
|
| 74 |
return jsonify({"error": str(e)}), 500
|
| 75 |
|
| 76 |
if not os.path.exists(filepath) or os.path.getsize(filepath) == 0:
|
| 77 |
-
return jsonify({"error": "
|
| 78 |
|
| 79 |
@after_this_request
|
| 80 |
def cleanup(response):
|
|
|
|
| 19 |
TMP_DIR = os.path.join(tempfile.gettempdir(), "mm_tts_outputs")
|
| 20 |
os.makedirs(TMP_DIR, exist_ok=True)
|
| 21 |
|
| 22 |
+
MAX_CHARS = 10000
|
| 23 |
|
| 24 |
|
| 25 |
def clamp_pct(value, lo=-50, hi=50):
|
|
|
|
| 35 |
return send_file(os.path.join(BASE_DIR, "index.html"))
|
| 36 |
|
| 37 |
|
| 38 |
+
@app.route("/about")
|
| 39 |
+
def about():
|
| 40 |
+
return send_file(os.path.join(BASE_DIR, "about.html"))
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
@app.route("/privacy")
|
| 44 |
+
def privacy():
|
| 45 |
+
return send_file(os.path.join(BASE_DIR, "privacy.html"))
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
@app.route("/terms")
|
| 49 |
+
def terms():
|
| 50 |
+
return send_file(os.path.join(BASE_DIR, "terms.html"))
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
@app.route("/style.css")
|
| 54 |
+
def style_css():
|
| 55 |
+
return send_file(os.path.join(BASE_DIR, "style.css"), mimetype="text/css")
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
@app.route("/app.js")
|
| 59 |
+
def app_js():
|
| 60 |
+
return send_file(os.path.join(BASE_DIR, "app.js"), mimetype="application/javascript")
|
| 61 |
+
|
| 62 |
+
|
| 63 |
@app.route("/api/voices")
|
| 64 |
def get_voices():
|
| 65 |
return jsonify(VOICES)
|
|
|
|
| 75 |
pitch = clamp_pct(data.get("pitch", 0))
|
| 76 |
|
| 77 |
if not text:
|
| 78 |
+
return jsonify({"error": "Please enter some text."}), 400
|
| 79 |
|
| 80 |
if len(text) > MAX_CHARS:
|
| 81 |
+
return jsonify({"error": f"Text must be {MAX_CHARS} characters or fewer."}), 400
|
| 82 |
|
| 83 |
if voice not in VOICES:
|
| 84 |
voice = DEFAULT_VOICE
|
|
|
|
| 99 |
return jsonify({"error": str(e)}), 500
|
| 100 |
|
| 101 |
if not os.path.exists(filepath) or os.path.getsize(filepath) == 0:
|
| 102 |
+
return jsonify({"error": "Audio generation failed. Please try again."}), 500
|
| 103 |
|
| 104 |
@after_this_request
|
| 105 |
def cleanup(response):
|
index.html
CHANGED
|
@@ -1,348 +1,75 @@
|
|
| 1 |
<!DOCTYPE html>
|
| 2 |
-
<html lang="
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
-
<title>
|
|
|
|
| 7 |
|
| 8 |
-
<!-- Fonts: Noto Sans Myanmar for Burmese script, Fraunces for English accents -->
|
| 9 |
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 10 |
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
| 11 |
-
<link href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,400..700;1,9..144,400..600&family=Noto+Sans+Myanmar:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
|
|
| 12 |
|
| 13 |
<!-- ===================== Google AdSense ===================== -->
|
| 14 |
<!-- Replace ca-pub-XXXXXXXXXXXXXXXX with your own AdSense publisher ID -->
|
| 15 |
<script async src="https://pagead2.googleadsense.com/pagead/js/adsbygoogle.js?client=ca-pub-XXXXXXXXXXXXXXXX" crossorigin="anonymous"></script>
|
| 16 |
-
|
| 17 |
-
<style>
|
| 18 |
-
:root{
|
| 19 |
-
--bg:#FAF6EE;
|
| 20 |
-
--surface:#FFFDF7;
|
| 21 |
-
--surface-2:#F3ECDE;
|
| 22 |
-
--ink:#2B2521;
|
| 23 |
-
--ink-soft:#8A7C6C;
|
| 24 |
-
--jade:#2F6F5E;
|
| 25 |
-
--jade-soft:#DCEAE5;
|
| 26 |
-
--amber:#D98C3D;
|
| 27 |
-
--amber-soft:#F6E3CC;
|
| 28 |
-
--line:#E8DFD2;
|
| 29 |
-
--radius:14px;
|
| 30 |
-
--serif:'Fraunces', serif;
|
| 31 |
-
--mm:'Noto Sans Myanmar', sans-serif;
|
| 32 |
-
}
|
| 33 |
-
|
| 34 |
-
*{ box-sizing:border-box; }
|
| 35 |
-
|
| 36 |
-
body{
|
| 37 |
-
margin:0;
|
| 38 |
-
background:var(--bg);
|
| 39 |
-
color:var(--ink);
|
| 40 |
-
font-family:var(--mm);
|
| 41 |
-
line-height:1.6;
|
| 42 |
-
-webkit-font-smoothing:antialiased;
|
| 43 |
-
}
|
| 44 |
-
|
| 45 |
-
a{ color:var(--jade); }
|
| 46 |
-
|
| 47 |
-
.wrap{
|
| 48 |
-
max-width:760px;
|
| 49 |
-
margin:0 auto;
|
| 50 |
-
padding:0 20px 64px;
|
| 51 |
-
}
|
| 52 |
-
|
| 53 |
-
/* ---------- Ad slots ---------- */
|
| 54 |
-
.ad-slot{
|
| 55 |
-
margin:0 auto;
|
| 56 |
-
padding:14px 0;
|
| 57 |
-
text-align:center;
|
| 58 |
-
max-width:760px;
|
| 59 |
-
}
|
| 60 |
-
.ad-slot .ad-label{
|
| 61 |
-
font-family:var(--serif);
|
| 62 |
-
font-style:italic;
|
| 63 |
-
font-size:11px;
|
| 64 |
-
letter-spacing:.12em;
|
| 65 |
-
text-transform:uppercase;
|
| 66 |
-
color:var(--ink-soft);
|
| 67 |
-
margin-bottom:6px;
|
| 68 |
-
}
|
| 69 |
-
|
| 70 |
-
/* ---------- Header ---------- */
|
| 71 |
-
header{
|
| 72 |
-
padding:48px 0 28px;
|
| 73 |
-
text-align:center;
|
| 74 |
-
}
|
| 75 |
-
.eyebrow{
|
| 76 |
-
font-family:var(--serif);
|
| 77 |
-
font-style:italic;
|
| 78 |
-
font-weight:500;
|
| 79 |
-
font-size:13px;
|
| 80 |
-
letter-spacing:.22em;
|
| 81 |
-
text-transform:uppercase;
|
| 82 |
-
color:var(--jade);
|
| 83 |
-
margin:0 0 10px;
|
| 84 |
-
}
|
| 85 |
-
h1{
|
| 86 |
-
font-family:var(--mm);
|
| 87 |
-
font-weight:700;
|
| 88 |
-
font-size:clamp(28px,7vw,42px);
|
| 89 |
-
margin:0 0 10px;
|
| 90 |
-
letter-spacing:.01em;
|
| 91 |
-
}
|
| 92 |
-
.tagline{
|
| 93 |
-
color:var(--ink-soft);
|
| 94 |
-
font-size:15px;
|
| 95 |
-
margin:0;
|
| 96 |
-
}
|
| 97 |
-
|
| 98 |
-
/* ---------- Signature waveform ---------- */
|
| 99 |
-
.wave{
|
| 100 |
-
display:flex;
|
| 101 |
-
align-items:center;
|
| 102 |
-
justify-content:center;
|
| 103 |
-
gap:4px;
|
| 104 |
-
height:34px;
|
| 105 |
-
margin:22px auto 0;
|
| 106 |
-
}
|
| 107 |
-
.wave .bar{
|
| 108 |
-
width:4px;
|
| 109 |
-
border-radius:3px;
|
| 110 |
-
background:linear-gradient(180deg, var(--jade), var(--amber));
|
| 111 |
-
height:10px;
|
| 112 |
-
animation:breathe 2.6s ease-in-out infinite;
|
| 113 |
-
transition:height .12s ease;
|
| 114 |
-
}
|
| 115 |
-
@keyframes breathe{
|
| 116 |
-
0%, 100% { height:8px; opacity:.55; }
|
| 117 |
-
50% { height:28px; opacity:1; }
|
| 118 |
-
}
|
| 119 |
-
.wave.is-active .bar{ animation:none; }
|
| 120 |
-
|
| 121 |
-
/* ---------- Card / manuscript panel ---------- */
|
| 122 |
-
.panel{
|
| 123 |
-
background:var(--surface);
|
| 124 |
-
border:1px solid var(--line);
|
| 125 |
-
border-radius:var(--radius);
|
| 126 |
-
padding:22px;
|
| 127 |
-
margin-top:22px;
|
| 128 |
-
box-shadow:0 1px 2px rgba(43,37,33,.03);
|
| 129 |
-
}
|
| 130 |
-
|
| 131 |
-
.panel h2{
|
| 132 |
-
font-family:var(--serif);
|
| 133 |
-
font-style:italic;
|
| 134 |
-
font-weight:500;
|
| 135 |
-
font-size:13px;
|
| 136 |
-
letter-spacing:.16em;
|
| 137 |
-
text-transform:uppercase;
|
| 138 |
-
color:var(--ink-soft);
|
| 139 |
-
margin:0 0 14px;
|
| 140 |
-
}
|
| 141 |
-
|
| 142 |
-
textarea{
|
| 143 |
-
width:100%;
|
| 144 |
-
min-height:160px;
|
| 145 |
-
resize:vertical;
|
| 146 |
-
border:1px solid var(--line);
|
| 147 |
-
border-radius:10px;
|
| 148 |
-
background:
|
| 149 |
-
repeating-linear-gradient(
|
| 150 |
-
to bottom,
|
| 151 |
-
transparent,
|
| 152 |
-
transparent 35px,
|
| 153 |
-
var(--surface-2) 35px,
|
| 154 |
-
var(--surface-2) 36px
|
| 155 |
-
),
|
| 156 |
-
var(--surface);
|
| 157 |
-
padding:14px 16px;
|
| 158 |
-
font-family:var(--mm);
|
| 159 |
-
font-size:16px;
|
| 160 |
-
line-height:36px;
|
| 161 |
-
color:var(--ink);
|
| 162 |
-
outline:none;
|
| 163 |
-
}
|
| 164 |
-
textarea:focus{ border-color:var(--jade); }
|
| 165 |
-
textarea::placeholder{ color:var(--ink-soft); }
|
| 166 |
-
|
| 167 |
-
.char-count{
|
| 168 |
-
text-align:right;
|
| 169 |
-
font-size:12px;
|
| 170 |
-
color:var(--ink-soft);
|
| 171 |
-
margin-top:6px;
|
| 172 |
-
font-family:var(--serif);
|
| 173 |
-
}
|
| 174 |
-
.char-count.over{ color:#C0492B; }
|
| 175 |
-
|
| 176 |
-
/* ---------- Voice cards ---------- */
|
| 177 |
-
.voices{
|
| 178 |
-
display:grid;
|
| 179 |
-
grid-template-columns:1fr 1fr;
|
| 180 |
-
gap:12px;
|
| 181 |
-
margin-top:8px;
|
| 182 |
-
}
|
| 183 |
-
.voice-card{
|
| 184 |
-
border:1px solid var(--line);
|
| 185 |
-
border-radius:10px;
|
| 186 |
-
padding:14px;
|
| 187 |
-
cursor:pointer;
|
| 188 |
-
background:var(--surface);
|
| 189 |
-
transition:border-color .15s ease, background .15s ease;
|
| 190 |
-
position:relative;
|
| 191 |
-
}
|
| 192 |
-
.voice-card input{
|
| 193 |
-
position:absolute;
|
| 194 |
-
opacity:0;
|
| 195 |
-
inset:0;
|
| 196 |
-
cursor:pointer;
|
| 197 |
-
margin:0;
|
| 198 |
-
}
|
| 199 |
-
.voice-card .name{
|
| 200 |
-
font-weight:600;
|
| 201 |
-
font-size:15px;
|
| 202 |
-
}
|
| 203 |
-
.voice-card .role{
|
| 204 |
-
font-family:var(--serif);
|
| 205 |
-
font-style:italic;
|
| 206 |
-
font-size:12px;
|
| 207 |
-
letter-spacing:.08em;
|
| 208 |
-
color:var(--ink-soft);
|
| 209 |
-
text-transform:uppercase;
|
| 210 |
-
margin-top:4px;
|
| 211 |
-
}
|
| 212 |
-
.voice-card.selected{
|
| 213 |
-
border-color:var(--jade);
|
| 214 |
-
background:var(--jade-soft);
|
| 215 |
-
}
|
| 216 |
-
.voice-card.selected .role{ color:var(--jade); }
|
| 217 |
-
|
| 218 |
-
/* ---------- Sliders ---------- */
|
| 219 |
-
.controls{
|
| 220 |
-
display:grid;
|
| 221 |
-
grid-template-columns:1fr 1fr;
|
| 222 |
-
gap:16px;
|
| 223 |
-
margin-top:18px;
|
| 224 |
-
}
|
| 225 |
-
.control label{
|
| 226 |
-
display:flex;
|
| 227 |
-
justify-content:space-between;
|
| 228 |
-
font-size:13px;
|
| 229 |
-
color:var(--ink-soft);
|
| 230 |
-
margin-bottom:6px;
|
| 231 |
-
font-family:var(--serif);
|
| 232 |
-
font-style:italic;
|
| 233 |
-
letter-spacing:.04em;
|
| 234 |
-
}
|
| 235 |
-
.control label span.val{
|
| 236 |
-
font-family:var(--mm);
|
| 237 |
-
font-style:normal;
|
| 238 |
-
color:var(--ink);
|
| 239 |
-
font-weight:600;
|
| 240 |
-
}
|
| 241 |
-
input[type="range"]{
|
| 242 |
-
width:100%;
|
| 243 |
-
accent-color:var(--jade);
|
| 244 |
-
}
|
| 245 |
-
|
| 246 |
-
@media (max-width:480px){
|
| 247 |
-
.controls{ grid-template-columns:1fr; }
|
| 248 |
-
}
|
| 249 |
-
|
| 250 |
-
/* ---------- Generate button ---------- */
|
| 251 |
-
.actions{
|
| 252 |
-
margin-top:22px;
|
| 253 |
-
display:flex;
|
| 254 |
-
gap:12px;
|
| 255 |
-
flex-wrap:wrap;
|
| 256 |
-
}
|
| 257 |
-
button{
|
| 258 |
-
font-family:var(--mm);
|
| 259 |
-
font-size:15px;
|
| 260 |
-
font-weight:600;
|
| 261 |
-
border:none;
|
| 262 |
-
border-radius:10px;
|
| 263 |
-
padding:13px 24px;
|
| 264 |
-
cursor:pointer;
|
| 265 |
-
transition:opacity .15s ease, transform .05s ease;
|
| 266 |
-
}
|
| 267 |
-
button:active{ transform:scale(.98); }
|
| 268 |
-
button:disabled{ opacity:.55; cursor:wait; }
|
| 269 |
-
|
| 270 |
-
.btn-primary{
|
| 271 |
-
background:var(--amber);
|
| 272 |
-
color:#fff;
|
| 273 |
-
flex:1;
|
| 274 |
-
}
|
| 275 |
-
.btn-primary:hover:not(:disabled){ opacity:.92; }
|
| 276 |
-
|
| 277 |
-
.btn-secondary{
|
| 278 |
-
background:var(--surface-2);
|
| 279 |
-
color:var(--ink);
|
| 280 |
-
border:1px solid var(--line);
|
| 281 |
-
}
|
| 282 |
-
|
| 283 |
-
/* ---------- Output ---------- */
|
| 284 |
-
.output{
|
| 285 |
-
margin-top:18px;
|
| 286 |
-
display:none;
|
| 287 |
-
}
|
| 288 |
-
.output.visible{ display:block; }
|
| 289 |
-
|
| 290 |
-
.output audio{
|
| 291 |
-
width:100%;
|
| 292 |
-
margin-top:14px;
|
| 293 |
-
}
|
| 294 |
-
|
| 295 |
-
.status{
|
| 296 |
-
font-size:13px;
|
| 297 |
-
color:var(--ink-soft);
|
| 298 |
-
margin-top:10px;
|
| 299 |
-
min-height:18px;
|
| 300 |
-
}
|
| 301 |
-
.status.error{ color:#C0492B; }
|
| 302 |
-
|
| 303 |
-
/* ---------- Footer ---------- */
|
| 304 |
-
footer{
|
| 305 |
-
text-align:center;
|
| 306 |
-
margin-top:40px;
|
| 307 |
-
font-size:12px;
|
| 308 |
-
color:var(--ink-soft);
|
| 309 |
-
font-family:var(--serif);
|
| 310 |
-
font-style:italic;
|
| 311 |
-
}
|
| 312 |
-
</style>
|
| 313 |
</head>
|
| 314 |
<body>
|
| 315 |
|
| 316 |
-
|
| 317 |
-
<div class="ad-slot">
|
| 318 |
-
<div class="ad-label">Advertisement</div>
|
| 319 |
-
<ins class="adsbygoogle"
|
| 320 |
-
style="display:block"
|
| 321 |
-
data-ad-client="ca-pub-XXXXXXXXXXXXXXXX"
|
| 322 |
-
data-ad-slot="1111111111"
|
| 323 |
-
data-ad-format="auto"
|
| 324 |
-
data-full-width-responsive="true"></ins>
|
| 325 |
-
<script>(adsbygoogle = window.adsbygoogle || []).push({});</script>
|
| 326 |
-
</div>
|
| 327 |
-
|
| 328 |
<div class="wrap">
|
| 329 |
-
<
|
| 330 |
-
|
| 331 |
-
<
|
| 332 |
-
<
|
| 333 |
-
<
|
| 334 |
-
|
| 335 |
-
|
| 336 |
-
<
|
| 337 |
-
|
| 338 |
-
|
| 339 |
-
|
| 340 |
-
|
| 341 |
-
|
| 342 |
-
|
| 343 |
-
<
|
| 344 |
-
<
|
| 345 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 346 |
<div class="voices" id="voices">
|
| 347 |
<label class="voice-card selected" data-voice="my-MM-NilarNeural">
|
| 348 |
<input type="radio" name="voice" value="my-MM-NilarNeural" checked>
|
|
@@ -358,17 +85,17 @@
|
|
| 358 |
|
| 359 |
<div class="controls">
|
| 360 |
<div class="control">
|
| 361 |
-
<label>
|
| 362 |
<input type="range" id="rate" min="-50" max="50" value="0" step="5">
|
| 363 |
</div>
|
| 364 |
<div class="control">
|
| 365 |
-
<label>
|
| 366 |
<input type="range" id="pitch" min="-50" max="50" value="0" step="5">
|
| 367 |
</div>
|
| 368 |
</div>
|
| 369 |
|
| 370 |
<div class="actions">
|
| 371 |
-
<button class="btn-primary" id="generateBtn">
|
| 372 |
</div>
|
| 373 |
|
| 374 |
<div class="status" id="status"></div>
|
|
@@ -376,11 +103,106 @@
|
|
| 376 |
<div class="output" id="output">
|
| 377 |
<audio id="player" controls></audio>
|
| 378 |
<div class="actions">
|
| 379 |
-
<a class="btn-secondary" id="downloadLink" download="myanmar_voice.mp3"
|
| 380 |
</div>
|
| 381 |
</div>
|
| 382 |
-
</
|
| 383 |
-
</
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 384 |
|
| 385 |
<!-- In-content ad slot -->
|
| 386 |
<div class="ad-slot">
|
|
@@ -394,135 +216,72 @@
|
|
| 394 |
<script>(adsbygoogle = window.adsbygoogle || []).push({});</script>
|
| 395 |
</div>
|
| 396 |
|
| 397 |
-
<
|
| 398 |
-
|
| 399 |
-
|
| 400 |
-
|
| 401 |
-
<
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
|
| 407 |
-
|
| 408 |
-
|
| 409 |
-
|
| 410 |
-
|
| 411 |
-
|
| 412 |
-
|
| 413 |
-
|
| 414 |
-
|
| 415 |
-
|
| 416 |
-
|
| 417 |
-
|
| 418 |
-
|
| 419 |
-
|
| 420 |
-
|
| 421 |
-
|
| 422 |
-
|
| 423 |
-
|
| 424 |
-
|
| 425 |
-
|
| 426 |
-
|
| 427 |
-
|
| 428 |
-
|
| 429 |
-
|
| 430 |
-
|
| 431 |
-
|
| 432 |
-
|
| 433 |
-
|
| 434 |
-
|
| 435 |
-
|
| 436 |
-
|
| 437 |
-
|
| 438 |
-
|
| 439 |
-
|
| 440 |
-
|
| 441 |
-
|
| 442 |
-
|
| 443 |
-
|
| 444 |
-
|
| 445 |
-
|
| 446 |
-
|
| 447 |
-
|
| 448 |
-
|
| 449 |
-
|
| 450 |
-
|
| 451 |
-
|
| 452 |
-
|
| 453 |
-
|
| 454 |
-
|
| 455 |
-
|
| 456 |
-
|
| 457 |
-
|
| 458 |
-
|
| 459 |
-
|
| 460 |
-
|
| 461 |
-
|
| 462 |
-
text.addEventListener('input', () => {
|
| 463 |
-
const len = text.value.length;
|
| 464 |
-
charCount.textContent = `${len} / 3000`;
|
| 465 |
-
charCount.classList.toggle('over', len > 3000);
|
| 466 |
-
});
|
| 467 |
-
|
| 468 |
-
// ---- Generate ----
|
| 469 |
-
const generateBtn = document.getElementById('generateBtn');
|
| 470 |
-
const status = document.getElementById('status');
|
| 471 |
-
const output = document.getElementById('output');
|
| 472 |
-
const player = document.getElementById('player');
|
| 473 |
-
const downloadLink = document.getElementById('downloadLink');
|
| 474 |
-
|
| 475 |
-
let currentObjectUrl = null;
|
| 476 |
-
|
| 477 |
-
generateBtn.addEventListener('click', async () => {
|
| 478 |
-
const value = text.value.trim();
|
| 479 |
-
if (!value) {
|
| 480 |
-
status.textContent = 'စာသား ထည့်ပေးပါ။';
|
| 481 |
-
status.classList.add('error');
|
| 482 |
-
return;
|
| 483 |
-
}
|
| 484 |
-
|
| 485 |
-
const voice = document.querySelector('input[name="voice"]:checked').value;
|
| 486 |
-
|
| 487 |
-
status.classList.remove('error');
|
| 488 |
-
status.textContent = 'အသံထုတ်နေပါသည်...';
|
| 489 |
-
generateBtn.disabled = true;
|
| 490 |
-
startWaveAnimation();
|
| 491 |
-
|
| 492 |
-
try {
|
| 493 |
-
const res = await fetch('/api/tts', {
|
| 494 |
-
method: 'POST',
|
| 495 |
-
headers: { 'Content-Type': 'application/json' },
|
| 496 |
-
body: JSON.stringify({
|
| 497 |
-
text: value,
|
| 498 |
-
voice: voice,
|
| 499 |
-
rate: Number(rate.value),
|
| 500 |
-
pitch: Number(pitch.value)
|
| 501 |
-
})
|
| 502 |
-
});
|
| 503 |
-
|
| 504 |
-
if (!res.ok) {
|
| 505 |
-
const err = await res.json().catch(() => ({}));
|
| 506 |
-
throw new Error(err.error || 'အသံထုတ်ခြင်း မအောင်မြင်ပါ');
|
| 507 |
-
}
|
| 508 |
-
|
| 509 |
-
const blob = await res.blob();
|
| 510 |
-
if (currentObjectUrl) URL.revokeObjectURL(currentObjectUrl);
|
| 511 |
-
currentObjectUrl = URL.createObjectURL(blob);
|
| 512 |
|
| 513 |
-
|
| 514 |
-
downloadLink.href = currentObjectUrl;
|
| 515 |
-
output.classList.add('visible');
|
| 516 |
-
status.textContent = 'အသံ အောင်မြင်စွာ ထုတ်ပြီးပါပြီ။';
|
| 517 |
-
player.play().catch(() => {});
|
| 518 |
-
} catch (e) {
|
| 519 |
-
status.textContent = e.message;
|
| 520 |
-
status.classList.add('error');
|
| 521 |
-
} finally {
|
| 522 |
-
generateBtn.disabled = false;
|
| 523 |
-
stopWaveAnimation();
|
| 524 |
-
}
|
| 525 |
-
});
|
| 526 |
-
</script>
|
| 527 |
</body>
|
| 528 |
</html>
|
|
|
|
| 1 |
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Myanmar Voice Studio — Free Myanmar Text to Speech (TTS)</title>
|
| 7 |
+
<meta name="description" content="Convert Myanmar (Burmese) text into natural-sounding speech for free. Choose from neural voices, adjust speed and pitch, and download MP3 audio instantly — no sign-up required.">
|
| 8 |
|
|
|
|
| 9 |
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 10 |
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
| 11 |
+
<link href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,400..700;1,9..144,400..600&family=Inter:wght@400;500;600&family=Noto+Sans+Myanmar:wght@400;500;600;700&display=swap" rel="stylesheet">
|
| 12 |
+
<link rel="stylesheet" href="/style.css">
|
| 13 |
|
| 14 |
<!-- ===================== Google AdSense ===================== -->
|
| 15 |
<!-- Replace ca-pub-XXXXXXXXXXXXXXXX with your own AdSense publisher ID -->
|
| 16 |
<script async src="https://pagead2.googleadsense.com/pagead/js/adsbygoogle.js?client=ca-pub-XXXXXXXXXXXXXXXX" crossorigin="anonymous"></script>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
</head>
|
| 18 |
<body>
|
| 19 |
|
| 20 |
+
<nav class="nav">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
<div class="wrap">
|
| 22 |
+
<a href="/" class="brand"><span class="dot"></span>Myanmar Voice Studio</a>
|
| 23 |
+
<div class="nav-links">
|
| 24 |
+
<a href="/" class="active">Home</a>
|
| 25 |
+
<a href="#tool">Try It</a>
|
| 26 |
+
<a href="#how-it-works">How It Works</a>
|
| 27 |
+
<a href="#faq">FAQ</a>
|
| 28 |
+
<a href="/about">About</a>
|
| 29 |
+
</div>
|
| 30 |
+
</div>
|
| 31 |
+
</nav>
|
| 32 |
+
|
| 33 |
+
<div class="wrap">
|
| 34 |
+
|
| 35 |
+
<header class="hero">
|
| 36 |
+
<p class="eyebrow">Free Online Tool</p>
|
| 37 |
+
<h1>Turn Myanmar Text Into<br>Natural Sounding Speech</h1>
|
| 38 |
+
<p class="lead">Myanmar Voice Studio uses high-quality neural voices to read your
|
| 39 |
+
Burmese text aloud. Paste up to 10,000 characters, fine-tune the speed and
|
| 40 |
+
pitch, and download a ready-to-use MP3 — completely free, no account needed.</p>
|
| 41 |
+
<div class="wave" id="wave"></div>
|
| 42 |
+
</header>
|
| 43 |
+
|
| 44 |
+
</div>
|
| 45 |
+
|
| 46 |
+
<!-- Top ad slot -->
|
| 47 |
+
<div class="ad-slot">
|
| 48 |
+
<div class="ad-label">Advertisement</div>
|
| 49 |
+
<ins class="adsbygoogle"
|
| 50 |
+
style="display:block"
|
| 51 |
+
data-ad-client="ca-pub-XXXXXXXXXXXXXXXX"
|
| 52 |
+
data-ad-slot="1111111111"
|
| 53 |
+
data-ad-format="auto"
|
| 54 |
+
data-full-width-responsive="true"></ins>
|
| 55 |
+
<script>(adsbygoogle = window.adsbygoogle || []).push({});</script>
|
| 56 |
+
</div>
|
| 57 |
+
|
| 58 |
+
<div class="wrap" id="tool">
|
| 59 |
+
|
| 60 |
+
<!-- Text input -->
|
| 61 |
+
<section class="tight">
|
| 62 |
+
<div class="panel">
|
| 63 |
+
<h3>Your Script</h3>
|
| 64 |
+
<textarea id="text" placeholder="Type or paste Myanmar text here..." maxlength="10000"></textarea>
|
| 65 |
+
<div class="char-count" id="charCount">0 / 10000</div>
|
| 66 |
+
</div>
|
| 67 |
+
</section>
|
| 68 |
+
|
| 69 |
+
<!-- Voice + settings -->
|
| 70 |
+
<section class="tight">
|
| 71 |
+
<div class="panel">
|
| 72 |
+
<h3>Voice</h3>
|
| 73 |
<div class="voices" id="voices">
|
| 74 |
<label class="voice-card selected" data-voice="my-MM-NilarNeural">
|
| 75 |
<input type="radio" name="voice" value="my-MM-NilarNeural" checked>
|
|
|
|
| 85 |
|
| 86 |
<div class="controls">
|
| 87 |
<div class="control">
|
| 88 |
+
<label>Speed <span class="val" id="rateVal">+0%</span></label>
|
| 89 |
<input type="range" id="rate" min="-50" max="50" value="0" step="5">
|
| 90 |
</div>
|
| 91 |
<div class="control">
|
| 92 |
+
<label>Pitch <span class="val" id="pitchVal">+0Hz</span></label>
|
| 93 |
<input type="range" id="pitch" min="-50" max="50" value="0" step="5">
|
| 94 |
</div>
|
| 95 |
</div>
|
| 96 |
|
| 97 |
<div class="actions">
|
| 98 |
+
<button class="btn-primary" id="generateBtn">Generate Voice</button>
|
| 99 |
</div>
|
| 100 |
|
| 101 |
<div class="status" id="status"></div>
|
|
|
|
| 103 |
<div class="output" id="output">
|
| 104 |
<audio id="player" controls></audio>
|
| 105 |
<div class="actions">
|
| 106 |
+
<a class="btn-secondary" id="downloadLink" download="myanmar_voice.mp3">Download MP3</a>
|
| 107 |
</div>
|
| 108 |
</div>
|
| 109 |
+
</div>
|
| 110 |
+
</section>
|
| 111 |
+
|
| 112 |
+
<!-- How it works -->
|
| 113 |
+
<section id="how-it-works">
|
| 114 |
+
<div class="section-head">
|
| 115 |
+
<p class="eyebrow">How It Works</p>
|
| 116 |
+
<h2>From text to voice in three steps</h2>
|
| 117 |
+
<p>No installation, no registration. Everything runs directly in your browser.</p>
|
| 118 |
+
</div>
|
| 119 |
+
<div class="grid">
|
| 120 |
+
<div class="card">
|
| 121 |
+
<div class="index">01</div>
|
| 122 |
+
<h3>Write or paste your text</h3>
|
| 123 |
+
<p>Add up to 10,000 characters of Myanmar text — scripts, articles, captions, or study notes.</p>
|
| 124 |
+
</div>
|
| 125 |
+
<div class="card">
|
| 126 |
+
<div class="index">02</div>
|
| 127 |
+
<h3>Pick a voice & tune it</h3>
|
| 128 |
+
<p>Choose between Nilar (female) and Thiha (male), then adjust the speaking speed and pitch.</p>
|
| 129 |
+
</div>
|
| 130 |
+
<div class="card">
|
| 131 |
+
<div class="index">03</div>
|
| 132 |
+
<h3>Generate & download</h3>
|
| 133 |
+
<p>Click Generate, preview the audio instantly, and download it as an MP3 file.</p>
|
| 134 |
+
</div>
|
| 135 |
+
</div>
|
| 136 |
+
</section>
|
| 137 |
+
|
| 138 |
+
<!-- Features -->
|
| 139 |
+
<section>
|
| 140 |
+
<div class="section-head">
|
| 141 |
+
<p class="eyebrow">Features</p>
|
| 142 |
+
<h2>Built for creators & learners</h2>
|
| 143 |
+
<p>Everything you need for quick, natural Myanmar voiceovers.</p>
|
| 144 |
+
</div>
|
| 145 |
+
<div class="grid">
|
| 146 |
+
<div class="card">
|
| 147 |
+
<h3>Natural Neural Voices</h3>
|
| 148 |
+
<p>Powered by Microsoft's neural text-to-speech engine for clear, lifelike Myanmar pronunciation.</p>
|
| 149 |
+
</div>
|
| 150 |
+
<div class="card">
|
| 151 |
+
<h3>Adjustable Speed & Pitch</h3>
|
| 152 |
+
<p>Slow it down for learning material, or speed it up for short-form video narration.</p>
|
| 153 |
+
</div>
|
| 154 |
+
<div class="card">
|
| 155 |
+
<h3>Up to 10,000 Characters</h3>
|
| 156 |
+
<p>Convert long articles, scripts, or chapters in a single request.</p>
|
| 157 |
+
</div>
|
| 158 |
+
<div class="card">
|
| 159 |
+
<h3>Instant MP3 Download</h3>
|
| 160 |
+
<p>Your audio file is ready to download and use the moment it's generated.</p>
|
| 161 |
+
</div>
|
| 162 |
+
<div class="card">
|
| 163 |
+
<h3>No Sign-up Required</h3>
|
| 164 |
+
<p>Start using the tool immediately — there are no accounts, passwords, or limits to unlock.</p>
|
| 165 |
+
</div>
|
| 166 |
+
<div class="card">
|
| 167 |
+
<h3>Free to Use</h3>
|
| 168 |
+
<p>Myanmar Voice Studio is free for personal, educational, and commercial projects.</p>
|
| 169 |
+
</div>
|
| 170 |
+
</div>
|
| 171 |
+
</section>
|
| 172 |
+
|
| 173 |
+
<!-- Use cases -->
|
| 174 |
+
<section>
|
| 175 |
+
<div class="section-head">
|
| 176 |
+
<p class="eyebrow">Use Cases</p>
|
| 177 |
+
<h2>Who is this for?</h2>
|
| 178 |
+
</div>
|
| 179 |
+
<div class="grid">
|
| 180 |
+
<div class="card">
|
| 181 |
+
<h3>Content Creators</h3>
|
| 182 |
+
<p>Generate voiceovers for YouTube videos, TikToks, and Reels in Myanmar language.</p>
|
| 183 |
+
</div>
|
| 184 |
+
<div class="card">
|
| 185 |
+
<h3>Educators & Students</h3>
|
| 186 |
+
<p>Turn lesson notes and reading material into audio for revision and accessibility.</p>
|
| 187 |
+
</div>
|
| 188 |
+
<div class="card">
|
| 189 |
+
<h3>Developers</h3>
|
| 190 |
+
<p>Prototype Myanmar-language apps, games, and IVR systems with quick sample audio.</p>
|
| 191 |
+
</div>
|
| 192 |
+
<div class="card">
|
| 193 |
+
<h3>Podcasters & Writers</h3>
|
| 194 |
+
<p>Preview how your written Myanmar content sounds when read aloud.</p>
|
| 195 |
+
</div>
|
| 196 |
+
<div class="card">
|
| 197 |
+
<h3>Accessibility</h3>
|
| 198 |
+
<p>Help readers who are visually impaired or prefer listening over reading.</p>
|
| 199 |
+
</div>
|
| 200 |
+
<div class="card">
|
| 201 |
+
<h3>Translators</h3>
|
| 202 |
+
<p>Check pronunciation and pacing of translated Myanmar scripts before recording.</p>
|
| 203 |
+
</div>
|
| 204 |
+
</div>
|
| 205 |
+
</section>
|
| 206 |
|
| 207 |
<!-- In-content ad slot -->
|
| 208 |
<div class="ad-slot">
|
|
|
|
| 216 |
<script>(adsbygoogle = window.adsbygoogle || []).push({});</script>
|
| 217 |
</div>
|
| 218 |
|
| 219 |
+
<!-- FAQ -->
|
| 220 |
+
<section id="faq">
|
| 221 |
+
<div class="section-head">
|
| 222 |
+
<p class="eyebrow">FAQ</p>
|
| 223 |
+
<h2>Frequently asked questions</h2>
|
| 224 |
+
</div>
|
| 225 |
+
|
| 226 |
+
<details class="faq-item" open>
|
| 227 |
+
<summary>Is Myanmar Voice Studio free to use?</summary>
|
| 228 |
+
<p>Yes. The tool is completely free for personal, educational, and commercial use. There are no hidden fees or subscriptions.</p>
|
| 229 |
+
</details>
|
| 230 |
+
|
| 231 |
+
<details class="faq-item">
|
| 232 |
+
<summary>Which Myanmar voices are available?</summary>
|
| 233 |
+
<p>You can choose between two neural voices: Nilar, a female voice, and Thiha, a male voice. Both are tuned for natural Burmese pronunciation.</p>
|
| 234 |
+
</details>
|
| 235 |
+
|
| 236 |
+
<details class="faq-item">
|
| 237 |
+
<summary>Can I change the speaking speed and pitch?</summary>
|
| 238 |
+
<p>Yes. Use the Speed and Pitch sliders before generating audio to make the voice sound slower, faster, deeper, or lighter.</p>
|
| 239 |
+
</details>
|
| 240 |
+
|
| 241 |
+
<details class="faq-item">
|
| 242 |
+
<summary>What is the maximum text length?</summary>
|
| 243 |
+
<p>You can convert up to 10,000 characters of Myanmar text in a single request.</p>
|
| 244 |
+
</details>
|
| 245 |
+
|
| 246 |
+
<details class="faq-item">
|
| 247 |
+
<summary>Can I use the audio in my videos or projects?</summary>
|
| 248 |
+
<p>Yes, generated audio files can be downloaded and used in your own videos, presentations, apps, and other projects.</p>
|
| 249 |
+
</details>
|
| 250 |
+
|
| 251 |
+
<details class="faq-item">
|
| 252 |
+
<summary>Is my text stored or shared with anyone?</summary>
|
| 253 |
+
<p>No. Text you submit is sent only to generate the audio file and is not stored on our servers afterwards. See our <a href="/privacy">Privacy Policy</a> for details.</p>
|
| 254 |
+
</details>
|
| 255 |
+
</section>
|
| 256 |
+
|
| 257 |
+
</div>
|
| 258 |
+
|
| 259 |
+
<footer>
|
| 260 |
+
<div class="wrap">
|
| 261 |
+
<div class="footer-grid">
|
| 262 |
+
<div class="footer-col">
|
| 263 |
+
<h4>Myanmar Voice Studio</h4>
|
| 264 |
+
<a href="/">Home</a>
|
| 265 |
+
<a href="#tool">Text to Speech Tool</a>
|
| 266 |
+
<a href="#how-it-works">How It Works</a>
|
| 267 |
+
</div>
|
| 268 |
+
<div class="footer-col">
|
| 269 |
+
<h4>Resources</h4>
|
| 270 |
+
<a href="#faq">FAQ</a>
|
| 271 |
+
<a href="/about">About</a>
|
| 272 |
+
</div>
|
| 273 |
+
<div class="footer-col">
|
| 274 |
+
<h4>Legal</h4>
|
| 275 |
+
<a href="/privacy">Privacy Policy</a>
|
| 276 |
+
<a href="/terms">Terms of Use</a>
|
| 277 |
+
</div>
|
| 278 |
+
</div>
|
| 279 |
+
<div class="footer-bottom">
|
| 280 |
+
© 2026 Myanmar Voice Studio. Voices powered by neural text-to-speech technology.
|
| 281 |
+
</div>
|
| 282 |
+
</div>
|
| 283 |
+
</footer>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 284 |
|
| 285 |
+
<script src="/app.js"></script>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 286 |
</body>
|
| 287 |
</html>
|
privacy.html
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Privacy Policy — Myanmar Voice Studio</title>
|
| 7 |
+
<meta name="description" content="Privacy Policy for Myanmar Voice Studio, including information on data handling, cookies, and third-party advertising.">
|
| 8 |
+
|
| 9 |
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 10 |
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
| 11 |
+
<link href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,400..700;1,9..144,400..600&family=Inter:wght@400;500;600&family=Noto+Sans+Myanmar:wght@400;500;600;700&display=swap" rel="stylesheet">
|
| 12 |
+
<link rel="stylesheet" href="/style.css">
|
| 13 |
+
<script async src="https://pagead2.googleadsense.com/pagead/js/adsbygoogle.js?client=ca-pub-XXXXXXXXXXXXXXXX" crossorigin="anonymous"></script>
|
| 14 |
+
</head>
|
| 15 |
+
<body>
|
| 16 |
+
|
| 17 |
+
<nav class="nav">
|
| 18 |
+
<div class="wrap">
|
| 19 |
+
<a href="/" class="brand"><span class="dot"></span>Myanmar Voice Studio</a>
|
| 20 |
+
<div class="nav-links">
|
| 21 |
+
<a href="/">Home</a>
|
| 22 |
+
<a href="/#tool">Try It</a>
|
| 23 |
+
<a href="/#how-it-works">How It Works</a>
|
| 24 |
+
<a href="/#faq">FAQ</a>
|
| 25 |
+
<a href="/about">About</a>
|
| 26 |
+
</div>
|
| 27 |
+
</div>
|
| 28 |
+
</nav>
|
| 29 |
+
|
| 30 |
+
<div class="wrap prose">
|
| 31 |
+
<h1>Privacy Policy</h1>
|
| 32 |
+
<p class="updated">Last updated: June 2026</p>
|
| 33 |
+
|
| 34 |
+
<p>This Privacy Policy explains how Myanmar Voice Studio ("we", "our", "the
|
| 35 |
+
site") handles information when you use our website and text-to-speech
|
| 36 |
+
tool.</p>
|
| 37 |
+
|
| 38 |
+
<h2>Information you provide</h2>
|
| 39 |
+
<p>The text you enter into the tool is sent to our server only to generate
|
| 40 |
+
the corresponding audio file. We do not require you to create an account,
|
| 41 |
+
and we do not knowingly collect names, email addresses, or other personal
|
| 42 |
+
identifiers through the tool itself.</p>
|
| 43 |
+
|
| 44 |
+
<h2>How generated audio is handled</h2>
|
| 45 |
+
<p>Audio files are generated on demand and streamed back to your browser for
|
| 46 |
+
playback and download. We do not permanently store the text you submit or
|
| 47 |
+
the audio files that are generated from it on our servers.</p>
|
| 48 |
+
|
| 49 |
+
<h2>Cookies and similar technologies</h2>
|
| 50 |
+
<p>Our website does not set its own tracking cookies for the core
|
| 51 |
+
text-to-speech tool. However, third-party services embedded on this site
|
| 52 |
+
— including advertising providers — may set cookies or use similar
|
| 53 |
+
technologies in your browser, as described below.</p>
|
| 54 |
+
|
| 55 |
+
<h2>Advertising (Google AdSense)</h2>
|
| 56 |
+
<p>We use Google AdSense to display advertisements on this site. Google and
|
| 57 |
+
its partners may use cookies, device identifiers, and similar
|
| 58 |
+
technologies to serve ads based on your visits to this and other
|
| 59 |
+
websites.</p>
|
| 60 |
+
<ul>
|
| 61 |
+
<li>You can learn more about how Google uses information from sites that
|
| 62 |
+
use its services at
|
| 63 |
+
<a href="https://policies.google.com/technologies/partner-sites" target="_blank" rel="noopener">policies.google.com/technologies/partner-sites</a>.</li>
|
| 64 |
+
<li>You can opt out of personalized advertising by visiting
|
| 65 |
+
<a href="https://adssettings.google.com" target="_blank" rel="noopener">Google Ads Settings</a>.</li>
|
| 66 |
+
<li>Third-party vendors, including Google, may use cookies to serve ads
|
| 67 |
+
based on a user's prior visits to this website or other websites.</li>
|
| 68 |
+
</ul>
|
| 69 |
+
|
| 70 |
+
<h2>Analytics</h2>
|
| 71 |
+
<p>We may use basic, privacy-respecting analytics to understand overall site
|
| 72 |
+
usage (for example, page views and approximate traffic sources). This
|
| 73 |
+
information is aggregated and is not used to identify individual
|
| 74 |
+
visitors.</p>
|
| 75 |
+
|
| 76 |
+
<h2>Children's privacy</h2>
|
| 77 |
+
<p>This site is not directed at children under the age of 13, and we do not
|
| 78 |
+
knowingly collect personal information from children.</p>
|
| 79 |
+
|
| 80 |
+
<h2>Third-party links</h2>
|
| 81 |
+
<p>Our site may contain links to other websites, including advertisers. We
|
| 82 |
+
are not responsible for the privacy practices or content of those
|
| 83 |
+
external sites.</p>
|
| 84 |
+
|
| 85 |
+
<h2>Changes to this policy</h2>
|
| 86 |
+
<p>We may update this Privacy Policy from time to time. Any changes will be
|
| 87 |
+
posted on this page with an updated "Last updated" date.</p>
|
| 88 |
+
|
| 89 |
+
<h2>Contact</h2>
|
| 90 |
+
<p>If you have questions about this Privacy Policy, please contact us at
|
| 91 |
+
<a href="mailto:contact@example.com">contact@example.com</a>.</p>
|
| 92 |
+
</div>
|
| 93 |
+
|
| 94 |
+
<footer>
|
| 95 |
+
<div class="wrap">
|
| 96 |
+
<div class="footer-grid">
|
| 97 |
+
<div class="footer-col">
|
| 98 |
+
<h4>Myanmar Voice Studio</h4>
|
| 99 |
+
<a href="/">Home</a>
|
| 100 |
+
<a href="/#tool">Text to Speech Tool</a>
|
| 101 |
+
<a href="/#how-it-works">How It Works</a>
|
| 102 |
+
</div>
|
| 103 |
+
<div class="footer-col">
|
| 104 |
+
<h4>Resources</h4>
|
| 105 |
+
<a href="/#faq">FAQ</a>
|
| 106 |
+
<a href="/about">About</a>
|
| 107 |
+
</div>
|
| 108 |
+
<div class="footer-col">
|
| 109 |
+
<h4>Legal</h4>
|
| 110 |
+
<a href="/privacy">Privacy Policy</a>
|
| 111 |
+
<a href="/terms">Terms of Use</a>
|
| 112 |
+
</div>
|
| 113 |
+
</div>
|
| 114 |
+
<div class="footer-bottom">
|
| 115 |
+
© 2026 Myanmar Voice Studio. Voices powered by neural text-to-speech technology.
|
| 116 |
+
</div>
|
| 117 |
+
</div>
|
| 118 |
+
</footer>
|
| 119 |
+
|
| 120 |
+
</body>
|
| 121 |
+
</html>
|
style.css
ADDED
|
@@ -0,0 +1,448 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
:root{
|
| 2 |
+
--bg:#F7F4ED;
|
| 3 |
+
--surface:#FFFFFF;
|
| 4 |
+
--surface-2:#F1EAD9;
|
| 5 |
+
--ink:#221F1C;
|
| 6 |
+
--ink-soft:#7A6E5F;
|
| 7 |
+
--jade:#2F6F5E;
|
| 8 |
+
--jade-soft:#E1EDE9;
|
| 9 |
+
--amber:#D98C3D;
|
| 10 |
+
--amber-soft:#FAEBD8;
|
| 11 |
+
--line:#E7E0D3;
|
| 12 |
+
--radius:14px;
|
| 13 |
+
--serif:'Fraunces', serif;
|
| 14 |
+
--sans:'Inter', sans-serif;
|
| 15 |
+
--mm:'Noto Sans Myanmar', sans-serif;
|
| 16 |
+
--maxw:920px;
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
*{ box-sizing:border-box; }
|
| 20 |
+
html{ scroll-behavior:smooth; }
|
| 21 |
+
|
| 22 |
+
body{
|
| 23 |
+
margin:0;
|
| 24 |
+
background:var(--bg);
|
| 25 |
+
color:var(--ink);
|
| 26 |
+
font-family:var(--sans);
|
| 27 |
+
line-height:1.65;
|
| 28 |
+
-webkit-font-smoothing:antialiased;
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
a{ color:var(--jade); text-decoration:none; }
|
| 32 |
+
a:hover{ text-decoration:underline; }
|
| 33 |
+
|
| 34 |
+
img{ max-width:100%; }
|
| 35 |
+
|
| 36 |
+
.wrap{
|
| 37 |
+
max-width:var(--maxw);
|
| 38 |
+
margin:0 auto;
|
| 39 |
+
padding:0 20px;
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
/* ---------- Ad slots ---------- */
|
| 43 |
+
.ad-slot{
|
| 44 |
+
margin:36px auto;
|
| 45 |
+
padding:14px 0;
|
| 46 |
+
text-align:center;
|
| 47 |
+
max-width:var(--maxw);
|
| 48 |
+
}
|
| 49 |
+
.ad-label{
|
| 50 |
+
font-family:var(--serif);
|
| 51 |
+
font-style:italic;
|
| 52 |
+
font-size:11px;
|
| 53 |
+
letter-spacing:.14em;
|
| 54 |
+
text-transform:uppercase;
|
| 55 |
+
color:var(--ink-soft);
|
| 56 |
+
margin-bottom:8px;
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
/* ---------- Nav ---------- */
|
| 60 |
+
.nav{
|
| 61 |
+
border-bottom:1px solid var(--line);
|
| 62 |
+
background:var(--surface);
|
| 63 |
+
}
|
| 64 |
+
.nav .wrap{
|
| 65 |
+
display:flex;
|
| 66 |
+
align-items:center;
|
| 67 |
+
justify-content:space-between;
|
| 68 |
+
padding:16px 20px;
|
| 69 |
+
flex-wrap:wrap;
|
| 70 |
+
gap:10px;
|
| 71 |
+
}
|
| 72 |
+
.brand{
|
| 73 |
+
display:flex;
|
| 74 |
+
align-items:center;
|
| 75 |
+
gap:8px;
|
| 76 |
+
font-family:var(--serif);
|
| 77 |
+
font-weight:700;
|
| 78 |
+
font-size:18px;
|
| 79 |
+
color:var(--ink);
|
| 80 |
+
}
|
| 81 |
+
.brand .dot{
|
| 82 |
+
width:10px; height:10px;
|
| 83 |
+
border-radius:50%;
|
| 84 |
+
background:linear-gradient(135deg, var(--jade), var(--amber));
|
| 85 |
+
display:inline-block;
|
| 86 |
+
}
|
| 87 |
+
.nav-links{
|
| 88 |
+
display:flex;
|
| 89 |
+
gap:18px;
|
| 90 |
+
flex-wrap:wrap;
|
| 91 |
+
font-size:14px;
|
| 92 |
+
}
|
| 93 |
+
.nav-links a{ color:var(--ink-soft); }
|
| 94 |
+
.nav-links a:hover{ color:var(--jade); }
|
| 95 |
+
.nav-links a.active{ color:var(--jade); font-weight:600; }
|
| 96 |
+
|
| 97 |
+
/* ---------- Hero ---------- */
|
| 98 |
+
.hero{
|
| 99 |
+
padding:52px 0 28px;
|
| 100 |
+
text-align:center;
|
| 101 |
+
}
|
| 102 |
+
.eyebrow{
|
| 103 |
+
font-family:var(--serif);
|
| 104 |
+
font-style:italic;
|
| 105 |
+
font-weight:500;
|
| 106 |
+
font-size:13px;
|
| 107 |
+
letter-spacing:.22em;
|
| 108 |
+
text-transform:uppercase;
|
| 109 |
+
color:var(--jade);
|
| 110 |
+
margin:0 0 12px;
|
| 111 |
+
}
|
| 112 |
+
h1{
|
| 113 |
+
font-family:var(--serif);
|
| 114 |
+
font-weight:700;
|
| 115 |
+
font-size:clamp(30px,7vw,46px);
|
| 116 |
+
margin:0 0 14px;
|
| 117 |
+
letter-spacing:-.01em;
|
| 118 |
+
}
|
| 119 |
+
.hero p.lead{
|
| 120 |
+
color:var(--ink-soft);
|
| 121 |
+
font-size:16px;
|
| 122 |
+
max-width:560px;
|
| 123 |
+
margin:0 auto;
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
/* ---------- Signature waveform ---------- */
|
| 127 |
+
.wave{
|
| 128 |
+
display:flex;
|
| 129 |
+
align-items:center;
|
| 130 |
+
justify-content:center;
|
| 131 |
+
gap:4px;
|
| 132 |
+
height:36px;
|
| 133 |
+
margin:26px auto 0;
|
| 134 |
+
}
|
| 135 |
+
.wave .bar{
|
| 136 |
+
width:4px;
|
| 137 |
+
border-radius:3px;
|
| 138 |
+
background:linear-gradient(180deg, var(--jade), var(--amber));
|
| 139 |
+
height:10px;
|
| 140 |
+
animation:breathe 2.6s ease-in-out infinite;
|
| 141 |
+
transition:height .12s ease;
|
| 142 |
+
}
|
| 143 |
+
@keyframes breathe{
|
| 144 |
+
0%, 100% { height:8px; opacity:.55; }
|
| 145 |
+
50% { height:30px; opacity:1; }
|
| 146 |
+
}
|
| 147 |
+
.wave.is-active .bar{ animation:none; }
|
| 148 |
+
|
| 149 |
+
/* ---------- Sections ---------- */
|
| 150 |
+
section{ padding:36px 0; }
|
| 151 |
+
section.tight{ padding:18px 0; }
|
| 152 |
+
|
| 153 |
+
.section-head{
|
| 154 |
+
text-align:center;
|
| 155 |
+
margin-bottom:28px;
|
| 156 |
+
}
|
| 157 |
+
.section-head .eyebrow{ margin-bottom:8px; }
|
| 158 |
+
h2{
|
| 159 |
+
font-family:var(--serif);
|
| 160 |
+
font-weight:700;
|
| 161 |
+
font-size:clamp(24px,5vw,32px);
|
| 162 |
+
margin:0 0 8px;
|
| 163 |
+
}
|
| 164 |
+
.section-head p{
|
| 165 |
+
color:var(--ink-soft);
|
| 166 |
+
font-size:15px;
|
| 167 |
+
max-width:520px;
|
| 168 |
+
margin:0 auto;
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
/* ---------- Tool panel ---------- */
|
| 172 |
+
.panel{
|
| 173 |
+
background:var(--surface);
|
| 174 |
+
border:1px solid var(--line);
|
| 175 |
+
border-radius:var(--radius);
|
| 176 |
+
padding:22px;
|
| 177 |
+
margin-top:18px;
|
| 178 |
+
box-shadow:0 1px 2px rgba(34,31,28,.03);
|
| 179 |
+
}
|
| 180 |
+
.panel h3{
|
| 181 |
+
font-family:var(--serif);
|
| 182 |
+
font-style:italic;
|
| 183 |
+
font-weight:500;
|
| 184 |
+
font-size:13px;
|
| 185 |
+
letter-spacing:.16em;
|
| 186 |
+
text-transform:uppercase;
|
| 187 |
+
color:var(--ink-soft);
|
| 188 |
+
margin:0 0 14px;
|
| 189 |
+
}
|
| 190 |
+
|
| 191 |
+
textarea{
|
| 192 |
+
width:100%;
|
| 193 |
+
min-height:170px;
|
| 194 |
+
resize:vertical;
|
| 195 |
+
border:1px solid var(--line);
|
| 196 |
+
border-radius:10px;
|
| 197 |
+
background:
|
| 198 |
+
repeating-linear-gradient(
|
| 199 |
+
to bottom, transparent, transparent 35px,
|
| 200 |
+
var(--surface-2) 35px, var(--surface-2) 36px
|
| 201 |
+
),
|
| 202 |
+
var(--surface);
|
| 203 |
+
padding:14px 16px;
|
| 204 |
+
font-family:var(--mm);
|
| 205 |
+
font-size:16px;
|
| 206 |
+
line-height:36px;
|
| 207 |
+
color:var(--ink);
|
| 208 |
+
outline:none;
|
| 209 |
+
}
|
| 210 |
+
textarea:focus{ border-color:var(--jade); }
|
| 211 |
+
textarea::placeholder{ color:var(--ink-soft); font-family:var(--sans); }
|
| 212 |
+
|
| 213 |
+
.char-count{
|
| 214 |
+
text-align:right;
|
| 215 |
+
font-size:12px;
|
| 216 |
+
color:var(--ink-soft);
|
| 217 |
+
margin-top:6px;
|
| 218 |
+
font-family:var(--serif);
|
| 219 |
+
}
|
| 220 |
+
.char-count.over{ color:#C0492B; }
|
| 221 |
+
|
| 222 |
+
/* ---------- Voice cards ---------- */
|
| 223 |
+
.voices{
|
| 224 |
+
display:grid;
|
| 225 |
+
grid-template-columns:1fr 1fr;
|
| 226 |
+
gap:12px;
|
| 227 |
+
margin-top:8px;
|
| 228 |
+
}
|
| 229 |
+
.voice-card{
|
| 230 |
+
border:1px solid var(--line);
|
| 231 |
+
border-radius:10px;
|
| 232 |
+
padding:14px;
|
| 233 |
+
cursor:pointer;
|
| 234 |
+
background:var(--surface);
|
| 235 |
+
transition:border-color .15s ease, background .15s ease;
|
| 236 |
+
position:relative;
|
| 237 |
+
}
|
| 238 |
+
.voice-card input{
|
| 239 |
+
position:absolute; opacity:0; inset:0; cursor:pointer; margin:0;
|
| 240 |
+
}
|
| 241 |
+
.voice-card .name{ font-family:var(--mm); font-weight:600; font-size:15px; }
|
| 242 |
+
.voice-card .role{
|
| 243 |
+
font-family:var(--serif);
|
| 244 |
+
font-style:italic;
|
| 245 |
+
font-size:12px;
|
| 246 |
+
letter-spacing:.08em;
|
| 247 |
+
color:var(--ink-soft);
|
| 248 |
+
text-transform:uppercase;
|
| 249 |
+
margin-top:4px;
|
| 250 |
+
}
|
| 251 |
+
.voice-card.selected{ border-color:var(--jade); background:var(--jade-soft); }
|
| 252 |
+
.voice-card.selected .role{ color:var(--jade); }
|
| 253 |
+
|
| 254 |
+
/* ---------- Sliders ---------- */
|
| 255 |
+
.controls{
|
| 256 |
+
display:grid;
|
| 257 |
+
grid-template-columns:1fr 1fr;
|
| 258 |
+
gap:16px;
|
| 259 |
+
margin-top:18px;
|
| 260 |
+
}
|
| 261 |
+
.control label{
|
| 262 |
+
display:flex;
|
| 263 |
+
justify-content:space-between;
|
| 264 |
+
font-size:13px;
|
| 265 |
+
color:var(--ink-soft);
|
| 266 |
+
margin-bottom:6px;
|
| 267 |
+
font-family:var(--serif);
|
| 268 |
+
font-style:italic;
|
| 269 |
+
letter-spacing:.04em;
|
| 270 |
+
}
|
| 271 |
+
.control label span.val{
|
| 272 |
+
font-family:var(--sans);
|
| 273 |
+
font-style:normal;
|
| 274 |
+
color:var(--ink);
|
| 275 |
+
font-weight:600;
|
| 276 |
+
}
|
| 277 |
+
input[type="range"]{ width:100%; accent-color:var(--jade); }
|
| 278 |
+
|
| 279 |
+
@media (max-width:480px){
|
| 280 |
+
.controls{ grid-template-columns:1fr; }
|
| 281 |
+
.voices{ grid-template-columns:1fr; }
|
| 282 |
+
}
|
| 283 |
+
|
| 284 |
+
/* ---------- Buttons ---------- */
|
| 285 |
+
.actions{ margin-top:22px; display:flex; gap:12px; flex-wrap:wrap; }
|
| 286 |
+
button, .btn{
|
| 287 |
+
font-family:var(--sans);
|
| 288 |
+
font-size:15px;
|
| 289 |
+
font-weight:600;
|
| 290 |
+
border:none;
|
| 291 |
+
border-radius:10px;
|
| 292 |
+
padding:13px 24px;
|
| 293 |
+
cursor:pointer;
|
| 294 |
+
transition:opacity .15s ease, transform .05s ease;
|
| 295 |
+
}
|
| 296 |
+
button:active{ transform:scale(.98); }
|
| 297 |
+
button:disabled{ opacity:.55; cursor:wait; }
|
| 298 |
+
|
| 299 |
+
.btn-primary{ background:var(--amber); color:#fff; flex:1; }
|
| 300 |
+
.btn-primary:hover:not(:disabled){ opacity:.92; }
|
| 301 |
+
|
| 302 |
+
.btn-secondary{
|
| 303 |
+
background:var(--surface-2);
|
| 304 |
+
color:var(--ink);
|
| 305 |
+
border:1px solid var(--line);
|
| 306 |
+
text-decoration:none;
|
| 307 |
+
display:inline-block;
|
| 308 |
+
text-align:center;
|
| 309 |
+
}
|
| 310 |
+
|
| 311 |
+
/* ---------- Output ---------- */
|
| 312 |
+
.output{ margin-top:18px; display:none; }
|
| 313 |
+
.output.visible{ display:block; }
|
| 314 |
+
.output audio{ width:100%; margin-top:14px; }
|
| 315 |
+
|
| 316 |
+
.status{ font-size:13px; color:var(--ink-soft); margin-top:10px; min-height:18px; }
|
| 317 |
+
.status.error{ color:#C0492B; }
|
| 318 |
+
|
| 319 |
+
/* ---------- Feature / step grids ---------- */
|
| 320 |
+
.grid{
|
| 321 |
+
display:grid;
|
| 322 |
+
grid-template-columns:repeat(3, 1fr);
|
| 323 |
+
gap:16px;
|
| 324 |
+
}
|
| 325 |
+
@media (max-width:720px){
|
| 326 |
+
.grid{ grid-template-columns:1fr 1fr; }
|
| 327 |
+
}
|
| 328 |
+
@media (max-width:480px){
|
| 329 |
+
.grid{ grid-template-columns:1fr; }
|
| 330 |
+
}
|
| 331 |
+
|
| 332 |
+
.card{
|
| 333 |
+
background:var(--surface);
|
| 334 |
+
border:1px solid var(--line);
|
| 335 |
+
border-radius:var(--radius);
|
| 336 |
+
padding:20px;
|
| 337 |
+
}
|
| 338 |
+
.card .index{
|
| 339 |
+
font-family:var(--serif);
|
| 340 |
+
font-style:italic;
|
| 341 |
+
font-size:13px;
|
| 342 |
+
color:var(--jade);
|
| 343 |
+
margin-bottom:6px;
|
| 344 |
+
}
|
| 345 |
+
.card h3{
|
| 346 |
+
font-family:var(--serif);
|
| 347 |
+
font-weight:600;
|
| 348 |
+
font-size:17px;
|
| 349 |
+
margin:0 0 6px;
|
| 350 |
+
text-transform:none;
|
| 351 |
+
letter-spacing:0;
|
| 352 |
+
color:var(--ink);
|
| 353 |
+
}
|
| 354 |
+
.card p{
|
| 355 |
+
font-size:14px;
|
| 356 |
+
color:var(--ink-soft);
|
| 357 |
+
margin:0;
|
| 358 |
+
}
|
| 359 |
+
|
| 360 |
+
/* ---------- FAQ ---------- */
|
| 361 |
+
.faq-item{
|
| 362 |
+
border-bottom:1px solid var(--line);
|
| 363 |
+
padding:16px 0;
|
| 364 |
+
}
|
| 365 |
+
.faq-item summary{
|
| 366 |
+
font-family:var(--serif);
|
| 367 |
+
font-weight:600;
|
| 368 |
+
font-size:16px;
|
| 369 |
+
cursor:pointer;
|
| 370 |
+
list-style:none;
|
| 371 |
+
display:flex;
|
| 372 |
+
justify-content:space-between;
|
| 373 |
+
align-items:center;
|
| 374 |
+
gap:12px;
|
| 375 |
+
}
|
| 376 |
+
.faq-item summary::-webkit-details-marker{ display:none; }
|
| 377 |
+
.faq-item summary::after{
|
| 378 |
+
content:"+";
|
| 379 |
+
font-size:20px;
|
| 380 |
+
color:var(--jade);
|
| 381 |
+
flex-shrink:0;
|
| 382 |
+
}
|
| 383 |
+
.faq-item[open] summary::after{ content:"\2212"; }
|
| 384 |
+
.faq-item p{
|
| 385 |
+
color:var(--ink-soft);
|
| 386 |
+
font-size:14px;
|
| 387 |
+
margin:10px 0 0;
|
| 388 |
+
}
|
| 389 |
+
|
| 390 |
+
/* ---------- Prose pages (about / privacy / terms) ---------- */
|
| 391 |
+
.prose{ padding:44px 0 60px; }
|
| 392 |
+
.prose h1{ text-align:left; margin-bottom:6px; }
|
| 393 |
+
.prose .updated{
|
| 394 |
+
font-family:var(--serif);
|
| 395 |
+
font-style:italic;
|
| 396 |
+
font-size:13px;
|
| 397 |
+
color:var(--ink-soft);
|
| 398 |
+
margin-bottom:28px;
|
| 399 |
+
}
|
| 400 |
+
.prose h2{
|
| 401 |
+
font-size:20px;
|
| 402 |
+
margin-top:32px;
|
| 403 |
+
}
|
| 404 |
+
.prose p, .prose li{
|
| 405 |
+
color:var(--ink-soft);
|
| 406 |
+
font-size:15px;
|
| 407 |
+
}
|
| 408 |
+
.prose ul{ padding-left:20px; }
|
| 409 |
+
.prose a{ color:var(--jade); }
|
| 410 |
+
|
| 411 |
+
/* ---------- Footer ---------- */
|
| 412 |
+
footer{
|
| 413 |
+
border-top:1px solid var(--line);
|
| 414 |
+
margin-top:40px;
|
| 415 |
+
padding:32px 0;
|
| 416 |
+
background:var(--surface);
|
| 417 |
+
}
|
| 418 |
+
.footer-grid{
|
| 419 |
+
display:flex;
|
| 420 |
+
justify-content:space-between;
|
| 421 |
+
flex-wrap:wrap;
|
| 422 |
+
gap:24px;
|
| 423 |
+
}
|
| 424 |
+
.footer-col h4{
|
| 425 |
+
font-family:var(--serif);
|
| 426 |
+
font-style:italic;
|
| 427 |
+
font-weight:500;
|
| 428 |
+
font-size:12px;
|
| 429 |
+
letter-spacing:.14em;
|
| 430 |
+
text-transform:uppercase;
|
| 431 |
+
color:var(--ink-soft);
|
| 432 |
+
margin:0 0 10px;
|
| 433 |
+
}
|
| 434 |
+
.footer-col a{
|
| 435 |
+
display:block;
|
| 436 |
+
font-size:14px;
|
| 437 |
+
color:var(--ink);
|
| 438 |
+
margin-bottom:6px;
|
| 439 |
+
}
|
| 440 |
+
.footer-col a:hover{ color:var(--jade); }
|
| 441 |
+
.footer-bottom{
|
| 442 |
+
margin-top:24px;
|
| 443 |
+
padding-top:16px;
|
| 444 |
+
border-top:1px solid var(--line);
|
| 445 |
+
font-size:12px;
|
| 446 |
+
color:var(--ink-soft);
|
| 447 |
+
text-align:center;
|
| 448 |
+
}
|
terms.html
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Terms of Use — Myanmar Voice Studio</title>
|
| 7 |
+
<meta name="description" content="Terms of Use for Myanmar Voice Studio, a free Myanmar text-to-speech tool.">
|
| 8 |
+
|
| 9 |
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 10 |
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
| 11 |
+
<link href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,400..700;1,9..144,400..600&family=Inter:wght@400;500;600&family=Noto+Sans+Myanmar:wght@400;500;600;700&display=swap" rel="stylesheet">
|
| 12 |
+
<link rel="stylesheet" href="/style.css">
|
| 13 |
+
<script async src="https://pagead2.googleadsense.com/pagead/js/adsbygoogle.js?client=ca-pub-XXXXXXXXXXXXXXXX" crossorigin="anonymous"></script>
|
| 14 |
+
</head>
|
| 15 |
+
<body>
|
| 16 |
+
|
| 17 |
+
<nav class="nav">
|
| 18 |
+
<div class="wrap">
|
| 19 |
+
<a href="/" class="brand"><span class="dot"></span>Myanmar Voice Studio</a>
|
| 20 |
+
<div class="nav-links">
|
| 21 |
+
<a href="/">Home</a>
|
| 22 |
+
<a href="/#tool">Try It</a>
|
| 23 |
+
<a href="/#how-it-works">How It Works</a>
|
| 24 |
+
<a href="/#faq">FAQ</a>
|
| 25 |
+
<a href="/about">About</a>
|
| 26 |
+
</div>
|
| 27 |
+
</div>
|
| 28 |
+
</nav>
|
| 29 |
+
|
| 30 |
+
<div class="wrap prose">
|
| 31 |
+
<h1>Terms of Use</h1>
|
| 32 |
+
<p class="updated">Last updated: June 2026</p>
|
| 33 |
+
|
| 34 |
+
<p>By using Myanmar Voice Studio (the "Service"), you agree to the following
|
| 35 |
+
terms. If you do not agree, please do not use the Service.</p>
|
| 36 |
+
|
| 37 |
+
<h2>Use of the Service</h2>
|
| 38 |
+
<p>The Service converts text you submit into spoken audio using
|
| 39 |
+
text-to-speech technology. You may use the Service for personal,
|
| 40 |
+
educational, and commercial purposes, subject to these terms.</p>
|
| 41 |
+
|
| 42 |
+
<h2>Acceptable use</h2>
|
| 43 |
+
<p>You agree not to use the Service to generate audio that is:</p>
|
| 44 |
+
<ul>
|
| 45 |
+
<li>Illegal, harmful, threatening, or abusive.</li>
|
| 46 |
+
<li>Defamatory, hateful, or discriminatory.</li>
|
| 47 |
+
<li>Used to impersonate a real person without consent, or to mislead
|
| 48 |
+
others about the source of the audio.</li>
|
| 49 |
+
<li>In violation of any applicable law or the rights of any third party.</li>
|
| 50 |
+
</ul>
|
| 51 |
+
<p>We reserve the right to restrict access to the Service for anyone who
|
| 52 |
+
misuses it.</p>
|
| 53 |
+
|
| 54 |
+
<h2>Generated audio</h2>
|
| 55 |
+
<p>You are responsible for the text you submit and for how you use the
|
| 56 |
+
resulting audio files. We make no claim of ownership over the text you
|
| 57 |
+
provide or the audio generated from it.</p>
|
| 58 |
+
|
| 59 |
+
<h2>Availability and accuracy</h2>
|
| 60 |
+
<p>The Service is provided on an "as is" and "as available" basis. We do not
|
| 61 |
+
guarantee that the Service will be uninterrupted, error-free, or that the
|
| 62 |
+
generated pronunciation will always be perfectly accurate.</p>
|
| 63 |
+
|
| 64 |
+
<h2>Limitation of liability</h2>
|
| 65 |
+
<p>To the fullest extent permitted by law, Myanmar Voice Studio and its
|
| 66 |
+
operator shall not be liable for any indirect, incidental, or
|
| 67 |
+
consequential damages arising from your use of the Service.</p>
|
| 68 |
+
|
| 69 |
+
<h2>Advertising</h2>
|
| 70 |
+
<p>The Service is supported by advertising served through Google AdSense.
|
| 71 |
+
See our <a href="/privacy">Privacy Policy</a> for details on how
|
| 72 |
+
advertising partners may use cookies and similar technologies.</p>
|
| 73 |
+
|
| 74 |
+
<h2>Changes to these terms</h2>
|
| 75 |
+
<p>We may update these Terms of Use from time to time. Continued use of the
|
| 76 |
+
Service after changes are posted constitutes acceptance of the updated
|
| 77 |
+
terms.</p>
|
| 78 |
+
|
| 79 |
+
<h2>Contact</h2>
|
| 80 |
+
<p>Questions about these terms can be sent to
|
| 81 |
+
<a href="mailto:contact@example.com">contact@example.com</a>.</p>
|
| 82 |
+
</div>
|
| 83 |
+
|
| 84 |
+
<footer>
|
| 85 |
+
<div class="wrap">
|
| 86 |
+
<div class="footer-grid">
|
| 87 |
+
<div class="footer-col">
|
| 88 |
+
<h4>Myanmar Voice Studio</h4>
|
| 89 |
+
<a href="/">Home</a>
|
| 90 |
+
<a href="/#tool">Text to Speech Tool</a>
|
| 91 |
+
<a href="/#how-it-works">How It Works</a>
|
| 92 |
+
</div>
|
| 93 |
+
<div class="footer-col">
|
| 94 |
+
<h4>Resources</h4>
|
| 95 |
+
<a href="/#faq">FAQ</a>
|
| 96 |
+
<a href="/about">About</a>
|
| 97 |
+
</div>
|
| 98 |
+
<div class="footer-col">
|
| 99 |
+
<h4>Legal</h4>
|
| 100 |
+
<a href="/privacy">Privacy Policy</a>
|
| 101 |
+
<a href="/terms">Terms of Use</a>
|
| 102 |
+
</div>
|
| 103 |
+
</div>
|
| 104 |
+
<div class="footer-bottom">
|
| 105 |
+
© 2026 Myanmar Voice Studio. Voices powered by neural text-to-speech technology.
|
| 106 |
+
</div>
|
| 107 |
+
</div>
|
| 108 |
+
</footer>
|
| 109 |
+
|
| 110 |
+
</body>
|
| 111 |
+
</html>
|