mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-30 16:49:55 +08:00
chore: update config template (#15344)
This commit is contained in:
@@ -1,23 +0,0 @@
|
||||
# select a revision to deploy, available values: stable, beta, canary
|
||||
AFFINE_REVISION=stable
|
||||
|
||||
# set the port for the server container it will expose the server on
|
||||
PORT=3010
|
||||
|
||||
# set the host for the server for outgoing links
|
||||
# AFFINE_SERVER_HTTPS=true
|
||||
# AFFINE_SERVER_HOST=affine.yourdomain.com
|
||||
# or
|
||||
# AFFINE_SERVER_EXTERNAL_URL=https://affine.yourdomain.com
|
||||
|
||||
# position of the database data to persist
|
||||
DB_DATA_LOCATION=~/.affine/self-host/postgres/pgdata
|
||||
# position of the upload data(images, files, etc.) to persist
|
||||
UPLOAD_LOCATION=~/.affine/self-host/storage
|
||||
# position of the configuration files to persist
|
||||
CONFIG_LOCATION=~/.affine/self-host/config
|
||||
|
||||
# database credentials
|
||||
DB_USERNAME=affine
|
||||
DB_PASSWORD=
|
||||
DB_DATABASE=affine
|
||||
@@ -1,10 +1,10 @@
|
||||
name: affine
|
||||
services:
|
||||
affine:
|
||||
image: ghcr.io/toeverything/affine:${AFFINE_REVISION:-stable}
|
||||
image: ghcr.io/toeverything/affine:stable
|
||||
container_name: affine_server
|
||||
ports:
|
||||
- '${PORT:-3010}:3010'
|
||||
- '3010:3010'
|
||||
depends_on:
|
||||
redis:
|
||||
condition: service_healthy
|
||||
@@ -13,30 +13,24 @@ services:
|
||||
affine_migration:
|
||||
condition: service_completed_successfully
|
||||
volumes:
|
||||
# custom configurations
|
||||
- ${UPLOAD_LOCATION}:/root/.affine/storage
|
||||
- ${CONFIG_LOCATION}:/root/.affine/config
|
||||
env_file:
|
||||
- .env
|
||||
- ./data/storage:/root/.affine/storage
|
||||
- ./config:/root/.affine/config
|
||||
environment:
|
||||
- REDIS_SERVER_HOST=redis
|
||||
- DATABASE_URL=postgresql://${DB_USERNAME}:${DB_PASSWORD}@postgres:5432/${DB_DATABASE:-affine}
|
||||
- DATABASE_URL=postgresql://affine@postgres:5432/affine
|
||||
- AFFINE_INDEXER_ENABLED=false
|
||||
restart: unless-stopped
|
||||
|
||||
affine_migration:
|
||||
image: ghcr.io/toeverything/affine:${AFFINE_REVISION:-stable}
|
||||
image: ghcr.io/toeverything/affine:stable
|
||||
container_name: affine_migration_job
|
||||
volumes:
|
||||
# custom configurations
|
||||
- ${UPLOAD_LOCATION}:/root/.affine/storage
|
||||
- ${CONFIG_LOCATION}:/root/.affine/config
|
||||
- ./data/storage:/root/.affine/storage
|
||||
- ./config:/root/.affine/config
|
||||
command: ['sh', '-c', 'node ./scripts/self-host-predeploy.js']
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
- REDIS_SERVER_HOST=redis
|
||||
- DATABASE_URL=postgresql://${DB_USERNAME}:${DB_PASSWORD}@postgres:5432/${DB_DATABASE:-affine}
|
||||
- DATABASE_URL=postgresql://affine@postgres:5432/affine
|
||||
- AFFINE_INDEXER_ENABLED=false
|
||||
depends_on:
|
||||
postgres:
|
||||
@@ -58,18 +52,14 @@ services:
|
||||
image: pgvector/pgvector:pg16
|
||||
container_name: affine_postgres
|
||||
volumes:
|
||||
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
|
||||
- ./data/postgres:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_USER: ${DB_USERNAME}
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||
POSTGRES_DB: ${DB_DATABASE:-affine}
|
||||
POSTGRES_USER: affine
|
||||
POSTGRES_DB: affine
|
||||
POSTGRES_INITDB_ARGS: '--data-checksums'
|
||||
# you better set a password for you database
|
||||
# or you may add 'POSTGRES_HOST_AUTH_METHOD=trust' to ignore postgres security policy
|
||||
POSTGRES_HOST_AUTH_METHOD: trust
|
||||
healthcheck:
|
||||
test:
|
||||
['CMD', 'pg_isready', '-U', "${DB_USERNAME}", '-d', "${DB_DATABASE:-affine}"]
|
||||
test: ['CMD', 'pg_isready', '-U', 'affine', '-d', 'affine']
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"$schema": "https://github.com/toeverything/affine/releases/latest/download/config.schema.json",
|
||||
"server": {
|
||||
"name": "AFFiNE Self-hosted",
|
||||
"externalUrl": "http://localhost:3010"
|
||||
},
|
||||
"copilot": {
|
||||
"enabled": true,
|
||||
"byok": {
|
||||
"enabled": true,
|
||||
"allowCustomEndpoint": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1140,17 +1140,17 @@
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to enable the copilot plugin. <br> Document: <a href=\"https://docs.affine.pro/self-host-affine/administer/ai\" target=\"_blank\">https://docs.affine.pro/self-host-affine/administer/ai</a>\n@default false",
|
||||
"description": "Enable AI features. Workspace owners configure provider keys in Workspace Settings → Integrations → AI BYOK.\n@default false",
|
||||
"default": false
|
||||
},
|
||||
"byok.enabled": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to enable workspace BYOK.\n@default true",
|
||||
"description": "Allow workspace owners and admins to configure AI provider keys through AI BYOK.\n@default true",
|
||||
"default": true
|
||||
},
|
||||
"byok.allowedProviders": {
|
||||
"type": "array",
|
||||
"description": "The allowlist for workspace BYOK providers.\n@default [\"openai\",\"anthropic\",\"gemini\",\"fal\"]",
|
||||
"description": "AI providers that workspace owners and admins may add through AI BYOK.\n@default [\"openai\",\"anthropic\",\"gemini\",\"fal\"]",
|
||||
"default": [
|
||||
"openai",
|
||||
"anthropic",
|
||||
@@ -1160,7 +1160,7 @@
|
||||
},
|
||||
"byok.allowCustomEndpoint": {
|
||||
"type": "boolean",
|
||||
"description": "Whether workspace BYOK custom endpoints are accepted.\n@default false",
|
||||
"description": "Allow AI BYOK keys to use a custom provider endpoint.\n@default false",
|
||||
"default": false
|
||||
},
|
||||
"byok.allowPrivateEndpoint": {
|
||||
|
||||
@@ -413,7 +413,7 @@ jobs:
|
||||
- name: Copy Selfhost Release Files
|
||||
run: |
|
||||
cp ./.docker/selfhost/compose.yml ./release/docker-compose.yml
|
||||
cp ./.docker/selfhost/.env.example ./release/.env.example
|
||||
cp ./.docker/selfhost/config.json.example ./release/config.json.example
|
||||
cp ./.docker/selfhost/schema.json ./release/config.schema.json
|
||||
- name: Generate Release yml
|
||||
run: |
|
||||
|
||||
@@ -217,21 +217,21 @@ declare global {
|
||||
|
||||
defineModuleConfig('copilot', {
|
||||
enabled: {
|
||||
desc: 'Whether to enable the copilot plugin. <br> Document: <a href="https://docs.affine.pro/self-host-affine/administer/ai" target="_blank">https://docs.affine.pro/self-host-affine/administer/ai</a>',
|
||||
desc: 'Enable AI features. Workspace owners configure provider keys in Workspace Settings → Integrations → AI BYOK.',
|
||||
default: false,
|
||||
},
|
||||
'byok.enabled': {
|
||||
desc: 'Whether to enable workspace BYOK.',
|
||||
desc: 'Allow workspace owners and admins to configure AI provider keys through AI BYOK.',
|
||||
default: true,
|
||||
shape: z.boolean(),
|
||||
},
|
||||
'byok.allowedProviders': {
|
||||
desc: 'The allowlist for workspace BYOK providers.',
|
||||
desc: 'AI providers that workspace owners and admins may add through AI BYOK.',
|
||||
default: ['openai', 'anthropic', 'gemini', 'fal'],
|
||||
shape: z.array(z.enum(['openai', 'anthropic', 'gemini', 'fal'])),
|
||||
},
|
||||
'byok.allowCustomEndpoint': {
|
||||
desc: 'Whether workspace BYOK custom endpoints are accepted.',
|
||||
desc: 'Allow AI BYOK keys to use a custom provider endpoint.',
|
||||
default: false,
|
||||
shape: z.boolean(),
|
||||
},
|
||||
|
||||
@@ -33,9 +33,6 @@ export const Workspaces = lazy(
|
||||
export const Queue = lazy(
|
||||
() => import(/* webpackChunkName: "queue" */ './modules/queue')
|
||||
);
|
||||
export const AI = lazy(
|
||||
() => import(/* webpackChunkName: "ai" */ './modules/ai')
|
||||
);
|
||||
export const About = lazy(
|
||||
() => import(/* webpackChunkName: "about" */ './modules/about')
|
||||
);
|
||||
@@ -131,7 +128,12 @@ export const App = () => {
|
||||
}
|
||||
/>
|
||||
<Route path={`${ROUTES.admin.queue}/*`} element={<Queue />} />
|
||||
<Route path={ROUTES.admin.ai} element={<AI />} />
|
||||
<Route
|
||||
path={ROUTES.admin.ai}
|
||||
element={
|
||||
<Navigate to={ROUTES.admin.settings.index} replace />
|
||||
}
|
||||
/>
|
||||
<Route path={ROUTES.admin.about} element={<About />} />
|
||||
<Route
|
||||
path={ROUTES.admin.settings.index}
|
||||
|
||||
@@ -367,19 +367,19 @@
|
||||
"copilot": {
|
||||
"enabled": {
|
||||
"type": "Boolean",
|
||||
"desc": "Whether to enable the copilot plugin. <br> Document: <a href=\"https://docs.affine.pro/self-host-affine/administer/ai\" target=\"_blank\">https://docs.affine.pro/self-host-affine/administer/ai</a>"
|
||||
"desc": "Enable AI features. Workspace owners configure provider keys in Workspace Settings → Integrations → AI BYOK."
|
||||
},
|
||||
"byok.enabled": {
|
||||
"type": "Boolean",
|
||||
"desc": "Whether to enable workspace BYOK."
|
||||
"desc": "Allow workspace owners and admins to configure AI provider keys through AI BYOK."
|
||||
},
|
||||
"byok.allowedProviders": {
|
||||
"type": "Array",
|
||||
"desc": "The allowlist for workspace BYOK providers."
|
||||
"desc": "AI providers that workspace owners and admins may add through AI BYOK."
|
||||
},
|
||||
"byok.allowCustomEndpoint": {
|
||||
"type": "Boolean",
|
||||
"desc": "Whether workspace BYOK custom endpoints are accepted."
|
||||
"desc": "Allow AI BYOK keys to use a custom provider endpoint."
|
||||
},
|
||||
"byok.allowPrivateEndpoint": {
|
||||
"type": "Boolean",
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
import { Switch } from '@affine/admin/components/ui/switch';
|
||||
import { cn } from '@affine/admin/utils';
|
||||
import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { Header } from '../header';
|
||||
|
||||
function AiPage() {
|
||||
const [enableAi, setEnableAi] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="h-dvh flex-1 flex-col flex">
|
||||
<Header title="AI" />
|
||||
<ScrollAreaPrimitive.Root
|
||||
className={cn('relative overflow-hidden w-full')}
|
||||
>
|
||||
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit] [&>div]:!block">
|
||||
<div className="p-6 max-w-3xl mx-auto">
|
||||
<div className="text-[20px]">AI</div>
|
||||
<div className="flex justify-between items-center">
|
||||
<div>
|
||||
<p className="text-sm font-medium mt-6">Enable AI</p>
|
||||
<p className="text-sm text-muted-foreground mt-1">
|
||||
AI functionality is not currently supported. Self-hosted AI
|
||||
support is in progress.
|
||||
</p>
|
||||
</div>
|
||||
<Switch
|
||||
checked={enableAi}
|
||||
onCheckedChange={setEnableAi}
|
||||
disabled={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</ScrollAreaPrimitive.Viewport>
|
||||
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
||||
className={cn(
|
||||
'flex touch-none select-none transition-colors',
|
||||
'h-full w-2.5 border-l border-l-transparent p-[1px]'
|
||||
)}
|
||||
>
|
||||
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
|
||||
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||
<ScrollAreaPrimitive.Corner />
|
||||
</ScrollAreaPrimitive.Root>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export { AiPage as Component };
|
||||
@@ -1,69 +0,0 @@
|
||||
import { Button } from '@affine/admin/components/ui/button';
|
||||
import { Input } from '@affine/admin/components/ui/input';
|
||||
import { Label } from '@affine/admin/components/ui/label';
|
||||
import { Separator } from '@affine/admin/components/ui/separator';
|
||||
import { useState } from 'react';
|
||||
|
||||
export function Keys() {
|
||||
const [openAIKey, setOpenAIKey] = useState('');
|
||||
const [falAIKey, setFalAIKey] = useState('');
|
||||
const [unsplashKey, setUnsplashKey] = useState('');
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-full gap-3 py-5 px-6 w-full">
|
||||
<div className="flex items-center">
|
||||
<span className="text-xl font-semibold">Keys</span>
|
||||
</div>
|
||||
<div className="flex-grow overflow-y-auto space-y-[10px]">
|
||||
<div className="flex flex-col rounded-md border py-4 gap-4">
|
||||
<div className="px-5 space-y-3">
|
||||
<Label className="text-sm font-medium">OpenAI Key</Label>
|
||||
<div className="flex items-center gap-2">
|
||||
<Input
|
||||
type="text"
|
||||
className="py-2 px-3 text-base font-normal placeholder:opacity-50"
|
||||
value={openAIKey}
|
||||
placeholder="sk-xxxxxxxxxxxxx-xxxxxxxxxxxxxx"
|
||||
onChange={e => setOpenAIKey(e.target.value)}
|
||||
/>
|
||||
<Button disabled>Save</Button>
|
||||
</div>
|
||||
</div>
|
||||
<Separator />
|
||||
<div className="px-5 space-y-3">
|
||||
<Label className="text-sm font-medium">Fal.AI Key</Label>
|
||||
<div className="flex items-center gap-2">
|
||||
<Input
|
||||
type="email"
|
||||
className="py-2 px-3 ext-base font-normal placeholder:opacity-50"
|
||||
value={falAIKey}
|
||||
placeholder="00000000-0000-0000-00000000:xxxxxxxxxxxxxxxxx"
|
||||
onChange={e => setFalAIKey(e.target.value)}
|
||||
/>
|
||||
<Button disabled>Save</Button>
|
||||
</div>
|
||||
</div>
|
||||
<Separator />
|
||||
<div className="px-5 space-y-3">
|
||||
<Label className="text-sm font-medium">Unsplash Key</Label>
|
||||
<div className="flex items-center gap-2">
|
||||
<Input
|
||||
type="password"
|
||||
className="py-2 px-3 ext-base font-normal placeholder:opacity-50"
|
||||
value={unsplashKey}
|
||||
placeholder="00000000-0000-0000-00000000:xxxxxxxxxxxxxxxxx"
|
||||
onChange={e => setUnsplashKey(e.target.value)}
|
||||
/>
|
||||
<Button disabled>Save</Button>
|
||||
</div>
|
||||
</div>
|
||||
<Separator />
|
||||
<div className="px-5 space-y-3 text-sm font-normal text-muted-foreground">
|
||||
Custom API keys may not perform as expected. AFFiNE does not
|
||||
guarantee results when using custom API keys.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -58,12 +58,6 @@ export function Nav({ isCollapsed = false }: NavProps) {
|
||||
label="Queue"
|
||||
isCollapsed={isCollapsed}
|
||||
/>
|
||||
{/* <NavItem
|
||||
to="/admin/ai"
|
||||
icon={<AiOutlineIcon fontSize={20} />}
|
||||
label="AI"
|
||||
isCollapsed={isCollapsed}
|
||||
/> */}
|
||||
<SettingsItem isCollapsed={isCollapsed} />
|
||||
<NavItem
|
||||
to={ROUTES.admin.about}
|
||||
|
||||
@@ -147,34 +147,19 @@ export const KNOWN_CONFIG_GROUPS = [
|
||||
fields: ['providers.google', 'providers.github', 'providers.oidc'],
|
||||
} as ConfigGroup<'oauth'>,
|
||||
{
|
||||
name: 'AI',
|
||||
name: 'AI BYOK',
|
||||
module: 'copilot',
|
||||
fields: [
|
||||
'enabled',
|
||||
'providers.openai',
|
||||
'providers.gemini',
|
||||
'providers.anthropic',
|
||||
'providers.fal',
|
||||
'unsplash',
|
||||
'exa',
|
||||
{
|
||||
key: 'storage',
|
||||
desc: 'The storage provider for copilot blobs',
|
||||
sub: 'provider',
|
||||
type: 'Enum',
|
||||
options: ['fs', 'aws-s3', 'cloudflare-r2'],
|
||||
key: 'enabled',
|
||||
desc: 'Enable AI features. Workspace owners configure provider keys in Workspace Settings → Integrations → AI BYOK.',
|
||||
},
|
||||
'byok.enabled',
|
||||
'byok.allowedProviders',
|
||||
'byok.allowCustomEndpoint',
|
||||
{
|
||||
key: 'storage',
|
||||
sub: 'bucket',
|
||||
type: 'String',
|
||||
desc: 'The bucket name for copilot blobs storage',
|
||||
},
|
||||
{
|
||||
key: 'storage',
|
||||
sub: 'config',
|
||||
type: 'JSON',
|
||||
desc: 'The S3 compatible config for the storage provider (endpoint/region/credentials).',
|
||||
key: 'byok.allowPrivateEndpoint',
|
||||
desc: 'Allow workspace owners and admins to connect BYOK providers on private network endpoints. Only enable this for trusted workspaces.',
|
||||
},
|
||||
],
|
||||
} as ConfigGroup<'copilot'>,
|
||||
|
||||
Reference in New Issue
Block a user