Raspberry Pi: The Same Task, Done Right - Python in the Terminal
The Same Task, Done Right - Python in the Terminal
Series: Building AI on the Raspberry Pi — Part 2 of 4 | Python CLI
Part 1 used bash and curl. It worked. Part 2 uses Python — and the code gets cleaner, the error handling gets real, and the output lands in a file you can actually use.
In Part 1 we sent a CSV file to Groq's API using nothing but a bash script and curl. It ran on a Raspberry Pi 3B+, took about two seconds, and came back with clean JSON. That was the proof of concept.
Now we do it properly.
Python ships with every Raspberry Pi OS installation. It handles JSON natively. It lets us write error handling that actually tells you what went wrong. And when we are done, we can write the output to a file instead of just printing to the screen.
Same CSV file. Same Groq API. Same task. Different tool — and a noticeably better result.
What Python Gives You That Bash Does Not
The bash version used grep and sed to pull content out of the API response. That works, but it is fragile. If the response format changes slightly or the model adds an unexpected character, the parsing breaks silently. You get garbage output and no explanation why.
Python parses JSON natively. You hand it the response, it gives you a dictionary. No grep. No sed. No guessing.
Python's
json
module handles all of that properly. You hand it the raw response string, it
gives you a structured dictionary, and you pull out exactly the field you need
with a clean key lookup. If something goes wrong, it raises an exception with
a useful message rather than printing nothing and exiting quietly.
Setup: One Library
Python's standard library can make HTTP requests, but the
requests
library is cleaner for API work. Install it once:
pip3 install requests
That is the only dependency. JSON parsing, file writing, error handling — all standard library.
The CSV File
Same file as Part 1. If you already have it, you are ready. If not, create
inventory.csv
in your home directory:
product,price
Widget A,12.99
Widget B,7.50
Gadget X,24.00
Gadget Y,3.75
Part Z,19.99
The Python Script
Create a file called
ai_csv.py:
import requests
import json
import sys
# Your Groq API key — free at console.groq.com
GROQ_API_KEY = "your_api_key_here"
GROQ_URL = "https://api.groq.com/openai/v1/chat/completions"
def load_csv(filepath):
"""Read the CSV file and return its contents as a string."""
try:
with open(filepath, "r") as f:
return f.read()
except FileNotFoundError:
print(f"Error: Could not find {filepath}")
sys.exit(1)
def call_groq(csv_data):
"""Send the CSV to Groq and return the model's response text."""
prompt = f"""Here is a CSV file with product inventory data:
{csv_data}
Please return a JSON array where each item has these fields:
- product (string)
- price (number)
- category (assign a reasonable category based on the product name)
Return only valid JSON. No explanation, no markdown, just the JSON array."""
headers = {
"Authorization": f"Bearer {GROQ_API_KEY}",
"Content-Type": "application/json"
}
payload = {
"model": "llama-3.3-70b-versatile",
"messages": [{"role": "user", "content": prompt}],
"temperature": 0.2
}
response = requests.post(GROQ_URL, headers=headers, json=payload)
response.raise_for_status()
data = response.json()
return data["choices"][0]["message"]["content"]
def save_json(content, output_path):
"""Parse and pretty-print the JSON, then save it to a file."""
try:
parsed = json.loads(content)
with open(output_path, "w") as f:
json.dump(parsed, f, indent=2)
print(f"Done. Output saved to {output_path}")
print(json.dumps(parsed, indent=2))
except json.JSONDecodeError as e:
print(f"The model returned something that isn't valid JSON: {e}")
print("Raw response:", content)
def main():
print("Loading CSV...")
csv_data = load_csv("inventory.csv")
print("Sending to Groq API...")
result = call_groq(csv_data)
print("Saving output...")
save_json(result, "output.json")
if __name__ == "__main__":
main()
Run it:
python3 ai_csv.py
What Came Back
Loading CSV...
Sending to Groq API...
Saving output...
Done. Output saved to output.json
[
{ "product": "Widget A", "price": 12.99, "category": "Widgets" },
{ "product": "Widget B", "price": 7.50, "category": "Widgets" },
{ "product": "Gadget X", "price": 24.00, "category": "Gadgets" },
{ "product": "Gadget Y", "price": 3.75, "category": "Gadgets" },
{ "product": "Part Z", "price": 19.99, "category": "Parts" }
]
And
output.json
now sits in your home directory, ready to pass to the next step in a pipeline,
load into a database, or feed into another script.
The actual working core of this script is 12 lines — load, call, save. The rest is error handling and clarity.
The Error Handling Is Not Optional
Notice the
response.raise_for_status()
line. If the API returns an error — expired key, rate limit, bad request —
that line raises an exception immediately with a clear HTTP status code.
Without it, the script would try to parse an error response as JSON and fail
in a confusing way.
On a Pi running unattended or as part of a larger workflow, clean failure matters. You want to know what broke and why.
What This Unlocks
Now that we have a proper Python foundation, the next steps open up. Swap out the CSV reading for a database query. Change the prompt to summarize instead of categorize. Schedule the script with cron to process a fresh file every morning.
The Pi is still doing almost no computation. It is orchestrating. That is the right role for it.
Next in the series — Part 3: Now It Has a Window: A Desktop AI App on Raspberry Pi OS. Same core logic, wrapped in a Tkinter desktop application with a file picker, results display, and save button.
Tested on Raspberry Pi 3B+ and 3A+ running Raspberry Pi OS 64-bit. Also works on Pi 4 and Pi 5.
Aaron Rose is a software engineer and technology writer at tech-reader.blog.
Catch up on the latest explainer videos, podcasts, and industry discussions below.
.jpg)
