Skip to content

Commit

Permalink
feat(webui): Add tts page
Browse files Browse the repository at this point in the history
Signed-off-by: Ettore Di Giacinto <[email protected]>
  • Loading branch information
mudler committed May 2, 2024
1 parent 4c38c75 commit 181d2a9
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 1 deletion.
33 changes: 33 additions & 0 deletions core/http/routes/ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,4 +237,37 @@ func RegisterUIRoutes(app *fiber.App,
// Render index
return c.Render("views/text2image", summary)
})

app.Get("/tts/:model", auth, func(c *fiber.Ctx) error {
backendConfigs := cl.GetAllBackendConfigs()

summary := fiber.Map{
"Title": "LocalAI - Generate images with " + c.Params("model"),
"ModelsConfig": backendConfigs,
"Model": c.Params("model"),
"Version": internal.PrintableVersion(),
}

// Render index
return c.Render("views/tts", summary)
})

app.Get("/tts/", auth, func(c *fiber.Ctx) error {

backendConfigs := cl.GetAllBackendConfigs()

if len(backendConfigs) == 0 {
return c.SendString("No models available")
}

summary := fiber.Map{
"Title": "LocalAI - Generate audio with " + backendConfigs[0].Name,
"ModelsConfig": backendConfigs,
"Model": backendConfigs[0].Name,
"Version": internal.PrintableVersion(),
}

// Render index
return c.Render("views/tts", summary)
})
}
64 changes: 64 additions & 0 deletions core/http/static/tts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
function submitKey(event) {
event.preventDefault();
localStorage.setItem("key", document.getElementById("apiKey").value);
document.getElementById("apiKey").blur();
}


function genAudio(event) {
event.preventDefault();
const input = document.getElementById("input").value;
const key = localStorage.getItem("key");

tts(key, input);
}

