feat: spirit engine — seance WS, entity minting/Codex, Piper TTS voices, wire telemetry

- WS /ws/session: modes, summon, anomaly fragments, streaming direct contact,
  passive wire-ghost ambient loop, per-user rate limits, event transcript
- entities: anomaly-signature fingerprinting, LLM minting + procedural
  fallback, Codex matching with contact counts and sightings
- tts: 8 local Piper voices (EN/ES), per-entity voice profiles, numpy
  effects chain (pitch/rate/bitcrush/echo/static)
- llm: streaming client, submit_stream in bounded queue, SpiritService
  with offline fallbacks for every channel
- routes: public /api/codex, /api/codex/{id}, /api/stats; /audio static mount
- models: Entity, EntitySighting, Event, ContactSession(entity_id, language)
This commit is contained in:
Indiana
2026-07-20 20:13:28 +00:00
parent 52afad1ad5
commit b9110f45de
28 changed files with 1997 additions and 4 deletions

View File

@@ -0,0 +1,83 @@
import uuid
import pytest
from sqlalchemy import select
from app.models.entity import Entity
def _make_entity(name="Vesper Wren", rarity="rare", signature="abc123def4567890"):
return Entity(
name=name,
epithet="the Static Widow",
persona="A voice worn smooth as sea glass.",
rarity_tier=rarity,
signature=signature,
voice_profile={"voice_id": "lessac", "pitch": -2, "rate": 0.95, "noise": 0.04},
visual_profile={"hue": 265, "form": "wisp"},
sample_quotes=["I am closer than the dial suggests."],
contact_count=3,
)
@pytest.mark.asyncio
async def test_codex_lists_entities(client, db_session):
db_session.add(_make_entity())
db_session.add(_make_entity("Hollow Briar", "common", "0123456789abcdef"))
await db_session.commit()
response = await client.get("/api/codex")
assert response.status_code == 200
names = {entity["name"] for entity in response.json()["entities"]}
assert names == {"Vesper Wren", "Hollow Briar"}
@pytest.mark.asyncio
async def test_codex_filters_by_rarity(client, db_session):
db_session.add(_make_entity())
db_session.add(_make_entity("Hollow Briar", "common", "0123456789abcdef"))
await db_session.commit()
response = await client.get("/api/codex?rarity=rare")
assert response.status_code == 200
entities = response.json()["entities"]
assert len(entities) == 1
assert entities[0]["name"] == "Vesper Wren"
@pytest.mark.asyncio
async def test_codex_detail_and_404(client, db_session):
entity = _make_entity()
db_session.add(entity)
await db_session.commit()
await db_session.refresh(entity)
response = await client.get(f"/api/codex/{entity.id}")
assert response.status_code == 200
body = response.json()
assert body["name"] == "Vesper Wren"
assert body["persona"].startswith("A voice")
assert body["sightings"] == 0
missing = await client.get(f"/api/codex/{uuid.uuid4()}")
assert missing.status_code == 404
@pytest.mark.asyncio
async def test_stats_counts_veil_activity(client, db_session):
db_session.add(_make_entity())
await db_session.commit()
response = await client.get("/api/stats")
assert response.status_code == 200
body = response.json()
assert body["entities"] == 1
assert body["sessions"] == 0
assert body["utterances"] == 0
assert body["anomalies"] == 0
@pytest.mark.asyncio
async def test_codex_is_public_without_auth(client):
assert (await client.get("/api/codex")).status_code == 200
assert (await client.get("/api/stats")).status_code == 200