Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Please contact [hello@swirlaiconnect.com](mailto:hello@swirlaiconnect.com) for m

# Additional Documentation

[Overview](https://docs.swirlaiconnect.com/) | [Quick Start](https://docs.swirlaiconnect.com/Quick-Start) | [User Guide](https://docs.swirlaiconnect.com/User-Guide) | [Admin Guide](https://docs.swirlaiconnect.com/Admin-Guide) | [M365 Guide](https://docs.swirlaiconnect.com/M365-Guide) | [Developer Guide](https://docs.swirlaiconnect.com/Developer-Guide) | [Developer Reference](https://docs.swirlaiconnect.com/Developer-Reference) | [AI Guide](https://docs.swirlaiconnect.com/AI-Guide)
[Overview](https://docs.swirlaiconnect.com/) | [Quick Start](https://docs.swirlaiconnect.com/Quick-Start) | [User Guide](https://docs.swirlaiconnect.com/User-Guide) | [Admin Guide](https://docs.swirlaiconnect.com/Admin-Guide) | [M365 Guide](https://docs.swirlaiconnect.com/M365-Guide) | [Developer Guide](https://docs.swirlaiconnect.com/Developer-Guide) | [Developer Reference](https://docs.swirlaiconnect.com/Developer-Reference) | [AI Search Guide](https://docs.swirlaiconnect.com/AI-Search.html) | [AI Search Assistant Guide](https://docs.swirlaiconnect.com/AI-Search-Assistant.html)

# Support

Expand Down
35 changes: 35 additions & 0 deletions doc/controlling-swirl-service.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,30 @@ sudo systemctl start swirl
sudo systemctl stop swirl
sudo systemctl restart swirl
```
### MacOS
> Note: The service must be installed as a user-level LaunchAgent (e.g., in `~Library/LaunchAgents/com.swirl.service.plist`).

**Start (manually):**
```bash
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.swirl.service.plist
```

**Stop:**
```bash
launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.swirl.service.plist
```

**Restart:**
```bash
launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.swirl.service.plist
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.swirl.service.plist
```

> Note: if `RunAtLoad` is set to `false`, the service won't run automatically when loaded. You'll need to explicitly start it using `kickstart`:
```bash
launchctl kickstart -k gui/$(id -u)/com.swirl.service
```

### Docker
### Monitoring the Service
To monitor the status of the Swirl service, you can use:
Expand All @@ -23,6 +47,17 @@ sudo systemctl status swirl
sudo journalctl -u swirl
```

### MacOS
To check if the service is running:
```bash
launchctl list | grep com.swirl.service
```

To monitor logs (if configured with `StandardOutPath` and `StandardErrorPath`):
```bash
tail -f $HOME/tmp/log/swirl-service.out $HOME/tmp/log/swirl-service.out
```

### Docker Monitoring
As the containers are standard docker containers, you can also monitor them via
- `docker inspect`
Expand Down
17 changes: 14 additions & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,19 @@ services:
env_file:
- .env
networks: ["swirl"]
command: ["python", "manage.py", "migrate"]
command: ["python", "swirl.py", "migrate", "-v"]

swirl-reload:
profiles: ["all", "reload"]
image: swirlai/release-swirl-search-enterprise:${SWIRL_VERSION}
container_name: swirl_app_reload_prompts
env_file:
- .env
networks: ["swirl"]
command: ["python", "swirl.py", "reload_ai_prompts"]
depends_on:
swirl:
condition: service_healthy

swirl:
profiles: ["all", "svc", "swirl"]
Expand All @@ -130,11 +142,10 @@ services:
volumes:
- ./nginx/nginx.template:/nginx/nginx.template
- ./scripts/swirl-load.sh:/tmp/swirl-load.sh
- ./scripts/swirl-health-check.sh:/tmp/swirl-health-check.sh
- ./uploads/:/app/uploads/
networks: ["swirl"]
healthcheck:
test: ["CMD-SHELL", "/tmp/swirl-health-check.sh || exit 1"]
test: ["CMD-SHELL", "/app/swirl-health-check.sh || exit 1"]
interval: 30s
timeout: 10s
retries: 3
Expand Down
13 changes: 9 additions & 4 deletions env.example
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,21 @@ CELERY_BROKER_URL="redis://redis:6379/0"
CELERY_RESULT_BACKEND="redis://redis:6379/0"
CSRF_TRUSTED_ORIGINS="http://localhost:8000" # CHANGE_ME
GOOGLE_APPLICATION_CREDENTIALS="/app/secrets/google-credentials.json"
GOOGLE_AUTH_CLIENT_ID=""

# Uncomment and set the GOOGLE_AUTH_CLIENT_ID if you want to use Google authentication
# GOOGLE_AUTH_CLIENT_ID=""

IN_PRODUCTION="False"
LOGIN_REDIRECT_URL=""
LOGOUT_REDIRECT_URL=""
MICROSOFT_CLIENT_ID=""
MICROSOFT_CLIENT_SECRET=""
MICROSOFT_REDIRECT_URI=""
MS_AUTH_CLIENT_ID=""
MS_TENANT_ID=""

# Uncomment and set the following if you want to use Microsoft authentication
# MS_AUTH_CLIENT_ID=""
# MS_TENANT_ID=""

OIDC_AUTHENTICATION_CALLBACK_URL=""
OIDC_OP_AUTHORIZATION_ENDPOINT=""
OIDC_OP_JWKS_ENDPOINT=""
Expand Down Expand Up @@ -65,7 +71,6 @@ SWIRL_RAG_DISTRIBUTION_STRATEGY="RoundRobin"
SWIRL_SVC="swirl"
SWIRL_TEXT_SUMMARIZATION_URL="http://ttm:7029"
TIKA_SERVER_ENDPOINT="http://tika:9998"
WEBSOCKET_TIMEOUT="90000"

# Secrets
ADMIN_PASSWORD="" # CHANGE_ME
Expand Down
26 changes: 26 additions & 0 deletions scripts/com.swirl.service.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.swirl.service</string>

<key>ProgramArguments</key>
<array>
<string>{{SWIRL_SCRIPT_PATH}}</string>
</array>

<key>KeepAlive</key>
<false/>

<key>RunAtLoad</key>
<true/>

<key>StandardOutPath</key>
<string>{{HOME_LOG_PATH}}/tmp/log/swirl-service.out</string>

<key>StandardErrorPath</key>
<string>{{HOME_LOG_PATH}}/tmp/log/swirl-service.err</string>
</dict>
</plist>
15 changes: 0 additions & 15 deletions scripts/swirl-health-check.sh

This file was deleted.

2 changes: 2 additions & 0 deletions scripts/swirl-load-job.sh
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,5 @@ fi

# Load Swirl's initial data
python swirl.py load_data
python swirl.py reload_ai_prompts
python swirl.py load_branding
70 changes: 54 additions & 16 deletions scripts/swirl-service.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ set -e
# Disable X11 for GUI apps to avoid DBUS-related issues
export DBUS_SESSION_BUS_ADDRESS=/dev/null

# Find full path to Docker binary
export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
export DOCKER_BIN="$(command -v docker)"

# Logging function
function log() {
echo "[$(date +%Y-%m-%dT%H:%M:%S) ${STAGE}] $1"
Expand All @@ -16,10 +20,17 @@ function error() {
echo "[$(date +%Y-%m-%dT%H:%M:%S) ${STAGE} ERROR] $1"
}


# Ensure log directory exists and redirect output to log file
mkdir -p /var/log/swirl
exec > >(tee -a /var/log/swirl/swirl.log) 2>&1
if [[ "$OSTYPE" == "darwin"* ]]; then
LOG_DIR="$HOME/Library/Logs/swirl"
log "Creating base log directory for MacOS: $LOG_DIR"
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
LOG_DIR="/var/log/swirl"
log "Creating base log directory for Linux: $LOG_DIR"
fi
mkdir -p "$LOG_DIR"
log "Log directory successfully created."
exec > >(tee -a "$LOG_DIR/swirl.log") 2>&1

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
log "Script directory: $SCRIPT_DIR"
Expand All @@ -28,7 +39,7 @@ log "Parent directory: $PARENT_DIR"

SERVICE_SETUP_FLAG="$PARENT_DIR/.swirl-service-setup-complete.flag"
ENV_FILE="$PARENT_DIR/.env"
EXAMPLE_ENV_FILE="$PARENT_DIR/.env.example"
EXAMPLE_ENV_FILE="$PARENT_DIR/env.example"

# Create .env file from example if not present
if [ ! -f "$ENV_FILE" ]; then
Expand Down Expand Up @@ -83,17 +94,46 @@ else
fi

# check for local images
if docker inspect "swirlai/release-swirl-search-enterprise:${SWIRL_VERSION}" > /dev/null 2>&1; then
if "${DOCKER_BIN}" inspect "swirlai/release-swirl-search-enterprise:${SWIRL_VERSION}" > /dev/null 2>&1; then
log "Setup: Found local Swirl image swirlai/release-swirl-search-enterprise:${SWIRL_VERSION}"
else
log "Setup: Local Swirl image swirlai/release-swirl-search-enterprise:${SWIRL_VERSION} not found. Pulling images from Docker Hub."
docker compose --profile all pull --quiet
"${DOCKER_BIN}" compose -f $PARENT_DIR/docker-compose.yml --profile all pull --quiet
fi

log "Setup: Setup starting"
log "Setup: Setup starting..."
log "Setup: Enabling Swirl service to start on boot..."

if [[ "$OSTYPE" == "linux-gnu"* ]]; then
if [[ "$OSTYPE" == "darwin"* ]]; then
log "Setup: Running on macOS (user-level LaunchAgent)."

SERVICE_FILE="$SCRIPT_DIR/com.swirl.service.plist"
REPLACEMENT="$SCRIPT_DIR/swirl-service.sh"

log "Setup: Patching service .plist file to use $REPLACEMENT..."
sed -i '' "s|{{SWIRL_SCRIPT_PATH}}|$REPLACEMENT|g" "$SERVICE_FILE"
sed -i '' "s|{{HOME_LOG_PATH}}|$HOME|g" "$SERVICE_FILE"
log "Setup: Service .plist file successfully patched"

log "Setup: Copying service .plist file to ~/Library/LaunchAgents/"
cp "$SERVICE_FILE" ~/Library/LaunchAgents/com.swirl.service.plist
log "Service .plist file successfully copied to ~/Library/LaunchAgents/com.swirl.service.plist"

# Verifies if the current shell is a valid GUI session
if launchctl print "gui/$(id -u)" &>/dev/null; then
log "Setup: Session supports user-level LaunchAgent. Bootstrapping..."

launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.swirl.service.plist 2>/dev/null || true
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.swirl.service.plist
launchctl enable gui/$(id -u)/com.swirl.service

log "Setup: LaunchAgent bootstrapped successfully."
log "To start Swirl manually, run the following command in a terminal: 'launchctl kickstart -k gui/\$(id -u)/com.swirl.service'"
else
log "WARNING: Current shell is not a GUI session."
log "You must manually run the following command in a terminal: 'launchctl bootstrap gui/\$(id -u) ~/Library/LaunchAgents/com.swirl.service.plist'"
fi
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
log "Setup: Running on Linux."

if [ ! -f "/etc/systemd/system/swirl.service" ]; then
Expand All @@ -114,7 +154,7 @@ else
fi
systemctl enable swirl

log "Start Service via: systemctl start swirl "
log "Start Service via: systemctl start swirl"
log "Monitor Service via: journalctl -u swirl"

else
Expand All @@ -129,15 +169,14 @@ fi
# Base profile for Swirl services
COMPOSE_PROFILES=svc


# Stop previously running Swirl containers
log "Stopping any Swirl containers from previous run"
docker compose --profile all stop
"${DOCKER_BIN}" compose -f $PARENT_DIR/docker-compose.yml --profile all stop

# Conditionally add local Postgres
if [ "$USE_LOCAL_POSTGRES" == "true" ]; then
log "Local Postgres is enabled. Starting service."
(COMPOSE_PROFILES=db docker compose up --pull never -d)
(COMPOSE_PROFILES=db "${DOCKER_BIN}" compose -f $PARENT_DIR/docker-compose.yml up --pull never -d)
log "Started local Postgres service."
sleep 15
fi
Expand Down Expand Up @@ -166,8 +205,6 @@ if [ "$USE_NGINX" == "true" ]; then

log "DNS name $SWIRL_FQDN resolved after $WAITED seconds."



TEMPLATE_FILE="$PARENT_DIR/nginx/nginx-template.tls"
UPDATE_MARKER="# swirl-service updated: USE_TLS=true, USE_CERT=false"

Expand Down Expand Up @@ -261,13 +298,14 @@ fi
ONETIME_JOB_FLAG="$PARENT_DIR/.swirl-application-setup-job-complete.flag"
if [ -f "$ONETIME_JOB_FLAG" ]; then
log "Application setup job already completed. Skipping initial setup."
COMPOSE_PROFILES="$COMPOSE_PROFILES,reload"
else
log "Setiing up run one-time application setup job..."
log "Setting up run one-time application setup job..."
# Run the initial setup job
COMPOSE_PROFILES="$COMPOSE_PROFILES,setup"
touch "$ONETIME_JOB_FLAG"
fi

# Final startup
log "Docker Compose Up with profiles: $COMPOSE_PROFILES"
COMPOSE_PROFILES=$COMPOSE_PROFILES docker compose up --pull never
COMPOSE_PROFILES=$COMPOSE_PROFILES "${DOCKER_BIN}" compose -f $PARENT_DIR/docker-compose.yml up --pull never