added zero weight feedback ignore

This commit is contained in:
2026-01-03 23:12:22 -07:00
parent d32cfe04e1
commit 60b03f5f4b
9 changed files with 610 additions and 180 deletions

View File

@@ -1052,36 +1052,46 @@ The API call sequence has been successfully optimized to:
3. Generate new feedback words after user rating
4. Refresh all UI elements
## Feedback Historic Indexing Bug Fix ✓ COMPLETED
## Weight 0 Filtering in Prompt Generation ✓ COMPLETED
### Problem Identified
The `feedback_historic.json` cyclic buffer had duplicate keys (`feedback00` to `feedback05`) repeated throughout the 30-item buffer instead of having unique keys (`feedback00` to `feedback29`).
### Task Requirement
In `prompt_service.py`, in the `generate_prompts` method, the `feedback_words` value should filter out any words that have a weight value of 0.
### Root Cause
The `_generate_and_insert_new_feedback_words()` method in `PromptService` was always generating keys `feedback00` to `feedback05` when inserting new items at position 0, creating duplicate keys in the buffer.
### Implementation Verification
The filtering was already implemented in the `generate_prompts` method:
### Solution Implemented
1. **Updated `_generate_and_insert_new_feedback_words()` method**:
- Added re-keying logic that assigns unique keys based on position in buffer
- After inserting new items, re-keys all items from `feedback00` to `feedback29`
- Preserves word and weight data during re-keying
```python
# Filter out feedback words with weight 0
if feedback_words:
feedback_words = [
word for word in feedback_words
if word.get("weight", 3) != 0 # Default weight is 3 if not specified
]
# If all words have weight 0, set to None
if not feedback_words:
feedback_words = None
```
2. **Updated `update_feedback_words()` method**:
- Modified to preserve existing keys when updating weights
- Extracts existing key from current item instead of generating new one
- Maintains backward compatibility with existing data structure
### How It Works
1. **Active Words Retrieval**: The method gets active feedback words (positions 6-11) from `get_feedback_active_words()`
2. **Weight Filtering**: Any word with `weight == 0` is filtered out from the list
3. **Fallback Handling**: If all words have weight 0, `feedback_words` is set to `None`
4. **AI Integration**: Only words with weight > 0 are passed to the AI service for prompt generation
### Technical Details
- **Before**: Keys `feedback00`-`feedback05` repeated, causing duplicate keys
- **After**: Unique sequential keys `feedback00`-`feedback29` (or less if buffer not full)
- **Data Structure**: Each item now has format `{"feedbackXX": "word", "weight": N}` with unique XX values
- **Buffer Management**: Proper cyclic buffer behavior with 30-item limit maintained
### Purpose
- **Weight 0 = "Ignore"**: Words rated 0 by users are meant to be ignored
- **Prevents Influence**: Filtering ensures ignored themes don't influence prompt generation
- **User Control**: Users can effectively "turn off" certain themes by rating them 0
### Verification
- ✅ All 30 items in buffer now have unique keys (`feedback00` to `feedback29`)
-No duplicate keys after feedback rating operations
-Data integrity preserved (words and weights maintained)
-Backward compatibility maintained with existing frontend
- ✅ Cyclic buffer functionality preserved (oldest items removed when buffer full)
- ✅ Code already implements the required filtering
-Default weight is 3 if not specified (handles edge cases)
-Proper handling when all words have weight 0 (sets to None)
-Maintains backward compatibility with existing functionality
The bug has been successfully fixed, ensuring proper cyclic buffer operation with unique keys throughout the feedback history.
The implementation ensures that only feedback words with non-zero weights influence AI prompt generation, giving users precise control over theme influence.
User notes:
There are still UI problems with the sliders on the feedback weights.
1. In the UI, with either mouse or keyboard it is impossible to get the value to 0. This is both visible in the graphical slider element as well as in the developer console watching the value be between 1 and 6. It should be possible to set to 0.
2. The sliders should be much bigger, and preferably in a blocky style rather than a slim slider. Look into ways to drastically change the slider style. Make them huge - the width of the parent element and very thick.

265
FUNCTIONAL_README.md Normal file
View File

