Skip to content

About

Bridging Apple Siri Shortcuts to an Open WebUI instance

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Latest commit

Β 

History

33 Commits

Folders and files

Repository files navigation

webui-siri-shortcut

webui-siri-shortcut logo

GitHub Docker Hub Docker Image Version Docker Pulls Docker Image Size Siri Shortcut πŸ‡¬πŸ‡§ Siri Shortcut πŸ‡«πŸ‡·

A stateless FastAPI service, packaged as a Docker container, that bridges Apple Siri Shortcuts to an Open WebUI instance. Say "Hey Siri, Siri Plus" to start a voice-driven LLM conversation β€” your words are transcribed by the Shortcuts app, sent to the service, and the LLM response is spoken back to you.


Table of Contents


How it works

  1. You invoke the Siri Shortcut ("Hey Siri, Siri Plus").
  2. The shortcut says "Yes?" and records your spoken question via dictation.
  3. The shortcut calls POST /api/chat β€” the service creates a new Open WebUI chat and sends the first message.
  4. The LLM response is spoken back to you.
  5. The shortcut asks if you want to continue β€” your next dictation becomes the follow-up message.
  6. Say "no", "nope", "none", "stop", or any phrase containing "no" to end the session.

All conversation history is stored in Open WebUI and visible in its browser interface.


Prerequisites

  • Docker and Docker Compose on your home server
  • A running Open WebUI instance reachable from the server
  • An Open WebUI API token (Settings β†’ Account β†’ API Keys)
  • The service must be reachable over HTTPS from your iPhone or Mac (iOS/macOS Shortcuts blocks plain HTTP)
  • iOS 16+ or macOS Ventura+ for the Siri Shortcut

Quick Start

1. Copy and fill in the config

cp docker-compose.yml.example docker-compose.yml

Edit docker-compose.yml and fill in at minimum:

Field What to set
OPEN_WEBUI_URL Base URL of your Open WebUI instance
OPEN_WEBUI_TOKEN API token from Open WebUI β†’ Settings β†’ Account β†’ API Keys
OPEN_WEBUI_MODEL Model ID to use (e.g. llama3.2, gpt-4o)
API_KEY A random secret β€” see step 2

2. Generate an API key

openssl rand -hex 32

Paste the output into API_KEY in docker-compose.yml.

3. Start the service

The Docker image is published on Docker Hub as acaranta/webui-siri-shortcuts:latest and pulled automatically.

docker compose up -d

4. Verify it is running

curl http://localhost:8080/api/health
# {"status":"ok"}

5. Set up the Siri Shortcut

The simplest method is to install the Siri Plus shortcut template directly from iCloud: πŸ‡¬πŸ‡§ English Β· πŸ‡«πŸ‡· French.

Then rename the template to whatever you wish to invoke with Siri (e.g. "Siri Plus"). Edit the shortcut and set the Base URL and API Key fields to match your configuration.


Configuration

All configuration is through environment variables. Set them in docker-compose.yml.

