Add service orchestration and web UI

This commit is contained in:
dwrz
2026-02-13 15:03:02 +00:00
parent 6f0509ff18
commit d5a27c776e
17 changed files with 3890 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
{{ define "body" }}
<body>
{{ template "main" . }}
{{ template "templates" . }}
</body>
{{ end }}

View File

@@ -0,0 +1,41 @@
{{ define "footer/compose" }}
<div class="compose">
<textarea
class="compose__textarea"
id="text-input"
placeholder="Type a message..."
aria-label="Message input"
rows="1"
></textarea>
<div class="compose__attachments" id="attachments"></div>
<div class="compose__actions">
<button
type="button"
class="compose__action-btn"
id="attach"
aria-label="Attach files"
>
<svg class="icon"><use href="/static/icons.svg#attach"></use></svg>
</button>
<input type="file" id="file-input" multiple hidden />
<div class="compose__actions-right">
<button
type="button"
class="compose__action-btn compose__action-btn--record"
id="ptt"
aria-label="Push to talk"
>
<svg class="icon"><use href="/static/icons.svg#mic"></use></svg>
</button>
<button
type="button"
class="compose__action-btn compose__action-btn--send"
id="send"
aria-label="Send message"
>
<svg class="icon"><use href="/static/icons.svg#send"></use></svg>
</button>
</div>
</div>
</div>
{{ end }}

View File

@@ -0,0 +1,6 @@
{{ define "footer" }}
<footer class="footer">
{{ template "footer/compose" . }}
{{ template "footer/toolbar" . }}
</footer>
{{ end }}

View File

@@ -0,0 +1,31 @@
{{ define "footer/toolbar" }}
<div class="footer__toolbar">
<button
type="button"
class="footer__toolbar-btn"
id="reset"
aria-label="Reset conversation"
>
<svg class="icon"><use href="/static/icons.svg#reset"></use></svg>
</button>
<div class="footer__toolbar-spacer"></div>
<select id="model" class="footer__select" aria-label="Model">
<option value="" disabled selected>
Loading...
</option>
</select>
<select id="voice" class="footer__select" aria-label="Voice">
<option value="" disabled selected>
Loading...
</option>
</select>
<button
type="button"
class="footer__toolbar-btn"
id="mute"
aria-label="Mute"
>
<svg class="icon"><use href="/static/icons.svg#volume"></use></svg>
</button>
</div>
{{ end }}

View File

@@ -0,0 +1,11 @@
{{ define "head" }}
<head>
<meta name="author" content="Chimerical LLC">
<meta charset="utf-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0, shrink-to-fit= no, interactive-widget=resizes-content">
<title>Odidere</title>
<link rel="stylesheet" href="/static/main.css">
<script defer src="/static/main.js"></script>
</head>
{{ end }}

View File

@@ -0,0 +1,5 @@
<!doctype html>
<html lang="en">
{{ template "head" . }}
{{ template "body" . }}
</html>

View File

@@ -0,0 +1,7 @@
{{ define "main" }}
<main class="container">
<section class="chat" id="chat" aria-live="polite">
</section>
{{ template "footer" . }}
</main>
{{ end }}

View File

@@ -0,0 +1,126 @@
{{ define "templates" }}
<template id="tpl-user-message">
<div class="message message--user">
<div class="message__icon" aria-hidden="true">
<svg class="icon"><use href="/static/icons.svg#user"></use></svg>
</div>
<div class="message__body">
<div class="message__content"></div>
<div class="message__actions">
<button
type="button"
class="message__action-btn"
data-action="inspect"
aria-label="Show details"
aria-expanded="false"
>
<svg class="icon"><use href="/static/icons.svg#inspect"></use></svg>
</button>
<button
type="button"
class="message__action-btn"
data-action="copy"
aria-label="Copy to clipboard"
>
<svg class="icon"><use href="/static/icons.svg#copy"></use></svg>
</button>
</div>
<div class="message__debug">
<dl class="message__debug-list"></dl>
</div>
</div>
</div>
</template>
<template id="tpl-assistant-message">
<div class="message message--assistant">
<div class="message__icon" aria-hidden="true">
<svg class="icon"><use href="/static/icons.svg#assistant"></use></svg>
</div>
<div class="message__body">
<div class="message__content"></div>
<div class="message__actions">
<button
type="button"
class="message__action-btn"
data-action="inspect"
aria-label="Show details"
aria-expanded="false"
>
<svg class="icon"><use href="/static/icons.svg#inspect"></use></svg>
</button>
<button
type="button"
class="message__action-btn"
data-action="copy"
aria-label="Copy to clipboard"
>
<svg class="icon"><use href="/static/icons.svg#copy"></use></svg>
</button>
</div>
<div class="message__debug">
<dl class="message__debug-list"></dl>
</div>
</div>
</div>
</template>
<template id="tpl-error-message">
<div class="message message--error message--assistant">
<div class="message__icon" aria-hidden="true">
<svg class="icon"><use href="/static/icons.svg#assistant"></use></svg>
</div>
<div class="message__body">
<div class="message__content"></div>
</div>
</div>
</template>
<template id="tpl-collapsible">
<details class="collapsible">
<summary class="collapsible__summary">
<span class="collapsible__label"></span>
</summary>
<div class="collapsible__content">
<pre></pre>
</div>
</details>
</template>
<template id="tpl-tool-call">
<details class="collapsible collapsible--tool">
<summary class="collapsible__summary">
<svg class="icon"><use href="/static/icons.svg#tool"></use></svg>
<span class="collapsible__label"></span>
</summary>
<div class="collapsible__content">
<div class="collapsible__section">
<div class="collapsible__section-label">Arguments</div>
<pre class="collapsible__pre" data-args></pre>
</div>
<div class="collapsible__section collapsible__section--output" hidden>
<div class="collapsible__section-label">Output</div>
<pre class="collapsible__pre" data-output></pre>
</div>
</div>
</details>
</template>
<template id="tpl-attachment-chip">
<div class="compose__attachment">
<span class="compose__attachment-name"></span>
<button
type="button"
class="compose__attachment-remove"
aria-label="Remove attachment"
>
<svg class="icon"><use href="/static/icons.svg#x-circle"></use></svg>
</button>
</div>
</template>
<template id="tpl-debug-row">
<dt></dt>
<dd></dd>
</template>
{{ end }}