Skip to content

Repository files navigation

BUD-E Flutter — OpenRouter Edition

School Bud-E is an AI learning companion: a chat app with voice in and voice out, image and song generation, document analysis, a curriculum search and a long-term memory that remembers what a learner is working on.

This edition talks to OpenRouter directly. Paste an OpenRouter key and every part of the app — the chat model, the vision model, speech recognition, speech output, image generation and music — runs on models you pick yourself from OpenRouter's live catalogue, with the privacy properties visible while you choose: EU hosting, zero data retention, price per million tokens.

It runs on Windows, macOS, Linux, Android and iOS from one codebase.

Model picker


Quick start

You need Flutter 3.7 or newer (flutter --version) and a key from openrouter.ai/keys.

git clone https://github.com/LAION-AI/bud-e-flutter-openrouter.git
cd bud-e-flutter-openrouter
flutter pub get

flutter run -d windows      # or: macos, linux, chrome, or a device id

Then open Settings (gear icon) and paste your key into Universal API key. A key starting with sk-or-v1- switches the whole app to OpenRouter; the status line under the field confirms it with "OpenRouter — direkt, ohne Middleware".

Press Save. That is the entire setup.

Android

flutter build apk --release
# build/app/outputs/flutter-apk/app-release.apk

Or grab the APK from the releases page and install it (you will have to allow installation from unknown sources). The app asks for the microphone permission on first use; everything else works without permissions.


Choosing models

Settings → OpenRouter-ModelleModelle auswählen opens the picker. It has one tab per job the app needs a model for:

Tab Job What it is used for
Chat llm the conversation
Vision vlm reading images, PDFs and documents
ASR asr transcribing what you say
TTS tts reading answers out loud
Bild image generating and editing pictures
Musik music writing songs

Inside a tab you can:

  • Filter by Alle / ZDR / EU / EU+ZDR / Gratis, with the count of matching models on each chip. "ZDR" means the provider offers zero data retention; "EU" means the model has at least one endpoint that runs inside the EU.
  • Search by any part of a model's name or id. Prefix matches come first, so typing mu puts Muse Spark at the top rather than something with "mu" in the middle of its description.
  • Sort by recommendation, price (up or down), name or context length.
  • Pick Automatisch (empfohlen) to let the app decide. It uses a recommended model and falls back to an alternative when a provider has an outage, which is what you want unless you have a reason to pin one.

Every card shows the model id, the badges (EU, ZDR, free, and whether a TTS model really speaks rather than composing), the price per million tokens for input and output, and the context length.

The list is never hardcoded. It is fetched from OpenRouter, cached on disk, refreshed every 30 minutes while you use the app and every six hours in a long session — so a model released next month appears without a new build. The header says how old the list is, and the refresh button forces an update. If OpenRouter is unreachable the last known list is used and labelled as stale.

What "EU" and "ZDR" actually do

Picking a model with those badges is not cosmetic. Each request is attempted in this order, and the first one that succeeds is used:

  1. strict — zero data retention and the region pinned to an EU endpoint (provider.only: ["google-vertex/eu"] and friends)
  2. zdr — zero data retention, any region
  3. plain — whatever OpenRouter picks

Model first, strictness second: swapping to the alternative model keeps EU and ZDR, whereas relaxing the policy gives them up. So a degraded EU endpoint costs a retry, not your privacy setting. If you pinned a model yourself, that model is tried at every strictness level before the app reaches for a different one — a choice you made is not silently swapped at the first hiccup.

OpenRouter's own EU host (eu.openrouter.ai) is used when the account has regional routing; ordinary keys get a 403 there, which the app notices once and then remembers, falling back to region pinning on the main host.

Speech output

TTS voices are vendor-specific, so voice, audio format and speaking style live in one editable settings field:

voice=Eve;format=mp3;style=calm, friendly, unhurried

Anything that is not a key=value directive is taken as the style, so you can just write how you want it to sound. Grok takes the style as an instructions field; Gemini wants it written in front of the text and only emits raw PCM, which the app wraps in a WAV header before playing. You do not have to know any of that — it is handled per model.


Features beyond the model picker

  • Wake words — "Hey Buddy" starts recording, "Go Buddy" sends it, "Stop Buddy" cancels or stops the reply. Runs fully on-device with ONNX models (~80 ms per inference). Off by default, and it switches itself back off if it fails to start, so a broken audio stack can never lock you out of the settings screen.
  • Three-tier memory — semantic (facts), episodic (past conversations) and working memory, with a nightly consolidation pass and a BM25 index for search.
  • Curriculum search — the German Bildungspläne (Hamburg) ship with the app, indexed for retrieval, so answers can cite the actual curriculum.
  • Document generation — PPTX, DOCX, PDF and HTML, written by a background sub-agent that can also generate the images it puts on the slides.
  • Document analysis — drop in a PDF or a photo and ask about it.
  • Sub-agents — long jobs run in the background with their own tool loop and report progress in the chat.

Two of the app's tools need the BUD-E middleware and are not available on an OpenRouter key, because OpenRouter has no equivalent service: code execution and HTML→PDF conversion. The app says so plainly instead of failing quietly.


Using the BUD-E middleware instead

If you have a BUD-E universal key (sbe-…#…), paste that instead. The app then routes everything through the middleware exactly as before, and the OpenRouter section disappears from the settings. Both paths are supported side by side — the key decides, nothing else.

Documentation

Document What is in it
docs/OPENROUTER.md how the OpenRouter integration works, endpoint by endpoint
docs/ARCHITECTURE.md app structure, services, providers
docs/CONTEXT_AND_MEMORY.md the memory system
docs/SKILLS_AND_TOOLS.md the tools the assistant can call
docs/DOCUMENT_GENERATION.md PPTX/DOCX/PDF generation
docs/CURRICULUM_SEARCH.md curriculum retrieval
docs/tests.md manual and automated test notes
README.de.md diese Anleitung auf Deutsch

Where your data lives

Everything is local, in the app's support directory:

  • Windows: %APPDATA%\ai.laion\school_bud_e_flutter\SchoolBudE\
  • macOS: ~/Library/Application Support/SchoolBudE/
  • Linux: ~/.local/share/SchoolBudE/
  • Android/iOS: the app's private storage

That folder holds settings.json (including your API key), the conversations, the memory files, the cached model catalogue and the workspace with generated files. No key is compiled into the app — the source ships with an empty default, and nothing is sent anywhere except to the API your key points at.

Development

flutter pub get
flutter analyze
flutter test
flutter run -d windows

A small debug HTTP server listens on http://localhost:8790 in desktop debug builds (/status, /messages, /send?text=…, /screenshot, /debug_log?last=100, /navigate?to=openrouter). It is not started on mobile.

Licence

Apache 2.0 — see LICENSE. Built by LAION.

About

School Bud-E as a Flutter app, wired to OpenRouter: pick the model for chat, vision, speech recognition, speech output, image and music from a live catalogue, filtered by EU hosting, zero data retention and price.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages