Tiny Jarvis
Hardware- 22 Devlogs
- 28 Total hours
Voice-activated local AI agent sitting on your desk running on a Raspberry pi 5, custom HAT with OLED screen and vintage control interface.
Voice-activated local AI agent sitting on your desk running on a Raspberry pi 5, custom HAT with OLED screen and vintage control interface.
sqlite local database in Python to store every question the user asks. (first time doing this ! very satisifying)feedparser python library, as well as trafilatura, for extracting text from HTML (for getting the text from the articles), which made the job ten times easier.mopidy-youtube integrated! and it works! All you have to do is press the button, say out loud “Play (song) …” and it will search for it in Youtube music (FREE MUSIC!!!) and play it.yt-dlp issue, and somehow it works.firmware and pcb to distinguish hardware from software.install.sh was finally tested and it works perfectly after a few tweaks! woohoo!README.md as recommended by the Stardance guides, and yh I agree it looks betterTime to make Tiny_Jarvis a little more like the real Jarvis….
SYSTEM METRICS SCREEN!
Displays in real time: battery life, cpu temperature, current time on the OLED screen.
Finished up the Mopidy part of the music player, can’t test it yet sadly (i don’t have access to my rpi5 right now) it was way more difficult than I thought
AIM: “Play …” -> searches through free music online database like Youtube music for query and plays the music if it finds it.
Added another quirky feature: flip a coin
Tell me if you have ideas of other new useful features
handle_prompt() function in main.py to handle any task-specific prompt given by the user.timer.py file which handles the timer feature, which is sort of complicated but now works (it displays on-screen in real time, which is pretty cool)main.py is now very clean and readable.main.py and cooking_helper.py
cooking_helper.py Unix-style, so that everything is cleaner and easier to debug or scale (in case the CSV file gets bigger)main.py, created an initialize() function which separates the tasks into an easier format. The AssistantDisplay class and the list of recipes is then passed onto the while True loop.main() function is now much simpler: it calls the initialization function, then in the loop it checks whether there are new recordings thanks to an imported function, if there are not it waits 0.2 seconds before checking again, and if there is then it runs the process_recording() function.main.pyhas the real control of initialization thanks to a listener.init_listener() function.speak(['Ingredients']) in main.py so Tiny_Jarvis will speak the ingredients of the chosen recipe out loudrandom.randint(0,33) to random.choice(list) way simpler and easier to read, and created a format_cooking_sentence(recipe_object) function so that main.py doesn’t have to manage that, way betteralsamixer, aplay and arecord
sounddevice and pyaudio which are both wrappers of the C library PortAudio. So a future change would be only using sounddevice for example, or vice versa.JOURNAL.md
AssistantDisplay class and created a neat function to show text using the python library luma.oled
textwrap module and it can now display 5 lines.cooking_helper.py in a cooking/ folderrecipes.csv
csv.DictReader object to access the info and organize it into a list, very useful.main.py so that when the user’s prompt starts with “Cooking”, it takes a random recipe from the csv file (using the random.randint(a, b) function) and returns a formatted sentence with all the info for cooking that recipe.JOURNAL.md
python main.py and somwhow got three errors in a row.trys and except Exception as e everywhere to prevent this.ssd1106 not being a real OLED screen part namegpiozero missing the rpi-lgpio library, which needs system-wide packages swig and liblgpio-dev so yh dependency hell.install.sh with these changes, now works perfectly.rpi-imager
user-data, cloud-init-ouput.log, etc… realized the Imager wasn’t writing the information in those files but others, booting it up into HDMI, checking the logs, managing to bypass username but not keyboard layout, etc… I EVEN TRIED LEGACY VERSIONS OF THE OS AND CREATING A wpa_supplicant.conf.rpi-imager version (even though I had updated it) and turns out my laptop just couldn’t get the latest version : it was 1.8.0, not 2.1.0 (the latest one).install.sh which is basically fire since you just runchmod +x install.sh
./install.sh
and the whole system-wide-packages-and-dependencies are all installed in the right order, easily.
llama.cpp
ai.py with this new feature, there are more settings than Ollama for optimizing performance for CPU-only (4 cores) which is great, however I had to download a .gguf from Hugging Face and accidentally ended up being given access to a repository for the model?! so i can now propose changes to that repo, for some reason…TypeError in main.py
JOURNAL.md, where I soldered and tested the prototype PCBs I ordered from JLCPCBAssistantDisplay class to better manage the OLED threads - way cleaner nowsentence_buffer() in ai.py and get_lastest_recordings() in listener.py, now the only function in main.py is main(). Clean!faster-whisper model by setting cpu_threads to 4 and beam_size to 1, even if we’ll lose a tiny bit in quality. Still a good tradeoffglob detected the file while it was being written to and passed it on to faster-whisper, then it would be corrupted and be mashed garbage. So I read some documentation about the queue module and used that, it’s way better and easier in the end.ollama’s ChatResponse class allows, when creating an instance of it, to write stream = True.sentence_buffer() that seperates them into a list of words, that are then given to Piper TTS in speaker.py
pyaudio to stream the Piper TTS output into the speakers! it’s actually just a Python wrapper for a C library called portaudio, so I ran into a LOT of dependency issues, but that’s a battle for another day.main.py into other files for better managementthreading, and realized it wasn’t that difficult to implement in my project.oled("thinking_animation.gif") it ran sequentially, so the whole script had to wait for the animation to finish, which obviously can’t happen.threading.Event() which enabled me to manage the “workers” way better (sorry, i’m getting used to the vocabulary)main.py for better explainability.Note: sadly it will be difficult to use threads in the rest of the code, since the process is, at its core, sequential.
Faster-whisperneeds audio to proceed, the ollama AI chatbot needs a prompt to continue, etc…
How to install section, there are tons of different commands to run to ensure it works first tryOLED.py: it now supports gifs, which is great because of Piskel which can turn simple animations into gifs.thinking_animation.gif and button_pressed.gif)listener.py for future debugging.One of the biggest issues with this project so far: the difficulty to test it! I don’t have all the required materials yet. I might use the
pytestmodule? we’ll see
Tiny_Jarvis/
├── .venv/
├── piper_voices/
├── recordings/ # New
├── assets/ # New
├── ai.py
├── listener.py # New
├── main.py
├── OLED.py
├── speaker.py
├── transcriber.py # New
├── README.md
└── requirements.txt
assets/ folder for the OLED screen visualsrecordings/ folder for the audio captured by the mic when the user is speakinglistener.py: actively listens for a button press; when pressed, records audio through the usb mic until the button is released, then that audio is sent to transcriber.py
transcriber.py: takes that audio and passes it as input into faster-whisper to “translate” into text !main.py: there is still a lot to be done if we are talking speed/efficiency, but the core pipeline is done.faster-whisper, then that text is given as prompt to the AI chatbot (like Qwen3-0.6B. The response is then turned into a voice using Piper TTS and outputted through the speaker!Possible future implementation of the threading module to make it faster, even though I have no idea how it works.
.venv/ so that all necessary python modules and packages are cleanly installed together.requirements.txt, where I put all the python modules I import in the project so that people can reuse it.piper_voices/ directory and downloaded a medium voice via python -m piper.download_voices en_US-lessac-medium
Tiny_Jarvis/
├── ai.py # the AI chatbot
├── main.py # the main script
├── OLED.py # The visuals!
└── speaker.py # the audio
main.py later on.README.md. It’s empty for now, will fill it in later.