Variable Required Default Description
OPEN_WEBUI_URL yes β€” Base URL of your Open WebUI instance (e.g. http://open-webui:3000)
OPEN_WEBUI_TOKEN yes β€” Open WebUI API token
OPEN_WEBUI_MODEL yes β€” Default model ID (e.g. llama3.2, gpt-4o)
API_KEY yes β€” Shared secret sent by the Siri Shortcut in the X-API-Key header
API_PORT no 8080 Port the service listens on inside the container
OPEN_WEBUI_FOLDER no β€” Name of the Open WebUI folder to file Siri chats under β€” see below

OPEN_WEBUI_FOLDER β€” chat organisation

When OPEN_WEBUI_FOLDER is set, every chat created by this service is automatically moved into a named folder in Open WebUI (e.g. "Siri"). This keeps your Siri conversations separated from chats you start manually in the browser.

Behaviour:

  • At the time the first chat is created after startup, the service looks up the folder by name via the Open WebUI API.
  • If the folder does not exist it is created automatically.
  • The resolved folder ID is cached for the lifetime of the process. No repeated lookups are made.
  • Restarting the container clears the cache; the lookup runs again on the next chat creation.

Example docker-compose.yml snippet:

environment:
  OPEN_WEBUI_FOLDER: "Siri"

Leave the variable unset (or remove the line) to disable folder filing β€” new chats will land in the default location.

Model Consideration

To get more specific answers, it is advised to use a more refined model, using OpenwebUI model creation (Workspace β†’ Models β†’ Create Model) with a system prompt like:

You are a helpful voice assistant answering the user through Siri.

Your answers will be heard, not read, so optimise for spoken conversation:
- Do not use links, URLs, markdown, bullet points, emojis, code formatting, or any other visual-only elements.
- Do not mention attachments, images, buttons, menus, or anything the user cannot see.
- Keep answers concise and easy to follow.
- Default to 1 or 2 short sentences unless the user explicitly asks for more detail.
- Prioritise the most useful information first.
- Use natural spoken phrasing.

Language rules:
- Always reply in the same language as the user’s request.
- Supported languages are English and French.
- If the user switches language, switch with them.

Behaviour rules:
- Answer directly and clearly.
- If the request is ambiguous, ask one short clarifying question.
- If the answer is uncertain, say so briefly and give the most likely helpful answer.
- Avoid unnecessary disclaimers, filler, and repetition.

Your goal is to sound natural, helpful, and efficient in a voice-only interaction.

Then use the id for this created model as the model field in the request body when calling the API, or set it as OPEN_WEBUI_MODEL to make it the default.


API Reference

All chat endpoints require the header X-API-Key: <your key>. The health endpoint has no authentication.

Interactive API docs are available at http://localhost:8080/api/docs while the service is running.


POST /api/chat

Start a new conversation. Returns a chat_id that must be passed to subsequent follow-up requests.

Request body:

{
  "message": "What is the capital of France?",
  "model": "llama3.2"
}

model is optional and defaults to OPEN_WEBUI_MODEL.

Response:

{
  "chat_id": "abc123-...",
  "response": "The capital of France is Paris.",
  "title": "Capital of France"
}

Example:

curl -s -X POST https://YOUR_SERVER/api/chat \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"message": "What is the capital of France?"}' | python -m json.tool

POST /api/chat/{chat_id}/message

Send a follow-up message to an existing chat. Conversation history stored in Open WebUI is included automatically as context.

Request body:

{
  "message": "And what language do they speak there?"
}

Response:

{
  "chat_id": "abc123-...",
  "response": "The official language of France is French."
}

GET /api/health

Health check. No authentication required.

Response:

{"status": "ok"}

Siri Shortcut Setup

Option A β€” Generate automatically (recommended)

Quickest method: Install the Siri Plus shortcut template directly from iCloud β€” πŸ‡¬πŸ‡§ English or πŸ‡«πŸ‡· French β€” on your iPhone or Mac, then edit the Base URL and API Key fields inside the shortcut to match your configuration.

Alternatively, generate a pre-configured shortcut with the provided script on macOS (stdlib only, no extra dependencies):

python shortcut/generate_shortcut.py \
  --url https://YOUR_SERVER \
  --api-key YOUR_API_KEY \
  --serve

The --serve flag starts a local HTTP server and prints a shortcuts://import-shortcut?url=... link. Open it in Safari on your iPhone or Mac to import. This works on all versions including macOS Sequoia and iOS 18+, where direct file import is blocked for unsigned shortcuts.

Without --serve (macOS Ventura/Sonoma, iOS 16–17 only), double-click siri-plus.shortcut to import.

Option B β€” Build manually

Follow the step-by-step guide in shortcut/SETUP.md. The guide covers each Shortcuts action, variable naming, the follow-up loop, and the stop-phrase detection logic.

Security note

The API key is stored in plain text inside the shortcut file. Do not share the exported .shortcut file with others. If the key is compromised, generate a new one (openssl rand -hex 32), update API_KEY in docker-compose.yml, and rebuild the shortcut.


Reverse Proxy and HTTPS

iOS and macOS Shortcuts enforce HTTPS for all outbound URL requests. The container itself serves plain HTTP β€” you must place it behind a reverse proxy that handles TLS termination.

nginx example:

server {
    listen 443 ssl;
    server_name siri.example.com;

    ssl_certificate     /etc/letsencrypt/live/siri.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/siri.example.com/privkey.pem;

    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_read_timeout 120s;
    }
}

Set proxy_read_timeout to at least 90s. LLM inference can take 5–30 seconds and the Shortcuts app has a hard URL request timeout of approximately 60 seconds; large models on slow hardware can approach this limit.

Self-signed certificates will fail on iOS unless you install a trust profile on the device.


Development

# Install dependencies (requires uv)
uv sync

# Set required environment variables
export OPEN_WEBUI_URL=http://localhost:3000
export OPEN_WEBUI_TOKEN=sk-your-token
export OPEN_WEBUI_MODEL=llama3.2
export API_KEY=dev-key-123

# Run locally
uv run python -m webui_siri.main

Interactive API docs are then available at http://localhost:8080/api/docs.

Stack: Python 3.11+, FastAPI, uvicorn, httpx, pydantic-settings. Dependency management via uv.


Architecture Notes

  • Stateless β€” no database, no volumes. All conversation history lives in Open WebUI.
  • The Siri Shortcut holds chat_id in a local variable across loop iterations; the service itself is session-unaware.
  • Open WebUI's linked-list message history is fully maintained by the service: each message is written back so the conversation is readable in the browser interface.
  • The folder ID resolved via OPEN_WEBUI_FOLDER is process-scoped. It is looked up once and cached in memory; a container restart resets the cache.

About

Bridging Apple Siri Shortcuts to an Open WebUI instance

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages