LocalAI/core/http/views/talk.html

124 lines
6.7 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="en">
{{template "views/partials/head" .}}
feat(ui): path prefix support via HTTP header (#4497) Makes the web app honour the `X-Forwarded-Prefix` HTTP request header that may be sent by a reverse-proxy in order to inform the app that its public routes contain a path prefix. For instance this allows to serve the webapp via a reverse-proxy/ingress controller under a path prefix/sub path such as e.g. `/localai/` while still being able to use the regular LocalAI routes/paths without prefix when directly connecting to the LocalAI server. Changes: * Add new `StripPathPrefix` middleware to strip the path prefix (provided with the `X-Forwarded-Prefix` HTTP request header) from the request path prior to matching the HTTP route. * Add a `BaseURL` utility function to build the base URL, honouring the `X-Forwarded-Prefix` HTTP request header. * Generate the derived base URL into the HTML (`head.html` template) as `<base/>` tag. * Make all webapp-internal URLs (within HTML+JS) relative in order to make the browser resolve them against the `<base/>` URL specified within each HTML page's header. * Make font URLs within the CSS files relative to the CSS file. * Generate redirect location URLs using the new `BaseURL` function. * Use the new `BaseURL` function to generate absolute URLs within gallery JSON responses. Closes #3095 TL;DR: The header-based approach allows to move the path prefix configuration concern completely to the reverse-proxy/ingress as opposed to having to align the path prefix configuration between LocalAI, the reverse-proxy and potentially other internal LocalAI clients. The gofiber swagger handler already supports path prefixes this way, see https://github.com/gofiber/swagger/blob/e2d9e9916d8809e8b23c4365f8acfbbd8a71c4cd/swagger.go#L79 Signed-off-by: Max Goltzsche <max.goltzsche@gmail.com>
2025-01-07 16:18:21 +00:00
<script defer src="static/talk.js"></script>
<body class="bg-gradient-to-br from-gray-900 to-gray-950 text-gray-200" x-data="{ key: $store.chat.key }">
<div class="flex flex-col min-h-screen">
{{template "views/partials/navbar" .}}
<div class="container mx-auto px-4 py-8 flex-grow">
<!-- Hero Section -->
<div class="bg-gradient-to-r from-blue-900/30 to-indigo-900/30 rounded-2xl shadow-xl p-8 mb-10">
<div class="max-w-4xl mx-auto text-center">
<h1 class="text-4xl md:text-5xl font-bold text-white mb-4">
<span class="bg-clip-text text-transparent bg-gradient-to-r from-blue-400 to-indigo-400">
<i class="fas fa-comments mr-2"></i>Talk Interface
</span>
</h1>
<p class="text-xl text-gray-300 mb-6">Speak with your AI models using voice interaction</p>
</div>
</div>
<!-- Talk Interface -->
<div class="max-w-3xl mx-auto">
<div class="bg-gray-800/90 border border-gray-700/50 rounded-xl overflow-hidden transition-all duration-300 shadow-lg shadow-blue-900/20">
<!-- Talk Interface Body -->
<div class="p-6">
<!-- Recording Status -->
<div id="recording" class="bg-red-900/20 border border-red-700/50 rounded-lg p-4 mb-4 flex items-center space-x-3" style="display: none;">
<i class="fa-solid fa-microphone text-2xl text-red-400 animate-pulse"></i>
<span class="text-red-200 font-medium">Recording... press "Stop recording" to stop</span>
</div>
<!-- Loader -->
<div id="loader" class="my-4 flex justify-center" style="display: none;">
<div class="animate-spin rounded-full h-10 w-10 border-t-2 border-b-2 border-blue-500"></div>
</div>
<!-- Status Text -->
<div id="statustext" class="my-4 p-3 bg-gray-700/50 border border-gray-600/50 rounded-lg text-gray-200" style="min-height: 3rem;">Press the record button to start recording.</div>
<!-- Note -->
<div class="bg-blue-900/20 border border-blue-700/50 rounded-lg p-4 mb-6">
<div class="flex items-start">
<i class="fas fa-info-circle text-blue-400 mt-1 mr-3 flex-shrink-0"></i>
<p class="text-gray-300">
<strong class="text-blue-300">Note:</strong> You need an LLM, an audio-transcription (whisper), and a TTS model installed for this to work. Select the appropriate models below and click 'Talk' to start recording. The recording will continue until you click 'Stop recording'. Make sure your microphone is set up and enabled.
</p>
</div>
</div>
<!-- Model Selectors -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-6">
<!-- LLM Model -->
<div class="space-y-2">
<label for="modelSelect" class="flex items-center text-gray-200 font-medium">
<i class="fas fa-brain text-blue-400 mr-2"></i>LLM Model
</label>
<select id="modelSelect"
class="w-full bg-gray-800 text-white border border-gray-700 focus:border-blue-500 focus:ring focus:ring-blue-500 focus:ring-opacity-30 rounded-lg shadow-sm p-2.5 appearance-none">
<option value="" disabled class="text-gray-400">Select a model</option>
{{ range .ModelsConfig }}
<option value="{{.}}" class="bg-gray-700 text-white">{{.}}</option>
{{ end }}
</select>
</div>
<!-- Whisper Model -->
<div class="space-y-2">
<label for="whisperModelSelect" class="flex items-center text-gray-200 font-medium">
<i class="fas fa-ear-listen text-purple-400 mr-2"></i>Whisper Model
</label>
<select id="whisperModelSelect"
class="w-full bg-gray-800 text-white border border-gray-700 focus:border-blue-500 focus:ring focus:ring-blue-500 focus:ring-opacity-30 rounded-lg shadow-sm p-2.5 appearance-none">
<option value="" disabled class="text-gray-400">Select a model</option>
{{ range .ModelsConfig }}
<option value="{{.}}" class="bg-gray-700 text-white">{{.}}</option>
{{ end }}
</select>
</div>
<!-- TTS Model -->
<div class="space-y-2">
<label for="ttsModelSelect" class="flex items-center text-gray-200 font-medium">
<i class="fas fa-volume-high text-green-400 mr-2"></i>TTS Model
</label>
<select id="ttsModelSelect"
class="w-full bg-gray-800 text-white border border-gray-700 focus:border-blue-500 focus:ring focus:ring-blue-500 focus:ring-opacity-30 rounded-lg shadow-sm p-2.5 appearance-none">
<option value="" disabled class="text-gray-400">Select a model</option>
{{ range .ModelsConfig }}
<option value="{{.}}" class="bg-gray-700 text-white">{{.}}</option>
{{ end }}
</select>
</div>
</div>
<!-- Buttons -->
<div class="flex items-center justify-between mt-8">
<button id="recordButton"
class="group flex items-center bg-red-600 hover:bg-red-700 text-white py-2 px-6 rounded-lg transition duration-300 ease-in-out transform hover:scale-105 hover:shadow-lg">
<i class="fas fa-microphone mr-2"></i>
<span>Talk</span>
<i class="fas fa-arrow-right opacity-0 group-hover:opacity-100 group-hover:translate-x-2 ml-2 transition-all duration-300"></i>
</button>
<a id="resetButton"
class="flex items-center text-blue-400 hover:text-blue-300 transition duration-200"
href="#">
<i class="fas fa-rotate-right mr-2"></i>
<span>Reset conversation</span>
</a>
</div>
<!-- Audio Playback -->
<audio id="audioPlayback" controls hidden></audio>
</div>
</div>
</div>
</div>
{{template "views/partials/footer" .}}
</div>
</body>
</html>