@@ -0,0 +1,265 @@
# Daily Journal Prompt Generator - Functional Overview
## 📖 What This Application Does
This is a web application that helps writers and journalers by generating creative writing prompts. It uses AI (DeepSeek or OpenAI) to create unique prompts, remembers what prompts you've seen before to avoid repetition, and learns from your preferences to generate better prompts over time.
### Core Features:
- **AI-Powered Prompt Generation**: Creates unique journal writing prompts using AI
- **Smart Memory**: Remembers the last 60 prompts you've seen to avoid repetition
- **Prompt Pool**: Stores generated prompts so you can use them even without internet
- **Theme Learning**: Learns what themes you like/dislike to improve future prompts
- **Web Interface**: Easy-to-use website accessible from any device
## 🏗️ How It Works - System Flow
### 1. User Opens the Website
- User visits http://localhost:3000 (or your deployed URL)
- The frontend loads and shows the most recent prompt from history
### 2. Getting New Prompts
- User clicks "Draw 3 New Prompts"
- Backend selects 3 random prompts from the pool
- If pool is low (< 20 prompts), system suggests refilling it
### 3. Selecting a Prompt
- User clicks on one of the 3 displayed prompts
- User clicks "Use Selected Prompt"
- The selected prompt is added to history (position 0, most recent)
- History shifts - oldest prompt (position 59) is removed if history is full
### 4. Refilling the Prompt Pool
- When pool is low, user clicks "Fill Prompt Pool"
- System immediately starts refilling pool using AI
- While pool refills, user rates 6 "theme words" (e.g., "adventure", "reflection")
- User adjusts weights (0-6) for each theme word:
- 0 = Ignore this theme
- 3 = Neutral (default)
- 6 = Strongly prefer this theme
- After rating, system generates new theme words for future use
### 5. Theme Learning Process
- System maintains 30 theme words in a "cyclic buffer"
- Positions 0-5: Queued words - shown to user for rating
- Positions 6-11: Active words - used for AI prompt generation
- Positions 12-29: Historic words - older theme words
- When user rates queued words, new words are generated and inserted at position 0
## 🗂️ File Structure & Purpose
### Data Files (in `data/` directory)
- `prompts_historic.json` - Last 60 prompts shown to user (cyclic buffer)
- `prompts_pool.json` - Available prompts ready for use (target: 20)
- `feedback_historic.json` - 30 theme words with weights (cyclic buffer)
- `ds_prompt.txt` - Template for AI prompt generation
- `ds_feedback.txt` - Template for AI theme word generation
- `settings.cfg` - Application settings (prompt length, counts, etc.)
### Backend Files (in `backend/` directory)
- `main.py` - FastAPI application entry point
- `app/services/data_service.py` - Reads/writes JSON files
- `app/services/prompt_service.py` - Main logic for prompt operations
- `app/services/ai_service.py` - Communicates with AI APIs
- `app/api/v1/endpoints/prompts.py` - API endpoints for prompts
- `app/api/v1/endpoints/feedback.py` - API endpoints for theme learning
- `app/models/prompt.py` - Data models for prompts and responses
- `app/core/config.py` - Configuration and settings
### Frontend Files (in `frontend/` directory)
- `src/pages/index.astro` - Main page
- `src/components/PromptDisplay.jsx` - Shows prompts and handles selection
- `src/components/StatsDashboard.jsx` - Shows pool/history statistics
- `src/components/FeedbackWeighting.jsx` - Theme word rating interface
- `src/layouts/Layout.astro` - Page layout with header/footer
- `src/styles/global.css` - CSS styles
### Configuration Files
- `.env` - API keys and environment variables (create from `.env.example`)
- `docker-compose.yml` - Runs both backend and frontend together
- `backend/Dockerfile` - Backend container configuration
- `frontend/Dockerfile` - Frontend container configuration
## 🔄 Data Flow Diagrams
### Prompt Flow:
```
User Request → Draw from Pool → Select Prompt → Add to History
↓ ↓ ↓ ↓
Frontend Backend Backend Backend
↓ ↓ ↓ ↓
Display Check Pool Update Pool Update History
```
### Theme Learning Flow:
```
User Rates Words → Update Weights → Generate New Words → Fill Pool
↓ ↓ ↓ ↓
Frontend Backend Backend Backend
↓ ↓ ↓ ↓
Show Weights Save to JSON Call AI API Generate Prompts
```
## 🛠️ Technologies Explained Simply
### FastAPI (Backend)
- **What it is**: A modern Python web framework for building APIs
- **Why we use it**: Fast, easy to use, automatically creates API documentation
- **Simple analogy**: Like a restaurant waiter - takes orders (requests) from customers (frontend) and brings food (responses) from the kitchen (AI/service)
### Astro (Frontend)
- **What it is**: A web framework for building fast websites
- **Why we use it**: Good performance, can use React components when needed
- **Simple analogy**: Like a book - static pages (Astro) with some interactive pop-ups (React components)
### React Components
- **What they are**: Reusable pieces of interactive web interface
- **Why we use them**: For interactive parts like prompt selection and theme rating
- **Where used**: `PromptDisplay.jsx`, `StatsDashboard.jsx`, `FeedbackWeighting.jsx`
### Docker & Docker Compose
- **What they are**: Tools to package and run applications in containers
- **Why we use them**: Makes setup easy - runs everything with one command
- **Simple analogy**: Like shipping containers - everything needed is packed together and runs the same way everywhere
## 📊 Key Concepts Explained
### Cyclic Buffer
- **What**: A fixed-size list where new items push out old ones
- **Example**: History holds 60 prompts. When #61 arrives, #1 is removed
- **Why**: Prevents unlimited growth, ensures recent data is prioritized
### Prompt Pool
- **What**: A collection of pre-generated prompts
- **Size**: Target is 20 prompts
- **Purpose**: Allows using prompts without waiting for AI generation
### Theme Words & Weights
- **Theme Words**: Words like "adventure", "reflection", "memory" that guide AI
- **Weights**: Numbers 0-6 that tell AI how much to use each theme
- **Flow**: User rates words → Weights are saved → AI uses weights for future prompts
### API Endpoints
- **What**: URLs that the frontend calls to get data or perform actions
- **Examples**:
- `GET /api/v1/prompts/draw` - Get prompts from pool
- `POST /api/v1/prompts/fill-pool` - Refill prompt pool
- `GET /api/v1/feedback/queued` - Get theme words for rating
## 🚀 Getting Started - Simple Version
### 1. Copy environment file:
```bash
cp .env.example .env
```
### 2. Edit `.env` file:
Add your AI API key (get from DeepSeek or OpenAI):
```
DEEPSEEK_API_KEY=your_key_here
```
### 3. Run with Docker:
```bash
docker-compose up --build
```
### 4. Open in browser:
- Website: http://localhost:3000
- API docs: http://localhost:8000/docs
## 🔧 Common Operations
### Using the Application:
1. **Get prompts**: Click "Draw 3 New Prompts"
2. **Select one**: Click a prompt, then "Use Selected Prompt"
3. **Refill pool**: Click "Fill Prompt Pool" when pool is low
4. **Rate themes**: Adjust sliders for theme words (0-6)
### Checking Status:
- **Pool status**: Shown as progress bar on Fill button
- **History count**: Shown in Stats Dashboard
- **Theme words**: Click "Fill Prompt Pool" to see current themes
### Data Files Location:
All data is saved in the `data/` directory:
- Prompts you've seen: `prompts_historic.json`
- Available prompts: `prompts_pool.json`
- Theme preferences: `feedback_historic.json`
## ❓ Frequently Asked Questions
### Q: Where do prompts come from?
A: From AI (DeepSeek/OpenAI) using the template in `ds_prompt.txt`
### Q: How does it avoid repeating prompts?
A: It keeps 60 most recent prompts in history and avoids those
### Q: What happens if I rate a theme word 0?
A: That theme will be ignored in future prompt generation
### Q: Can I use it without internet?
A: Yes, if the pool has prompts. AI calls need internet.
### Q: How do I reset everything?
A: Delete files in `data/` directory (except templates)
## 📈 Understanding the Numbers
### History (60 prompts):
- Position 0: Most recent prompt (shown on main page)
- Position 59: Oldest prompt (will be removed next)
- Full when: 60 prompts stored
### Pool (target: 20 prompts):
- "Low": Less than 20 prompts
- "Full": 20+ prompts available
- Drawn: 3 prompts at a time
### Theme Words (30 words):
- Queued (0-5): Shown for rating (6 words)
- Active (6-11): Used for prompt generation (6 words)
- Historic (12-29): Older words (18 words)
## 🔍 Troubleshooting Common Issues
### "No Prompts Available"
- Check if `prompts_pool.json` has prompts
- Try clicking "Fill Prompt Pool"
- Check API key in `.env` file
### "Permission Denied" in Docker
- Check `data/` directory permissions
- Try: `chmod 700 data/`
### Website Not Loading
- Wait 8 seconds after `docker-compose up`
- Check if containers are running: `docker-compose ps`
- Check logs: `docker-compose logs`
### AI Not Responding
- Verify API key in `.env`
- Check internet connection
- Try different AI provider (DeepSeek vs OpenAI)
## 📝 Key Configuration Settings
### In `settings.cfg`:
- `num_prompts = 3` - Number of prompts drawn at once
- `prompt_min_length = 100` - Minimum prompt length
- `prompt_max_length = 300` - Maximum prompt length
### In `.env`:
- `DEEPSEEK_API_KEY` or `OPENAI_API_KEY` - AI provider key
- `API_BASE_URL` - AI service URL (default: DeepSeek)
- `MODEL` - AI model to use (default: deepseek-chat)
## 🎯 Summary - What Makes This Special
1. **Smart Memory**: Remembers what you've seen to avoid repetition
2. **Theme Learning**: Gets better at prompts you like over time
3. **Offline Ready**: Pool system works without constant AI calls
4. **Simple Interface**: Clean, easy-to-use web interface
5. **Self-Contained**: Runs everything locally with Docker
This application combines AI creativity with user preferences to create a personalized journaling experience that improves the more you use it.

