156 lines
4.6 KiB
TypeScript
156 lines
4.6 KiB
TypeScript
// Application configuration
|
|
export interface AppConfig {
|
|
adminDid: string;
|
|
adminHandle: string;
|
|
aiDid: string;
|
|
aiHandle: string;
|
|
aiDisplayName: string;
|
|
aiAvatar: string;
|
|
aiDescription: string;
|
|
collections: {
|
|
base: string; // Base collection like "ai.syui.log"
|
|
};
|
|
host: string;
|
|
rkey?: string; // Current post rkey if on post page
|
|
aiEnabled: boolean;
|
|
aiAskAi: boolean;
|
|
aiProvider: string;
|
|
aiModel: string;
|
|
aiHost: string;
|
|
aiSystemPrompt: string;
|
|
allowedHandles: string[]; // Handles allowed for OAuth authentication
|
|
atprotoPds: string; // Configured PDS for admin/ai handles
|
|
// Legacy - prefer per-user PDS detection
|
|
bskyPublicApi: string;
|
|
atprotoApi: string;
|
|
}
|
|
|
|
// Collection name builders (similar to Rust implementation)
|
|
export function getCollectionNames(base: string) {
|
|
if (!base) {
|
|
// Fallback to default
|
|
base = 'ai.syui.log';
|
|
}
|
|
|
|
const collections = {
|
|
comment: base,
|
|
user: `${base}.user`,
|
|
chat: `${base}.chat`,
|
|
chatLang: `${base}.chat.lang`,
|
|
chatComment: `${base}.chat.comment`,
|
|
};
|
|
|
|
return collections;
|
|
}
|
|
|
|
// Generate collection names from host
|
|
// Format: ${reg}.${name}.${sub}
|
|
// Example: log.syui.ai -> ai.syui.log
|
|
function generateBaseCollectionFromHost(host: string): string {
|
|
try {
|
|
// Remove protocol if present
|
|
const cleanHost = host.replace(/^https?:\/\//, '');
|
|
|
|
// Split host into parts
|
|
const parts = cleanHost.split('.');
|
|
|
|
if (parts.length < 2) {
|
|
throw new Error('Invalid host format');
|
|
}
|
|
|
|
// Reverse the parts for collection naming
|
|
// log.syui.ai -> ai.syui.log
|
|
const reversedParts = parts.reverse();
|
|
const result = reversedParts.join('.');
|
|
return result;
|
|
} catch (error) {
|
|
// Fallback to default
|
|
return 'ai.syui.log';
|
|
}
|
|
}
|
|
|
|
// Extract rkey from current URL
|
|
// /posts/xxx -> xxx (remove .html if present)
|
|
function extractRkeyFromUrl(): string | undefined {
|
|
const pathname = window.location.pathname;
|
|
const match = pathname.match(/\/posts\/([^/]+)\/?$/);
|
|
if (match) {
|
|
// Remove .html extension if present
|
|
return match[1].replace(/\.html$/, '');
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
// Get application configuration from environment variables
|
|
export function getAppConfig(): AppConfig {
|
|
const host = import.meta.env.VITE_APP_HOST || 'https://log.syui.ai';
|
|
const adminDid = import.meta.env.VITE_ADMIN_DID || 'did:plc:uqzpqmrjnptsxezjx4xuh2mn';
|
|
const adminHandle = import.meta.env.VITE_ADMIN_HANDLE || 'syui.ai';
|
|
const aiDid = import.meta.env.VITE_AI_DID || 'did:plc:4hqjfn7m6n5hno3doamuhgef';
|
|
const aiHandle = import.meta.env.VITE_AI_HANDLE || 'yui.syui.ai';
|
|
const aiDisplayName = import.meta.env.VITE_AI_DISPLAY_NAME || 'ai';
|
|
const aiAvatar = import.meta.env.VITE_AI_AVATAR || '';
|
|
const aiDescription = import.meta.env.VITE_AI_DESCRIPTION || '';
|
|
|
|
// Priority: Environment variables > Auto-generated from host
|
|
const autoGeneratedBase = generateBaseCollectionFromHost(host);
|
|
let baseCollection = import.meta.env.VITE_OAUTH_COLLECTION || autoGeneratedBase;
|
|
|
|
// Ensure base collection is never undefined
|
|
if (!baseCollection) {
|
|
baseCollection = 'ai.syui.log';
|
|
}
|
|
|
|
const collections = {
|
|
base: baseCollection,
|
|
};
|
|
|
|
const rkey = extractRkeyFromUrl();
|
|
|
|
// AI configuration
|
|
const aiEnabled = import.meta.env.VITE_AI_ENABLED === 'true';
|
|
const aiAskAi = import.meta.env.VITE_AI_ASK_AI === 'true';
|
|
const aiProvider = import.meta.env.VITE_AI_PROVIDER || 'ollama';
|
|
const aiModel = import.meta.env.VITE_AI_MODEL || 'gemma2:2b';
|
|
const aiHost = import.meta.env.VITE_AI_HOST || 'https://ollama.syui.ai';
|
|
const aiSystemPrompt = import.meta.env.VITE_AI_SYSTEM_PROMPT || 'You are a helpful AI assistant trained on this blog\'s content.';
|
|
const atprotoPds = import.meta.env.VITE_ATPROTO_PDS || 'syu.is';
|
|
const bskyPublicApi = import.meta.env.VITE_BSKY_PUBLIC_API || 'https://public.api.bsky.app';
|
|
const atprotoApi = import.meta.env.VITE_ATPROTO_API || 'https://bsky.social';
|
|
|
|
// Parse allowed handles list
|
|
const allowedHandlesStr = import.meta.env.VITE_ATPROTO_HANDLE_LIST || '[]';
|
|
let allowedHandles: string[] = [];
|
|
try {
|
|
allowedHandles = JSON.parse(allowedHandlesStr);
|
|
} catch {
|
|
// If parsing fails, allow all handles (empty array means no restriction)
|
|
allowedHandles = [];
|
|
}
|
|
|
|
return {
|
|
adminDid,
|
|
adminHandle,
|
|
aiDid,
|
|
aiHandle,
|
|
aiDisplayName,
|
|
aiAvatar,
|
|
aiDescription,
|
|
collections,
|
|
host,
|
|
rkey,
|
|
aiEnabled,
|
|
aiAskAi,
|
|
aiProvider,
|
|
aiModel,
|
|
aiHost,
|
|
aiSystemPrompt,
|
|
allowedHandles,
|
|
atprotoPds,
|
|
bskyPublicApi,
|
|
atprotoApi
|
|
};
|
|
}
|
|
|
|
// Export singleton instance
|
|
export const appConfig = getAppConfig(); |