| --- |
| title: Inside Out |
| emoji: π¬ |
| colorFrom: yellow |
| colorTo: purple |
| sdk: gradio |
| sdk_version: 6.16.0 |
| app_file: app.py |
| pinned: false |
| license: apache-2.0 |
| short_description: Let your emotions speak for you |
| tags: |
| - track:wood |
| - sponsor:openai |
| - sponsor:nvidia |
| - achievement:offgrid |
| - achievement:offbrand |
| - achievement:llama |
| - achievement:sharing |
| - achievement:fieldnotes |
| --- |
| |
| # Inside Out β Chat with Your Emotions π |
|
|
| A warm little Gradio app, inspired by Pixar's *Inside Out*, where a cast of |
| emotion agents chime in on whatever is on your mind. It isn't an advice bot β |
| it's a gentle mirror that helps you **notice and name what you're really |
| feeling**. |
|
|
| π£ Featured on X: [@QuicklyLearnIt](https://x.com/QuicklyLearnIt/status/2066334265336570107?s=20) |
|
|
| You type a message. A handful of emotions light up and respond, each in their |
| own distinct voice, followed by a soft reflection inviting you to notice which |
| feeling rings most true. You can also **tap any emotion chip** at the top to |
| invite that one to speak up directly. |
|
|
| ## The cast |
|
|
| Powered by multiple agents β one per emotion (from *Inside Out* and *Inside |
| Out 2*): |
|
|
| β¨ Joy Β· π Sadness Β· π¨ Fear Β· π₯ Anger Β· π€’ Disgust Β· π§‘ Anxiety Β· π Envy Β· |
| π Boredom Β· π³ Embarrassment |
|
|
| For each message, an **orchestrator agent** decides which 2β4 emotions would |
| naturally speak up, those emotion agents respond **in parallel**, and a final |
| **reflection agent** helps you make sense of the mix. The emotion chips along |
| the top double as buttons: tap one and that single emotion chimes in on the |
| conversation so far. |
|
|
| ## Try saying⦠|
|
|
| Not sure where to start? These exercise different emotional mixes: |
|
|
| - "I have a big exam tomorrow and I haven't studied enough." |
| - "My best friend got the promotion I was hoping for and I don't know how to feel." |
| - "I just sent an email to my whole team with an embarrassing typo in it." |
| - "I moved to a new city and I feel really lonely here." |
| - "I finally finished a project I've been working on for months!" |
| - "Lately everything just feels gray and pointless." |
| - "My roommate keeps leaving dirty dishes everywhere and I'm so done." |
| - "I got into the program I applied for but now I'm terrified I'll fail." |
| - "Is it normal to feel happy and sad at the same time?" |
| - "I have talked about the issue with my wife a few time and we can't reach an agreement. i don't know what to do now." |
|
|
| ## Run it |
|
|
| ```bash |
| pip install -r requirements.txt |
| python app.py # open http://localhost:7860 |
| ``` |
|
|
| Configuration is read from the environment, and a local **`.env`** file is |
| loaded automatically if present (via `python-dotenv`): |
|
|
| ```bash |
| # .env (real shell environment variables take precedence) |
| HF_TOKEN=hf_... # enables model-generated replies |
| GOOGLE_CLIENT_ID=... # optional, enables Google sign-in |
| GOOGLE_CLIENT_SECRET=... |
| GOOGLE_ALLOWED_DOMAIN=example.com # optional, restrict to one Workspace domain |
| SESSION_SECRET=change-me |
| SHOW_LOGIN=true # optional, shows the login sidebar |
| ``` |
|
|
| - **`HF_TOKEN`** lets the model (set by `HF_MODEL` in `app.py`, currently |
| `google/gemma-4-26B-A4B-it`) generate the emotion responses. Without it the |
| app still runs in a lightweight **offline demo mode** (keyword-based |
| responses), so you can always see the experience. Pick a regular *instruct* |
| model β a reasoning/"thinking" model returns its answer in a separate |
| `reasoning` field and leaves `content` empty, which falls back to demo lines. |
| On startup the app logs `HF_TOKEN present: True/False` (boolean only, never |
| the value) so you can confirm the token reached the app β handy in Space logs. |
| - **Google sign-in** is required when `GOOGLE_CLIENT_ID` and |
| `GOOGLE_CLIENT_SECRET` are set; otherwise the app runs as an open local demo. |
|
|
| ### Hot reload (dev) |
|
|
| ```bash |
| DEV=1 python app.py # uvicorn watches the source and reloads on save |
| ``` |
|
|
| ### Local serving with llama.cpp |
|
|
| Set **`LOCAL_SERVING=true`** to run entirely on your own machine β the app then |
| talks to a local [llama.cpp](https://github.com/ggml-org/llama.cpp) server |
| (OpenAI-compatible) instead of the hosted HF Inference API, and **no `HF_TOKEN` |
| is needed**. |
|
|
| ```bash |
| LOCAL_SERVING=true python app.py |
| ``` |
|
|
| On startup the app **auto-discovers a local GGUF** for `HF_MODEL` under |
| `~/models` (override with `LOCAL_MODELS_DIR`, or pin an exact file with |
| `LOCAL_MODEL_PATH`) and **launches `llama-server` for you** β no separate |
| terminal needed. It reuses an already-running server if one is up, and shuts |
| its own down on exit. A 30B-A3B / 26B-A4B model at ~4-bit fits a 24 GB GPU. |
|
|
| Prefer to run the server yourself? Just start it first and the app will reuse it: |
|
|
| ```bash |
| llama-server -m /path/to/model.gguf --jinja --reasoning-budget 0 \ |
| -ngl 99 -c 8192 --port 8088 |
| ``` |
|
|
| - **Reasoning models:** `USE_REASONING` defaults to **`false`**, which serves the |
| model with `--reasoning-budget 0` so it answers directly. Many models (Gemma 4, |
| Nemotron, Qwen3β¦) otherwise default to a "thinking" mode that leaves `content` |
| empty and falls back to demo lines. Set `USE_REASONING=true` to let the model |
| think β the agent layer then strips the `<think>β¦</think>` chain-of-thought |
| from replies (and uses larger token budgets so the answer is reached). |
| - Override the endpoint with `LOCAL_LLM_BASE_URL` (default |
| `http://localhost:8088/v1`), the llama.cpp binary with `LLAMA_SERVER_BIN`, and |
| the reported model name with `LOCAL_LLM_MODEL`. The startup log shows |
| `serving=local-llama.cpp | reasoning=off` so you can confirm the active backend. |
|
|
| ## How it works |
|
|
| | File | Purpose | |
| |-----------------|--------------------------------------------------------------------| |
| | `app.py` | Gradio UI β theme/CSS, emotion chip-buttons, chat + chime callbacks, FastAPI mount and optional Google OAuth. | |
| | `agents.py` | Orchestrator, per-emotion agents (run in parallel), and the closing reflection. | |
| | `emotions.py` | Each emotion's display name, persona, color, and emoji. | |
|
|
| The Gradio UI is mounted onto a FastAPI app via `gr.mount_gradio_app`, which is |
| where the custom theme/CSS and the Google OAuth routes are wired in. Model calls |
| go through Hugging Face's chat-completion API; recent conversation (up to the |
| last 100 turns) is fed back to the agents as readable context. |
|
|
| ## A gentle note |
|
|
| This is a playful tool for self-reflection, **not** a substitute for |
| professional mental-health support. If you're struggling, please reach out to |
| someone you trust or a qualified professional. |
|
|