async function tts(key, input) {
document.getElementById("loader").style.display = "block";
document.getElementById("input").value = "";
document.getElementById("input").disabled = true;

const model = document.getElementById("tts-model").value;
const response = await fetch("/tts", {
method: "POST",
headers: {
Authorization: `Bearer ${key}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: model,
input: input,
}),
});
if (!response.ok) {
const jsonData = await response.json(); // Now safely parse JSON
var div = document.getElementById('result');
div.innerHTML = '<p style="color:red;">Error: ' +jsonData.error.message + '</p>';
return;
}

var div = document.getElementById('result'); // Get the div by its ID
var link=document.createElement('a');
link.className = "m-2 float-right inline-block rounded bg-primary px-6 pb-2.5 mb-3 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-primary-3 transition duration-150 ease-in-out hover:bg-primary-accent-300 hover:shadow-primary-2 focus:bg-primary-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-primary-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong";
link.innerHTML = "<i class='fa-solid fa-download'></i> Download result";
const blob = await response.blob();
link.href=window.URL.createObjectURL(blob);

div.innerHTML = ''; // Clear the existing content of the div
div.appendChild(link); // Add the new img element to the div
console.log(link)
document.getElementById("loader").style.display = "none";
document.getElementById("input").disabled = false;
document.getElementById("input").focus();
}

document.getElementById("key").addEventListener("submit", submitKey);
document.getElementById("input").focus();
document.getElementById("tts").addEventListener("submit", genAudio);
document.getElementById("loader").style.display = "none";

const storeKey = localStorage.getItem("key");
if (storeKey) {
document.getElementById("apiKey").value = storeKey;
}

4 changes: 3 additions & 1 deletion core/http/views/chat.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@

<div class="flex items-center justify-between">

<h1 class="text-lg font-semibold">Chat with {{.Model}}</h1>
<h1 class="text-lg font-semibold"> <i class="fa-solid fa-comments"></i> Chat with {{.Model}} <a href="https://localai.io/features/text-generation/" target="_blank" >
<i class="fas fa-circle-info pr-2"></i>
</a></h1>
<div x-show="component === 'menu'" id="menu">
<button
@click="$store.chat.clear()"
Expand Down
1 change: 1 addition & 0 deletions core/http/views/partials/navbar.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<a href="/browse/" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fas fa-brain pr-2"></i> Models</a>
<a href="/chat/" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fa-solid fa-comments pr-2"></i> Chat</a>
<a href="/text2image/" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fas fa-image pr-2"></i> Generate images</a>
<a href="/tts/" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fa-solid fa-music pr-2"></i> TTS </a>
<a href="/swagger/" class="text-gray-400 hover:text-white px-3 py-2 rounded"><i class="fas fa-code pr-2"></i> API</a>
</div>
</div>
Expand Down
11 changes: 11 additions & 0 deletions core/http/views/text2image.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,19 @@

{{template "views/partials/navbar" .}}
<div class="container mx-auto px-4 flex-grow " x-data="{ component: 'menu' }">


<div class="mt-12">
<div class="flex items-center justify-center text-center pb-2">
<span class="text-3xl font-semibold text-gray-100">
🖼️ Text to Image
<a href="https://localai.io/models/" target="_blank" >
<i class="fas fa-circle-info pr-2"></i>
</a>
</span>

</div>

<div class="text-center font-semibold text-gray-100">
<div class="flex items-center justify-between">

Expand Down
86 changes: 86 additions & 0 deletions core/http/views/tts.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<!DOCTYPE html>
<html lang="en">
{{template "views/partials/head" .}}
<script defer src="/static/tts.js"></script>

<body class="bg-gray-900 text-gray-200">
<div class="flex flex-col min-h-screen">

{{template "views/partials/navbar" .}}
<div class="container mx-auto px-4 flex-grow " x-data="{ component: 'menu' }">
<div class="mt-12">
<div class="flex items-center justify-center text-center pb-2">
<span class="text-3xl font-semibold text-gray-100">
<i class="fa-solid fa-music"></i> Text to speech/audio
<a href="https://localai.io/features/text-to-audio/" target="_blank" >
<i class="fas fa-circle-info pr-2"></i>
</a>
</span>

</div>
<div class="text-center font-semibold text-gray-100">
<div class="flex items-center justify-between">

<div x-show="component === 'menu'" id="menu">
<button @click="component = 'key'" title="Update API key"
class="m-2 float-right inline-block rounded bg-primary px-6 pb-2.5 mb-3 pt-2.5 text-xs font-medium uppercase leading-normal text-white shadow-primary-3 transition duration-150 ease-in-out hover:bg-primary-accent-300 hover:shadow-primary-2 focus:bg-primary-accent-300 focus:shadow-primary-2 focus:outline-none focus:ring-0 active:bg-primary-600 active:shadow-primary-2 dark:shadow-black/30 dark:hover:shadow-dark-strong dark:focus:shadow-dark-strong dark:active:shadow-dark-strong"
>Set API Key🔑</button>
</div>
<form x-show="component === 'key'" id="key">
<input
type="password"
id="apiKey"
name="apiKey"
placeholder="OpenAI API Key"
x-model.lazy="key"
/>
<button @click="component = 'menu'" type="submit" title="Save API key">
🔒
</button>
</form>

<select x-data="{ link : '' }" x-model="link" x-init="$watch('link', value => window.location = link)"
class="bg-gray-800 text-white border border-gray-600 focus:border-blue-500 focus:ring focus:ring-blue-500 focus:ring-opacity-50 rounded-md shadow-sm p-2 appearance-none"
>
<!-- Options -->
<option value="" disabled class="text-gray-400" >Select a model</option>
{{ $model:=.Model}}
{{ range .ModelsConfig }}
{{ if eq .Name $model }}
<option value="/tts/{{.Name}}" selected class="bg-gray-700 text-white">{{.Name}}</option>
{{ else }}
<option value="/tts/{{.Name}}" class="bg-gray-700 text-white">{{.Name}}</option>
{{ end }}
{{ end }}
</select>

</div>
</div>

<div class="mt-12">
<input id="tts-model" type="hidden" value="{{.Model}}">
<form id="tts" action="/tts/{{.Model}}" method="get">
<input
type="text"
id="input"
name="input"
placeholder="Prompt…"
autocomplete="off"
class="p-2 border rounded w-full bg-gray-600 text-white placeholder-gray-300"
required
/>
</form>
<div class="container max-w-screen-lg mx-auto mt-4 pb-10 flex justify-center">
<div id="loader" class="my-2 loader" ></div>
</div>
<div class="container max-w-screen-lg mx-auto mt-4 pb-10 flex justify-center">
<div id="result" class="mx-auto"></div>
</div>
</div>
</div>
</div>

{{template "views/partials/footer" .}}
</div>
</body>
</html>

0 comments on commit 181d2a9

Please sign in to comment.