Skip to content

FloLey/Prism

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Prisme

Prisme generates synthetic personas with a large language model and lets you probe how they react to things. You describe a population, Prisme creates rich, individual personas (demographics, life story, opinions, fears, aspirations, and a 9-axis personality/ideology profile), groups them, and lets you run "stimuli" past them to see how different slices of a synthetic public might respond. It supports personas from France, the USA, and Belgium.

It is a full-stack app: a FastAPI + PostgreSQL backend that orchestrates the generation pipeline and talks to Google's Gemini API, and a React frontend that visualizes personas and their axes as radar charts.

Status: a personal project, actively built. The product was previously named "Hibiki"; any leftover reference to that name is a rename in progress.

Core concepts

  • Persona - one synthetic individual with a structured portrait: name, age, gender, location, occupation, family situation, religion, life story, opinions, media consumption, hobbies, fears, aspirations, and more. Each persona is scored on 9 axes: age, education, ses, openness, agreeableness, economic, societal, institution, ambiguity_tolerance.
  • Bubble - a population definition: the filters and intent that describe the kind of people to generate.
  • Cluster - a grouping of bubbles.
  • Job - one generation run. Jobs are checkpointed stage by stage, so a backend restart resumes where it left off.
  • Stimulus - something you want the personas to evaluate (the thing a survey shows them).
  • Country - every persona belongs to one of France, USA, Belgium, which drives its context and the language of its generated content.

How persona generation works

Generation is a text-first, batched pipeline (one batched LLM call per persona per stage; concurrent jobs hitting the same model share a batch):

  1. sketch - Verbalized Sampling: the model returns several candidate sketches with self-assessed probabilities, and one is drawn by weighted-random sampling (this is what gives the population diversity).
  2. enrich - flesh the chosen sketch into a richer narrative.
  3. structure - emit the final structured persona portrait.
  4. naming - a classifier picks name attributes, then a sampler draws an actual first and last name.

Every LLM call uses a strict response schema so the output parses reliably.

Tech stack

Layer Stack
Backend Python 3.12, FastAPI, SQLAlchemy + Alembic, async batched LLM pipeline
Database PostgreSQL 16 (pgvector extension, for persona similarity)
LLM Google Gemini (Generative Language API), structured output
Frontend React 19, Vite, TanStack Query, Recharts (radar charts)
Dev/infra Docker Compose, GitHub Actions CI

Quick start

You need Docker and Docker Compose.

# 1. configure the local environment
cp .env.example .env
# edit .env: choose a local POSTGRES_PASSWORD; optionally set GEMINI_API_KEY
#            (you can also set the key later from the in-app Settings page)

# 2. build and start the stack
docker compose up --build

Then open:

Day to day, docker compose up is enough. The frontend source is bind-mounted, so editing .tsx/.css hot-reloads with no rebuild. Rebuild the backend after any backend change (docker compose up -d --build backend): it has no bind mount, its code is copied into the image at build time. The database schema is managed by Alembic and migrated automatically on backend startup.

To stop: docker compose down (add --volumes to also drop the Postgres data).

Configuration

Read from .env (see .env.example):

Variable Default Purpose
POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DB - local database credentials
GEMINI_API_KEY empty Gemini key; if blank, set it from the in-app Settings page
MODEL_NAME gemini-3-flash-preview the Gemini model used for generation
GEMINI_MAX_CONCURRENCY 10 max concurrent in-flight LLM requests

.env is gitignored and never committed.

Running tests

# backend (pytest, against the prisme_test database)
docker compose run --rm -v "$PWD/backend/tests:/app/tests:ro" backend pytest

# frontend (vitest)
docker compose exec frontend ./node_modules/.bin/vitest run

The backend test suite guards itself against running on any database whose name does not end in _test (the tests truncate tables).

Lint and type-check

The backend image ships production deps only, so lint and type-check run on the host in a virtualenv:

cd backend
python3 -m venv .venv                                          # one time
.venv/bin/pip install -r requirements.txt -r requirements-dev.txt

.venv/bin/ruff check .          # lint
.venv/bin/ruff format --check . # formatter (drop --check to apply)
.venv/bin/mypy app              # type-check (every function in app/ is annotated)

Frontend: docker compose exec frontend npm run typecheck and npm run lint.

CI (GitHub Actions, .github/workflows/ci.yml) runs the Alembic migration round-trip, ruff, mypy, and pytest for the backend, plus typecheck, lint, and vitest for the frontend, on every push and pull request.

Project layout

Prisme/
  compose.yml            # dev stack: db (Postgres+pgvector), backend, frontend
  backend/               # FastAPI app
    app/
      api/               # routes: bubbles, clusters, personas, stimuli, jobs, ...
      services/          # generation pipeline, Gemini client, batching
      persona_schema.py  # source of truth for persona enums
      llm_schemas.py     # Gemini-safe response schemas
    migrations/          # Alembic schema migrations
    tests/
  frontend/              # React + Vite app (radar visualizations, persona UI)
  db-init/               # creates the prisme_test database on first boot
  specs/                 # design specs (some early ones are French archives)
  CLAUDE.md              # coding conventions and the full commands reference

Documentation

  • CLAUDE.md is the source of truth for coding conventions: the English-only rule, naming conventions, the generation pipeline, multi-country support, and the complete ports/commands/Alembic reference. Read it before contributing.
  • specs/ holds the design specs. prisme_phase1_spec.md and prisme_phase2_spec.md are kept as historical French archives; the others are the current English specs.

About

Synthetic persona generation and opinion simulation, powered by Gemini (FastAPI + PostgreSQL + React)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors