fix: fast node creation, first-run modal, simplified docs
- Skip AI calls when no valid OpenAI key (fixes 9-13s timeout) - Add first-run modal prompting for API key - Rewrite README for first-time users - Add /api/health endpoint - Remove all Anthropic references (not used in OS) - Fix bootstrap script (dev:local → dev) - Fix next.config.js devIndicators warning - Add Node 18+ version check 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.5
parent
38386afea4
commit
7beba57f63
@@ -15,11 +15,66 @@ export interface DescriptionInput {
|
||||
dimensions?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we have a valid OpenAI API key configured.
|
||||
* Checks both environment variable and validates format.
|
||||
*/
|
||||
export function hasValidOpenAiKey(): boolean {
|
||||
const key = process.env.OPENAI_API_KEY;
|
||||
if (!key || key === 'your-openai-api-key-here') return false;
|
||||
// Valid OpenAI keys start with sk- or sk-proj-
|
||||
return key.startsWith('sk-') && key.length > 20;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a simple fallback description without AI.
|
||||
* Used when no API key is available or for simple inputs.
|
||||
*/
|
||||
export function generateFallbackDescription(input: DescriptionInput): string {
|
||||
const { title, type, metadata, dimensions } = input;
|
||||
|
||||
// Build a contextual fallback
|
||||
const parts: string[] = [];
|
||||
|
||||
if (metadata?.author || metadata?.channel_name) {
|
||||
parts.push(`By ${metadata.author || metadata.channel_name}`);
|
||||
}
|
||||
|
||||
if (type) {
|
||||
parts.push(type.charAt(0).toUpperCase() + type.slice(1));
|
||||
}
|
||||
|
||||
if (dimensions?.length) {
|
||||
parts.push(`in ${dimensions.slice(0, 2).join(', ')}`);
|
||||
}
|
||||
|
||||
if (parts.length > 0) {
|
||||
return `${parts.join(' — ')}: ${title.slice(0, 200)}`;
|
||||
}
|
||||
|
||||
return `Knowledge item: ${title.slice(0, 250)}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a 280-character description for a knowledge node.
|
||||
* Contextually grounded - adapts to node type (person, concept, article, etc.)
|
||||
*
|
||||
* IMPORTANT: Returns fallback immediately if no valid API key is configured.
|
||||
* This prevents slow node creation (9-13s timeout) when OpenAI is unavailable.
|
||||
*/
|
||||
export async function generateDescription(input: DescriptionInput): Promise<string> {
|
||||
// Fast path: skip AI if no valid API key
|
||||
if (!hasValidOpenAiKey()) {
|
||||
console.log(`[DescriptionService] No valid OpenAI key, using fallback for: "${input.title}"`);
|
||||
return generateFallbackDescription(input);
|
||||
}
|
||||
|
||||
// Fast path: skip AI for very short inputs (likely just notes)
|
||||
if (!input.content && !input.link && input.title.length < 30) {
|
||||
console.log(`[DescriptionService] Short input, using fallback for: "${input.title}"`);
|
||||
return generateFallbackDescription(input);
|
||||
}
|
||||
|
||||
try {
|
||||
const prompt = buildDescriptionPrompt(input);
|
||||
|
||||
@@ -43,7 +98,7 @@ export async function generateDescription(input: DescriptionInput): Promise<stri
|
||||
} catch (error) {
|
||||
console.error('[DescriptionService] Error generating description:', error);
|
||||
// Return a fallback description
|
||||
return `This is a ${input.type || 'knowledge item'} titled "${input.title.slice(0, 200)}".`;
|
||||
return generateFallbackDescription(input);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user