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

@@ -31,7 +31,7 @@ settingsRoutes.put('/', async (c) => {
const data: Record<string, unknown> = {};
if (aiProvider !== undefined) data.aiProvider = aiProvider;
if (aiApiKey !== undefined) data.aiApiKey = aiApiKey;
if (aiModel !== undefined) data.aiModel = aiModel || 'gpt-4';
if (aiModel !== undefined) data.aiModel = aiModel;
if (aiBaseUrl !== undefined) data.aiBaseUrl = aiBaseUrl;
if (journalPrompt !== undefined) data.journalPrompt = journalPrompt;
if (language !== undefined) data.language = language;
@@ -67,3 +67,34 @@ settingsRoutes.post('/validate-key', async (c) => {
return c.json({ data: { valid: false }, error: null });
}
});
settingsRoutes.post('/test', async (c) => {
const body = await c.req.json();
const { provider, apiKey, model, baseUrl } = body;
if (!provider) {
return c.json({ data: null, error: { code: 'VALIDATION_ERROR', message: 'provider is required' } }, 400);
}
const { createAIProvider } = await import('../services/ai/provider');
try {
const aiProvider = createAIProvider({
provider,
apiKey: apiKey || '',
model: model || undefined,
baseUrl: baseUrl || undefined,
});
const result = await aiProvider.generate('Say "OK" if you can read this.', 'You are a test assistant. Respond with just "OK".');
if (result.toLowerCase().includes('ok')) {
return c.json({ data: { valid: true, message: 'Connection successful!' }, error: null });
} else {
return c.json({ data: { valid: false }, error: { code: 'TEST_FAILED', message: 'Model responded but with unexpected output' } });
}
} catch (err) {
const message = err instanceof Error ? err.message : 'Connection failed';
return c.json({ data: { valid: false }, error: { code: 'TEST_FAILED', message } });
}
});