
Your AI-powered companion for mindful job applications
Technologies β’ Features β’ Installation β’ Usage β’ File Structure β’ Architecture β’ Contributing
Lemon River is a job application assistant that helps you manage and tailor your applications while maintaining a personal touch. Unlike automated application tools, Lemon River acts as your intelligent companion, listening for voice commands and helping you organize information as you naturally browse through job postings. It's designed to be a keyboard-driven interface for efficient workflow, with some voice commands for convenience.
The reason why I built this app is because I couldn't find a job application assistant that was both easy to use and customizable. I also wanted to learn how to build a desktop application in Python. Online solutions like Simplify are great, but it isn't customizable and I wanted to build my own. I used to keep track of my applications in a Notion page, but the app was very inefficient and I always had to switch between tabs to copy and paste information from the postings into my job application tracking table. Lemon River solves this by allowing you to capture information as you browse through job postings, and then organize it based on your voice commands while having access to your clipboard.
- Ollama for the LLM server
- MLX Whisper for the speech recognition
- PyQt6 for the UI
- ripgrep for resume template indexing
- diff-match-patch for resume version control
- Voice-Activated Workflow: Just say "lemon river" to start capturing job details (configurable)
- Clipboard Intelligence: Seamlessly captures and organizes information from your clipboard based on voice commands
- Smart Application Management:
- Track application status
- Store company details
- Manage application Q&As
- Keep notes and follow-ups (e.g. OA questions, interview questions, etc.)
- Resume Tools:
- Create tailored resumes on your own with diffing, template selection, ripgrep search, and more
- Compare versions
- Preview in real-time
- Track changes
- Modern UI: Beautiful, keyboard-driven interface for efficient workflow
Before running the app, grant the following permissions:
- System Preferences β Privacy & Security β Input Monitoring
- System Preferences β Security & Privacy β Full Disk Access
- System Preferences β Security & Privacy β Accessibility
- Microphone access (will be requested on first launch)
- Not tested
- Not tested
- ollama (server must be running)
- Python 3.13+ (Haven't tested with other versions)
- Clone the repository
git clone https://github.com/yourusername/lemon-river.git
cd lemon-river
- Install dependencies
pip install -r requirements.txt
- Start the ollama server
ollama serve
# Also need to pull the model you are using
# e.g. the ones I tested with
ollama pull llama3.2
ollama pull llama3-groq-tool-use
- Run Lemon River
python main.py
- Kill Lemon River
# For some reason the multiprocessing library sometimes doesn't want to die, so this is more reliable
pkill -f main.py
lemon-river/
βββ agent/ # Voice command and processing logic
β βββ command_handler.py # Handles voice command interpretation and execution with LLM
β βββ voice_processor.py # Voice command preprocessor
βββ gui/ # User interface components
β βββ job_window.py # Job application capture window
β βββ main_window.py # Main application window
β βββ dataclasses.py # App related data classes
β βββ tabs/ # Different tabs in the main window
β βββ widgets/ # Reusable UI components
βββ db/ # Database adapter, may include the db file when ran
βββ docs/ # Documentation and images
βββ recordings/ # Temporary voice recording storage
βββ tests/ # Unit and integration tests
βββ voice/ # Voice processing utilities
βββ main.py # Entry point
βββ llm.py # LLM integration and tool calls
βββ utils.py # Shared utility functions
βββ requirements.txt # Python dependencies
- Start Browsing: Open job postings as you normally would
- Activate: Say "lemon river" to start capturing
- Capture Information: Use voice commands while copying text:
- "Add title" - Capture job title from your clipboard
- "Add company" - Capture company name from your clipboard
- "Add description" - Capture job description from your clipboard
- "Add question" - Store application questions from your clipboard
- "Add answer" - Store your answers from your clipboard
- And more! Check agent/command_handler.py for the full list
- Save: Say "lemon save" when done, or "lemon sneeze" to close the window for later
- Manage: Use the main window to:
- Track all your applications
- Create tailored resumes (with ripgrep for resume template indexing)
- Compare different versions (with Google's diff-match-patch)
- Preview applications (pdf)
- Uses sounddevice to capture audio from your microphone in chunks
- Detects when the user's speaking based on their volume (adjust based on your needs)
- Uses root mean squared to detect when the user is done speaking (Basically, we store the last 0.5s of speech as a chunk and compare the root mean squared of that chunk with the volume threshold. This is because the user might have brief pauses in speech, so we need to account for that)
- Saves as a wav file in a recordings folder (with a timestamp in the filename so it's easier to sort recency)
- Uses MLX Whisper to transcribe your voice commands (as a separate multiprocessing process)
- The transcription is added to a local token buffer
- If activation phrase or command is detected in the token buffer, the command handler is triggered and the token buffer is cleared
- The command handler uses ollama tool calling to handle the command, and smartly detects if the user is done speaking (wait_for_completion tool call v.s. process_command tool call)
- The command handler then returns the response to the job window, which then updates the UI
- Since LLMs are sometimes not reliable, there is a locking mechanism for each field that prevents it from being overwritten until the user unlocks it
- Very specific activation phrase, hide phrase, and save phrase since using LLMs for this is too overkill
- Job window directly updates main_window after saving, so no need to refresh
- Main window utilizes a lot of pyqtSignals to emit and listen to events to sync data between tabs and the database
- Add insanely-fast-whisper for non-macOS platforms
- Cross-platform support (Windows, Linux)
- Configurable resumes path
- Custom keybindings
- Resume version control
- Better system than "Notes" for OA/Interview/Research information
- Improved ripgrep search (include file names in search)
- Configurable voice commands
- Unit and integration tests
- Better logging system
- Potential optimizations with application syncing
- Better documentation
- Build pipeline with pyinstaller (it did not work well on macOS with pyinstaller)
- Vim mode
I need contributions! Please see our Contributing Guide for details.
Lemon River supports fine-tuning the LLM model for better voice command recognition. The fine-tuning process improves the model's ability to:
- Accurately recognize commands like "add title", "add company", etc.
- Determine when a command is incomplete
- Ignore casual conversation that isn't meant as a command
To quickly set up a fine-tuned model:
./fine_tuning/setup_model.sh
This will:
- Generate training data with many examples
- Create an optimized Ollama config
- Create a model using the Modelfile
- Update your .env file to use the new model
For more control over the fine-tuning process:
-
Generate training data:
python -m fine_tuning.fine_tuning --create-data-only
-
Create a model from the Modelfile:
ollama create lemon-cmd -f Modelfile
-
Configure your environment: Update your
.env
file:LLM_MODEL="lemon-cmd" LLM_TEMPERATURE=0.1 LLM_MAX_TOKENS=512 LLM_TOP_P=0.95 LLM_TOP_K=40
-
Test the model:
python -m fine_tuning.demo
This project is licensed under the MIT License - see the LICENSE file for details.
- Ollama for the LLM server
- MLX Whisper for the speech recognition
- PyQt6 for the UI
- ripgrep for resume template indexing
- diff-match-patch for resume version control