work / FIG. 02
← all systemsAI Call Processor & Analytics Agent
Cake manufacturer, ~200 support calls a day. Calls are transcribed with PII redaction, classified by an LLM into a structured data table — and a chat agent on Telegram and web answers "how many negative calls this week?" in seconds.
- call → classified in ~30 s (was ~7 h)
- 100% call coverage (was 30–40%)
- self-healing: sweeper + error alerts
The scenario
A cake manufacturer scenario: an online bakery running phone orders and delivery, roughly 200 customer calls a day — feedback, complaints, order questions. Before automation, one employee listened to every call by hand, scored the tone, tagged a category and logged it in a report. At 200 calls a day that ate 8–10 working hours, so only 30–40% of calls actually got reviewed — the rest were skipped by default.
| Pain | Consequence |
|---|---|
| 8–10 hours/day of manual listening | Complaints get a response the next day, or later |
| No aggregated statistics | No visibility into negative-call %, trends by category |
| No fast lookup | Impossible to answer “what went wrong last week” in 30 seconds |
| Subjective scoring | Different reviewers, different tone judgments |
| 30–40% coverage | Most feedback is never seen |
What I built
Six n8n workflows sharing one Google Sheets queue and one n8n Data Table.
Calls: Processor (schedule every 2 minutes, 17 nodes) pulls a call URL from the queue, takes an atomic lock, sends it to AssemblyAI for Ukrainian transcription with speaker diarization and PII redaction, classifies it with an LLM into sentiment + category, and writes the result to the Data Table. Calls under 10 seconds are filtered out before they ever reach the LLM.
Calls: Stats Tool and Calls: Drill Down Tool are sub-workflows the agent calls as tools — one returns aggregates (totals, % negative, top categories), the other returns specific matching calls filtered by date range, sentiment, category and limit. The drill-down tool exists as its own sub-workflow specifically because n8n’s built-in Data Table tool for AI agents mixed up filter operator names (_le vs _lte) in testing — a hand-written Code-node filter replaced it.
Calls: Agent is the chat interface — a Telegram bot and a basic-auth web chat, both backed by the same LangChain agent with per-channel memory, so a manager can ask “how many negative calls this week?” or “show me 3 quality complaints” and get an answer with real examples, not a canned summary.
Calls: Errors and Calls: Sweeper keep the pipeline honest. Errors sends a Telegram alert with the execution link on any failure. Sweeper runs hourly, finds rows stuck in “Processing” for more than 15 minutes — an AssemblyAI callback that never arrived — and resets them, so the system recovers without anyone touching it.
Architecture
The diagram above matches the running workflows: a Google Sheets queue feeds the Processor, which hands transcription to AssemblyAI and classification to Gemini, writes to a Data Table, and lets the Agent read that table through two specialized tools — with Sweeper and Errors watching the whole pipeline for stalls and failures.
Hard lessons that shaped it
- Async beats polling. AssemblyAI transcribes over a webhook callback, and the workflow uses n8n’s Wait/Resume pattern instead of polling for status: the execution serializes to the database and wakes on the callback, so one worker can hold hundreds of “sleeping” calls at once without burning capacity.
- A Sheets lock has to be atomic, or two runs double-process the same call.
appendOrUpdatewith matching columns turned out to be enough of a primitive to make the queue concurrency-safe without a separate lock table. - Two specialized tools beat one universal one. Splitting Stats (aggregates) from Drill Down (specific rows) gave the agent a clean decision tree. A single do-everything tool was harder for the model to use correctly.
- The model swap mattered more than prompt tuning. Switching classification from a free general-purpose model to Gemini 2.5 Flash raised valid-JSON output from ~85% to ~99% — the single biggest reliability gain in the build.
- Store the pointer, not the payload. The Data Table keeps
transcript_id, not the full transcript text — storage-aware design that stretches n8n’s 50 MB Data Table limit to roughly a year of data at this call volume.
Results
Metrics are measured in test runs — this is a demo build, not a client testimonial.
| Metric | Before | After |
|---|---|---|
| Manual review time | 8–10 h/day | 0 |
| Time from call to classification | ~7 hours | 30–60 seconds |
| Call coverage | 30–40% | 100% |
| Time to answer an analytics question | 15–30 min manually | 3–5 seconds via chat agent |
| End-to-end execution time | — | ~26 seconds (measured) |
| Pipeline running cost | — | ~$8–12/month (AssemblyAI + OpenRouter) |
contact
Have a process that eats your team's hours?
Describe it in a couple of sentences — I'll reply with an automation plan: what to build, what it touches, and what it will save.