05. HTML Frontend Basics
Create app/templates/index.html. This is a single-file frontend—no build step, no framework:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Local Chatbot</title>
<style>
body { font-family: system-ui; max-width: 720px; margin: 2rem auto; padding: 0 1rem; }
#chat { border: 1px solid #ccc; height: 400px; overflow-y: auto; padding: 1rem; }
.msg { margin: 0.5rem 0; }
.user { color: #0066cc; }
.assistant { color: #333; }
</style>
</head>
<body>
<h1>Chatbot</h1>
<div id="chat"></div>
<form id="form">
<textarea id="input" rows="3" style="width:100%;"></textarea>
<button type="submit">Send</button>
</form>
<script>
// JS goes here
</script>
</body>
</html>
Wire it into FastAPI. Update app/main.py:
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
app = FastAPI()
@app.get("/", response_class=HTMLResponse)
async def root():
with open("app/templates/index.html") as f:
return f.read()
If the file path is wrong, FastAPI returns a 500 with FileNotFoundError. Use an absolute path or mount the templates directory. For now, use a relative path from the project root.
Local verification checkpoint
Run the smallest example from this chapter in a local workspace and record the package version, runtime, data path, and observed output. If the result depends on model size, vector count, CPU/GPU backend, or available memory, note that constraint beside the exercise so the lesson remains reproducible.
Local verification checkpoint
Run the smallest example from this chapter in a local workspace and record the package version, runtime, data path, and observed output. If the result depends on model size, vector count, CPU/GPU backend, or available memory, note that constraint beside the exercise so the lesson remains reproducible.
Add a model selector <select id="model"> to the HTML and populate it via a fetch("/models") call on page load.