feat: v0.0.1 - Groq provider, timezone, journal context, test connection, task logging
Added: - Groq AI provider (free, fast with llama-3.3-70b-versatile) - Timezone setting (22 timezones) - Journal context: include previous journals (3/7/14/30 days) - Test connection button for AI providers - Per-provider settings (API key, model, base URL remembered) - Detailed task logging (full prompts and responses) - Tasks page with expandable details - Progress modal with steps and AI output details Fixed: - Groq API endpoint (https://api.groq.com/openai/v1/chat/completions) - Ollama baseUrl leaking to other providers - Database schema references - Proper Prisma migrations (data-safe) Changed: - Default AI: OpenAI → Groq - Project renamed: TotalRecall → DearDiary - Strict anti-hallucination prompt - Docker uses prisma migrate deploy (non-destructive)
This commit is contained in:
66
backend/src/services/ai/groq.ts
Normal file
66
backend/src/services/ai/groq.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import type { AIProvider, AIProviderConfig } from './provider';
|
||||
|
||||
export class GroqProvider implements AIProvider {
|
||||
provider = 'groq' as const;
|
||||
private apiKey: string;
|
||||
private model: string;
|
||||
private baseUrl: string;
|
||||
|
||||
constructor(config: AIProviderConfig) {
|
||||
this.apiKey = config.apiKey;
|
||||
this.model = config.model || 'llama-3.3-70b-versatile';
|
||||
this.baseUrl = config.baseUrl || 'https://api.groq.com/openai/v1';
|
||||
}
|
||||
|
||||
async generate(prompt: string, systemPrompt?: string): Promise<string> {
|
||||
const messages: Array<{ role: string; content: string }> = [];
|
||||
|
||||
if (systemPrompt) {
|
||||
messages.push({ role: 'system', content: systemPrompt });
|
||||
}
|
||||
|
||||
messages.push({ role: 'user', content: prompt });
|
||||
|
||||
const response = await fetch(`${this.baseUrl}/chat/completions`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${this.apiKey}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: this.model,
|
||||
messages,
|
||||
temperature: 0.7,
|
||||
max_tokens: 2000,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.text();
|
||||
throw new Error(`Groq API error: ${response.status} ${error}`);
|
||||
}
|
||||
|
||||
const data = await response.json() as { choices: Array<{ message: { content: string } }> };
|
||||
return data.choices[0]?.message?.content || '';
|
||||
}
|
||||
|
||||
async validate(): Promise<boolean> {
|
||||
try {
|
||||
const response = await fetch(`${this.baseUrl}/chat/completions`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${this.apiKey}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: this.model,
|
||||
messages: [{ role: 'user', content: 'test' }],
|
||||
max_tokens: 5,
|
||||
}),
|
||||
});
|
||||
return response.ok || response.status === 400;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
export interface AIProvider {
|
||||
provider: 'openai' | 'anthropic' | 'ollama' | 'lmstudio';
|
||||
provider: 'openai' | 'anthropic' | 'ollama' | 'lmstudio' | 'groq';
|
||||
generate(prompt: string, systemPrompt?: string): Promise<string>;
|
||||
validate?(): Promise<boolean>;
|
||||
}
|
||||
|
||||
export interface AIProviderConfig {
|
||||
provider: 'openai' | 'anthropic' | 'ollama' | 'lmstudio';
|
||||
provider: 'openai' | 'anthropic' | 'ollama' | 'lmstudio' | 'groq';
|
||||
apiKey: string;
|
||||
model?: string;
|
||||
baseUrl?: string;
|
||||
@@ -15,6 +15,7 @@ import { OpenAIProvider } from './openai';
|
||||
import { AnthropicProvider } from './anthropic';
|
||||
import { OllamaProvider } from './ollama';
|
||||
import { LMStudioProvider } from './lmstudio';
|
||||
import { GroqProvider } from './groq';
|
||||
|
||||
export function createAIProvider(config: AIProviderConfig): AIProvider {
|
||||
switch (config.provider) {
|
||||
@@ -26,6 +27,8 @@ export function createAIProvider(config: AIProviderConfig): AIProvider {
|
||||
return new OllamaProvider(config);
|
||||
case 'lmstudio':
|
||||
return new LMStudioProvider(config);
|
||||
case 'groq':
|
||||
return new GroqProvider(config);
|
||||
default:
|
||||
throw new Error(`Unknown AI provider: ${config.provider}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user