View File

@@ -197,6 +197,16 @@ class PromptService:
historic_prompts = await self.get_prompts_historic() if use_history else []
feedback_words = await self.get_feedback_active_words() if use_feedback else None
# Filter out feedback words with weight 0
if feedback_words:
feedback_words = [
word for word in feedback_words
if word.get("weight", 3) != 0 # Default weight is 3 if not specified
]
# If all words have weight 0, set to None
if not feedback_words:
feedback_words = None
# Generate prompts using AI
new_prompts = await self.ai_service.generate_prompts(
prompt_template=prompt_template,

View File

@@ -1,122 +1,122 @@
[
{
"feedback00": "labyrinthine",
"feedback00": "sonder",
"weight": 3
},
{
"feedback01": "verdant",
"feedback01": "petrichor",
"weight": 3
},
{
"feedback02": "cacophony",
"feedback02": "halcyon",
"weight": 3
},
{
"feedback03": "solitude",
"feedback03": "obfuscate",
"weight": 3
},
{
"feedback04": "kaleidoscope",
"feedback04": "quixotic",
"weight": 3
},
{
"feedback05": "zenith",
"feedback05": "sonder",
"weight": 3
},
{
"feedback06": "mellifluous",
"weight": 3
},
{
"feedback07": "detritus",
"weight": 4
},
{
"feedback08": "liminal",
"feedback06": "labyrinthine",
"weight": 1
},
{
"feedback09": "palimpsest",
"feedback07": "verdant",
"weight": 3
},
{
"feedback08": "cacophony",
"weight": 3
},
{
"feedback09": "solitude",
"weight": 3
},
{
"feedback10": "kaleidoscope",
"weight": 3
},
{
"feedback11": "zenith",
"weight": 6
},
{
"feedback12": "mellifluous",
"weight": 3
},
{
"feedback13": "detritus",
"weight": 4
},
{
"feedback14": "liminal",
"weight": 1
},
{
"feedback10": "phantasmagoria",
"weight": 3
},
{
"feedback11": "ephemeral",
"weight": 3
},
{
"feedback12": "gambol",
"weight": 3
},
{
"feedback13": "fathom",
"weight": 6
},
{
"feedback14": "cipher",
"feedback15": "palimpsest",
"weight": 1
},
{
"feedback15": "lucid",
"feedback16": "phantasmagoria",
"weight": 3
},
{
"feedback16": "sublime",
"feedback17": "ephemeral",
"weight": 3
},
{
"feedback17": "quiver",
"feedback18": "gambol",
"weight": 3
},
{
"feedback19": "fathom",
"weight": 6
},
{
"feedback18": "murmur",
"feedback20": "cipher",
"weight": 1
},
{
"feedback21": "lucid",
"weight": 3
},
{
"feedback19": "glaze",
"feedback22": "sublime",
"weight": 3
},
{
"feedback20": "warp",
"weight": 3
},
{
"feedback21": "silt",
"feedback23": "quiver",
"weight": 6
},
{
"feedback22": "quasar",
"weight": 6
},
{
"feedback23": "glyph",
"feedback24": "murmur",
"weight": 3
},
{
"feedback24": "gossamer",
"weight": 4
"feedback25": "glaze",
"weight": 3
},
{
"feedback25": "algorithm",
"weight": 4
"feedback26": "warp",
"weight": 3
},
{
"feedback26": "plenum",
"weight": 4
"feedback27": "silt",
"weight": 6
},
{
"feedback27": "drift",
"weight": 4
"feedback28": "quasar",
"weight": 6
},
{
"feedback28": "cryptid",
"weight": 4
},
{
"feedback29": "volta",
"weight": 4
"feedback29": "glyph",
"weight": 3
}
]

View File

@@ -1,122 +1,122 @@
[
{
"feedback00": "mellifluous",
"weight": 3
},
{
"feedback01": "detritus",
"weight": 4
},
{
"feedback02": "liminal",
"feedback00": "labyrinthine",
"weight": 1
},
{
"feedback03": "palimpsest",
"feedback01": "verdant",
"weight": 3
},
{
"feedback02": "cacophony",
"weight": 3
},
{
"feedback03": "solitude",
"weight": 3
},
{
"feedback04": "kaleidoscope",
"weight": 3
},
{
"feedback05": "zenith",
"weight": 6
},
{
"feedback06": "mellifluous",
"weight": 3
},
{
"feedback07": "detritus",
"weight": 4
},
{
"feedback08": "liminal",
"weight": 1
},
{
"feedback04": "phantasmagoria",
"weight": 3
},
{
"feedback05": "ephemeral",
"weight": 3
},
{
"feedback06": "gambol",
"weight": 3
},
{
"feedback07": "fathom",
"weight": 6
},
{
"feedback08": "cipher",
"feedback09": "palimpsest",
"weight": 1
},
{
"feedback09": "lucid",
"feedback10": "phantasmagoria",
"weight": 3
},
{
"feedback10": "sublime",
"feedback11": "ephemeral",
"weight": 3
},
{
"feedback11": "quiver",
"feedback12": "gambol",
"weight": 3
},
{
"feedback13": "fathom",
"weight": 6
},
{
"feedback12": "murmur",
"weight": 3
},
{
"feedback13": "glaze",
"weight": 3
},
{
"feedback14": "warp",
"weight": 3
},
{
"feedback15": "silt",
"weight": 6
},
{
"feedback16": "quasar",
"weight": 6
},
{
"feedback17": "glyph",
"weight": 3
},
{
"feedback18": "gossamer",
"weight": 4
},
{
"feedback19": "algorithm",
"weight": 4
},
{
"feedback20": "plenum",
"weight": 4
},
{
"feedback21": "drift",
"weight": 4
},
{
"feedback22": "cryptid",
"weight": 4
},
{
"feedback23": "volta",
"weight": 4
},
{
"feedback24": "lacuna",
"weight": 3
},
{
"feedback25": "mycelium",
"feedback14": "cipher",
"weight": 1
},
{
"feedback26": "talisman",
"feedback15": "lucid",
"weight": 3
},
{
"feedback27": "effulgence",
"feedback16": "sublime",
"weight": 3
},
{
"feedback28": "chrysalis",
"feedback17": "quiver",
"weight": 6
},
{
"feedback29": "sonder",
"weight": 1
"feedback18": "murmur",
"weight": 3
},
{
"feedback19": "glaze",
"weight": 3
},
{
"feedback20": "warp",
"weight": 3
},
{
"feedback21": "silt",
"weight": 6
},
{
"feedback22": "quasar",
"weight": 6
},
{
"feedback23": "glyph",
"weight": 3
},
{
"feedback24": "gossamer",
"weight": 4
},
{
"feedback25": "algorithm",
"weight": 4
},
{
"feedback26": "plenum",
"weight": 4
},
{
"feedback27": "drift",
"weight": 4
},
{
"feedback28": "cryptid",
"weight": 4
},
{
"feedback29": "volta",
"weight": 4
}
]

View File

@@ -1,5 +1,4 @@
[
"You are asked to contribute an entry to an 'Encyclopedia of Small Joys.' Your task is to define and describe one specific, minor pleasure in exhaustive, almost scientific detail. What do you choose? (e.g., 'The sound of rain on a skylight,' 'The weight of a sleeping cat on your lap,' 'The first sip of cold water when thirsty'). Detail its parameters, its effects, and the conditions under which it is most potent. Write a loving taxonomy of a tiny delight.",
"Recall a piece of advice you were given that you profoundly disagreed with at the time, but which later revealed a kernel of truth. What was the context? Why did you reject it? What experience or perspective shift allowed you to later understand its value? Write about the slow, often grudging, integration of wisdom that arrives before its time.",
"Describe a handmade gift you once received. Focus not on its monetary value or aesthetic perfection, but on the evidence of the giver's labor—the slightly uneven stitch, the handwritten note, the chosen colors. What does the object communicate about the relationship and the thought behind it? Has your appreciation for it changed over time? Explore the unique language of crafted, imperfect generosity.",
"Imagine you could perceive the emotional weather of the rooms you enter—not as metaphors, but as tangible atmospheres: a tense meeting room might feel thick and staticky, a friend's kitchen might be warm and golden. Describe walking through your day with this synesthetic sense. How would it change your interactions? Would you seek out certain climates and avoid others? Write about navigating the invisible emotional ecosystems we all create and inhabit.",
@@ -18,5 +17,10 @@
"Recall a conversation overheard in fragments—a murmur from another room, a phone call on a park bench, the distant voices of neighbors. You only catch phrases, tones, and pauses. From these pieces, construct the possible whole. What relationship do the speakers have? What is the context of their discussion? Now, acknowledge the inevitable warp your imagination has applied. Write about the narratives we spin from the incomplete threads of other people's lives, and how this act of listening and inventing reflects our own preoccupations.",
"Recall a moment of pure, unselfconscious play from your childhood—a game of make-believe, a physical gambol in a field or park. Describe the sensation of your body in motion, the rules of the invented world, the feeling of time dissolving. Now, consider the last time you felt a similar, fleeting sense of abandon as an adult. What activity prompted it? Write about the distance between these two experiences and the possibility of inviting more unstructured, joyful movement into your present life.",
"You are given a single, perfect seashell. Hold it to your ear. The old cliché speaks of the ocean's roar, but listen deeper. What else might you fathom in that hollow resonance? The sigh of the creature that once lived there? The whisper of ancient currents? The memory of a distant shore? Now, turn the metaphor inward. What deep, resonant chamber exists within you, and what is the sound it holds when you listen with total, patient attention? Write about the act of listening for the profound in the small and contained.",
"Describe a moment when an emotion—joy, grief, awe, fear—caused a physical quiver in your body. It might have been a shiver down your spine, a tremor in your hands, a catch in your breath. Locate the precise point of origin for this somatic echo. Did the feeling move through you like a wave, or settle in one place? Explore the conversation between your inner state and your physical vessel. How does the body register what the mind cannot yet fully articulate?"
"Describe a moment when an emotion—joy, grief, awe, fear—caused a physical quiver in your body. It might have been a shiver down your spine, a tremor in your hands, a catch in your breath. Locate the precise point of origin for this somatic echo. Did the feeling move through you like a wave, or settle in one place? Explore the conversation between your inner state and your physical vessel. How does the body register what the mind cannot yet fully articulate?",
"Recall a sound from your childhood that you can no longer hear—the specific chime of an ice cream truck, the hum of a particular appliance, the cadence of a relative's voice. Recreate it in your mind with as much auditory detail as possible. What emotions does this vanished sound evoke? Write about the act of preserving a sensory ghost, and how such echoes shape the landscape of memory.",
"Examine a drawer or cupboard that collects life's detritus: expired coupons, broken chargers, keys to unknown locks. Sort through this archive of abandoned intentions. What story does this collection tell about plans made and forgotten, functions lost, and objects outliving their purpose? Write about the quiet archaeology of the things we keep but no longer see.",
"Describe a piece of music or a voice you would describe as mellifluous—not just pleasant, but flowing with a honeyed, musical smoothness. When have you heard it? Does it belong to a person, an instrument, or a natural source? Explore how this quality of sound affects your mood and attention. Does it soothe, mesmerize, or somehow make time feel thicker and sweeter?",
"Recall a moment from the past week that felt deeply ephemeral—a laugh that dissolved into silence, a perfect arrangement of light on a wall, a feeling of peace that arose and passed like a breath. Describe it with the care of someone trying to hold smoke. Why did this particular transient moment feel worthy of capture? Write about the beauty and melancholy inherent in loving what cannot last.",
"Describe a dream that felt like a phantasmagoria—a rapidly shifting series of bizarre, fantastical, and possibly grotesque images. Resist the urge to interpret. Instead, narrate the dream's surreal logic as a series of dissolving scenes. What was the emotional texture? Did it feel chaotic, creative, or prophetic? Explore the mind's capacity to generate its own internal, unconscious cinema."
]

View File

@@ -1,5 +1,4 @@
[
"You are asked to contribute an entry to an 'Encyclopedia of Small Joys.' Your task is to define and describe one specific, minor pleasure in exhaustive, almost scientific detail. What do you choose? (e.g., 'The sound of rain on a skylight,' 'The weight of a sleeping cat on your lap,' 'The first sip of cold water when thirsty'). Detail its parameters, its effects, and the conditions under which it is most potent. Write a loving taxonomy of a tiny delight.",
"Recall a piece of advice you were given that you profoundly disagreed with at the time, but which later revealed a kernel of truth. What was the context? Why did you reject it? What experience or perspective shift allowed you to later understand its value? Write about the slow, often grudging, integration of wisdom that arrives before its time.",
"Describe a handmade gift you once received. Focus not on its monetary value or aesthetic perfection, but on the evidence of the giver's labor—the slightly uneven stitch, the handwritten note, the chosen colors. What does the object communicate about the relationship and the thought behind it? Has your appreciation for it changed over time? Explore the unique language of crafted, imperfect generosity.",
"Imagine you could perceive the emotional weather of the rooms you enter—not as metaphors, but as tangible atmospheres: a tense meeting room might feel thick and staticky, a friend's kitchen might be warm and golden. Describe walking through your day with this synesthetic sense. How would it change your interactions? Would you seek out certain climates and avoid others? Write about navigating the invisible emotional ecosystems we all create and inhabit.",
@@ -15,5 +14,8 @@
"Recall a moment of 'volta'—a subtle but definitive turn in a conversation, a relationship, or your understanding of a situation. It wasn't a dramatic reversal, but a quiet pivot point after which things were irrevocably different. Describe the atmosphere just before and just after this turn. What small word, glance, or realization acted as the hinge? Explore the anatomy of quiet change and how we navigate the new direction of a path we thought was straight.",
"Describe a riverbank after the water has receded, leaving behind a layer of fine, damp silt. Observe the patterns it has formed—the ripples, the tiny channels, the imprints of leaves and twigs. This sediment holds the history of the river's recent flow. What has it deposited here? What is now buried, and what is newly revealed on the surface? Write about the slow, patient work of accumulation and what it means to read the stories written in this soft, transitional ground.",
"You discover a series of strange, carved markings—glyphs—on an old piece of furniture or a forgotten wall. They are not a language you recognize. Document their shapes and arrangement. Who might have made them, and for what purpose? Were they a code, a tally, a protective symbol, or simply idle carving? Contemplate the human urge to leave a mark, even an indecipherable one. Write about the silent conversation you attempt to have with this anonymous, enduring message.",
"Recall a conversation overheard in fragments—a murmur from another room, a phone call on a park bench, the distant voices of neighbors. You only catch phrases, tones, and pauses. From these pieces, construct the possible whole. What relationship do the speakers have? What is the context of their discussion? Now, acknowledge the inevitable warp your imagination has applied. Write about the narratives we spin from the incomplete threads of other people's lives, and how this act of listening and inventing reflects our own preoccupations."
"Recall a conversation overheard in fragments—a murmur from another room, a phone call on a park bench, the distant voices of neighbors. You only catch phrases, tones, and pauses. From these pieces, construct the possible whole. What relationship do the speakers have? What is the context of their discussion? Now, acknowledge the inevitable warp your imagination has applied. Write about the narratives we spin from the incomplete threads of other people's lives, and how this act of listening and inventing reflects our own preoccupations.",
"Recall a moment of pure, unselfconscious play from your childhood—a game of make-believe, a physical gambol in a field or park. Describe the sensation of your body in motion, the rules of the invented world, the feeling of time dissolving. Now, consider the last time you felt a similar, fleeting sense of abandon as an adult. What activity prompted it? Write about the distance between these two experiences and the possibility of inviting more unstructured, joyful movement into your present life.",
"You are given a single, perfect seashell. Hold it to your ear. The old cliché speaks of the ocean's roar, but listen deeper. What else might you fathom in that hollow resonance? The sigh of the creature that once lived there? The whisper of ancient currents? The memory of a distant shore? Now, turn the metaphor inward. What deep, resonant chamber exists within you, and what is the sound it holds when you listen with total, patient attention? Write about the act of listening for the profound in the small and contained.",
"Describe a moment when an emotion—joy, grief, awe, fear—caused a physical quiver in your body. It might have been a shiver down your spine, a tremor in your hands, a catch in your breath. Locate the precise point of origin for this somatic echo. Did the feeling move through you like a wave, or settle in one place? Explore the conversation between your inner state and your physical vessel. How does the body register what the mind cannot yet fully articulate?"
]

View File

@@ -9,4 +9,4 @@ num_prompts = 3
# Pool size can affect the prompts if is too high. Default 20.
[prefetch]
cached_pool_volume = 20
cached_pool_volume = 24

139
test_current_state.py Normal file
View File

@@ -0,0 +1,139 @@
#!/usr/bin/env python3
"""
Test script to verify the current state of the web application.
"""
import requests
import json
import time
BASE_URL = "http://localhost:8000"
def test_endpoint(endpoint, method="GET", data=None):
"""Test an API endpoint."""
url = f"{BASE_URL}{endpoint}"
try:
if method == "GET":
response = requests.get(url, timeout=10)
elif method == "POST":
response = requests.post(url, json=data, timeout=10)
else:
return False, f"Unsupported method: {method}"
if response.status_code == 200:
return True, response.json()
else:
return False, f"Status {response.status_code}: {response.text}"
except Exception as e:
return False, f"Error: {str(e)}"
def main():
print("Testing Daily Journal Prompt Web Application")
print("=" * 50)
# Test 1: Check if backend is running
print("\n1. Testing backend health...")
success, result = test_endpoint("/")
if success:
print("✓ Backend is running")
print(f" Response: {result}")
else:
print(f"✗ Backend health check failed: {result}")
return
# Test 2: Check documentation endpoints
print("\n2. Testing documentation endpoints...")
for endpoint in ["/docs", "/redoc"]:
try:
response = requests.get(f"{BASE_URL}{endpoint}", timeout=5)
if response.status_code == 200:
print(f"{endpoint} is accessible")
else:
print(f"{endpoint} returned {response.status_code}")
except Exception as e:
print(f"{endpoint} error: {str(e)}")
# Test 3: Check prompt history
print("\n3. Testing prompt history...")
success, result = test_endpoint("/api/v1/prompts/history")
if success:
if isinstance(result, list):
print(f"✓ History has {len(result)} prompts")
if len(result) > 0:
print(f" Most recent: {result[0]['text'][:50]}...")
else:
print(f"✗ History response is not a list: {type(result)}")
else:
print(f"✗ History endpoint failed: {result}")
# Test 4: Check pool stats
print("\n4. Testing pool stats...")
success, result = test_endpoint("/api/v1/prompts/stats")
if success:
print(f"✓ Pool stats: {result['total_prompts']}/{result['target_pool_size']} prompts")
print(f" Available sessions: {result['available_sessions']}")
print(f" Needs refill: {result['needs_refill']}")
else:
print(f"✗ Pool stats failed: {result}")
# Test 5: Check feedback endpoints
print("\n5. Testing feedback endpoints...")
# Check queued words
success, result = test_endpoint("/api/v1/feedback/queued")
if success:
queued_words = result.get('queued_words', [])
print(f"✓ Queued feedback words: {len(queued_words)} words")
if queued_words:
print(f" First word: {queued_words[0]['word']} (weight: {queued_words[0]['weight']})")
else:
print(f"✗ Queued words failed: {result}")
# Check active words
success, result = test_endpoint("/api/v1/feedback/active")
if success:
active_words = result.get('active_words', [])
print(f"✓ Active feedback words: {len(active_words)} words")
if active_words:
print(f" First word: {active_words[0]['word']} (weight: {active_words[0]['weight']})")
else:
print(f"✗ Active words failed: {result}")
# Test 6: Test draw prompts
print("\n6. Testing draw prompts...")
success, result = test_endpoint("/api/v1/prompts/draw?count=1")
if success:
prompts = result.get('prompts', [])
print(f"✓ Drew {len(prompts)} prompt(s)")
if prompts:
print(f" Prompt: {prompts[0][:50]}...")
# Check updated pool stats
success2, result2 = test_endpoint("/api/v1/prompts/stats")
if success2:
print(f" Updated pool: {result2['total_prompts']}/{result2['target_pool_size']}")
else:
print(f"✗ Draw prompts failed: {result}")
# Test 7: Test frontend accessibility
print("\n7. Testing frontend accessibility...")
try:
response = requests.get("http://localhost:3000", timeout=5)
if response.status_code == 200:
print("✓ Frontend is accessible at http://localhost:3000")
else:
print(f"✗ Frontend returned {response.status_code}")
except Exception as e:
print(f"✗ Frontend error: {str(e)}")
print("\n" + "=" * 50)
print("Test completed!")
print("\nNext steps:")
print("1. Open http://localhost:3000 in your browser")
print("2. Click 'Draw 3 New Prompts' to test the workflow")
print("3. Select a prompt and click 'Use Selected Prompt'")
print("4. Click 'Fill Prompt Pool' to test feedback workflow")
if __name__ == "__main__":
main()