UNPKG

pulse-ai-utils

Version:

Utility functions and helpers for AI-powered applications

192 lines (191 loc) 6.14 kB
import OpenAI from 'openai'; import { z, ZodTypeAny } from 'zod'; import QueryCache from './query-cache'; export type WaterfallStreamEvent = { type: 'strategy_start'; strategy: string; timestamp: number; } | { type: 'data_item'; item: any; strategy: string; source: string; } | { type: 'cache_hit'; itemCount: number; strategy: string; cacheType: string; } | { type: 'web_search_performed'; itemCount: number; strategy: string; } | { type: 'fallback_start'; strategy: string; } | { type: 'strategy_complete'; strategy: string; } | { type: 'error'; error: string; strategy: string; isTimeout?: boolean; } | { type: 'parallel_start'; strategies: string[]; timestamp: number; } | { type: 'duplicate_skipped'; itemId: string; strategy: string; }; export interface LLMConfig { model: string; apiKey?: string; baseURL?: string; headers?: Record<string, string>; } export declare abstract class LLMBase { protected openai: OpenAI; protected defaultModel: string; protected cache: QueryCache; constructor(config: LLMConfig, openaiInstance?: OpenAI, cache?: QueryCache); protected abstract createOpenAIInstance(config: LLMConfig): OpenAI; protected getApiKey(): string; protected abstract getProviderName(): string; protected isTestMode(): boolean; get model(): string; get client(): OpenAI; protected parseModelResponse<T extends ZodTypeAny>(response: any, zodSchema: T): z.infer<T>; protected enhanceWithImages(items: any[], responseFormatName: string): Promise<void>; /** * Fetches structured data from web search using streaming * Uses chat completions API with streaming for better handling of large responses */ fetchStructuredDataFromWebStream<T extends ZodTypeAny>({ model, prompt, recommendedSources, zodSchema, userLocation, locationGranularity, systemPrompt, timeline, responseFormatName, customFormat, options }: { model?: string; prompt: string; recommendedSources?: string[]; zodSchema: T; userLocation: any; locationGranularity: string; systemPrompt?: string; timeline?: string; responseFormatName?: string; customFormat?: (schema: ZodTypeAny, name: string) => any; options?: Record<string, any>; }): Promise<z.infer<T>>; /** * Generator version that yields items as they are parsed from the stream */ fetchStructuredDataFromWebStreamGenerator<T extends ZodTypeAny>({ model, prompt, recommendedSources, zodSchema, userLocation, locationGranularity, systemPrompt, timeline, responseFormatName, customFormat, options }: { model?: string; prompt: string; recommendedSources?: string[]; zodSchema: T; userLocation: any; locationGranularity: string; systemPrompt?: string; timeline?: string; responseFormatName?: string; customFormat?: (schema: ZodTypeAny, name: string) => any; options?: Record<string, any>; }): AsyncGenerator<any>; /** * Non-streaming version using responses.parse API */ /** * Build user prompt with date and location */ private buildUserPrompt; /** * Check if error is a JSON parsing error */ private isJsonParsingError; /** * Parse response with fallback to salvaging partial JSON */ private parseResponseWithFallback; /** * Process and cache results only if we have actual data */ private processAndCacheResults; /** * Helper method to parse streamed content */ private parseStreamedContent; /** * Fetches structured data from web search * * @param options.resultLimit - Maximum number of results to request (default: 20) * @param options.useStreaming - Use streaming implementation (default: true for better reliability) * * Note: The responses.parse API doesn't support max_tokens parameter. * Token limits are controlled by the model's context window. * We use result limiting in the prompt to prevent response truncation. */ fetchStructuredData<T extends ZodTypeAny>({ model, prompt, html, zodSchema, responseFormatName, }: { model?: string; prompt: string; html: string; zodSchema: T; responseFormatName?: string; }): Promise<z.infer<T>>; /** * Search content chunks for longer documents */ searchChunks(query: string, limit?: number, threshold?: number): Promise<any[]>; /** * Generate embedding for a given text * Used for custom vector operations */ generateEmbedding(text: string): Promise<number[]>; /** * Execute all strategies in parallel and stream results with deduplication */ executeParallelStrategyStream({ prompt, area, region, country, timeline, systemPrompt, options, enableWebSearchLLM, lat, lng, radius }: { prompt: string; area: string; region?: string; country?: string; timeline?: string; systemPrompt?: string; options?: Record<string, any>; enableWebSearchLLM?: boolean; lat?: number; lng?: number; radius?: number; }): AsyncGenerator<WaterfallStreamEvent>; /** * Get appropriate stream for each strategy */ private getStrategyStream; /** * Create a safe wrapper around strategy streams that catches all errors */ private createSafeStrategyStream; /** * Stream results from Firestore query cache */ private streamQueryCache; /** * Stream results from Supabase RAG cache */ private streamRAGCache; /** * Stream results from Supabase vector search */ private streamVectorSearch; /** * Stream results from Supabase hybrid search */ private streamHybridSearch; /** * Stream results from web search */ private streamWebSearch; /** * Infer timeline from query text */ private inferTimelineFromQuery; }