75 lines
3.8 KiB
HTML
75 lines
3.8 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}Voice Assistant — {{ settings.APP_NAME }}{% endblock %}
|
|
{% block content %}
|
|
<div class="page" style="max-width:560px">
|
|
<h1 class="greeting">Voice Assistant (Jervis)</h1>
|
|
<p class="muted">Type a command for the home assistant — it's sent to the local LLM agent, which acts (lights, shopping, weather, reminders…) and speaks the reply on the house speakers.</p>
|
|
<div class="admin-panel">
|
|
<div class="linkout-card stack">
|
|
{% if error %}<div class="form-error">{{ error }}</div>{% endif %}
|
|
<form method="post" action="/voice" onsubmit="onSend()">
|
|
<div class="form-field">
|
|
<label for="message">Command</label>
|
|
<textarea class="text-input" id="message" name="message" rows="2" required
|
|
placeholder="e.g. what time is it, what's the weather, turn on the lights, play some music, Donald tell me a joke…"
|
|
style="resize:vertical; min-height:2.9em">{{ command or '' }}</textarea>
|
|
</div>
|
|
<div style="display:flex;gap:8px">
|
|
<button class="button button-primary" style="flex:1" type="submit" id="sendBtn">Send</button>
|
|
<button class="button button-utility" type="button" id="clearMsg">Clear</button>
|
|
</div>
|
|
</form>
|
|
<div id="waiting" class="waiting">
|
|
<span class="spinner"></span> Working — asking Jervis…
|
|
</div>
|
|
<style>
|
|
.waiting { display: none; align-items: center; gap: 8px; margin-top: 14px; color: #555; font: var(--type-body-sm); }
|
|
.spinner { width: 16px; height: 16px; border: 2px solid #d7d7d7; border-top-color: var(--primary, #0075de); border-radius: 50%; animation: spin .7s linear infinite; flex: none; }
|
|
@keyframes spin { to { transform: rotate(360deg); } }
|
|
</style>
|
|
<script>
|
|
function onSend() {
|
|
var b = document.getElementById('sendBtn');
|
|
if (b) { b.disabled = true; b.textContent = 'Sending…'; }
|
|
var w = document.getElementById('waiting');
|
|
if (w) { w.style.display = 'flex'; }
|
|
}
|
|
var clearMsg = document.getElementById('clearMsg');
|
|
if (clearMsg) clearMsg.addEventListener('click', function () {
|
|
var m = document.getElementById('message');
|
|
if (m) m.value = '';
|
|
m && m.focus();
|
|
});
|
|
</script>
|
|
{% if reply %}
|
|
<div class="linkout-card stack" style="margin-top:16px">
|
|
<strong>Jervis:</strong>
|
|
<p style="margin:8px 0 0">{{ reply }}</p>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="linkout-card stack" style="margin-top:16px">
|
|
<strong>Things Jervis can do:</strong>
|
|
<ul style="margin:8px 0 0 18px; padding:0; line-height:1.8">
|
|
<li>answer a question (general knowledge)</li>
|
|
<li>search the web for current info (news, prices, events)</li>
|
|
<li>tell the time / today's date</li>
|
|
<li>give the weather</li>
|
|
<li>add items to the shopping list</li>
|
|
<li>turn lights/switches on or off, run scenes/scripts (Home Assistant)</li>
|
|
<li>play a song, album or artist (Spotify, via Mopidy)</li>
|
|
<li>pause, resume, stop, skip, and change volume on the music</li>
|
|
<li>set a timer — speaks when it finishes</li>
|
|
<li>set a reminder — speaks at the time</li>
|
|
<li>speak in a different voice (HAL 9000, Donald Trump, Picard, Eminem, GLaDOS, Ryan, BT-7274)</li>
|
|
<li>feed the fish</li>
|
|
<li>send a message to Sam/Finn/Harry/Joanna or the whole family (WhatsApp, email, Telegram, ntfy)</li>
|
|
</ul>
|
|
</div>
|
|
<p class="faint margin-top" style="font: var(--type-caption)">
|
|
Uses the local voice agent on `.13` (OmniRoute LLM). Replies are also spoken via Snapcast.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %} |