The attention all goes to the newest Llama release and the RAG benchmarks, while the standard advice for personal knowledge management is still to copy and paste your highlights by hand. So I built a Kindle AI summary pipeline instead, and most of the work turned out to sit in the raw text file rather than in the model.
Open My Clippings.txt on a Kindle and you get an unindexed, append-only dump of every highlight you have ever made, including the ones you deleted a second later and the ones you widened. Throwing a prompt at that file will not give you a usable summary. You have to clean and deduplicate it first.
The anatomy of a clipping: parsing the mess
Extraction comes first. Older Kindles have no SQLite database like the newer annotations.db, so what you get is a text file with entries separated by ten equal signs. A single regex over the whole thing does not hold up, because the metadata lines vary between Kindle versions.
The parser below is a little more deliberate. It splits the raw text on that separator, then pulls out the book title and the location index. You need the location to sort highlights in the order they appear in the book rather than the order you happened to make them.
def bbioon_parse_clippings(file_path):
from pathlib import Path
import re
raw = Path(file_path).read_text(encoding="utf-8")
entries = raw.split("==========")
highlights = []
for entry in entries:
lines = [l.strip() for l in entry.strip().split("\n") if l.strip()]
if len(lines) < 3:
continue
book = lines[0]
location_match = re.search(r"Location (\d+)", lines[1])
if not location_match:
continue
location = int(location_match.group(1))
text = " ".join(lines[2:]).strip()
highlights.append({
"book": book,
"location": location,
"text": text
})
return highlights
The deduplication bottleneck
Deduplication is where a Kindle AI summary pipeline usually breaks. Every time you drag a highlight wider on the device, the Kindle writes a new entry holding the old text plus the extra words, and keeps the original too. Feed all of those in and the summary comes back repeating itself. The fix is longest-string matching: where one highlight contains another, keep the longer one and drop the rest before anything reaches the model.
Plenty of AI wrappers skip that step. They push the whole 2MB file into the context window, and the output is garbage for reasons that have nothing to do with the model. Roughly 90% of the work here is unglamorous cleaning logic.
Local inference with Ollama
With the data structured, inference runs locally through Ollama. I run Mistral or Llama 3 on my own machine because my reading highlights are private. No cluster is involved: a subprocess call to the Ollama CLI is enough, it costs nothing per run, and the highlights never reach a third-party server.
The same shape of automation shows up in client work. For a production example, the write-up on taxonomy and SEO automation uses the same approach: clean the input carefully, then keep the prompt structured enough that the output stays predictable.
def bbioon_summarize(text, model="mistral"):
import subprocess
prompt = f"Produce a structured summary of these highlights:\n\n{text}"
result = subprocess.run(
["ollama", "run", model],
input=prompt,
text=True,
capture_output=True
)
return result.stdout
If pipeline work like this is eating your development hours, I can take it on. I have been wrestling with WordPress and custom automation since the 4.x days.
Where the work actually is
The model matters less than the parsing in a local Kindle AI summary pipeline. Split the clippings file correctly, collapse the expanded duplicates, and a small model running on your own hardware handles the summarizing without complaint.