feat: v0.1.0 - geolocation capture, calendar, search, Starlight docs site
- Automatic browser geolocation capture on event creation - Reverse geocoding via Nominatim API for place names - Full-text search with SQLite FTS5 - Calendar view for browsing past entries - DateNavigator component for day navigation - SearchModal with Ctrl+K shortcut - QuickAddWidget with Ctrl+J shortcut - Starlight documentation site with GitHub Pages deployment - Multiple AI provider support (Groq, OpenAI, Anthropic, Ollama, LM Studio) - Multi-user registration support BREAKING: Events now include latitude/longitude/placeName fields
This commit is contained in:
406
todo/ai_style.md
Normal file
406
todo/ai_style.md
Normal file
@@ -0,0 +1,406 @@
|
||||
# AI Diary Style Feature Specification
|
||||
|
||||
## Overview
|
||||
|
||||
This document outlines a feature allowing users to customize the writing style/voice of AI-generated diary pages. Currently, the journal generation uses a fixed system prompt stored in Settings. This feature would provide a more robust, user-friendly way to define and manage diary writing styles.
|
||||
|
||||
---
|
||||
|
||||
## Feature Description
|
||||
|
||||
Users can select from predefined style presets or create custom styles that influence how the AI writes their diary pages. Each style defines tone, voice, formatting preferences, and specific writing guidelines that get injected into the generation prompt.
|
||||
|
||||
### Core Capabilities
|
||||
|
||||
1. **Style Presets**: Pre-defined writing styles (formal, casual, poetic, etc.)
|
||||
2. **Custom Styles**: User-defined styles with full control over prompt components
|
||||
3. **Per-Diary Override**: Ability to use a different style for specific dates
|
||||
4. **Style Preview**: Generate a sample diary to preview style before use
|
||||
5. **Multiple Presets**: Create and switch between multiple saved styles
|
||||
|
||||
---
|
||||
|
||||
## Style Preset Definitions
|
||||
|
||||
### 1. Formal
|
||||
|
||||
**Voice**: Professional, polished, articulate
|
||||
**Use Case**: Users who want their diary to read like well-crafted prose
|
||||
|
||||
```
|
||||
System Prompt Component:
|
||||
You write in a formal, articulate style. Use complete sentences and proper grammar.
|
||||
Avoid contractions and colloquialisms. Maintain a reflective, thoughtful tone.
|
||||
Structure your diary with clear paragraphs that flow logically.
|
||||
```
|
||||
|
||||
**Sample Output**:
|
||||
> Today began with considerable promise. The morning meeting concluded successfully, yielding clarity on the project timeline. Subsequent hours were devoted to deep work, punctuated by brief exchanges with colleagues. The afternoon brought an unexpected interruption, though it proved fruitful in unexpected ways. Tomorrow presents new challenges that require careful preparation.
|
||||
|
||||
---
|
||||
|
||||
### 2. Casual
|
||||
|
||||
**Voice**: Relaxed, friendly, conversational
|
||||
**Use Case**: Users who want their diary to feel like chatting with a good friend
|
||||
|
||||
```
|
||||
System Prompt Component:
|
||||
Write in a casual, friendly tone as if talking to a close friend. Use contractions naturally.
|
||||
Keep it relaxed and easygoing. Short sentences are fine. Include natural pauses and "ums."
|
||||
Make it feel like you're debriefing the day with someone who gets you.
|
||||
```
|
||||
|
||||
**Sample Output**:
|
||||
> So here's how today went... The morning was pretty productive, got through most of my todo list before lunch which was nice. Had this weird interaction with a coworker around 2pm that threw me off for a bit, but I think we figured it out. The rest of the afternoon flew by. Anyway, tomorrow's another day!
|
||||
|
||||
---
|
||||
|
||||
### 3. Poetic
|
||||
|
||||
**Voice**: Literary, evocative, lyrical
|
||||
**Use Case**: Users who appreciate beautiful, descriptive language
|
||||
|
||||
```
|
||||
System Prompt Component:
|
||||
Write in a poetic, literary style. Use sensory details, metaphors, and evocative language.
|
||||
Let sentences breathe with varied rhythm. Paint scenes with words. Find beauty in ordinary moments.
|
||||
Use occasional line breaks for emphasis. Let the writing have a lyrical quality.
|
||||
```
|
||||
|
||||
**Sample Output**:
|
||||
> The light crept through the window this morning like a slow, golden tide. Meetings blurred together—a symphony of voices and shifting priorities. There was a moment, somewhere between the third cup of coffee and the afternoon's weight, when the world seemed to hold its breath. Tonight, the stars are sharp and numerous. Tomorrow, another page turns.
|
||||
|
||||
---
|
||||
|
||||
### 4. Minimalist
|
||||
|
||||
**Voice**: Concise, direct, stripped-back
|
||||
**Use Case**: Users who prefer brevity and clarity over elaboration
|
||||
|
||||
```
|
||||
System Prompt Component:
|
||||
Write in a minimalist style. Keep sentences short and direct. Cut unnecessary words.
|
||||
No flourishes or embellishments. Get to the point. Use bullet points if helpful.
|
||||
Focus on facts and essential observations only. Less is more.
|
||||
```
|
||||
|
||||
**Sample Output**:
|
||||
> - Morning: Team sync, focused work block
|
||||
> - Afternoon: Client call, project review
|
||||
> - Evening: Walk, read
|
||||
> Notable: Finally resolved the bug that's been nagging me
|
||||
> Tomorrow: Deadline for presentation
|
||||
|
||||
---
|
||||
|
||||
### 5. Conversational
|
||||
|
||||
**Voice**: Warm, personal, storytelling
|
||||
**Use Case**: Users who want their diary to feel like telling a story
|
||||
|
||||
```
|
||||
System Prompt Component:
|
||||
Write as if telling a story to someone who cares. First person, warm and personal.
|
||||
Use "I" naturally. Describe things the way you'd explain them to a friend.
|
||||
Include small details that bring the day to life. Make it feel present and immediate.
|
||||
```
|
||||
|
||||
**Sample Output**:
|
||||
> So I have to tell you about today—it was one of those days where everything just clicked, you know? First thing this morning I sat down and finally cracked that problem I've been working on for weeks. The feeling was amazing. Then at lunch I ran into this old friend I hadn't seen in forever and we talked for an hour. The rest of the day was chill by comparison. I'm really grateful for days like this.
|
||||
|
||||
---
|
||||
|
||||
### 6. Reflective
|
||||
|
||||
**Voice**: Introspective, thoughtful, philosophical
|
||||
**Use Case**: Users who want to explore the meaning behind their days
|
||||
|
||||
```
|
||||
System Prompt Component:
|
||||
Write with an introspective, reflective lens. Explore what events meant, not just what happened.
|
||||
Ask yourself questions. Examine patterns and connections. Go deeper than surface events.
|
||||
Consider what you learned, what surprised you, what you'll carry forward.
|
||||
```
|
||||
|
||||
**Sample Output**:
|
||||
> What strikes me most about today is how the small moments added up to something meaningful. The conversation with the new team member revealed that sometimes the most valuable insights come from unexpected places. I notice I've been carrying some anxiety about the project, yet today's progress reminded me that I've handled difficult things before. What does it mean to be building something that matters? These questions linger as the day closes.
|
||||
|
||||
---
|
||||
|
||||
## Prompt Engineering for Each Style
|
||||
|
||||
### Structure Comparison
|
||||
|
||||
All styles share this base structure:
|
||||
1. **Style Directive**: How to write (tone, voice)
|
||||
2. **Content Requirements**: What to include
|
||||
3. **Structure Guidance**: How to organize
|
||||
4. **Example Integration**: From user events
|
||||
|
||||
### Style-Specific Additions
|
||||
|
||||
| Style | Sentence Length | Emotion | Formatting | Vocabulary |
|
||||
|-------|-----------------|---------|------------|------------|
|
||||
| Formal | Long, complex | Moderate | Paragraphs | Sophisticated |
|
||||
| Casual | Short-mixed | High | Mixed | Simple |
|
||||
| Poetic | Varied | Very high | Line breaks | Rich |
|
||||
| Minimalist | Very short | Low | Lists/bullets | Plain |
|
||||
| Conversational | Short-medium | High | Paragraphs | Colloquial |
|
||||
| Reflective | Medium-long | High | Open paragraphs | Thoughtful |
|
||||
|
||||
### JSON Response Handling
|
||||
|
||||
The AI returns JSON for title + content. Style affects:
|
||||
- **Title style**: Formal (proper nouns), Casual (lowercase ok), Poetic (evocative)
|
||||
- **Content style**: Applied through system prompt injection
|
||||
|
||||
---
|
||||
|
||||
## UI for Selecting/Creating Styles
|
||||
|
||||
### Settings Page Addition
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ DIARY STYLE │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ Current Style: [Casual ▼] [Preview] │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ STYLE PRESETS [+ Create New] │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ ● Formal │ │
|
||||
│ │ ○ Casual │ │
|
||||
│ │ ○ Poetic │ │
|
||||
│ │ ○ Minimalist │ │
|
||||
│ │ ○ Custom: Morning Pages │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
```
|
||||
|
||||
### Style Editor Modal
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ CREATE / EDIT STYLE │
|
||||
│ │
|
||||
│ Name: [ ] │
|
||||
│ │
|
||||
│ Style Directive: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ Write in a... │ │
|
||||
│ │ │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ Content Requirements: │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ • Summarize key events │ │
|
||||
│ │ • Include emotions and reflections │ │
|
||||
│ │ • End with forward-looking thought │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ Example Tone (optional): │
|
||||
│ ┌─────────────────────────────────────────────────┐ │
|
||||
│ │ "Today was a good day. I felt..." │ │
|
||||
│ └─────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [Cancel] [Save Style] │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Per-Diary Style Override
|
||||
|
||||
On the journal generation page (`/journal/:date`):
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ GENERATE DIARY [⚙ Style: Casual]│
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
Clicking style button opens dropdown to override for this single generation.
|
||||
|
||||
### Style Preview Feature
|
||||
|
||||
Generate a "test" diary using current events + selected style:
|
||||
- Modal shows generated preview
|
||||
- "Apply this style" button to save as default
|
||||
- Useful for testing custom styles before committing
|
||||
|
||||
---
|
||||
|
||||
## Storage of Custom Styles
|
||||
|
||||
### Database Schema Addition
|
||||
|
||||
```prisma
|
||||
model StylePreset {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
name String
|
||||
isDefault Boolean @default(false)
|
||||
|
||||
// Style components
|
||||
styleDirective String // Core tone/voice instructions
|
||||
contentRequirements String? // What to include
|
||||
structureGuidance String? // How to organize
|
||||
exampleText String? // Sample tone (optional)
|
||||
|
||||
// Metadata
|
||||
isBuiltIn Boolean @default(false) // True for official presets
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([userId])
|
||||
}
|
||||
```
|
||||
|
||||
### Settings Model Update
|
||||
|
||||
```prisma
|
||||
model Settings {
|
||||
// ... existing fields
|
||||
defaultStyleId String? // FK to StylePreset
|
||||
|
||||
defaultStyleId String?
|
||||
defaultStyle StylePreset? @relation(fields: [defaultStyleId], references: [id])
|
||||
}
|
||||
```
|
||||
|
||||
### Journal Model Update (for per-diary override)
|
||||
|
||||
```prisma
|
||||
model Journal {
|
||||
// ... existing fields
|
||||
stylePresetId String? // Override style for this specific journal
|
||||
stylePreset StylePreset? @relation(fields: [stylePresetId], references: [id])
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Design
|
||||
|
||||
### New Endpoints
|
||||
|
||||
```
|
||||
GET /api/v1/styles // List user's styles
|
||||
POST /api/v1/styles // Create custom style
|
||||
GET /api/v1/styles/:id // Get specific style
|
||||
PUT /api/v1/styles/:id // Update style
|
||||
DELETE /api/v1/styles/:id // Delete custom style
|
||||
POST /api/v1/styles/:id/preview // Generate preview with this style
|
||||
|
||||
PUT /api/v1/settings/default-style // Set default style
|
||||
```
|
||||
|
||||
### Generation Integration
|
||||
|
||||
In `journal.ts`, modify the generation to:
|
||||
1. Check `journal.stylePresetId` for per-diary override
|
||||
2. Fall back to `settings.defaultStyleId`
|
||||
3. Fall back to legacy `settings.journalPrompt` (for backwards compatibility)
|
||||
4. Build style prompt from StylePreset or use journalPrompt directly
|
||||
|
||||
### Prompt Building Logic
|
||||
|
||||
```typescript
|
||||
function buildStylePrompt(style: StylePreset | null, journalPrompt: string): string {
|
||||
if (!style) return journalPrompt;
|
||||
|
||||
const parts = [
|
||||
style.styleDirective,
|
||||
style.contentRequirements && `\n\nRequirements:\n${style.contentRequirements}`,
|
||||
style.structureGuidance && `\n\nStructure:\n${style.structureGuidance}`,
|
||||
style.exampleText && `\n\nTone example: "${style.exampleText}"`,
|
||||
].filter(Boolean);
|
||||
|
||||
return parts.join('\n\n') + '\n\n' + journalPrompt;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Complexity
|
||||
|
||||
### Phase 1: Core Infrastructure (Medium)
|
||||
- [ ] Database schema changes (StylePreset model)
|
||||
- [ ] Settings model update
|
||||
- [ ] Journal model update
|
||||
- [ ] New API routes for CRUD operations
|
||||
- [ ] Seed default presets on first run
|
||||
|
||||
### Phase 2: UI Components (Medium)
|
||||
- [ ] Style selector in Settings
|
||||
- [ ] Style editor modal (create/edit)
|
||||
- [ ] Preview modal with generation
|
||||
- [ ] Per-diary override UI
|
||||
|
||||
### Phase 3: Generation Integration (Low)
|
||||
- [ ] Update journal generation to use style
|
||||
- [ ] Handle migration from old journalPrompt
|
||||
- [ ] Add style_id to generation task logging
|
||||
|
||||
### Complexity Breakdown
|
||||
|
||||
| Component | Complexity | Notes |
|
||||
|-----------|------------|-------|
|
||||
| Database Schema | Low | Simple additions, Prisma handles migration |
|
||||
| API Routes | Medium | Standard CRUD, ~100 lines |
|
||||
| Style Editor UI | Medium | Form with preview, ~200 lines |
|
||||
| Preview Feature | Medium | Requires new generation endpoint |
|
||||
| Per-Diary Override | Low | Simple FK field + dropdown |
|
||||
| Migration Path | Low | Handle nulls gracefully |
|
||||
|
||||
### Estimated Time
|
||||
- Backend: 2-3 hours
|
||||
- Frontend: 3-4 hours
|
||||
- Testing: 1 hour
|
||||
|
||||
---
|
||||
|
||||
## Priority Recommendation
|
||||
|
||||
### Recommended Priority: **Phase 2 (Medium-High)**
|
||||
|
||||
This feature adds significant user value with moderate implementation effort.
|
||||
|
||||
**Justification**:
|
||||
1. **High Impact**: Users frequently want personalized output
|
||||
2. **Low Risk**: Feature is additive, doesn't break existing flows
|
||||
3. **Builds on Existing**: Leverages already-implemented journal generation
|
||||
4. **Differentiated**: Few journaling apps offer this level of customization
|
||||
|
||||
### Implementation Order
|
||||
|
||||
1. **First**: Add StylePreset model + seed default styles
|
||||
2. **Second**: Update journal generation to use style
|
||||
3. **Third**: Basic style selector in Settings
|
||||
4. **Fourth**: Style editor for custom styles
|
||||
5. **Fifth**: Preview feature (optional, can ship later)
|
||||
|
||||
### Considerations
|
||||
|
||||
- **Migration**: Existing users with custom `journalPrompt` should be converted to a "Custom" style preset on first migration
|
||||
- **Defaults**: Pre-build the 6 style presets so users have immediate options
|
||||
- **Validation**: Ensure style prompts don't exceed model context limits
|
||||
- **Preview**: Consider rate-limiting preview generation to prevent abuse
|
||||
|
||||
---
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
1. **Style Transfer**: Copy another user's shared style (community feature)
|
||||
2. **Learning from Edits**: After user edits generated diary, update style
|
||||
3. **Multi-language Styles**: Different writing styles per language
|
||||
4. **Style Analytics**: Show which styles user uses most
|
||||
5. **Export/Import**: Share style configurations
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
The AI Style feature transforms DearDiary from a basic AI diarist into a personalized writing assistant. By giving users control over tone, voice, and formatting, we create a more engaging journaling experience that matches individual preferences.
|
||||
|
||||
The implementation is straightforward given the existing architecture, and the feature delivers immediate value without requiring significant refactoring or risk.
|
||||
Reference in New Issue
Block a user