diff --git a/README.md b/README.md index b7cd5a0..bb920d1 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,19 @@ A Python tool that uses OpenAI-compatible AI endpoints to generate creative writ cd daily-journal-prompt ``` -2. **Set up environment variables**: +2. **Set up a Python virtual environment (recommended)**: + ```bash + # Create a virtual environment + python -m venv venv + + # Activate the virtual environment + # On Linux/macOS: + source venv/bin/activate + # On Windows: + # venv\Scripts\activate + ``` + +3. **Set up environment variables**: ```bash cp example.env .env ``` @@ -39,9 +51,9 @@ A Python tool that uses OpenAI-compatible AI endpoints to generate creative writ # OPENAI_API_KEY="sk-your-openai-api-key" ``` -3. **Install required Python packages**: +4. **Install required Python packages**: ```bash - pip install openai python-dotenv + pip install -r requirements.txt ``` ## 📁 Project Structure @@ -49,6 +61,11 @@ A Python tool that uses OpenAI-compatible AI endpoints to generate creative writ ``` daily-journal-prompt/ ├── README.md # This documentation +├── generate_prompts.py # Main Python script with rich interface +├── simple_generate.py # Lightweight version without rich dependency +├── run.sh # Convenience bash script +├── test_project.py # Test suite for the project +├── requirements.txt # Python dependencies ├── ds_prompt.txt # AI prompt template for generating journal prompts ├── historic_prompts.json # History of previous 60 prompts (JSON format) ├── example.env # Example environment configuration @@ -58,26 +75,68 @@ daily-journal-prompt/ ### File Descriptions -- **ds_prompt.txt**: The core prompt template that instructs the AI to generate 6 new journal prompts while avoiding repetition with the last 60 prompts. -- **historic_prompts.json**: A JSON array containing the last 60 generated prompts. This file is updated each time new prompts are generated. -- **example.env**: Template for your environment configuration. Copy this to `.env` and add your API key. -- **.env**: Your actual environment variables (not tracked in git for security). +- **generate_prompts.py**: Main Python script with interactive mode, rich formatting, and full features +- **simple_generate.py**: Lightweight version without rich dependency for basic usage +- **run.sh**: Convenience bash script for easy execution +- **test_project.py**: Test suite to verify project setup +- **requirements.txt**: Python dependencies (openai, python-dotenv, rich) +- **ds_prompt.txt**: The core prompt template that instructs the AI to generate 6 new journal prompts +- **historic_prompts.json**: JSON array containing the last 60 generated prompts +- **example.env**: Template for your environment configuration +- **.env**: Your actual environment variables (not tracked in git for security) -## 🔧 Implementation Status +## 🎯 Quick Start -This repository currently provides: -- ✅ Complete prompt template for AI interaction -- ✅ Historic prompt database with 60 example prompts -- ✅ Environment configuration template -- ✅ Comprehensive documentation +### Using the Bash Script (Recommended) +```bash +# Make the script executable +chmod +x run.sh -**To complete the implementation**, you need to: -1. Create a Python script (see example above) -2. Add API key parsing and AI client initialization -3. Implement prompt parsing and history management -4. Add error handling and user interface +# Generate prompts (default) +./run.sh -The example Python code in the "Getting Started" section provides a complete starting point. +# Interactive mode with rich interface +./run.sh --interactive + +# Simple version without rich dependency +./run.sh --simple + +# Show statistics +./run.sh --stats + +# Show help +./run.sh --help +``` + +### Using Python Directly +```bash +# First, activate your virtual environment (if using one) +# On Linux/macOS: +# source venv/bin/activate +# On Windows: +# venv\Scripts\activate + +# Install dependencies +pip install -r requirements.txt + +# Generate prompts (default) +python generate_prompts.py + +# Interactive mode +python generate_prompts.py --interactive + +# Show statistics +python generate_prompts.py --stats + +# Simple version (no rich dependency needed) +python simple_generate.py +``` + +### Testing Your Setup +```bash +# Run the test suite +python test_project.py +``` ## 🔧 Usage @@ -85,10 +144,10 @@ The example Python code in the "Getting Started" section provides a complete sta ### Prompt Generation Process 1. The system reads the template from `ds_prompt.txt` -2. It loads the previous 60 prompts from `historic_prompts.json` +2. It loads the previous 60 prompts from the fixed length cyclic buffer `historic_prompts.json` 3. The AI generates 6 new prompts, attempting to minimize repetition -4. New prompts are added to the history (maintaining only the last 60) -5. User selects one prompt for their journal writing session +4. Six new prompts are offered (maintaining only the last 60) +5. User selects one prompt for their journal writing session, which is added to the `historic_prompts.json` cyclic buffer. ## 📝 Prompt Examples diff --git a/__pycache__/generate_prompts.cpython-313.pyc b/__pycache__/generate_prompts.cpython-313.pyc new file mode 100644 index 0000000..54a3be3 Binary files /dev/null and b/__pycache__/generate_prompts.cpython-313.pyc differ diff --git a/__pycache__/simple_generate.cpython-313.pyc b/__pycache__/simple_generate.cpython-313.pyc new file mode 100644 index 0000000..88e7f4d Binary files /dev/null and b/__pycache__/simple_generate.cpython-313.pyc differ diff --git a/__pycache__/test_project.cpython-313.pyc b/__pycache__/test_project.cpython-313.pyc new file mode 100644 index 0000000..c8bec39 Binary files /dev/null and b/__pycache__/test_project.cpython-313.pyc differ diff --git a/__pycache__/test_prompt_logic.cpython-313.pyc b/__pycache__/test_prompt_logic.cpython-313.pyc new file mode 100644 index 0000000..a34362b Binary files /dev/null and b/__pycache__/test_prompt_logic.cpython-313.pyc differ diff --git a/generate_prompts.py b/generate_prompts.py new file mode 100644 index 0000000..a8b3ac9 --- /dev/null +++ b/generate_prompts.py @@ -0,0 +1,371 @@ +#!/usr/bin/env python3 +""" +Daily Journal Prompt Generator +A tool that uses AI to generate creative writing prompts for daily journaling. +""" + +import os +import json +import sys +import argparse +from datetime import datetime +from typing import List, Dict, Any, Optional +from pathlib import Path + +from openai import OpenAI +from dotenv import load_dotenv +from rich.console import Console +from rich.panel import Panel +from rich.table import Table +from rich.prompt import Prompt, Confirm +from rich.progress import Progress, SpinnerColumn, TextColumn + + +class JournalPromptGenerator: + """Main class for generating journal prompts using AI.""" + + def __init__(self, config_path: str = ".env"): + """Initialize the generator with configuration.""" + self.console = Console() + self.config_path = config_path + self.client = None + self.historic_prompts = [] + self.prompt_template = "" + + # Load configuration + self._load_config() + + # Load data files + self._load_prompt_template() + self._load_historic_prompts() + + def _load_config(self): + """Load configuration from environment file.""" + load_dotenv(self.config_path) + + # Get API key + self.api_key = os.getenv("DEEPSEEK_API_KEY") or os.getenv("OPENAI_API_KEY") + if not self.api_key: + self.console.print("[red]Error: No API key found in .env file[/red]") + self.console.print("Please add DEEPSEEK_API_KEY or OPENAI_API_KEY to your .env file") + sys.exit(1) + + # Get API base URL (default to DeepSeek) + self.base_url = os.getenv("API_BASE_URL", "https://api.deepseek.com") + + # Get model (default to deepseek-chat) + self.model = os.getenv("MODEL", "deepseek-chat") + + # Initialize OpenAI client + self.client = OpenAI( + api_key=self.api_key, + base_url=self.base_url + ) + + def _load_prompt_template(self): + """Load the prompt template from ds_prompt.txt.""" + try: + with open("ds_prompt.txt", "r") as f: + self.prompt_template = f.read() + except FileNotFoundError: + self.console.print("[red]Error: ds_prompt.txt not found[/red]") + sys.exit(1) + + def _load_historic_prompts(self): + """Load historic prompts from JSON file.""" + try: + with open("historic_prompts.json", "r") as f: + self.historic_prompts = json.load(f) + except FileNotFoundError: + self.console.print("[yellow]Warning: historic_prompts.json not found, starting with empty history[/yellow]") + self.historic_prompts = [] + except json.JSONDecodeError: + self.console.print("[yellow]Warning: historic_prompts.json is corrupted, starting with empty history[/yellow]") + self.historic_prompts = [] + + def _save_historic_prompts(self): + """Save historic prompts to JSON file (keeping only first 60).""" + # Keep only the first 60 prompts (newest are at the beginning) + if len(self.historic_prompts) > 60: + self.historic_prompts = self.historic_prompts[:60] + + with open("historic_prompts.json", "w") as f: + json.dump(self.historic_prompts, f, indent=2) + + def _renumber_prompts(self): + """Renumber all prompts to maintain prompt00-prompt59 range.""" + renumbered_prompts = [] + for i, prompt_dict in enumerate(self.historic_prompts): + # Get the prompt text from the first key in the dictionary + prompt_key = list(prompt_dict.keys())[0] + prompt_text = prompt_dict[prompt_key] + + # Create new prompt with correct numbering + new_prompt_key = f"prompt{i:02d}" + renumbered_prompts.append({ + new_prompt_key: prompt_text + }) + + self.historic_prompts = renumbered_prompts + + def add_prompt_to_history(self, prompt_text: str): + """ + Add a single prompt to the historic prompts cyclic buffer. + The new prompt becomes prompt00, all others shift down, and prompt59 is discarded. + """ + # Create the new prompt object + new_prompt = { + "prompt00": prompt_text + } + + # Shift all existing prompts down by one position + # We'll create a new list starting with the new prompt + updated_prompts = [new_prompt] + + # Add all existing prompts, shifting their numbers down by one + for i, prompt_dict in enumerate(self.historic_prompts): + if i >= 59: # We only keep 60 prompts total (00-59) + break + + # Get the prompt text + prompt_key = list(prompt_dict.keys())[0] + prompt_text = prompt_dict[prompt_key] + + # Create prompt with new number (shifted down by one) + new_prompt_key = f"prompt{i+1:02d}" + updated_prompts.append({ + new_prompt_key: prompt_text + }) + + self.historic_prompts = updated_prompts + self._save_historic_prompts() + + def _prepare_prompt(self) -> str: + """Prepare the full prompt with historic context.""" + # Format historic prompts for the AI + if self.historic_prompts: + historic_context = json.dumps(self.historic_prompts, indent=2) + full_prompt = f"{self.prompt_template}\n\nPrevious prompts:\n{historic_context}" + else: + full_prompt = self.prompt_template + + return full_prompt + + def _parse_ai_response(self, response_content: str) -> List[Dict[str, str]]: + """ + Parse the AI response to extract new prompts. + Expected format: JSON array with keys "newprompt0" to "newprompt5" + """ + try: + # Try to parse as JSON + data = json.loads(response_content) + + # Convert to list of prompt dictionaries + new_prompts = [] + for i in range(6): + key = f"newprompt{i}" + if key in data: + prompt_text = data[key] + prompt_obj = { + f"prompt{len(self.historic_prompts) + i:02d}": prompt_text + } + new_prompts.append(prompt_obj) + + return new_prompts + + except json.JSONDecodeError: + # If not valid JSON, try to extract prompts from text + self.console.print("[yellow]Warning: AI response is not valid JSON, attempting to extract prompts...[/yellow]") + + # Look for patterns in the text + lines = response_content.strip().split('\n') + new_prompts = [] + + for i, line in enumerate(lines[:6]): # Take first 6 non-empty lines + line = line.strip() + if line and len(line) > 50: # Reasonable minimum length for a prompt + prompt_obj = { + f"prompt{len(self.historic_prompts) + i:02d}": line + } + new_prompts.append(prompt_obj) + + return new_prompts + + def generate_prompts(self) -> List[Dict[str, str]]: + """Generate new journal prompts using AI.""" + self.console.print("\n[cyan]Generating new journal prompts...[/cyan]") + + # Prepare the prompt + full_prompt = self._prepare_prompt() + + # Show progress + with Progress( + SpinnerColumn(), + TextColumn("[progress.description]{task.description}"), + transient=True, + ) as progress: + task = progress.add_task("Calling AI API...", total=None) + + try: + # Call the AI API + response = self.client.chat.completions.create( + model=self.model, + messages=[ + {"role": "system", "content": "You are a creative writing assistant that generates journal prompts. Always respond with valid JSON."}, + {"role": "user", "content": full_prompt} + ], + temperature=0.7, + max_tokens=2000 + ) + + response_content = response.choices[0].message.content + + except Exception as e: + self.console.print(f"[red]Error calling AI API: {e}[/red]") + return [] + + # Parse the response + new_prompts = self._parse_ai_response(response_content) + + if not new_prompts: + self.console.print("[red]Error: Could not parse any prompts from AI response[/red]") + return [] + + # Note: Prompts are NOT added to historic_prompts here + # They will be added only when the user chooses one in interactive mode + # via the add_prompt_to_history() method + + return new_prompts + + def display_prompts(self, prompts: List[Dict[str, str]]): + """Display generated prompts in a nice format.""" + self.console.print("\n" + "="*60) + self.console.print("[bold green]✨ NEW JOURNAL PROMPTS GENERATED ✨[/bold green]") + self.console.print("="*60 + "\n") + + for i, prompt_dict in enumerate(prompts, 1): + # Extract prompt text (key is like "prompt60", "prompt61", etc.) + prompt_key = list(prompt_dict.keys())[0] + prompt_text = prompt_dict[prompt_key] + + # Create a panel for each prompt + panel = Panel( + f"[cyan]{prompt_text}[/cyan]", + title=f"[bold]Prompt #{i}[/bold]", + border_style="blue", + padding=(1, 2) + ) + self.console.print(panel) + self.console.print() # Empty line between prompts + + def show_history_stats(self): + """Show statistics about prompt history.""" + total_prompts = len(self.historic_prompts) + + table = Table(title="Prompt History Statistics") + table.add_column("Metric", style="cyan") + table.add_column("Value", style="green") + + table.add_row("Total prompts in history", str(total_prompts)) + table.add_row("History capacity", "60 prompts") + table.add_row("Available slots", str(max(0, 60 - total_prompts))) + + self.console.print(table) + + def interactive_mode(self): + """Run in interactive mode with user prompts.""" + self.console.print(Panel.fit( + "[bold]Daily Journal Prompt Generator[/bold]\n" + "Generate creative writing prompts for your journal practice", + border_style="green" + )) + + while True: + self.console.print("\n[bold]Options:[/bold]") + self.console.print("1. Generate new prompts") + self.console.print("2. View history statistics") + self.console.print("3. Exit") + + choice = Prompt.ask("\nEnter your choice", choices=["1", "2", "3"], default="1") + + if choice == "1": + new_prompts = self.generate_prompts() + if new_prompts: + self.display_prompts(new_prompts) + + # Ask if user wants to save a prompt + if Confirm.ask("\nWould you like to save one of these prompts to a file?"): + prompt_num = Prompt.ask( + "Which prompt number would you like to save?", + choices=[str(i) for i in range(1, len(new_prompts) + 1)], + default="1" + ) + + prompt_idx = int(prompt_num) - 1 + prompt_dict = new_prompts[prompt_idx] + prompt_key = list(prompt_dict.keys())[0] + prompt_text = prompt_dict[prompt_key] + + # Save to file + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + filename = f"journal_prompt_{timestamp}.txt" + + with open(filename, "w") as f: + f.write(f"Journal Prompt - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n") + f.write("="*50 + "\n\n") + f.write(prompt_text) + f.write("\n\n" + "="*50 + "\n") + f.write("Happy writing! ✍️\n") + + self.console.print(f"[green]Prompt saved to {filename}[/green]") + + # Add the chosen prompt to historic prompts cyclic buffer + self.add_prompt_to_history(prompt_text) + self.console.print(f"[green]Prompt added to history as prompt00[/green]") + + elif choice == "2": + self.show_history_stats() + + elif choice == "3": + self.console.print("[green]Goodbye! Happy journaling! 📓[/green]") + break + + +def main(): + """Main entry point for the script.""" + parser = argparse.ArgumentParser(description="Generate journal prompts using AI") + parser.add_argument( + "--interactive", "-i", + action="store_true", + help="Run in interactive mode" + ) + parser.add_argument( + "--config", "-c", + default=".env", + help="Path to configuration file (default: .env)" + ) + parser.add_argument( + "--stats", "-s", + action="store_true", + help="Show history statistics" + ) + + args = parser.parse_args() + + # Initialize generator + generator = JournalPromptGenerator(config_path=args.config) + + if args.stats: + generator.show_history_stats() + elif args.interactive: + generator.interactive_mode() + else: + # Default: generate and display prompts + new_prompts = generator.generate_prompts() + if new_prompts: + generator.display_prompts(new_prompts) + + +if __name__ == "__main__": + main() + diff --git a/historic_prompts.json b/historic_prompts.json index c712dd8..d8631d8 100644 --- a/historic_prompts.json +++ b/historic_prompts.json @@ -1,182 +1,182 @@ [ -{ -"prompt00": "Describe a memory you have that is tied to a specific smell. Don't just tell the story of the event; focus on describing the scent itself in as much detail as possible—its texture, its weight in the air, its nuances. How does conjuring that smell now make you feel in your body? Let the description of the aroma lead you back into the memory's landscape." -}, -{ -"prompt01": "Write a letter to your 15-year-old self. Be kind, be blunt, be humorous, or be stern. What do you know now that you desperately needed to hear then? What mystery about your future life could you tantalizingly hint at without giving it all away? Don't just give advice; try to capture the voice and tone you wish an older, wiser person had used with you." -}, -{ -"prompt02": "You find a forgotten door in a place you know well—your home, your workplace, your daily park. It wasn't there yesterday. You open it. Describe what is on the other side using only sensory details: sight, sound, temperature, smell. Do not explain its purpose or origin. Simply document the experience of crossing that threshold." -}, -{ -"prompt03": "Make a list of ten tiny, perfect moments from the past month that no one else probably noticed or would remember. The way light fell on a spoon, a stranger's half-smile, the sound of rain stopping. Elaborate on at least three of them, expanding them into full vignettes. Why did these micro-moments stick with you?" -}, -{ -"prompt04": "Invent a mythological creature for a modern urban setting. What does it look like? What is its behavior and habitat (e.g., subway tunnels, server farms, air vents)? What folklore do people whisper about it? What does it symbolize—anxiety, forgotten connections, hope? Describe a recent 'sighting' of this creature in vivid detail." -}, -{ -"prompt05": "Choose an object in your immediate line of sight that is not electronic. Write its biography. Where was it made? Who owned it before you? What conversations has it overheard? What secrets does it hold? What small damages or wear marks does it have, and what story does each tell? Give this ordinary item an epic history." -}, -{ -"prompt06": "Describe your current emotional state as a weather system. Is it a still, high-pressure fog? A sudden, sharp hailstorm? A lingering, humid drizzle? Map its boundaries, its intensity, its forecast. What terrain does it move over—the mountains of your responsibilities, the plains of your routine? How does it affect your internal climate?" -}, -{ -"prompt07": "Recall a time you were deeply embarrassed. Write about it from the perspective of a sympathetic observer who was there—or invent one. How might they have perceived the event? What context or kindness might they have seen that you, in your self-focused shame, completely missed? Reframe the memory through their eyes." -}, -{ -"prompt08": "What skill or craft have you always wanted to learn but haven't? Immerse yourself in a detailed fantasy of mastering it. Describe the feel of the tools in your hands, the initial frustrations, the first small success, the growing muscle memory. What does the final, perfected product of your labor look or feel like? Live in that imagined成就感." -}, -{ -"prompt09": "Write a dialogue between two aspects of yourself (e.g., Your Ambitious Self and Your Tired Self; Your Cynical Self and Your Hopeful Self). Give them distinct voices. What are they arguing about, negotiating, or planning? Don't just state positions; let them bicker, persuade, or sit in silence together. See where the conversation goes." -}, -{ -"prompt10": "Describe your childhood home from the perspective of a small animal (a mouse, a squirrel, a bird) that lived there concurrently with you. What did this creature notice about your family's rhythms, the layout, the dangers, and the treasures (crumbs, cozy materials)? How did it perceive you, the giant human child?" -}, -{ -"prompt11": "List five paths your life could have taken if you'd made one different choice. Briefly outline each alternate reality. Then, choose one and dive deep: write a journal entry from that version of you today. What are their worries, joys, and regrets? How is their voice similar to or different from your own?" -}, -{ -"prompt12": "Think of a person you see regularly but do not know (a barista, a neighbor, a commuter). Invent a rich, secret inner life for them. What profound private mission are they on? What hidden talent do they possess? What great sorrow or hope are they carrying today as they serve your coffee or stand on the platform? Write from their perspective." -}, -{ -"prompt13": "What is a belief you held strongly five or ten years ago that you have since questioned or abandoned? Trace the evolution of that change. Was it a sudden shattering or a slow erosion? What person, experience, or piece of information was the catalyst? Describe the feeling of the ground shifting under that particular piece of your worldview." -}, -{ -"prompt14": "Describe a common, mundane process (making tea, tying your shoes, doing laundry) in extreme, almost absurdly epic detail, as if you were writing a sacred manual or a scientific treatise for an alien civilization. Break down every micro-action, every sensation, every potential variable. Find the profound in the procedural." -}, -{ -"prompt15": "You are given a suitcase and told you must leave your home in one hour, not knowing if or when you'll return. You can only take what fits in the case. Describe, in real-time, the frantic and deliberate process of choosing. What practical items make the cut? What irreplaceable tokens? What do you leave behind, and what does that feel like?" -}, -{ -"prompt16": "Write about water in three different forms: as a memory involving a body of water (ocean, river, bath), as a description of drinking a glass of water right now, and as a metaphor for an emotion. Move seamlessly between these three aspects. Let the fluidity of the theme connect them." -}, -{ -"prompt17": "What does silence sound like in your current environment? Don't just say 'quiet.' Describe the layers of sound that actually constitute the silence—the hums, ticks, distant rumbles, the sound of your own body. Now, project what this same space sounded like 100 years ago, and what it might sound like 100 years from now." -}, -{ -"prompt18": "Create a recipe for a dish that represents your current life phase. List ingredients (e.g., \"two cups of transition,\" \"a pinch of anxiety,\" \"a steady base of routine\"). Write the instructions, including the method, cooking time, and necessary equipment. Describe the final product's taste, texture, and who it should be shared with." -}, -{ -"prompt19": "Recall a dream from the past week, however fragmentary. Don't interpret it. Instead, expand it. Continue the narrative from where it left off. Describe the dream logic, the landscape, the characters. Let it become a story. Where does your dreaming mind take you when given free rein on the page?" -}, -{ -"prompt20": "Make a list of everything that is blue in your immediate environment. Describe each shade specifically (slate, cobalt, robin's egg, faded denim). Then, choose one blue object and write about its journey to being here, in this blue state, in front of you. How did it get its color? What has it reflected?" -}, -{ -"prompt21": "Write a eulogy for something you've lost that isn't a person—a habit, a version of a city, a relationship dynamic, a part of your identity. Acknowledge its virtues and its flaws. Say goodbye properly, with humor, regret, and gratitude. What did it give you? What space has its departure created?" -}, -{ -"prompt22": "Describe your hands. Not just their appearance, but their capabilities, their scars, their memories. What have they held, built, comforted, or torn down? What do their specific aches and strengths tell you about the life you've lived so far? If your hands could speak, what would they say they want to do next?" -}, -{ -"prompt23": "Imagine you can overhear the conversation of the people at the table next to you in a café, but they are speaking in a language you don't understand. Based on their tone, gestures, pauses, and expressions, invent the dialogue. What crucial, funny, or tragic misunderstanding are they having? What are they *really* talking about?" -}, -{ -"prompt24": "What is a piece of art (a song, painting, film, book) that fundamentally moved you? Describe the first time you encountered it. Don't just analyze why it's good; describe the physical and emotional reaction it provoked. Has its meaning changed for you over time? How does it live inside you now?" -}, -{ -"prompt25": "You have one day completely alone, with no obligations and no possibility of communication. The power and internet are out. How do you spend the hours from waking to sleeping? Detail the rituals, the wanderings, the thoughts, the meals. Do you enjoy the solitude or chafe against it? What arises in the quiet?" -}, -{ -"prompt26": "Personify a negative emotion you've been feeling lately (e.g., anxiety, envy, restlessness). Give it a name, a form, a voice. Write a character profile of it. What does it want? What does it fear? What flawed logic does it operate under? Then, write a short scene of you having a cup of tea with it, listening to its perspective." -}, -{ -"prompt27": "Describe a city you've never been to, based solely on the stories, images, and snippets you've absorbed about it. Build it from imagination and second-hand clues. Then, contrast that with a description of your own street, seen with the hyper-attentive eyes of a first-time visitor. Make the familiar alien, and the alien familiar." -}, -{ -"prompt28": "Think of a crossroads in your past. Now, imagine you see a ghost of your former self standing there, frozen in that moment of decision. What would you want to say to that ghost? Would you offer comfort, a warning, or just silent companionship? Write the encounter. Does the ghost speak back?" -}, -{ -"prompt29": "What is a tradition in your family or community—big or small—that you find meaningful? Describe its sensory details, its rhythms, its players. Now, trace its origin. How did it start? Has it mutated over time? What does its continued practice say about what your family values, fears, or hopes for?" -}, -{ -"prompt30": "Choose a year from your past. Catalog the soundtrack of that year: songs on the radio, albums you loved, jingles, background music. For each, describe a specific memory or feeling it evokes. How does the music of that time period color your memory of the entire era? What does it sound like to you now?" -}, -{ -"prompt31": "Write instructions for a stranger on how to be you for a day. Include the essential routines, the internal dialogues to expect, the things to avoid, the small comforts to lean on, and the passwords to your various anxieties. Be brutally honest and surprisingly practical. What would they find hardest to mimic?" -}, -{ -"prompt32": "Describe a moment of unexpected kindness, either given or received. Don't frame it as a grand gesture. Focus on a small, almost invisible act. What were the circumstances? Why was it so potent? How did it ripple out, changing the temperature of your day or your perception of someone?" -}, -{ -"prompt33": "You discover you have a superpower, but it is frustratingly mundane and specific (e.g., the ability to always know exactly what time it is without a clock, to perfectly fold fitted sheets, to find lost buttons). Explore the practical uses, the minor heroics, the unexpected downsides, and the peculiar loneliness of this unique gift." -}, -{ -"prompt34": "Go to a window. Describe the view in extreme detail, as if painting it with words, for five minutes. Then, close your eyes and describe the view from a window that was significant to you in the past (your childhood bedroom, a previous office, a grandparent's house). Juxtapose the two landscapes on the page." -}, -{ -"prompt35": "What is a question you are tired of being asked? Write a rant about why it's so irritating, reductive, or painful. Then, flip it: write the question you wish people would ask you instead. Answer that new question fully and generously." -}, -{ -"prompt36": "Describe a hobby or interest you have from the perspective of someone who finds it utterly baffling and boring. Then, defend it with the passionate zeal of a true devotee. Try to convey its magic and depth to this imagined skeptic. What is the core beauty you see that they miss?" -}, -{ -"prompt37": "List ten things you would do if you were not afraid. They can be grand (quit my job) or small (sing karaoke). Choose one and vividly imagine doing it. Walk through every step, from decision to action to aftermath. How does the air feel different on the other side of that fear?" -}, -{ -"prompt38": "Write about a time you got exactly what you wanted—and it was not what you expected. Describe the desire, the anticipation, the moment of attainment, and the subtle (or not-so-subtle) disappointment or confusion that followed. What did that experience teach you about wanting?" -}, -{ -"prompt39": "Personify your favorite season. Give it a personality, a wardrobe, a way of speaking, a scent. Write a monologue from its perspective. What does it think of humans? What is its purpose? What does it love and resent about its place in the yearly cycle? Let it defend itself against its critics." -}, -{ -"prompt40": "Describe a room after a significant emotional event has occurred (a fight, a celebration, a profound conversation), but without mentioning the event or the people. Let the objects, the disarray, the quality of light, the lingering smells tell the story. What is the room holding now?" -}, -{ -"prompt41": "What is a rule you live by? It can be profound ('assume good intent') or practical ('never grocery shop hungry'). Explain its origin story. When have you broken it, and what were the consequences? How has following it shaped your life? Argue for its universal adoption." -}, -{ -"prompt42": "Imagine you can send a message of exactly 100 words into the future, to be read by you in ten years. What do you say? What do you ask? What current worry do you want to soothe, or what current joy do you want future-you to remember? Write the message. Then, write a 100-word message from you-ten-years-ago to present-you." -}, -{ -"prompt43": "Describe a color to someone who has been blind from birth. Use metaphor, texture, temperature, sound, emotion, and memory. Don't rely on sight-based comparisons ('like the sky'). Try to make them *feel* the essence of 'red' or 'blue' or 'gold' in their bones." -}, -{ -"prompt44": "Write about a book that changed your mind. Not just one you loved, but one that actively altered your perspective on a topic. Describe your stance before, the unsettling process of reading it, and the new landscape of thought afterwards. What made you vulnerable to its argument?" -}, -{ -"prompt45": "Catalog the contents of a junk drawer or a cluttered bag—yours or an imagined one. Describe each item with care, as an archaeologist might. Then, construct a biography of the drawer's owner based solely on these artifacts. What story do these mundane relics tell?" -}, -{ -"prompt46": "What does your body know how to do that your mind often forgets? (e.g., breathe deeply, relax into sleep, find rhythm in a walk). Write a series of instructions from your body to your mind, teaching it this skill again. Use the language of sensation, not thought." -}, -{ -"prompt47": "Describe a journey you take every day (commute, walk the dog, trip to the kitchen) as a epic quest. Cast yourself as the hero, the mundane obstacles as trials (the traffic dragon, the staircase mountain), and the destination as a holy grail. Infuse the ordinary with mythic significance." -}, -{ -"prompt48": "Write a review of today, as if it were a product, a performance, or a restaurant. Give it star ratings in different categories (Productivity, Serendipity, Comfort, Learning). Write the critic's summary. Be witty, be harsh, be fair. What was the highlight? The biggest flaw? Would you recommend today to a friend?" -}, -{ -"prompt49": "Think of a word you love the sound of. Write it at the top of the page. Now, free-associate from that word—not just meanings, but sounds, memories, images. Let it spin a web of connections. Where does it lead you? Try to capture the aesthetic and emotional resonance of the word itself." -}, -{ -"prompt50": "Describe a piece of technology you use daily from the perspective of a person from 200 years ago. Have them stumble upon it and try to deduce its purpose, its magic, and its societal implications from its form and behavior. What would they find beautiful, terrifying, or absurd?" -}, -{ -"prompt51": "Write a gratitude list, but for difficult things. Be specific. Not just 'my job,' but 'the particular frustration of my project that forced me to learn a new skill.' Find the hidden gift in the challenge, the strength forged in the irritation, the clarity born of the sorrow." -}, -{ -"prompt52": "You meet a version of yourself from a parallel universe where one key life detail is different (you chose a different career, never moved, stayed with a different partner). Have a conversation with them. What do you envy? What do you pity? What fundamental part of 'you' remains the same?" -}, -{ -"prompt53": "Describe a taste from your childhood that you can almost, but not quite, recall—a specific candy, a grandparent's dish, a seasonal treat. Try to chase the memory with all your senses. What else was happening when you tasted it? Who was there? Why is it lost? The struggle to remember is the story." -}, -{ -"prompt54": "What is a place that feels like a sanctuary to you? Describe it not just physically, but atmospherically. What rules (spoken or unspoken) govern it? What happens to your internal noise when you enter? What would it mean to carry the essence of that place with you into busier, louder realms?" -}, -{ -"prompt55": "Write about waiting. Describe a specific time you were waiting for something (big or small). Capture the texture of the time itself—how it stretched, what you noticed, the cycles of hope and boredom. What did you learn in the suspension? The action is in the inaction." -}, -{ -"prompt56": "Compose a manifesto for a very small, personal revolution. What outdated pattern, fear, or limitation are you overthrowing? What are your guiding principles? What is your first, tiny act of rebellion? Use bold, declarative language. Declare your independence from something that no longer serves you." -}, -{ -"prompt57": "Describe a conflict you witnessed but were not part of—between strangers, friends, or family members. Focus on the subtext: the body language, the words not said, the history simmering beneath the surface. What did you understand about each person from this glimpse? Why has this particular conflict stuck with you?" -}, -{ -"prompt58": "Look at the oldest photograph you have of yourself. Describe the child in that photo objectively, as if they are a stranger. What do you see in their eyes, posture, and environment? What might they be hoping for or fearing? Write a letter to that child, not as your past self, but as a distant relative meeting them for the first time." -}, -{ -"prompt59": "Imagine your life as a landscape—is it a coastline, a forest, a desert, a cityscape? Describe its features: the stable mountains, the changing weather, the overgrown paths, the clearings. Where are you currently located in this landscape? What direction are you traveling? What lies just beyond the visible horizon?" -} + { + "prompt00": "\"newprompt0\": \"Write a detailed portrait of a tree you know well\u2014not just its appearance, but its history in that spot, the way its branches move in different winds, the creatures that inhabit it, the shadows it casts at various hours. Imagine its perspective across seasons and years. What has it witnessed? What would it say about change, resilience, or stillness if it could speak? Let the tree become a mirror for your own sense of place and time.\"," + }, + { + "prompt01": "Describe a memory you have that is tied to a specific smell. Don't just tell the story of the event; focus on describing the scent itself in as much detail as possible\u2014its texture, its weight in the air, its nuances. How does conjuring that smell now make you feel in your body? Let the description of the aroma lead you back into the memory's landscape." + }, + { + "prompt02": "Write a letter to your 15-year-old self. Be kind, be blunt, be humorous, or be stern. What do you know now that you desperately needed to hear then? What mystery about your future life could you tantalizingly hint at without giving it all away? Don't just give advice; try to capture the voice and tone you wish an older, wiser person had used with you." + }, + { + "prompt03": "You find a forgotten door in a place you know well\u2014your home, your workplace, your daily park. It wasn't there yesterday. You open it. Describe what is on the other side using only sensory details: sight, sound, temperature, smell. Do not explain its purpose or origin. Simply document the experience of crossing that threshold." + }, + { + "prompt04": "Make a list of ten tiny, perfect moments from the past month that no one else probably noticed or would remember. The way light fell on a spoon, a stranger's half-smile, the sound of rain stopping. Elaborate on at least three of them, expanding them into full vignettes. Why did these micro-moments stick with you?" + }, + { + "prompt05": "Invent a mythological creature for a modern urban setting. What does it look like? What is its behavior and habitat (e.g., subway tunnels, server farms, air vents)? What folklore do people whisper about it? What does it symbolize\u2014anxiety, forgotten connections, hope? Describe a recent 'sighting' of this creature in vivid detail." + }, + { + "prompt06": "Choose an object in your immediate line of sight that is not electronic. Write its biography. Where was it made? Who owned it before you? What conversations has it overheard? What secrets does it hold? What small damages or wear marks does it have, and what story does each tell? Give this ordinary item an epic history." + }, + { + "prompt07": "Describe your current emotional state as a weather system. Is it a still, high-pressure fog? A sudden, sharp hailstorm? A lingering, humid drizzle? Map its boundaries, its intensity, its forecast. What terrain does it move over\u2014the mountains of your responsibilities, the plains of your routine? How does it affect your internal climate?" + }, + { + "prompt08": "Recall a time you were deeply embarrassed. Write about it from the perspective of a sympathetic observer who was there\u2014or invent one. How might they have perceived the event? What context or kindness might they have seen that you, in your self-focused shame, completely missed? Reframe the memory through their eyes." + }, + { + "prompt09": "What skill or craft have you always wanted to learn but haven't? Immerse yourself in a detailed fantasy of mastering it. Describe the feel of the tools in your hands, the initial frustrations, the first small success, the growing muscle memory. What does the final, perfected product of your labor look or feel like? Live in that imagined\u6210\u5c31\u611f." + }, + { + "prompt10": "Write a dialogue between two aspects of yourself (e.g., Your Ambitious Self and Your Tired Self; Your Cynical Self and Your Hopeful Self). Give them distinct voices. What are they arguing about, negotiating, or planning? Don't just state positions; let them bicker, persuade, or sit in silence together. See where the conversation goes." + }, + { + "prompt11": "Describe your childhood home from the perspective of a small animal (a mouse, a squirrel, a bird) that lived there concurrently with you. What did this creature notice about your family's rhythms, the layout, the dangers, and the treasures (crumbs, cozy materials)? How did it perceive you, the giant human child?" + }, + { + "prompt12": "List five paths your life could have taken if you'd made one different choice. Briefly outline each alternate reality. Then, choose one and dive deep: write a journal entry from that version of you today. What are their worries, joys, and regrets? How is their voice similar to or different from your own?" + }, + { + "prompt13": "Think of a person you see regularly but do not know (a barista, a neighbor, a commuter). Invent a rich, secret inner life for them. What profound private mission are they on? What hidden talent do they possess? What great sorrow or hope are they carrying today as they serve your coffee or stand on the platform? Write from their perspective." + }, + { + "prompt14": "What is a belief you held strongly five or ten years ago that you have since questioned or abandoned? Trace the evolution of that change. Was it a sudden shattering or a slow erosion? What person, experience, or piece of information was the catalyst? Describe the feeling of the ground shifting under that particular piece of your worldview." + }, + { + "prompt15": "Describe a common, mundane process (making tea, tying your shoes, doing laundry) in extreme, almost absurdly epic detail, as if you were writing a sacred manual or a scientific treatise for an alien civilization. Break down every micro-action, every sensation, every potential variable. Find the profound in the procedural." + }, + { + "prompt16": "You are given a suitcase and told you must leave your home in one hour, not knowing if or when you'll return. You can only take what fits in the case. Describe, in real-time, the frantic and deliberate process of choosing. What practical items make the cut? What irreplaceable tokens? What do you leave behind, and what does that feel like?" + }, + { + "prompt17": "Write about water in three different forms: as a memory involving a body of water (ocean, river, bath), as a description of drinking a glass of water right now, and as a metaphor for an emotion. Move seamlessly between these three aspects. Let the fluidity of the theme connect them." + }, + { + "prompt18": "What does silence sound like in your current environment? Don't just say 'quiet.' Describe the layers of sound that actually constitute the silence\u2014the hums, ticks, distant rumbles, the sound of your own body. Now, project what this same space sounded like 100 years ago, and what it might sound like 100 years from now." + }, + { + "prompt19": "Create a recipe for a dish that represents your current life phase. List ingredients (e.g., \"two cups of transition,\" \"a pinch of anxiety,\" \"a steady base of routine\"). Write the instructions, including the method, cooking time, and necessary equipment. Describe the final product's taste, texture, and who it should be shared with." + }, + { + "prompt20": "Recall a dream from the past week, however fragmentary. Don't interpret it. Instead, expand it. Continue the narrative from where it left off. Describe the dream logic, the landscape, the characters. Let it become a story. Where does your dreaming mind take you when given free rein on the page?" + }, + { + "prompt21": "Make a list of everything that is blue in your immediate environment. Describe each shade specifically (slate, cobalt, robin's egg, faded denim). Then, choose one blue object and write about its journey to being here, in this blue state, in front of you. How did it get its color? What has it reflected?" + }, + { + "prompt22": "Write a eulogy for something you've lost that isn't a person\u2014a habit, a version of a city, a relationship dynamic, a part of your identity. Acknowledge its virtues and its flaws. Say goodbye properly, with humor, regret, and gratitude. What did it give you? What space has its departure created?" + }, + { + "prompt23": "Describe your hands. Not just their appearance, but their capabilities, their scars, their memories. What have they held, built, comforted, or torn down? What do their specific aches and strengths tell you about the life you've lived so far? If your hands could speak, what would they say they want to do next?" + }, + { + "prompt24": "Imagine you can overhear the conversation of the people at the table next to you in a caf\u00e9, but they are speaking in a language you don't understand. Based on their tone, gestures, pauses, and expressions, invent the dialogue. What crucial, funny, or tragic misunderstanding are they having? What are they *really* talking about?" + }, + { + "prompt25": "What is a piece of art (a song, painting, film, book) that fundamentally moved you? Describe the first time you encountered it. Don't just analyze why it's good; describe the physical and emotional reaction it provoked. Has its meaning changed for you over time? How does it live inside you now?" + }, + { + "prompt26": "You have one day completely alone, with no obligations and no possibility of communication. The power and internet are out. How do you spend the hours from waking to sleeping? Detail the rituals, the wanderings, the thoughts, the meals. Do you enjoy the solitude or chafe against it? What arises in the quiet?" + }, + { + "prompt27": "Personify a negative emotion you've been feeling lately (e.g., anxiety, envy, restlessness). Give it a name, a form, a voice. Write a character profile of it. What does it want? What does it fear? What flawed logic does it operate under? Then, write a short scene of you having a cup of tea with it, listening to its perspective." + }, + { + "prompt28": "Describe a city you've never been to, based solely on the stories, images, and snippets you've absorbed about it. Build it from imagination and second-hand clues. Then, contrast that with a description of your own street, seen with the hyper-attentive eyes of a first-time visitor. Make the familiar alien, and the alien familiar." + }, + { + "prompt29": "Think of a crossroads in your past. Now, imagine you see a ghost of your former self standing there, frozen in that moment of decision. What would you want to say to that ghost? Would you offer comfort, a warning, or just silent companionship? Write the encounter. Does the ghost speak back?" + }, + { + "prompt30": "What is a tradition in your family or community\u2014big or small\u2014that you find meaningful? Describe its sensory details, its rhythms, its players. Now, trace its origin. How did it start? Has it mutated over time? What does its continued practice say about what your family values, fears, or hopes for?" + }, + { + "prompt31": "Choose a year from your past. Catalog the soundtrack of that year: songs on the radio, albums you loved, jingles, background music. For each, describe a specific memory or feeling it evokes. How does the music of that time period color your memory of the entire era? What does it sound like to you now?" + }, + { + "prompt32": "Write instructions for a stranger on how to be you for a day. Include the essential routines, the internal dialogues to expect, the things to avoid, the small comforts to lean on, and the passwords to your various anxieties. Be brutally honest and surprisingly practical. What would they find hardest to mimic?" + }, + { + "prompt33": "Describe a moment of unexpected kindness, either given or received. Don't frame it as a grand gesture. Focus on a small, almost invisible act. What were the circumstances? Why was it so potent? How did it ripple out, changing the temperature of your day or your perception of someone?" + }, + { + "prompt34": "You discover you have a superpower, but it is frustratingly mundane and specific (e.g., the ability to always know exactly what time it is without a clock, to perfectly fold fitted sheets, to find lost buttons). Explore the practical uses, the minor heroics, the unexpected downsides, and the peculiar loneliness of this unique gift." + }, + { + "prompt35": "Go to a window. Describe the view in extreme detail, as if painting it with words, for five minutes. Then, close your eyes and describe the view from a window that was significant to you in the past (your childhood bedroom, a previous office, a grandparent's house). Juxtapose the two landscapes on the page." + }, + { + "prompt36": "What is a question you are tired of being asked? Write a rant about why it's so irritating, reductive, or painful. Then, flip it: write the question you wish people would ask you instead. Answer that new question fully and generously." + }, + { + "prompt37": "Describe a hobby or interest you have from the perspective of someone who finds it utterly baffling and boring. Then, defend it with the passionate zeal of a true devotee. Try to convey its magic and depth to this imagined skeptic. What is the core beauty you see that they miss?" + }, + { + "prompt38": "List ten things you would do if you were not afraid. They can be grand (quit my job) or small (sing karaoke). Choose one and vividly imagine doing it. Walk through every step, from decision to action to aftermath. How does the air feel different on the other side of that fear?" + }, + { + "prompt39": "Write about a time you got exactly what you wanted\u2014and it was not what you expected. Describe the desire, the anticipation, the moment of attainment, and the subtle (or not-so-subtle) disappointment or confusion that followed. What did that experience teach you about wanting?" + }, + { + "prompt40": "Personify your favorite season. Give it a personality, a wardrobe, a way of speaking, a scent. Write a monologue from its perspective. What does it think of humans? What is its purpose? What does it love and resent about its place in the yearly cycle? Let it defend itself against its critics." + }, + { + "prompt41": "Describe a room after a significant emotional event has occurred (a fight, a celebration, a profound conversation), but without mentioning the event or the people. Let the objects, the disarray, the quality of light, the lingering smells tell the story. What is the room holding now?" + }, + { + "prompt42": "What is a rule you live by? It can be profound ('assume good intent') or practical ('never grocery shop hungry'). Explain its origin story. When have you broken it, and what were the consequences? How has following it shaped your life? Argue for its universal adoption." + }, + { + "prompt43": "Imagine you can send a message of exactly 100 words into the future, to be read by you in ten years. What do you say? What do you ask? What current worry do you want to soothe, or what current joy do you want future-you to remember? Write the message. Then, write a 100-word message from you-ten-years-ago to present-you." + }, + { + "prompt44": "Describe a color to someone who has been blind from birth. Use metaphor, texture, temperature, sound, emotion, and memory. Don't rely on sight-based comparisons ('like the sky'). Try to make them *feel* the essence of 'red' or 'blue' or 'gold' in their bones." + }, + { + "prompt45": "Write about a book that changed your mind. Not just one you loved, but one that actively altered your perspective on a topic. Describe your stance before, the unsettling process of reading it, and the new landscape of thought afterwards. What made you vulnerable to its argument?" + }, + { + "prompt46": "Catalog the contents of a junk drawer or a cluttered bag\u2014yours or an imagined one. Describe each item with care, as an archaeologist might. Then, construct a biography of the drawer's owner based solely on these artifacts. What story do these mundane relics tell?" + }, + { + "prompt47": "What does your body know how to do that your mind often forgets? (e.g., breathe deeply, relax into sleep, find rhythm in a walk). Write a series of instructions from your body to your mind, teaching it this skill again. Use the language of sensation, not thought." + }, + { + "prompt48": "Describe a journey you take every day (commute, walk the dog, trip to the kitchen) as a epic quest. Cast yourself as the hero, the mundane obstacles as trials (the traffic dragon, the staircase mountain), and the destination as a holy grail. Infuse the ordinary with mythic significance." + }, + { + "prompt49": "Write a review of today, as if it were a product, a performance, or a restaurant. Give it star ratings in different categories (Productivity, Serendipity, Comfort, Learning). Write the critic's summary. Be witty, be harsh, be fair. What was the highlight? The biggest flaw? Would you recommend today to a friend?" + }, + { + "prompt50": "Think of a word you love the sound of. Write it at the top of the page. Now, free-associate from that word\u2014not just meanings, but sounds, memories, images. Let it spin a web of connections. Where does it lead you? Try to capture the aesthetic and emotional resonance of the word itself." + }, + { + "prompt51": "Describe a piece of technology you use daily from the perspective of a person from 200 years ago. Have them stumble upon it and try to deduce its purpose, its magic, and its societal implications from its form and behavior. What would they find beautiful, terrifying, or absurd?" + }, + { + "prompt52": "Write a gratitude list, but for difficult things. Be specific. Not just 'my job,' but 'the particular frustration of my project that forced me to learn a new skill.' Find the hidden gift in the challenge, the strength forged in the irritation, the clarity born of the sorrow." + }, + { + "prompt53": "You meet a version of yourself from a parallel universe where one key life detail is different (you chose a different career, never moved, stayed with a different partner). Have a conversation with them. What do you envy? What do you pity? What fundamental part of 'you' remains the same?" + }, + { + "prompt54": "Describe a taste from your childhood that you can almost, but not quite, recall\u2014a specific candy, a grandparent's dish, a seasonal treat. Try to chase the memory with all your senses. What else was happening when you tasted it? Who was there? Why is it lost? The struggle to remember is the story." + }, + { + "prompt55": "What is a place that feels like a sanctuary to you? Describe it not just physically, but atmospherically. What rules (spoken or unspoken) govern it? What happens to your internal noise when you enter? What would it mean to carry the essence of that place with you into busier, louder realms?" + }, + { + "prompt56": "Write about waiting. Describe a specific time you were waiting for something (big or small). Capture the texture of the time itself\u2014how it stretched, what you noticed, the cycles of hope and boredom. What did you learn in the suspension? The action is in the inaction." + }, + { + "prompt57": "Compose a manifesto for a very small, personal revolution. What outdated pattern, fear, or limitation are you overthrowing? What are your guiding principles? What is your first, tiny act of rebellion? Use bold, declarative language. Declare your independence from something that no longer serves you." + }, + { + "prompt58": "Describe a conflict you witnessed but were not part of\u2014between strangers, friends, or family members. Focus on the subtext: the body language, the words not said, the history simmering beneath the surface. What did you understand about each person from this glimpse? Why has this particular conflict stuck with you?" + }, + { + "prompt59": "Look at the oldest photograph you have of yourself. Describe the child in that photo objectively, as if they are a stranger. What do you see in their eyes, posture, and environment? What might they be hoping for or fearing? Write a letter to that child, not as your past self, but as a distant relative meeting them for the first time." + } ] \ No newline at end of file diff --git a/journal_prompt_20260102_151231.txt b/journal_prompt_20260102_151231.txt new file mode 100644 index 0000000..934d46d --- /dev/null +++ b/journal_prompt_20260102_151231.txt @@ -0,0 +1,7 @@ +Journal Prompt - 2026-01-02 15:12:31 +================================================== + +"newprompt0": "Write a detailed portrait of a tree you know well—not just its appearance, but its history in that spot, the way its branches move in different winds, the creatures that inhabit it, the shadows it casts at various hours. Imagine its perspective across seasons and years. What has it witnessed? What would it say about change, resilience, or stillness if it could speak? Let the tree become a mirror for your own sense of place and time.", + +================================================== +Happy writing! ✍️ diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..ffc4889 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +openai>=1.0.0 +python-dotenv>=1.0.0 +rich>=13.0.0 + diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..d36da92 --- /dev/null +++ b/run.sh @@ -0,0 +1,101 @@ +#!/bin/bash +# Daily Journal Prompt Generator - Run Script + +set -e + +echo "📓 Daily Journal Prompt Generator" +echo "=================================" + +# Check if Python is installed +if ! command -v python3 &> /dev/null; then + echo "❌ Python 3 is required but not installed." + exit 1 +fi + +# Check if .env file exists +if [ ! -f ".env" ]; then + echo "⚠️ .env file not found. Creating from example..." + if [ -f "example.env" ]; then + cp example.env .env + echo "✅ Created .env file from example." + echo " Please edit .env and add your API key." + exit 1 + else + echo "❌ example.env not found either." + exit 1 + fi +fi + +# Check if dependencies are installed +echo "🔍 Checking dependencies..." +if ! python3 -c "import openai, dotenv" &> /dev/null; then + echo "📦 Installing dependencies..." + pip install -r requirements.txt +fi + +# Parse command line arguments +INTERACTIVE=false +SIMPLE=false +STATS=false +HELP=false + +while [[ $# -gt 0 ]]; do + case $1 in + -i|--interactive) + INTERACTIVE=true + shift + ;; + -s|--simple) + SIMPLE=true + shift + ;; + --stats) + STATS=true + shift + ;; + -h|--help) + HELP=true + shift + ;; + *) + echo "❌ Unknown option: $1" + echo " Use -h for help" + exit 1 + ;; + esac +done + +if [ "$HELP" = true ]; then + echo "Usage: ./run.sh [OPTIONS]" + echo "" + echo "Options:" + echo " -i, --interactive Run in interactive mode (with rich interface)" + echo " -s, --simple Run simple version (no rich dependency)" + echo " --stats Show prompt history statistics" + echo " -h, --help Show this help message" + echo "" + echo "Examples:" + echo " ./run.sh # Generate prompts (default)" + echo " ./run.sh -i # Interactive mode" + echo " ./run.sh -s # Simple version" + echo " ./run.sh --stats # Show statistics" + exit 0 +fi + +if [ "$STATS" = true ]; then + echo "📊 Showing statistics..." + python3 generate_prompts.py --stats +elif [ "$INTERACTIVE" = true ]; then + echo "🎮 Starting interactive mode..." + python3 generate_prompts.py --interactive +elif [ "$SIMPLE" = true ]; then + echo "⚡ Running simple version..." + python3 simple_generate.py +else + echo "✨ Generating prompts..." + python3 generate_prompts.py +fi + +echo "" +echo "✅ Done! Happy journaling! 📓" + diff --git a/simple_generate.py b/simple_generate.py new file mode 100644 index 0000000..ac86ba5 --- /dev/null +++ b/simple_generate.py @@ -0,0 +1,261 @@ +#!/usr/bin/env python3 +""" +Simple Daily Journal Prompt Generator +A lightweight version without rich dependency. +""" + +import os +import json +import sys +import argparse +from datetime import datetime +from typing import List, Dict, Any + +from openai import OpenAI +from dotenv import load_dotenv + + +class SimplePromptGenerator: + """Simple version without rich dependency.""" + + def __init__(self, config_path: str = ".env"): + """Initialize the generator with configuration.""" + self.config_path = config_path + self.client = None + self.historic_prompts = [] + self.prompt_template = "" + + # Load configuration + self._load_config() + + # Load data files + self._load_prompt_template() + self._load_historic_prompts() + + def _load_config(self): + """Load configuration from environment file.""" + load_dotenv(self.config_path) + + # Get API key + self.api_key = os.getenv("DEEPSEEK_API_KEY") or os.getenv("OPENAI_API_KEY") + if not self.api_key: + print("Error: No API key found in .env file") + print("Please add DEEPSEEK_API_KEY or OPENAI_API_KEY to your .env file") + sys.exit(1) + + # Get API base URL (default to DeepSeek) + self.base_url = os.getenv("API_BASE_URL", "https://api.deepseek.com") + + # Get model (default to deepseek-chat) + self.model = os.getenv("MODEL", "deepseek-chat") + + # Initialize OpenAI client + self.client = OpenAI( + api_key=self.api_key, + base_url=self.base_url + ) + + def _load_prompt_template(self): + """Load the prompt template from ds_prompt.txt.""" + try: + with open("ds_prompt.txt", "r") as f: + self.prompt_template = f.read() + except FileNotFoundError: + print("Error: ds_prompt.txt not found") + sys.exit(1) + + def _load_historic_prompts(self): + """Load historic prompts from JSON file.""" + try: + with open("historic_prompts.json", "r") as f: + self.historic_prompts = json.load(f) + except (FileNotFoundError, json.JSONDecodeError): + print("Warning: Starting with empty prompt history") + self.historic_prompts = [] + + def _save_historic_prompts(self): + """Save historic prompts to JSON file (keeping only last 60).""" + # Keep only the last 60 prompts + if len(self.historic_prompts) > 60: + self.historic_prompts = self.historic_prompts[-60:] + + with open("historic_prompts.json", "w") as f: + json.dump(self.historic_prompts, f, indent=2) + + def _prepare_prompt(self) -> str: + """Prepare the full prompt with historic context.""" + if self.historic_prompts: + historic_context = json.dumps(self.historic_prompts, indent=2) + full_prompt = f"{self.prompt_template}\n\nPrevious prompts:\n{historic_context}" + else: + full_prompt = self.prompt_template + + return full_prompt + + def _parse_ai_response(self, response_content: str) -> List[Dict[str, str]]: + """Parse the AI response to extract new prompts.""" + try: + # Try to parse as JSON + data = json.loads(response_content) + + # Convert to list of prompt dictionaries + new_prompts = [] + for i in range(6): + key = f"newprompt{i}" + if key in data: + prompt_text = data[key] + prompt_obj = { + f"prompt{len(self.historic_prompts) + i:02d}": prompt_text + } + new_prompts.append(prompt_obj) + + return new_prompts + + except json.JSONDecodeError: + # If not valid JSON, try to extract prompts from text + print("Warning: AI response is not valid JSON, attempting to extract prompts...") + + # Look for patterns in the text + lines = response_content.strip().split('\n') + new_prompts = [] + + for i, line in enumerate(lines[:6]): + line = line.strip() + if line and len(line) > 50: + prompt_obj = { + f"prompt{len(self.historic_prompts) + i:02d}": line + } + new_prompts.append(prompt_obj) + + return new_prompts + + def generate_prompts(self) -> List[Dict[str, str]]: + """Generate new journal prompts using AI.""" + print("\nGenerating new journal prompts...") + + # Prepare the prompt + full_prompt = self._prepare_prompt() + + try: + # Call the AI API + print("Calling AI API...") + response = self.client.chat.completions.create( + model=self.model, + messages=[ + {"role": "system", "content": "You are a creative writing assistant that generates journal prompts. Always respond with valid JSON."}, + {"role": "user", "content": full_prompt} + ], + temperature=0.7, + max_tokens=2000 + ) + + response_content = response.choices[0].message.content + + except Exception as e: + print(f"Error calling AI API: {e}") + return [] + + # Parse the response + new_prompts = self._parse_ai_response(response_content) + + if not new_prompts: + print("Error: Could not parse any prompts from AI response") + return [] + + # Add to historic prompts + self.historic_prompts.extend(new_prompts) + + # Save updated history + self._save_historic_prompts() + + return new_prompts + + def display_prompts(self, prompts: List[Dict[str, str]]): + """Display generated prompts in a simple format.""" + print("\n" + "="*60) + print("✨ NEW JOURNAL PROMPTS GENERATED ✨") + print("="*60 + "\n") + + for i, prompt_dict in enumerate(prompts, 1): + # Extract prompt text + prompt_key = list(prompt_dict.keys())[0] + prompt_text = prompt_dict[prompt_key] + + print(f"Prompt #{i}:") + print("-" * 40) + print(prompt_text) + print("-" * 40 + "\n") + + def show_history_stats(self): + """Show statistics about prompt history.""" + total_prompts = len(self.historic_prompts) + + print("\nPrompt History Statistics:") + print("-" * 30) + print(f"Total prompts in history: {total_prompts}") + print(f"History capacity: 60 prompts") + print(f"Available slots: {max(0, 60 - total_prompts)}") + + def save_prompt_to_file(self, prompt_dict: Dict[str, str], filename: str = None): + """Save a prompt to a text file.""" + prompt_key = list(prompt_dict.keys())[0] + prompt_text = prompt_dict[prompt_key] + + if not filename: + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + filename = f"journal_prompt_{timestamp}.txt" + + with open(filename, "w") as f: + f.write(f"Journal Prompt - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n") + f.write("="*50 + "\n\n") + f.write(prompt_text) + f.write("\n\n" + "="*50 + "\n") + f.write("Happy writing! ✍️\n") + + print(f"Prompt saved to {filename}") + + +def main(): + """Main entry point for the simple script.""" + parser = argparse.ArgumentParser(description="Generate journal prompts using AI (simple version)") + parser.add_argument( + "--stats", "-s", + action="store_true", + help="Show history statistics" + ) + parser.add_argument( + "--save", "-S", + type=int, + help="Save a specific prompt number to file (1-6)" + ) + parser.add_argument( + "--config", "-c", + default=".env", + help="Path to configuration file (default: .env)" + ) + + args = parser.parse_args() + + # Initialize generator + generator = SimplePromptGenerator(config_path=args.config) + + if args.stats: + generator.show_history_stats() + else: + # Generate prompts + new_prompts = generator.generate_prompts() + if new_prompts: + generator.display_prompts(new_prompts) + + # Save specific prompt if requested + if args.save: + prompt_num = args.save + if 1 <= prompt_num <= len(new_prompts): + generator.save_prompt_to_file(new_prompts[prompt_num - 1]) + else: + print(f"Error: Prompt number must be between 1 and {len(new_prompts)}") + + +if __name__ == "__main__": + main() + diff --git a/test_project.py b/test_project.py new file mode 100644 index 0000000..bac9110 --- /dev/null +++ b/test_project.py @@ -0,0 +1,283 @@ +#!/usr/bin/env python3 +""" +Test script for the Daily Journal Prompt Generator. +This script tests basic functionality without making actual API calls. +""" + +import json +import os +import sys +from unittest.mock import Mock, patch +from datetime import datetime + +# Add current directory to path to import our modules +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +# Mock response for testing +MOCK_AI_RESPONSE = '''{ + "newprompt0": "Describe a place from your childhood that no longer exists. What made it special? What sounds, smells, and textures do you remember?", + "newprompt1": "Write a letter to your future self 10 years from now. What hopes, fears, and questions do you want to share?", + "newprompt2": "Imagine you wake up with a new superpower that only works on Tuesdays. What is it and how do you use it?", + "newprompt3": "Describe a meal that represents your cultural heritage. Who taught you to make it? What memories are tied to it?", + "newprompt4": "Write about a time you got lost, literally or metaphorically. What did you discover along the way?", + "newprompt5": "Create a dialogue between your current self and your teenage self. What would you talk about?" +}''' + + +def test_file_structure(): + """Test that required files exist.""" + print("Testing file structure...") + + required_files = [ + "ds_prompt.txt", + "historic_prompts.json", + ".env", + "example.env" + ] + + all_exist = True + for file in required_files: + if os.path.exists(file): + print(f" ✓ {file} exists") + else: + print(f" ✗ {file} missing") + all_exist = False + + return all_exist + + +def test_json_parsing(): + """Test that historic_prompts.json is valid JSON.""" + print("\nTesting JSON parsing...") + + try: + with open("historic_prompts.json", "r") as f: + data = json.load(f) + + if isinstance(data, list): + print(f" ✓ historic_prompts.json is valid JSON (contains {len(data)} prompts)") + return True + else: + print(" ✗ historic_prompts.json is not a list") + return False + + except json.JSONDecodeError as e: + print(f" ✗ historic_prompts.json is not valid JSON: {e}") + return False + except FileNotFoundError: + print(" ✗ historic_prompts.json not found") + return False + + +def test_prompt_template(): + """Test that the prompt template is readable.""" + print("\nTesting prompt template...") + + try: + with open("ds_prompt.txt", "r") as f: + content = f.read() + + if len(content) > 0: + print(f" ✓ ds_prompt.txt is readable ({len(content)} characters)") + + # Check for key phrases + key_phrases = ["6 writing prompts", "500 and 1000 characters", "JSON array"] + found_phrases = [] + for phrase in key_phrases: + if phrase.lower() in content.lower(): + found_phrases.append(phrase) + + if found_phrases: + print(f" ✓ Contains key phrases: {', '.join(found_phrases)}") + else: + print(" ⚠ Missing some expected key phrases") + + return True + else: + print(" ✗ ds_prompt.txt is empty") + return False + + except FileNotFoundError: + print(" ✗ ds_prompt.txt not found") + return False + + +def test_mock_ai_response(): + """Test parsing of mock AI response.""" + print("\nTesting AI response parsing...") + + try: + # Test JSON parsing + data = json.loads(MOCK_AI_RESPONSE) + + # Check structure + expected_keys = [f"newprompt{i}" for i in range(6)] + missing_keys = [key for key in expected_keys if key not in data] + + if missing_keys: + print(f" ✗ Missing keys in mock response: {missing_keys}") + return False + + print(f" ✓ Mock response parsed successfully") + print(f" ✓ Contains all 6 expected prompts") + + # Check prompt lengths + for i in range(6): + prompt = data[f"newprompt{i}"] + if len(prompt) < 50: + print(f" ⚠ Prompt {i} is very short ({len(prompt)} characters)") + + return True + + except json.JSONDecodeError as e: + print(f" ✗ Failed to parse mock JSON: {e}") + return False + + +def test_environment_file(): + """Test that environment file has API key.""" + print("\nTesting environment file...") + + try: + with open(".env", "r") as f: + content = f.read() + + # Check for API key + if "DEEPSEEK_API_KEY=" in content or "OPENAI_API_KEY=" in content: + print(" ✓ .env file contains API key configuration") + + # Check if it's the example or real key + if "sk-your-actual-api-key" in content or "sk-something" in content: + print(" ⚠ .env appears to contain example API key (needs real key)") + else: + print(" ✓ .env appears to contain real API key") + + return True + else: + print(" ✗ .env missing API key configuration") + return False + + except FileNotFoundError: + print(" ✗ .env file not found") + return False + + +def test_requirements_file(): + """Test that requirements.txt exists and has expected packages.""" + print("\nTesting requirements file...") + + if os.path.exists("requirements.txt"): + try: + with open("requirements.txt", "r") as f: + content = f.read() + + expected_packages = ["openai", "python-dotenv"] + found_packages = [] + + for package in expected_packages: + if package in content: + found_packages.append(package) + + if found_packages: + print(f" ✓ requirements.txt contains: {', '.join(found_packages)}") + + missing = [p for p in expected_packages if p not in found_packages] + if missing: + print(f" ⚠ Missing packages: {', '.join(missing)}") + + return True + else: + print(" ✗ requirements.txt missing expected packages") + return False + + except Exception as e: + print(f" ✗ Error reading requirements.txt: {e}") + return False + else: + print(" ✗ requirements.txt not found") + return False + + +def test_python_scripts(): + """Test that Python scripts are syntactically valid.""" + print("\nTesting Python scripts...") + + scripts_to_test = ["generate_prompts.py", "simple_generate.py"] + all_valid = True + + for script in scripts_to_test: + if os.path.exists(script): + try: + with open(script, "r") as f: + # Try to compile the script + compile(f.read(), script, 'exec') + print(f" ✓ {script} is valid Python") + except SyntaxError as e: + print(f" ✗ {script} has syntax error: {e}") + all_valid = False + except Exception as e: + print(f" ✗ Error testing {script}: {e}") + all_valid = False + else: + print(f" ✗ {script} not found") + all_valid = False + + return all_valid + + +def main(): + """Run all tests.""" + print("="*60) + print("DAILY JOURNAL PROMPT GENERATOR - TEST SUITE") + print("="*60) + + tests = [ + ("File Structure", test_file_structure), + ("JSON Parsing", test_json_parsing), + ("Prompt Template", test_prompt_template), + ("Mock AI Response", test_mock_ai_response), + ("Environment File", test_environment_file), + ("Requirements File", test_requirements_file), + ("Python Scripts", test_python_scripts), + ] + + results = [] + + for test_name, test_func in tests: + try: + result = test_func() + results.append((test_name, result)) + except Exception as e: + print(f" ✗ {test_name} failed with exception: {e}") + results.append((test_name, False)) + + # Summary + print("\n" + "="*60) + print("TEST SUMMARY") + print("="*60) + + passed = sum(1 for _, result in results if result) + total = len(results) + + for test_name, result in results: + status = "✓ PASS" if result else "✗ FAIL" + print(f"{status}: {test_name}") + + print(f"\nTotal: {passed}/{total} tests passed") + + if passed == total: + print("\n✅ All tests passed! The project is ready to use.") + print("\nNext steps:") + print("1. Make sure your .env file has a real API key") + print("2. Install dependencies: pip install -r requirements.txt") + print("3. Run: python generate_prompts.py --interactive") + else: + print(f"\n⚠ {total - passed} test(s) failed. Please fix the issues above.") + + return passed == total + + +if __name__ == "__main__": + success = main() + sys.exit(0 if success else 1) + diff --git a/test_prompt_logic.py b/test_prompt_logic.py new file mode 100644 index 0000000..17d1bc2 --- /dev/null +++ b/test_prompt_logic.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +""" +Test script to verify the prompt numbering logic. +""" + +import json +from datetime import datetime + +def test_renumbering(): + """Test the renumbering logic.""" + + # Create a sample historic prompts list + historic_prompts = [] + for i in range(60): + historic_prompts.append({ + f"prompt{i:02d}": f"Old prompt {i}" + }) + + print(f"Original prompts: {len(historic_prompts)}") + print(f"First prompt key: {list(historic_prompts[0].keys())[0]}") + print(f"Last prompt key: {list(historic_prompts[-1].keys())[0]}") + + # Simulate adding 6 new prompts (as the current code would create them) + new_prompts = [] + for i in range(6): + new_prompts.append({ + f"prompt{len(historic_prompts) + i:02d}": f"New prompt {i}" + }) + + print(f"\nNew prompts to add: {len(new_prompts)}") + for i, prompt in enumerate(new_prompts): + print(f" New prompt {i}: {list(prompt.keys())[0]}") + + # Prepend new prompts (reverse to maintain order) + for prompt in reversed(new_prompts): + historic_prompts.insert(0, prompt) + + print(f"\nAfter prepending: {len(historic_prompts)} prompts") + print(f"First 3 prompts keys:") + for i in range(3): + print(f" {i}: {list(historic_prompts[i].keys())[0]}") + + # Renumber all prompts + renumbered_prompts = [] + for i, prompt_dict in enumerate(historic_prompts): + prompt_key = list(prompt_dict.keys())[0] + prompt_text = prompt_dict[prompt_key] + + new_prompt_key = f"prompt{i:02d}" + renumbered_prompts.append({ + new_prompt_key: prompt_text + }) + + print(f"\nAfter renumbering: {len(renumbered_prompts)} prompts") + print(f"First 10 prompts keys:") + for i in range(10): + print(f" prompt{i:02d}: {list(renumbered_prompts[i].keys())[0]} = {renumbered_prompts[i][f'prompt{i:02d}'][:30]}...") + + # Keep only first 60 + if len(renumbered_prompts) > 60: + renumbered_prompts = renumbered_prompts[:60] + + print(f"\nAfter keeping only first 60: {len(renumbered_prompts)} prompts") + print(f"First prompt: {list(renumbered_prompts[0].keys())[0]} = {renumbered_prompts[0]['prompt00'][:30]}...") + print(f"Last prompt: {list(renumbered_prompts[-1].keys())[0]} = {renumbered_prompts[-1]['prompt59'][:30]}...") + + # Verify the range + for i in range(60): + expected_key = f"prompt{i:02d}" + actual_key = list(renumbered_prompts[i].keys())[0] + if expected_key != actual_key: + print(f"ERROR: Expected {expected_key}, got {actual_key}") + return False + + print("\n✅ All tests passed! Prompt numbering is correct.") + return True + +if __name__ == "__main__": + test_renumbering() +