Ein Anderssono 95d308b326
Build and publish frontend / publish (push) Successful in 1m10s
Serve Piper voice credits as readable text
2026-10-16 07:10:55 +02:00
2026-10-16 07:08:39 +02:00
2026-10-14 07:41:39 +00:00
2026-10-16 07:08:39 +02:00

AI-spel frontend

This repository contains the static Swedish web client for the AI-driven life simulator. The intended deployment is a small Nginx pod in the ai-spel namespace. The existing Rust service remains authoritative for accounts, game state, and all /api/... routes.

After login, character creation and play use one dialogue history and one text input. The player writes a free biography, receives a temporary AI draft, can request revisions, and approves it by writing godkänn. The player then receives a proposed start world and place based on the biography. That draft can also be revised in dialogue and is saved only after a second explicit godkänn. Drafts stay in the browser until approval and are lost if the page is reloaded first. The backend creates the character and initializes the world only after their respective approvals.

During play the UI has no persistent location, task, inventory, economy, status, or purchase panels. The player asks for information or writes an action in the same input. Rust validates state changes; the AI can only propose a typed intent. A direct request to travel may establish a new place and an encounter when Rust commits that movement.

If the player asks to find or approach someone and no NPC is present, the direct dialogue scene may propose one person and an opening line. Rust creates that NPC only for the explicit request and commits the first exchange idempotently; a later turn continues the saved conversation. Clear requests about the current location are answered from its saved facts without asking the player to restate what they want to inspect.

The separate /admin route provides an authenticated operations view for player search/profile/trace, YAML prompt assets, generated Luau rules with validation results, runtime debug logging, and the append-only audit log. All privileged data comes from the Rust /api/admin/... API; the browser never connects directly to PostgreSQL. Backend endpoints require accounts.is_admin=true. The Driftloggar view lets an administrator switch debug=true on or off without restarting pods; the setting is stored in PostgreSQL and propagated to running replicas. Verbose pod logs include request, AI-call, validation, and commit metadata but never raw player text, prompts, model responses, sessions, or secrets. Full protected prompt/provider exchanges remain in the audited player trace.

The game is text- and dialogue-based and uses no images. Place descriptions include sound, smell, air/temperature, touch/surface, and spatial-orientation cues. Visible details may also be described in words, but are never required to understand the scene or play. The transcript is screen-reader announced, and Enter submits the input while Shift+Enter inserts a newline; no separate send button is required.

Player-facing speech uses Piper TTS in WebAssembly in the browser after audio is activated by a user gesture. It reads game dialogue, onboarding, account responses, character and world creation, gameplay replies, in-game errors, and microphone disclosures; the /admin route is excluded. The audio is decoded and played through the Web Audio API, independently of speechSynthesis. The first unauthenticated visit keeps the introduction visible and it can be started with Läs introduktionen. New game replies are read automatically and the transcript remains available to screen readers and as text. Returning players hear the latest saved game reply when they reopen the game. The player can change speaking rate; narrator pitch is neutral and character pitch is varied consistently by voice identity. These preferences are stored in browser localStorage. If WebAssembly, model loading, or audio playback fails, the same content remains available as text and the dialogue offers a retry.

The Piper engine, WebAssembly runtime, and all three Swedish medium voice models (Alma, Lisa, and NST) are served from this frontend's same-origin /tts/piper-wasm-v1/ path. The Gitea pipeline downloads the pinned model files, verifies their sizes and cryptographic hashes, and packages them into the versioned frontend image. The browser's Piper adapter redirects the library's built-in model URLs to this same-origin server; it does not request voice files from Hugging Face. A voice model is fetched on first use and cached in browser storage when supported. The game currently uses the NST model. Dialogue text is synthesized on the device and is not sent to a TTS provider. Voice model attribution and license references are available in the voice settings and at /tts/piper-wasm-v1/voices/ATTRIBUTION.txt.

The microphone button beside the text field uses Web Speech API when available and sends only its final Swedish transcript through the same submission path as typed text. Before its first use, the client explains that the browser may process audio through a provider-selected service; the game itself does not receive or store recordings, while the final transcript is saved as ordinary dialogue. Writing röstinställningar or saying röstkommando alternativ opens temporary voice controls in the dialogue. The player can adjust speaking rate and enable or disable short audio cues. Voice preferences are stored in browser localStorage.

When a character or NPC is created, its saved voice identity is masculine, feminine, or neutral. The biography prompt only assigns masculine/feminine when the character is explicitly described that way; otherwise it uses neutral. Piper applies a stable, subtle pitch/rate profile per character, so a character keeps the same sound across visits. Narration always uses neutral pitch.

System voice commands require the prefix röstkommando: upprepa, avbryt, hjälp, alternativ, or paus. Without the prefix, the same words remain ordinary dialogue. Speech recognition and synthesis are browser-dependent; release acceptance must record which real iPhone/Safari/VoiceOver and Android/Chrome/TalkBack combinations were actually checked.

On iPhone and iPad, Safari requires a user gesture to unlock Web Audio. The frontend resumes the audio context during a trusted tap or key press and then reads generated replies automatically. Voice settings include Testa ljudet; if a game reply does not start, a Läs senaste repliken button appears in the dialogue. First use can take longer while the voice model downloads; progress and errors are announced in the dialogue. Actual iPhone/iPad playback remains a release acceptance check and must not be claimed until tested on a device.

The browser and API stay on the same public origin, https://ai-spel.k3s.k0.nu. The ingress routes / to this frontend service and routes /api, /version, and /health to the Rust service. That keeps the current server-side session cookie same-origin and avoids browser CORS configuration.

Release flow

VERSION is the only version source for this repository. Gitea Actions on the existing large runner runs the static checks, Helm lint/template, publishes a commit image, bumps the patch version through scripts/bump-version.py, creates the matching release commit and Git tag, and publishes the release image, Helm chart, and rendered frontend manifest to Harbor. Argo CD tracks the newest published frontend chart. The image and chart releases use the same version as the commit and tag.

CI needs repository Action secrets named HARBOR_USERNAME and HARBOR_PASSWORD. The Harbor pull secret harbor-pull is already present in the Kubernetes namespace. Argo CD uses the existing ai-spel project and Harbor OCI credentials.

The first Argo Application is described in deploy/argocd/application.yaml. The backend ingress routes /api, /version, and health checks to Rust while serving the static client at /. Both services share the same origin so the session cookie remains same-origin.

Builds, checks, and runtime verification happen in the pipeline and Kubernetes. Do not run the app, tests, container images, or binaries locally.

S
Description
Statisk webbfrontend för den AI-drivna svenska livssimulatorn
Readme MIT
1.1 MiB
Languages
HTML 62.9%
JavaScript 31.6%
Shell 4.2%
Python 1.1%
Dockerfile 0.2%