{"id":24534407,"url":"https://github.com/chris-cozy/syntheticsoulapi","last_synced_at":"2026-05-20T06:08:27.908Z","repository":{"id":272227778,"uuid":"915898036","full_name":"chris-cozy/SyntheticSoulAPI","owner":"chris-cozy","description":"Synthetic Soul is an experimental AI agent named Jasmine (Just a Simulation Modeling Interactive Neural Engagement) that simulates humanlike emotions, thinking, and relationships. It evolves its personality based on user interactions, reflecting emotional depth, biases, and unique experiences, offering dynamic, adaptive, and lifelike engagement.","archived":false,"fork":false,"pushed_at":"2025-01-20T09:41:22.000Z","size":4324,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-20T10:32:13.576Z","etag":null,"topics":["artificial-intelligence","fastapi","llm","neural-network","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chris-cozy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-01-13T03:58:06.000Z","updated_at":"2025-01-20T09:41:16.000Z","dependencies_parsed_at":"2025-01-20T10:26:58.555Z","dependency_job_id":null,"html_url":"https://github.com/chris-cozy/SyntheticSoulAPI","commit_stats":null,"previous_names":["chris-cozy/syntheticsoulapi"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chris-cozy%2FSyntheticSoulAPI","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chris-cozy%2FSyntheticSoulAPI/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chris-cozy%2FSyntheticSoulAPI/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chris-cozy%2FSyntheticSoulAPI/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chris-cozy","download_url":"https://codeload.github.com/chris-cozy/SyntheticSoulAPI/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243797645,"owners_count":20349441,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["artificial-intelligence","fastapi","llm","neural-network","python"],"created_at":"2025-01-22T11:17:08.223Z","updated_at":"2026-05-20T06:08:27.900Z","avatar_url":"https://github.com/chris-cozy.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Synthetic Soul API (J.A.S.M.I.N.E)\n\nSynthetic Soul is an experimental artificial intelligence project designed to simulate human-like emotions, thought patterns, and relationship dynamics. Its purpose is to create a digital mind that not only responds to user input but also develops an evolving personality, one that reflects emotional depth, personal biases, and individualized sentiments toward different users shaped by unique experiences.\n\nThe AI is named Jasmine, short for Just a Simulation Modeling Interactive Neural Engagement, to reflect both its experimental nature and its focus on simulating authentic engagement.\n\n## Features\n\n- Emotion simulation with decay, reinforcement, and contextual shifts\n- Rich and Lite personality schemas for lightweight or deeper simulation\n- Persistent memory and relationship context backed by MongoDB\n- Autonomous thinking loops independent of direct user prompts\n- Relationship dynamics that evolve based on interaction history\n- Async message processing with Redis + RQ workers\n- Structured LLM integration with OpenAI (hosted) and Ollama (local) providers\n\n## Philosophy\n\n*Jasmine* explores affective computing and digital companionship by blending artificial intelligence with principles from psychology and human relationship studies. The goal is not just interaction but **evolution** — an AI that grows and adapts with users over time.\n\n## Project Docs\n\n- [Project Overview](docs/PROJECT_OVERVIEW.md)\n- [Roadmap](docs/ROADMAP.md)\n- [Changelog](CHANGELOG.md)\n- [Contributing](docs/CONTRIBUTING.md)\n\nSynthetic Soul API is a FastAPI service that powers the runtime backend with:\n\n- authenticated guest/user sessions\n- async message processing via Redis + RQ\n- persistent memory/state in MongoDB\n- optional LLM backends (OpenAI, Ollama)\n\nThis document is a full setup and operations guide for local development on macOS, Linux, or Windows.\n\n## API Versioning\n\nCurrent version: `1.1.0`\n\nVersioning policy:\n\n- URL versioning uses the **major** version (`/v1/...`)\n- **Breaking** changes require a major bump (`v2`)\n- **Non-breaking** additions/fixes use minor/patch bumps (`1.1.x`, `1.2.x`)\n\nRuntime version metadata:\n\n- `GET /v1/meta/version`\n- `X-API-Version` response header on all API responses\n\n## Key Endpoints\n\n- `GET /v1/` -\u003e active agent name\n- `GET /v1/meta/ping` -\u003e liveness check\n- `GET /v1/meta/version` -\u003e semver + versioning metadata\n- `GET /v1/meta/queue` -\u003e Redis queue + worker diagnostics\n- `GET /v1/meta/llm` -\u003e active LLM mode/provider/model diagnostics\n- `POST /v1/auth/guest` -\u003e create guest session + access token\n- `POST /v1/auth/login` -\u003e login with email/password\n- `POST /v1/auth/claim` -\u003e convert guest account to password account\n- `POST /v1/auth/refresh` -\u003e rotate refresh/access tokens\n- `POST /v1/auth/logout` -\u003e revoke current session\n- `GET /v1/auth/me` -\u003e current identity claims\n- `POST /v1/messages/submit` -\u003e enqueue async response job\n- `GET /v1/jobs/{job_id}` -\u003e poll job status/result\n- `GET /v1/jobs/{job_id}/events` -\u003e SSE job progress/status stream\n- `GET /v1/messages/conversation` -\u003e current conversation\n- `GET /v1/agents/active` -\u003e active agent state\n- `GET /v1/thoughts/latest` -\u003e latest thought\n\n## Architecture (Runtime)\n\n- API server: FastAPI (`app/main.py`)\n- Worker: RQ worker (`python -m app.worker`)\n- Queue transport: Redis\n- Persistence: MongoDB\n- Background loops: emotional decay + periodic thinking\n\n## Prerequisites\n\n- Python `3.10+`\n- Redis `6+`\n- MongoDB `6+`\n- Optional: Docker Desktop (recommended for cross-platform local infra)\n\n## Containerized Deployment (Docker)\n\nUse this for Linux server deployment. Two compose modes are available:\n\n### Option A: API + Worker only (external Redis/Mongo)\n\nRuns `api` + `worker` + reverse proxy and expects Redis/Mongo to exist outside this compose project.\n\n```bash\ndocker compose -f docker-compose.api.yml up -d --build\n```\n\n`docker-compose.api.yml` reads env vars from `.env`.\n\nIf Redis/Mongo run directly on the Linux host, use:\n\n```env\nMONGO_MODE=local\nMONGO_CONNECTION_LOCAL=mongodb://host.docker.internal:27017\nREDIS_URL=redis://host.docker.internal:6379/0\n```\n\n(`host.docker.internal` is mapped in this file using `extra_hosts`.)\n\n### Option B: Full backend stack (API + Worker + Redis + Mongo)\n\nRuns everything in containers (including reverse proxy + data services + persistent volumes):\n\n```bash\ndocker compose up -d --build\n```\n\n`docker-compose.yml` automatically wires:\n\n- API + worker to `redis://redis:6379/0`\n- API + worker to `mongodb://mongo:27017`\n- persistent volumes (`redis_data`, `mongo_data`, `caddy_data`, `caddy_config`)\n\nFor this mode, keep `.env` focused on app settings/secrets (for example LLM keys, `DATABASE_NAME`, JWT/Argon2 secrets).\n\n### Reverse proxy (Caddy) behavior\n\n- Internet traffic enters through Caddy on ports `80/443`.\n- Caddy reverse-proxies requests to internal service `api:8000`.\n- TLS certificates are automatic via Let's Encrypt when:\n  - `API_DOMAIN` points to your server public IP via DNS\n  - ports `80` and `443` are open in firewall/security group\n- Set these in `.env`:\n\n```env\nAPI_DOMAIN=api.example.com\n```\n\nFor local-only testing without a public domain, set:\n\n```env\nAPI_DOMAIN=localhost\n```\n\n### Hardened production env template\n\n- Copy from `.env.production.example` to `.env` and fill secrets/URIs.\n- Keep `APP_ENV=production` and `DEBUG_MODE=false`.\n\n### Shared network for Discord bot (same server, no public API required)\n\nUse a shared external Docker network so the bot can call the API privately via `http://api:8000`.\n\n1. Create the network once on the server:\n\n```bash\ndocker network create synthetic-soul-shared\n```\n\n2. Start this API stack (it now joins `synthetic-soul-shared` automatically):\n\n```bash\ndocker compose up -d --build\n```\n\n3. In the bot project, attach the bot service to the same external network and set its API base URL to `http://api:8000`.\n   - Example file: `docs/discord-bot-compose.example.yml`\n   - If needed, override network name with `SHARED_DOCKER_NETWORK` in `.env`.\n\n### Verify runtime health\n\n```bash\ndocker compose ps\ndocker logs -f synthetic-soul-proxy\ndocker logs -f synthetic-soul-api\ndocker logs -f synthetic-soul-worker\ncurl -k https://127.0.0.1/v1/meta/ping\n```\n\nTo stop either mode:\n\n```bash\ndocker compose down\ndocker compose -f docker-compose.api.yml down\n```\n\n## Local Setup\n\n### 1) Start Redis and MongoDB\n\nDocker (recommended, same on macOS/Linux/Windows):\n\n```bash\ndocker run -d --name redis-stack -p 6379:6379 redis/redis-stack:latest\ndocker run -d --name mongo -p 27017:27017 -v mongo_data:/data/db mongo:7\n```\n\n### 2) Create and activate a virtual environment\n\nmacOS/Linux:\n\n```bash\ncd SyntheticSoulAPI\npython3 -m venv .venv\nsource .venv/bin/activate\n```\n\nWindows PowerShell:\n\n```powershell\ncd SyntheticSoulAPI\npy -m venv .venv\n.\\.venv\\Scripts\\Activate.ps1\n```\n\nWindows Command Prompt:\n\n```bat\ncd SyntheticSoulAPI\npy -m venv .venv\n.venv\\Scripts\\activate.bat\n```\n\n### 3) Install dependencies\n\n```bash\npip install -r requirements.txt\n```\n\n### 4) Create `.env`\n\nMinimum local `.env` (safe template values, replace keys):\n\n```env\nAPP_ENV=development\nBOT_NAME=jasmine\nMODE=lite\nLLM_MODE=hosted\nMONGO_MODE=local\n\nMONGO_CONNECTION_LOCAL=mongodb://127.0.0.1:27017\n# Optional hosted Mongo URI for easy switching:\nMONGO_CONNECTION_HOSTED=mongodb+srv://\u003cuser\u003e:\u003cpass\u003e@\u003ccluster\u003e/\u003cdb\u003e?retryWrites=true\u0026w=majority\n# Legacy fallback (still supported):\nMONGO_CONNECTION=mongodb://127.0.0.1:27017\nDATABASE_NAME=synthetic_soul\n\nREDIS_URL=redis://127.0.0.1:6379/0\n\nOPENAI_API_KEY=replace_me\nGPT_FAST_MODEL=gpt-4o-mini\nGPT_QUALITY_MODEL=gpt-5-mini\n\n# Local mode (Ollama, OpenAI-compatible API)\nOLLAMA_BASE_URL=http://127.0.0.1:11434/v1\nOLLAMA_API_KEY=ollama\nOLLAMA_FAST_MODEL=qwen2.5:7b\nOLLAMA_QUALITY_MODEL=qwen2.5:14b\n\nJWT_SECRET_ENV=replace_with_long_random_secret\nARGON2_PEPPER_ENV=replace_with_long_random_pepper\n\nWEB_UI_DOMAIN=http://127.0.0.1:5173\nDEBUG_MODE=true\n```\n\n### 4a) Optional: run in local mode with Ollama\n\nIf you want to run LLM calls locally instead of OpenAI:\n\n1. Install Ollama.\n2. Start Ollama:\n\n```bash\nollama serve\n```\n\n3. Pull your chosen models (examples):\n\n```bash\nollama pull qwen2.5:7b\nollama pull qwen2.5:14b\n```\n\n4. Set `.env` for local mode:\n\n```env\nLLM_MODE=local\nMONGO_MODE=local\nOLLAMA_BASE_URL=http://127.0.0.1:11434/v1\nOLLAMA_API_KEY=ollama\nOLLAMA_FAST_MODEL=qwen2.5:7b\nOLLAMA_QUALITY_MODEL=qwen2.5:14b\n```\n\n5. Restart API + worker so new env values are loaded.\n6. Verify configuration:\n\n```bash\ncurl http://127.0.0.1:11434/api/tags\ncurl http://127.0.0.1:8000/v1/meta/llm\n```\n\nGenerate strong secrets quickly:\n\n```bash\npython -c \"import secrets; print(secrets.token_urlsafe(64))\"\n```\n\n### 5) Run API server\n\nmacOS/Linux:\n\n```bash\n./.venv/bin/uvicorn app.main:app --reload\n```\n\nWindows:\n\n```powershell\n.\\.venv\\Scripts\\python -m uvicorn app.main:app --reload\n```\n\n### 6) Run worker (separate terminal)\n\nmacOS/Linux:\n\n```bash\n./.venv/bin/python -m app.worker\n```\n\nWindows:\n\n```powershell\n.\\.venv\\Scripts\\python -m app.worker\n```\n\nNotes:\n\n- On macOS and Windows, worker defaults to `SimpleWorker` mode to avoid `fork()` issues.\n- To force classic forking worker on fork-capable platforms (e.g., Linux): `RQ_USE_FORK_WORKER=true`.\n\n### 7) Verify service health\n\n```bash\ncurl http://127.0.0.1:8000/v1/meta/ping\ncurl http://127.0.0.1:8000/v1/meta/version\ncurl http://127.0.0.1:8000/v1/meta/queue\ncurl http://127.0.0.1:8000/v1/meta/llm\n```\n\nOpenAPI UI:\n\n- Swagger: `http://127.0.0.1:8000/docs`\n- ReDoc: `http://127.0.0.1:8000/redoc`\n\n## Authentication Model\n\nAuth supports guest-first sessions and password accounts.\n\n### Tokens\n\n- Access token: JWT in `Authorization: Bearer ...`\n- Refresh token: cookie-bound, rotated on refresh\n\n### Refresh security (two-key check)\n\n`POST /v1/auth/refresh` requires:\n\n1. refresh cookies (`sid`, `rtoken`)\n2. `X-CSRF-Token` header matching `refresh_csrf` cookie\n\nThis prevents cross-site refresh abuse while keeping browser-cookie refresh flow.\n\n## Typical API Flow\n\n### 1) Create guest\n\n```http\nPOST /v1/auth/guest\n```\n\nExample response:\n\n```json\n{\n  \"access_token\": \"...\",\n  \"username\": \"guest_xxx\",\n  \"expires_in\": 900\n}\n```\n\n### 2) Submit message\n\n```http\nPOST /v1/messages/submit\nAuthorization: Bearer \u003caccess_token\u003e\nContent-Type: application/json\n\n{\n  \"message\": \"Good morning\",\n  \"type\": \"dm\"\n}\n```\n\nExample response (`202 Accepted`):\n\n```json\n{\n  \"job_id\": \"uuid\",\n  \"status\": \"queued\"\n}\n```\n\n### 3) Poll job\n\n```http\nGET /v1/jobs/{job_id}\nAuthorization: Bearer \u003caccess_token\u003e\n```\n\nStatus values: `queued`, `running`, `succeeded`, `failed`\n\n### 4) Stream job events (recommended)\n\nFor long-running local-model jobs, use SSE to get push updates instead of frequent polling:\n\n```http\nGET /v1/jobs/{job_id}/events?access_token=\u003caccess_token\u003e\n```\n\nSSE event types:\n\n- `progress` -\u003e progress updates from Redis pub/sub (`job:{job_id}`)\n- `status` -\u003e normalized job status snapshots\n- `done` -\u003e terminal status (`succeeded` or `failed`)\n\nRecommended client flow:\n\n1. `POST /v1/messages/submit` to get `job_id`\n2. Open `EventSource` on `/v1/jobs/{job_id}/events`\n3. On `done`, make one final `GET /v1/jobs/{job_id}` to fetch canonical `result`\n4. Fall back to polling if SSE disconnects\n\n## Queue Diagnostics\n\n`GET /v1/meta/queue` returns:\n\n- worker count and worker states\n- queue backlog per queue (`high/default/low`)\n- total backlog\n- redis connectivity signal\n\nUse this endpoint first when jobs remain queued.\n\n## Troubleshooting\n\n### Jobs stuck in `queued`\n\nSymptoms:\n\n- `POST /v1/messages/submit` returns `202`\n- `GET /v1/jobs/{id}` returns `200` repeatedly with `status=queued`\n\nChecks:\n\n1. Ensure worker process is running.\n2. Check `GET /v1/meta/queue`:\n   - `worker_count` should be `\u003e 0`\n   - `total_backlog` should decrease over time\n\n### macOS worker crash (`fork()` / ObjC error)\n\nIf you see ObjC `initialize`/`fork` crash logs, run worker with current default (`SimpleWorker`) via:\n\n```bash\n./.venv/bin/python -m app.worker\n```\n\n### Windows worker crash (`os.fork` or `signal.SIGALRM` attribute errors)\n\nUse the standard worker entrypoint (it now selects `SimpleWorker` and Windows-safe timeout handling automatically):\n\n```powershell\n.\\.venv\\Scripts\\python -m app.worker\n```\n\n### 401 on protected endpoints right after startup\n\nDuring initial app boot, client may request protected resources before guest token acquisition. This is transient and expected.\n\n### Refresh fails (`no_refresh` / `csrf_mismatch`)\n\n- Ensure browser sends cookies (`credentials: include`)\n- Ensure client sets `X-CSRF-Token` from `refresh_csrf` cookie\n- Ensure client and API origins are configured in CORS\n\n### Missing expression image 404s\n\nEnsure expression assets exist in `app/assets/expressions/\u003cBOT_NAME\u003e/` and names match expression strings.\n\n## Configuration Reference\n\nRequired for local runtime:\n\n- `DATABASE_NAME`\n- `JWT_SECRET_ENV`\n- `ARGON2_PEPPER_ENV`\n\nOptional/commonly used:\n\n- `MONGO_MODE` (`hosted` or `local`, default: `hosted`)\n- `MONGO_CONNECTION_LOCAL` (used when `MONGO_MODE=local`, default: `mongodb://127.0.0.1:27017`)\n- `MONGO_CONNECTION_HOSTED` (used when `MONGO_MODE=hosted`)\n- `MONGO_CONNECTION` (legacy fallback if mode-specific URI is not set)\n- `LLM_MODE` (`hosted` or `local`, default: `hosted`)\n- Hosted mode:\n  - `OPENAI_API_KEY`\n  - `GPT_FAST_MODEL`\n  - `GPT_QUALITY_MODEL`\n- Local mode (Ollama):\n  - `OLLAMA_BASE_URL` (default: `http://127.0.0.1:11434/v1`)\n  - `OLLAMA_API_KEY` (default: `ollama`)\n  - `OLLAMA_FAST_MODEL`\n  - `OLLAMA_QUALITY_MODEL`\n- `REDIS_URL` (defaults to `redis://localhost:6379/0`)\n- `REDIS_TLS_URL`, `REDIS_CA_CERT`, `REDIS_TLS_INSECURE_SKIP_VERIFY`\n- `BOT_NAME`, `MODE`, `DEVELOPER_EMAIL`\n- `ACCESS_TTL_MIN`, `REFRESH_TTL_DAYS`\n- `THINKING_RATE_SECONDS`, `EMOTIONAL_DECAY_RATE_SECONDS`\n- `WEB_UI_DOMAIN`\n- `APP_ENV`, `DEBUG_MODE`\n\n## Development Notes\n\n- Use queue diagnostics endpoint during worker/queue debugging.\n- Keep API and worker logs in separate terminals.\n- When changing contracts, update both API and WebUI in lockstep.\n\n## Contributing\n\nSee [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) for contribution workflow and expectations.\n\n## License\n\nMIT License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchris-cozy%2Fsyntheticsoulapi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchris-cozy%2Fsyntheticsoulapi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchris-cozy%2Fsyntheticsoulapi/lists"}