Overview
What this is
The Visitor Feedback Analysis Bot is a small, self-contained Python service that turns a weekly pile of raw visitor feedback into a short, decision-ready digest for the people who run a destination. It runs on a schedule, with no analyst in the loop for the routine week.
Each run it does four things:
- Ingests feedback exports (post-visit surveys, online reviews, on-site kiosk comments, social) dropped into a folder as orcode
.csv.code.json - Classifies every item with an AI model into a fixed operational taxonomy: a single theme, a sentiment, a 1-to-5 severity, an owning team, and a short verbatim evidence quote.
- Detects emerging issues by comparing this week's negative volume per theme against its own trailing average, so a genuine spike surfaces before it becomes a pattern.
- Writes a weekly digest (Markdown, optionally emailed) that leads with what changed, what is getting worse, and the single most important thing to act on first.
Who it is for
A Department of Culture and Tourism, Abu Dhabi (DCT) champion who owns visitor experience across cultural sites, heritage attractions, tourism destinations, creative-industry venues, or the National Library. It is built for an operational team that already collects feedback but cannot read all of it, and that needs a consistent, repeatable weekly read rather than a one-off analysis.
The outcome
Instead of thousands of ungoverned free-text comments, the destination manager receives one page every Monday: an at-a-glance sentiment split, a ranked list of emerging issues with a recommended action and a suggested owner for each, the standing negative themes, what went well, and a method note reminding the reader that themes and sentiment are AI-assigned and should be spot-checked. The classification taxonomy, the emerging-issue thresholds, the models, and the schedule are all set in one
config.yamlReplace the placeholders (
<DESTINATION><ENTITY_NAME><API_KEY><ENTITY_DOMAIN>config.yamlRepository Files
| 1 | # Visitor Feedback Analysis Bot |
| 2 | |
| 3 | A small, scheduled Python service that turns raw visitor feedback (surveys, reviews, |
| 4 | kiosk comments) into a decision-ready weekly digest for destination managers at the |
| 5 | Department of Culture and Tourism, Abu Dhabi (DCT). |
| 6 | |
| 7 | Each run it ingests feedback exports, classifies every item into a controlled taxonomy |
| 8 | with Claude, detects themes whose negative volume is spiking against their own trailing |
| 9 | average, and writes (optionally emails) a one-page Markdown digest. |
| 10 | |
| 11 | ## What it produces |
| 12 | |
| 13 | `reports/digest-YYYY-MM-DD.md` with: a headline, a sentiment snapshot, ranked emerging |
| 14 | issues (each with a recommended action and owner), standing negative themes, what went |
| 15 | well, and a method note. |
| 16 | |
| 17 | ## Quick start |
| 18 | |
| 19 | ```bash |
| 20 | python -m venv .venv && source .venv/bin/activate |
| 21 | pip install -r requirements.txt |
| 22 | cp .env.example .env # set ANTHROPIC_API_KEY=<API_KEY> |
| 23 | mkdir -p data/inbox reports |
| 24 | # drop one or more .csv / .json exports into data/inbox, then: |
| 25 | python -m src.scheduler --once |
| 26 | cat reports/digest-*.md |
| 27 | ``` |
| 28 | |
| 29 | To run it on a schedule instead of once (default Monday 07:00 Asia/Dubai): |
| 30 | |
| 31 | ```bash |
| 32 | python -m src.scheduler # registers the weekly job and blocks |
| 33 | ``` |
| 34 | |
| 35 | ## Input format |
| 36 | |
| 37 | Drop `.csv` or `.json` files into `data/inbox`. The loader recognises common column |
| 38 | names, so real exports usually need no reshaping: |
| 39 | |
| 40 | | Meaning | Accepted column names | |
| 41 | |---------|-----------------------| |
| 42 | | text | comment, feedback, review, text, message | |
| 43 | | rating | rating, score, stars | |
| 44 | | date | date, created_at, timestamp, submitted_at | |
| 45 | | id | id, response_id, review_id, uuid | |
| 46 | | language| language, lang, locale | |
| 47 | |
| 48 | Items with no text are skipped; items are de-duplicated by id. |
| 49 | |
| 50 | ## Configuration |
| 51 | |
| 52 | All tuning lives in `config.yaml`: the model ids, the batch size, the source folders, |
| 53 | the controlled `theme_vocabulary`, the emerging-issue thresholds (`min_mentions`, |
| 54 | `spike_multiple`, `history_weeks`), and the cron schedule. No code change is needed to |
| 55 | retune the pipeline. |
| 56 | |
| 57 | ## Prompts |
| 58 | |
| 59 | The two engineered prompts are plain text files you can paste straight into an agent: |
| 60 | |
| 61 | - `prompts/classify_feedback.md` classifies a batch of items into the taxonomy. |
| 62 | - `prompts/digest_writer.md` turns aggregated statistics into the final digest. |
| 63 | |
| 64 | ## Layout |
| 65 | |
| 66 | ``` |
| 67 | config.yaml |
| 68 | requirements.txt |
| 69 | .env.example |
| 70 | prompts/classify_feedback.md |
| 71 | prompts/digest_writer.md |
| 72 | src/ingest.py # collect + normalise exports |
| 73 | src/classify.py # FeedbackClassifier + RESULT_SCHEMA |
| 74 | src/analyze.py # aggregate + emerging detection + history |
| 75 | src/digest.py # Claude narrative + save + optional email |
| 76 | src/scheduler.py # entrypoint: --once or weekly cron |
| 77 | ``` |
| 78 | |
| 79 | ## Notes and limits |
| 80 | |
| 81 | Themes, sentiment, and severity are AI-assigned and should be spot-checked before they |
| 82 | drive a decision. This is not a census (it reads only what you export) and not a safety |
| 83 | system (route real incidents through your existing process). Replace every placeholder |
| 84 | (`<DESTINATION>`, `<ENTITY_NAME>`, `<API_KEY>`, `<ENTITY_DOMAIN>`) with your own values. |
| 85 |