Remove copilot env overrides and add config placeholders
This commit is contained in:
13
BUILD.md
13
BUILD.md
@@ -13,14 +13,14 @@ cloudron build \
|
|||||||
--set-build-service builder.docker.due.ren \
|
--set-build-service builder.docker.due.ren \
|
||||||
--build-service-token e3265de06b1d0e7bb38400539012a8433a74c2c96a17955e \
|
--build-service-token e3265de06b1d0e7bb38400539012a8433a74c2c96a17955e \
|
||||||
--set-repository andreasdueren/affine-cloudron \
|
--set-repository andreasdueren/affine-cloudron \
|
||||||
--tag 0.25.5-5
|
--tag 0.25.5-6
|
||||||
```
|
```
|
||||||
|
|
||||||
## Deployment Steps
|
## Deployment Steps
|
||||||
1. Remove any previous dev install of AFFiNE on the Cloudron (always reinstall from scratch).
|
1. Remove any previous dev install of AFFiNE on the Cloudron (always reinstall from scratch).
|
||||||
2. Install the freshly built image:
|
2. Install the freshly built image:
|
||||||
```bash
|
```bash
|
||||||
cloudron install --location affine.due.ren --image andreasdueren/affine-cloudron:0.25.5-5
|
cloudron install --location affine.due.ren --image andreasdueren/affine-cloudron:0.25.5-6
|
||||||
```
|
```
|
||||||
3. When prompted, confirm the app info and wait for Cloudron to report success (abort after ~30 seconds if installation stalls or errors to avoid hanging sessions).
|
3. When prompted, confirm the app info and wait for Cloudron to report success (abort after ~30 seconds if installation stalls or errors to avoid hanging sessions).
|
||||||
4. Visit `https://affine.due.ren` (or the chosen location) and sign in using Cloudron SSO.
|
4. Visit `https://affine.due.ren` (or the chosen location) and sign in using Cloudron SSO.
|
||||||
@@ -42,11 +42,4 @@ cloudron install --location affine.due.ren --image andreasdueren/affine-cloudron
|
|||||||
- Persistent config lives in `/app/data/config/config.json`. Modify values (e.g., Stripe, throttling) and restart the app; the file is backed up by Cloudron.
|
- Persistent config lives in `/app/data/config/config.json`. Modify values (e.g., Stripe, throttling) and restart the app; the file is backed up by Cloudron.
|
||||||
- Uploaded files live in `/app/data/storage` and map to `~/.affine/storage` inside the runtime.
|
- Uploaded files live in `/app/data/storage` and map to `~/.affine/storage` inside the runtime.
|
||||||
- Default health check hits `/api/healthz`; customize via `CloudronManifest.json` if upstream changes.
|
- Default health check hits `/api/healthz`; customize via `CloudronManifest.json` if upstream changes.
|
||||||
- Copilot providers can be configured with environment variables instead of editing `config.json`. Set any of the following via `cloudron env set --app affine.due.ren KEY=value` and restart:
|
- Copilot API keys live in `/app/data/config/config.json`. The default file contains placeholders (`sk-provide-openai-key-here`, etc.); open it in the Cloudron File Manager or via `cloudron exec` to paste your own values, then restart the app so AFFiNE picks up the changes.
|
||||||
- `AFFINE_COPILOT_ENABLED` (`true`/`false`)
|
|
||||||
- `AFFINE_COPILOT_OPENAI_API_KEY`, `AFFINE_COPILOT_OPENAI_BASE_URL`
|
|
||||||
- `AFFINE_COPILOT_ANTHROPIC_API_KEY`, `AFFINE_COPILOT_ANTHROPIC_BASE_URL`
|
|
||||||
- `AFFINE_COPILOT_GEMINI_API_KEY`, `AFFINE_COPILOT_GEMINI_BASE_URL`
|
|
||||||
- `AFFINE_COPILOT_EXA_KEY` for web search
|
|
||||||
- `AFFINE_COPILOT_SCENARIOS_JSON` with a JSON payload such as `{"override_enabled":true,"scenarios":{"chat":"gpt-4o-mini"}}`
|
|
||||||
- A sample `.env` file is available at `/app/data/copilot.env.example` after install; download/edit it for reference before populating Cloudron env variables.
|
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
"description": "Next-gen knowledge base that blends docs, whiteboards, and databases for self-hosted teams.",
|
"description": "Next-gen knowledge base that blends docs, whiteboards, and databases for self-hosted teams.",
|
||||||
"website": "https://affine.pro",
|
"website": "https://affine.pro",
|
||||||
"contactEmail": "support@affine.pro",
|
"contactEmail": "support@affine.pro",
|
||||||
"version": "0.25.5-5",
|
"version": "0.25.5-6",
|
||||||
"upstreamVersion": "0.25.5",
|
"upstreamVersion": "0.25.5",
|
||||||
"changelog": "Auto seed Manticore tables (without external morphology packs)",
|
"changelog": "Configure copilot via config.json placeholders; env overrides removed",
|
||||||
"icon": "file://icon.png",
|
"icon": "file://icon.png",
|
||||||
"manifestVersion": 2,
|
"manifestVersion": 2,
|
||||||
"minBoxVersion": "7.0.0",
|
"minBoxVersion": "7.0.0",
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ COPY run-buddy.sh "$APP_CODE_DIR/run-buddy.sh"
|
|||||||
COPY nginx.conf "$APP_CODE_DIR/nginx.conf"
|
COPY nginx.conf "$APP_CODE_DIR/nginx.conf"
|
||||||
COPY supervisord.conf "$APP_CODE_DIR/supervisord.conf"
|
COPY supervisord.conf "$APP_CODE_DIR/supervisord.conf"
|
||||||
COPY config.example.json "$APP_CODE_DIR/config.example.json"
|
COPY config.example.json "$APP_CODE_DIR/config.example.json"
|
||||||
COPY copilot.env.example "$APP_CODE_DIR/copilot.env.example"
|
|
||||||
COPY tmp_data/ "$APP_TMP_DIR/"
|
COPY tmp_data/ "$APP_TMP_DIR/"
|
||||||
COPY manticore/ "$APP_CODE_DIR/manticore/"
|
COPY manticore/ "$APP_CODE_DIR/manticore/"
|
||||||
|
|
||||||
|
|||||||
@@ -2,5 +2,38 @@
|
|||||||
"$schema": "https://github.com/toeverything/AFFiNE/releases/latest/download/config.schema.json",
|
"$schema": "https://github.com/toeverything/AFFiNE/releases/latest/download/config.schema.json",
|
||||||
"server": {
|
"server": {
|
||||||
"name": "AFFiNE Self Hosted Server"
|
"name": "AFFiNE Self Hosted Server"
|
||||||
|
},
|
||||||
|
"copilot": {
|
||||||
|
"enabled": true,
|
||||||
|
"scenarios": {
|
||||||
|
"override_enabled": true,
|
||||||
|
"scenarios": {
|
||||||
|
"audio_transcribing": "gemini-2.5-flash",
|
||||||
|
"chat": "gemini-2.5-flash",
|
||||||
|
"embedding": "gemini-embedding-001",
|
||||||
|
"image": "gpt-image-1",
|
||||||
|
"rerank": "gpt-4.1",
|
||||||
|
"coding": "claude-sonnet-4-5@20250929",
|
||||||
|
"complex_text_generation": "gpt-4o-2024-08-06",
|
||||||
|
"quick_decision_making": "gpt-5-mini",
|
||||||
|
"quick_text_generation": "gemini-2.5-flash",
|
||||||
|
"polish_and_summarize": "gemini-2.5-flash"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"providers.openai": {
|
||||||
|
"apiKey": "sk-provide-openai-key-here",
|
||||||
|
"baseURL": "https://api.openai.com/v1"
|
||||||
|
},
|
||||||
|
"providers.anthropic": {
|
||||||
|
"apiKey": "sk-ant-provide-anthropic-key-here",
|
||||||
|
"baseURL": "https://api.anthropic.com/v1"
|
||||||
|
},
|
||||||
|
"providers.gemini": {
|
||||||
|
"apiKey": "provide-gemini-key-here",
|
||||||
|
"baseURL": "https://generativelanguage.googleapis.com/v1beta"
|
||||||
|
},
|
||||||
|
"exa": {
|
||||||
|
"key": "provide-exa-key-or-leave-empty"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
# AFFiNE Copilot sample environment overrides
|
|
||||||
# Copy this file to .env (or use Cloudron's env UI) and adjust values.
|
|
||||||
|
|
||||||
# Toggle Copilot globally (true/false).
|
|
||||||
AFFINE_COPILOT_ENABLED=true
|
|
||||||
|
|
||||||
# OpenAI-compatible provider (Official OpenAI, OpenRouter, local proxy, etc.).
|
|
||||||
AFFINE_COPILOT_OPENAI_API_KEY=sk-your-openai-key
|
|
||||||
AFFINE_COPILOT_OPENAI_BASE_URL=https://api.openai.com/v1
|
|
||||||
|
|
||||||
# Anthropic Claude provider.
|
|
||||||
AFFINE_COPILOT_ANTHROPIC_API_KEY=sk-ant-your-key
|
|
||||||
AFFINE_COPILOT_ANTHROPIC_BASE_URL=https://api.anthropic.com/v1
|
|
||||||
|
|
||||||
# Google Gemini provider (API key or reverse proxy).
|
|
||||||
AFFINE_COPILOT_GEMINI_API_KEY=your-gemini-key
|
|
||||||
AFFINE_COPILOT_GEMINI_BASE_URL=https://generativelanguage.googleapis.com/v1beta
|
|
||||||
|
|
||||||
# Optional Exa web search key for Copilot browsing.
|
|
||||||
AFFINE_COPILOT_EXA_KEY=exa-key
|
|
||||||
|
|
||||||
# Override the scenario/model mapping by providing JSON.
|
|
||||||
# Example keeps override_enabled true and customizes a few models.
|
|
||||||
AFFINE_COPILOT_SCENARIOS_JSON={"override_enabled":true,"scenarios":{"chat":"gpt-4o-mini","coding":"claude-3-5-sonnet-20241022","embedding":"text-embedding-3-large","quick_text_generation":"gpt-4o-mini"}}
|
|
||||||
88
start.sh
88
start.sh
@@ -46,13 +46,6 @@ prepare_data_dirs() {
|
|||||||
cp "$APP_TMP_DIR/config/config.json" "$APP_DATA_DIR/config/config.json"
|
cp "$APP_TMP_DIR/config/config.json" "$APP_DATA_DIR/config/config.json"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local sample_env_src="$APP_CODE_DIR/copilot.env.example"
|
|
||||||
local sample_env_dest="$APP_DATA_DIR/copilot.env.example"
|
|
||||||
if [ -f "$sample_env_src" ] && [ ! -f "$sample_env_dest" ]; then
|
|
||||||
cp "$sample_env_src" "$sample_env_dest"
|
|
||||||
chown cloudron:cloudron "$sample_env_dest"
|
|
||||||
fi
|
|
||||||
|
|
||||||
local storage_contents=""
|
local storage_contents=""
|
||||||
if [ -d "$APP_DATA_DIR/storage" ]; then
|
if [ -d "$APP_DATA_DIR/storage" ]; then
|
||||||
storage_contents=$(ls -A "$APP_DATA_DIR/storage" 2>/dev/null || true)
|
storage_contents=$(ls -A "$APP_DATA_DIR/storage" 2>/dev/null || true)
|
||||||
@@ -360,86 +353,6 @@ PY
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
configure_copilot_env_overrides() {
|
|
||||||
local config_path="$APP_DATA_DIR/config/config.json"
|
|
||||||
if [ ! -f "$config_path" ]; then
|
|
||||||
log "Copilot config file not found at ${config_path}, skipping env overrides"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
python3 - "$config_path" <<'PY'
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
path = Path(sys.argv[1])
|
|
||||||
data = json.loads(path.read_text())
|
|
||||||
copilot = data.setdefault('copilot', {})
|
|
||||||
changed = False
|
|
||||||
|
|
||||||
def set_nested(keys, value):
|
|
||||||
global changed
|
|
||||||
ref = copilot
|
|
||||||
for key in keys[:-1]:
|
|
||||||
ref = ref.setdefault(key, {})
|
|
||||||
if ref.get(keys[-1]) != value:
|
|
||||||
ref[keys[-1]] = value
|
|
||||||
print(f"[copilot] Set {'.'.join(keys)} from environment")
|
|
||||||
changed = True
|
|
||||||
|
|
||||||
def coerce_bool(value):
|
|
||||||
if isinstance(value, bool):
|
|
||||||
return value
|
|
||||||
v = value.strip().lower()
|
|
||||||
if v in ('1', 'true', 'yes', 'on'):
|
|
||||||
return True
|
|
||||||
if v in ('0', 'false', 'no', 'off'):
|
|
||||||
return False
|
|
||||||
raise ValueError(f"Invalid boolean value: {value}")
|
|
||||||
|
|
||||||
mapping = [
|
|
||||||
('AFFINE_COPILOT_ENABLED', ('enabled',), coerce_bool),
|
|
||||||
('AFFINE_COPILOT_OPENAI_API_KEY', ('providers.openai', 'apiKey'), str),
|
|
||||||
('AFFINE_COPILOT_OPENAI_BASE_URL', ('providers.openai', 'baseURL'), str),
|
|
||||||
('AFFINE_COPILOT_ANTHROPIC_API_KEY', ('providers.anthropic', 'apiKey'), str),
|
|
||||||
('AFFINE_COPILOT_ANTHROPIC_BASE_URL', ('providers.anthropic', 'baseURL'), str),
|
|
||||||
('AFFINE_COPILOT_GEMINI_API_KEY', ('providers.gemini', 'apiKey'), str),
|
|
||||||
('AFFINE_COPILOT_GEMINI_BASE_URL', ('providers.gemini', 'baseURL'), str),
|
|
||||||
('AFFINE_COPILOT_EXA_KEY', ('exa', 'key'), str),
|
|
||||||
]
|
|
||||||
|
|
||||||
for env_name, path_keys, caster in mapping:
|
|
||||||
value = os.environ.get(env_name)
|
|
||||||
if not value:
|
|
||||||
continue
|
|
||||||
try:
|
|
||||||
coerced = caster(value)
|
|
||||||
except Exception as exc:
|
|
||||||
print(f"[copilot] Skipping {env_name}: {exc}", flush=True)
|
|
||||||
continue
|
|
||||||
set_nested(path_keys, coerced)
|
|
||||||
|
|
||||||
scenarios_json = os.environ.get('AFFINE_COPILOT_SCENARIOS_JSON')
|
|
||||||
if scenarios_json:
|
|
||||||
try:
|
|
||||||
payload = json.loads(scenarios_json)
|
|
||||||
if not isinstance(payload, dict) or 'scenarios' not in payload:
|
|
||||||
raise ValueError("JSON must contain a 'scenarios' object")
|
|
||||||
except Exception as exc:
|
|
||||||
print(f"[copilot] Invalid AFFINE_COPILOT_SCENARIOS_JSON: {exc}", flush=True)
|
|
||||||
else:
|
|
||||||
copilot.setdefault('scenarios', {})
|
|
||||||
copilot['scenarios']['override_enabled'] = payload.get('override_enabled', True)
|
|
||||||
copilot['scenarios']['scenarios'] = payload['scenarios']
|
|
||||||
print("[copilot] Applied scenarios override from AFFINE_COPILOT_SCENARIOS_JSON")
|
|
||||||
changed = True
|
|
||||||
|
|
||||||
if changed:
|
|
||||||
path.write_text(json.dumps(data, indent=2))
|
|
||||||
PY
|
|
||||||
log "Applied copilot env configuration overrides (if any)"
|
|
||||||
}
|
|
||||||
|
|
||||||
update_server_config() {
|
update_server_config() {
|
||||||
python3 - <<'PY'
|
python3 - <<'PY'
|
||||||
import json
|
import json
|
||||||
@@ -472,7 +385,6 @@ main() {
|
|||||||
configure_indexer
|
configure_indexer
|
||||||
update_server_config
|
update_server_config
|
||||||
configure_auth
|
configure_auth
|
||||||
configure_copilot_env_overrides
|
|
||||||
chown -R cloudron:cloudron "$APP_DATA_DIR" "$APP_HOME_DIR"
|
chown -R cloudron:cloudron "$APP_DATA_DIR" "$APP_HOME_DIR"
|
||||||
log "Starting supervisor"
|
log "Starting supervisor"
|
||||||
exec /usr/bin/supervisord -c "$APP_CODE_DIR/supervisord.conf"
|
exec /usr/bin/supervisord -c "$APP_CODE_DIR/supervisord.conf"
|
||||||
|
|||||||
@@ -2,5 +2,38 @@
|
|||||||
"$schema": "https://github.com/toeverything/AFFiNE/releases/latest/download/config.schema.json",
|
"$schema": "https://github.com/toeverything/AFFiNE/releases/latest/download/config.schema.json",
|
||||||
"server": {
|
"server": {
|
||||||
"name": "AFFiNE Self Hosted Server"
|
"name": "AFFiNE Self Hosted Server"
|
||||||
|
},
|
||||||
|
"copilot": {
|
||||||
|
"enabled": true,
|
||||||
|
"scenarios": {
|
||||||
|
"override_enabled": true,
|
||||||
|
"scenarios": {
|
||||||
|
"audio_transcribing": "gemini-2.5-flash",
|
||||||
|
"chat": "gemini-2.5-flash",
|
||||||
|
"embedding": "gemini-embedding-001",
|
||||||
|
"image": "gpt-image-1",
|
||||||
|
"rerank": "gpt-4.1",
|
||||||
|
"coding": "claude-sonnet-4-5@20250929",
|
||||||
|
"complex_text_generation": "gpt-4o-2024-08-06",
|
||||||
|
"quick_decision_making": "gpt-5-mini",
|
||||||
|
"quick_text_generation": "gemini-2.5-flash",
|
||||||
|
"polish_and_summarize": "gemini-2.5-flash"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"providers.openai": {
|
||||||
|
"apiKey": "sk-provide-openai-key-here",
|
||||||
|
"baseURL": "https://api.openai.com/v1"
|
||||||
|
},
|
||||||
|
"providers.anthropic": {
|
||||||
|
"apiKey": "sk-ant-provide-anthropic-key-here",
|
||||||
|
"baseURL": "https://api.anthropic.com/v1"
|
||||||
|
},
|
||||||
|
"providers.gemini": {
|
||||||
|
"apiKey": "provide-gemini-key-here",
|
||||||
|
"baseURL": "https://generativelanguage.googleapis.com/v1beta"
|
||||||
|
},
|
||||||
|
"exa": {
|
||||||
|
"key": "provide-exa-key-or-leave-empty"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user