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:
lotherk
2026-03-26 21:56:29 +00:00
parent 37871271cc
commit 5c217853de
27 changed files with 1026 additions and 260 deletions

View 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;
}
}
}