build api and frountend
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>EPUB Admin</title>
|
||||
<script src="https://unpkg.com/htmx.org@2.0.4"></script>
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<nav>
|
||||
<a href="/">Search</a>
|
||||
<a href="/books">Books</a>
|
||||
<a href="/admin">Admin</a>
|
||||
</nav>
|
||||
<h1>Admin</h1>
|
||||
<section id="admin-status"></section>
|
||||
<section class="actions">
|
||||
<form hx-post="/admin/scan" hx-target="#admin-status" hx-swap="innerHTML">
|
||||
<button type="submit">Scan</button>
|
||||
</form>
|
||||
<form hx-post="/admin/embed-missing" hx-target="#admin-status" hx-swap="innerHTML">
|
||||
<button type="submit">Embed</button>
|
||||
</form>
|
||||
<form hx-post="/admin/embed-all" hx-target="#admin-status" hx-swap="innerHTML">
|
||||
<button type="submit">Embed all</button>
|
||||
</form>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Embeddings</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Model</th>
|
||||
<th>Dimensions</th>
|
||||
<th>Embedded</th>
|
||||
<th>Missing</th>
|
||||
<th>Total chunks</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in stats %}
|
||||
<tr>
|
||||
<td>{{ item.model_name }}</td>
|
||||
<td>{{ item.dimension }}</td>
|
||||
<td>{{ item.embedded_chunks }}</td>
|
||||
<td>{{ item.missing_chunks }}</td>
|
||||
<td>{{ item.total_chunks }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,32 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% if source %}{{ source.title }}{% else %}Book not found{% endif %}</title>
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<nav>
|
||||
<a href="/">Search</a>
|
||||
<a href="/books">Books</a>
|
||||
<a href="/admin">Admin</a>
|
||||
</nav>
|
||||
{% if source %}
|
||||
<h1>{{ source.title }}</h1>
|
||||
<p class="meta">{{ source.author or "Unknown author" }}</p>
|
||||
<dl>
|
||||
<dt>File</dt>
|
||||
<dd>{{ source.file_path }}</dd>
|
||||
<dt>Chapters</dt>
|
||||
<dd>{{ chapter_count }}</dd>
|
||||
<dt>Chunks</dt>
|
||||
<dd>{{ chunk_count }}</dd>
|
||||
</dl>
|
||||
{% else %}
|
||||
<h1>Book not found</h1>
|
||||
{% endif %}
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>EPUB Books</title>
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<nav>
|
||||
<a href="/">Search</a>
|
||||
<a href="/books">Books</a>
|
||||
<a href="/admin">Admin</a>
|
||||
</nav>
|
||||
<h1>Books</h1>
|
||||
{% if sources %}
|
||||
<ol class="results">
|
||||
{% for source in sources %}
|
||||
<li>
|
||||
<h2><a href="/books/{{ source.id }}">{{ source.title }}</a></h2>
|
||||
<p class="meta">{{ source.author or "Unknown author" }}</p>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
{% else %}
|
||||
<p>No EPUBs indexed.</p>
|
||||
{% endif %}
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
<p class="status">{{ message }}</p>
|
||||
@@ -0,0 +1 @@
|
||||
<p class="error">{{ message }}</p>
|
||||
@@ -0,0 +1,74 @@
|
||||
<div class="rank-label">{{ response.rank_label }}</div>
|
||||
{% if response.timings %}
|
||||
<section class="runtime">
|
||||
<h2>Runtime</h2>
|
||||
<p class="meta">Total {{ "%.1f"|format(response.total_runtime_ms) }} ms</p>
|
||||
<ol class="timing-chart">
|
||||
{% set total = response.total_runtime_ms %}
|
||||
{% set ns = namespace(remaining=total) %}
|
||||
{% for step in response.timings %}
|
||||
{% set width = (step.duration_ms / total * 100) if total else 0 %}
|
||||
{% if step.counts_toward_total %}
|
||||
{% set ns.remaining = ns.remaining - step.duration_ms %}
|
||||
{% endif %}
|
||||
<li>
|
||||
<span class="timing-label">{{ step.name }}</span>
|
||||
<span class="timing-bar"><span style="width: {{ "%.2f"|format(width) }}%"></span></span>
|
||||
<span class="timing-value">{{ "%.1f"|format(step.duration_ms) }} ms</span>
|
||||
<span class="timing-remaining">{{ "%.1f"|format([ns.remaining, 0]|max) }} ms left</span>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
</section>
|
||||
{% endif %}
|
||||
<section class="answer">
|
||||
<h2>Answer</h2>
|
||||
<p>{{ answer }}</p>
|
||||
</section>
|
||||
{% if response.results %}
|
||||
<ol class="results">
|
||||
{% for result in response.results %}
|
||||
<li>
|
||||
<h2>{{ result.source_title }}</h2>
|
||||
<p class="meta">
|
||||
{% if result.source_author %}{{ result.source_author }}{% endif %}
|
||||
{% if result.chapter_title %} · {{ result.chapter_title }}{% endif %}
|
||||
{% if result.page_label %} · page {{ result.page_label }}{% endif %}
|
||||
</p>
|
||||
<p>{{ result.text }}</p>
|
||||
<dl class="scores">
|
||||
<div>
|
||||
<dt>final</dt>
|
||||
<dd>{{ "%.3f"|format(result.score) }}</dd>
|
||||
</div>
|
||||
{% if result.rerank_score is not none %}
|
||||
<div>
|
||||
<dt>rerank</dt>
|
||||
<dd>{{ "%.3f"|format(result.rerank_score) }}</dd>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if result.vector_score is not none %}
|
||||
<div>
|
||||
<dt>vector cosine</dt>
|
||||
<dd>{{ "%.3f"|format(result.vector_score) }}</dd>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if result.bm25_score is not none %}
|
||||
<div>
|
||||
<dt>BM25</dt>
|
||||
<dd>{{ "%.6f"|format(result.bm25_score) }}</dd>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if result.fused_score is not none %}
|
||||
<div>
|
||||
<dt>RRF</dt>
|
||||
<dd>{{ "%.3f"|format(result.fused_score) }}</dd>
|
||||
</div>
|
||||
{% endif %}
|
||||
</dl>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
{% else %}
|
||||
<p>No results.</p>
|
||||
{% endif %}
|
||||
@@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>EPUB Search</title>
|
||||
<script src="https://unpkg.com/htmx.org@2.0.4"></script>
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<nav>
|
||||
<a href="/">Search</a>
|
||||
<a href="/books">Books</a>
|
||||
<a href="/admin">Admin</a>
|
||||
</nav>
|
||||
<h1>EPUB Search</h1>
|
||||
<form hx-post="/search" hx-target="#results" hx-swap="innerHTML">
|
||||
<label for="query">Search</label>
|
||||
<textarea id="query" name="query" rows="4" required></textarea>
|
||||
<label class="check">
|
||||
<input type="checkbox" name="rerank" value="true" {% if config.rerank.enabled %}checked{% endif %}>
|
||||
Rerank
|
||||
</label>
|
||||
<button type="submit">Search</button>
|
||||
</form>
|
||||
<section id="results"></section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user