CourseNatural Language Processing: The Complete Course · Course guide · part 4 of 73
Part 4 · Course guide

The Project: the Tidewell Cycles Inbox

11 min read·14 Oct 2026

Every lesson in this course is set at one company, on one project. Tidewell Cycles is made up. The shop, its people, its customers, its products, every message and every number in the project are fictional and simulated. The real cases that open each lesson are separate, cited, and clearly marked as real.

The company

Tidewell Cycles is an independent bike shop and repair workshop in Bristol with a small web shop. It sells city bikes, e-bikes, a gravel bike, a children's bike, accessories and workshop services. Customers write in by email, through the web form on the website, and in product reviews. All of it lands in one shared inbox.

On Wednesday 1 July 2026 Tidewell started delivering to Germany, Spain and France. Until then almost every message was in English. From July about four in ten are in German, Spanish or French.

Money in this course is in pounds sterling (GBP), the currency Tidewell sells in. Hosted model prices are in US dollars, as the providers publish them; Module 10 says which is which wherever both appear.

The problem

The inbox received 200 to 270 messages a month in the spring, and about 430 a month since July (simulated, measured from the shared data). One person, Ines, reads them part-time. She forwards repair bookings to Dev in the workshop, product questions to Callum, and the rest she answers herself; spam stays with her too, by default, because nothing filters it. Spam, a battery fault and a summer sale have all arrived in the same queue, and nobody can say which problems are getting worse.

Rosa, the owner, wants five jobs done:

  1. Route every message to the right person (intent classification).
  2. Pull out the order number, product, fault and preferred date, so nobody retypes them (extraction).
  3. Tell her each Monday what customers are unhappy about, and whether it is getting worse (sentiment and topics over time).
  4. Suggest the right help-centre article to Ines while she replies (semantic search and question answering).
  5. Handle German, Spanish and French messages without hiring for each language (multilingual NLP and translation).

You are the contractor Rosa hires to do it. Module 1 Lesson 1 sets the five jobs; the capstone delivers them.

What this course uses the project for

This course teaches natural language processing from the ground up: text as data, rules, tokens, linguistic structure, vectors, classifiers, evaluation, sentiment, topics, embeddings, transformers, extraction, question answering, summarisation, translation, and large language models used as one more tool. The inbox is the instrument. The same hand-written test set (hard_test, 80 messages) is scored by every method as it arrives: the rule router in Module 1, TF-IDF models in Module 4, embeddings in Module 6, a fine-tuned DistilBERT in Module 7 and hosted LLMs in Module 10. By the end you have one honest comparison table, with cost.

It is not the BrightCart store (AI Engineering), the Harbourline Freight engagement (Forward Deployed Engineer), the returns desk (Agentic AI Engineer), the Quillpath support desk (Large Language Models), Hollin Answers (RAG), the notes assistant (MCP), the TinyFormer lab (Transformers) or the Booknook shelf (Python). Tidewell is a different company, with a different cast, data and problem.

The people

NameRoleIn the project
Rosa MensahOwnerSets the five jobs, makes the decisions, reads the Monday report, signs off the capstone. Cares about cost and about not upsetting customers
Ines DuarteCustomer service, part-time; speaks Spanish and PortugueseReads the inbox. Writes the label definitions and labels the hand-written test set. The main user of search and routing
Dev MalhotraWorkshop leadReceives repair bookings and warranty faults; wants booking fields extracted
Callum ReidRuns the web shop and the e-bike rangeOwns the help-centre articles and the product list
Amara OseiPart-time bookkeeper who also looks after data protectionAsks the privacy questions: redaction before storage, how long messages are kept, whether customer text may be sent to a hosted model. Her questions are answered from named, verified sources and marked "not legal advice"
YouNLP contractorBuild the inbox service, from the first regular expression to the capstone

Customers come from a fixed list of 60 fictional names in the shared data (30 women and 30 men, 36 writing in English and 8 each in German, Spanish and French), deliberately varied in origin so that the Module 10 fairness check has something to measure. No customer is a recurring character except Mrs Joan Hartley of Clifton, whose long, polite, increasingly angry thread about her Volt 2 battery (TH01) is the running example for summarisation and escalation. Do not add named staff; a customer may appear in one lesson only.

The products

Fourteen products, fixed. SKUs, names and prices come from PRODUCTS in 06-shared-data.md and never vary.

SKUProductPriceKind
TW-VOLT2-BLKVolt 2 (e-bike; the battery-fault product)£2,199e-bike
TW-VOLT2-STPVolt 2 Step-Through£2,249e-bike
TW-HARB-GRNHarbour (city bike)£649bike
TW-HKID-20RHarbour Kids 20£329bike
TW-CAUS-GRYCauseway (gravel bike)£1,149bike
TW-PANN-SETCommuter Pannier Set£89accessory
TW-BATT-500Volt 2 battery pack (500 Wh)£549accessory
TW-LOCK-DLKLockSure D-lock£45accessory
TW-LITE-BCNBeacon Light Set£39accessory
TW-SERV-BASBasic Service£65service
TW-SERV-FULFull Service£129service
TW-REPR-PUNPuncture Repair£18service
TW-DIAG-EBKE-bike Diagnostic£45service
TW-GIFT-CRDGift Card£25 to £200 (£50 in the data)gift

Identifiers have fixed shapes, so that Module 1 can find them with regular expressions:

ThingShapeExample
Order numberTW- and six digitsTW-104233
SKUTW-, four or five capitals or digits, -, threeTW-BATT-500
Repair ticketRJ-2026- and four digitsRJ-2026-0412
Message idTW-M and four digitsTW-M0001
Battery batchVB- and four digitsVB-0426 (the faulty batch)
Help-centre articleKB01 to KB24KB05
Email addressalways on the reserved .example domainjoan.hartley@post.example, help@tidewell.example
Phone numberOfcom's drama range07700 900123
UK postcodevalid format, tied to nobodyBS3 4QT

The rules

The help centre (KB01 to KB24 in the shared data) is the written policy. The facts lessons rely on most:

RuleValueArticle
Returns30 days from delivery, unused and in original packaging; sale items the same. Free UK returns label; EU customers pay £14.95 return postageKB01
RefundsSent within 5 working days of the return arriving; duplicate charges refunded in full, usually the same dayKB02
Bike returns14 days, not ridden outdoors; UK collection free, EU collection £79KB03
WarrantyFrames 5 years; e-bike motors and batteries 2 years; other parts 1 year. Wear parts (tyres, tubes, brake pads, chains, cassettes) and crash damage are not coveredKB04
Battery batch VB-0426Some Volt 2 battery packs (500 Wh) sold March to May 2026; may stop charging or run flat quickly; replaced free; check the label under the packKB05
Volt 2 range40 to 80 km (about 25 to 50 miles) a chargeKB07
UK deliveryParcels 2 to 4 working days, free over £50 (else £4.95); bikes 3 to 5 working days, £29KB08
EU delivery (from 1 July 2026)Parcels 4 to 7 working days, £14.95; bikes 5 to 8 working days, £79; import charges includedKB09
CourierParcelNorth until 9 August 2026; SwiftDrop from 10 August 2026 (both fictional)KB10
WorkshopMonday to Saturday, 9:00 to 17:30. Basic Service £65 (about an hour), Full Service £129 (one working day), Puncture Repair £18 (same day if in before 10:00), E-bike Diagnostic £45 (taken off any repair you book)KB14 to KB17
RepliesWithin one working day; in English, German, Spanish or French since 1 July 2026KB22
DataMessages kept 18 months after the last order or message, then deleted; card details removed before storage; requests to privacy@tidewell.exampleKB21

Two project rules are not in the help centre:

  • Labels come from Ines's written definitions, LABELS in the shared data. Seven intents: order_status, returns_refund, repair_booking, product_question, warranty_fault, praise, spam. Three sentiments: neg, neu, pos. When a message fits two intents, the label is the one that needs action first, and hard_test records the second.
  • Amara's rule for hosted models (agreed with Rosa in Module 10): only redacted text, with names, emails, phone numbers and postcodes replaced, may be sent to a hosted model, and the lesson that does it names the provider's own data terms rather than guessing them. This is the project's rule, not legal advice.

The data

All Tidewell data is simulated and generated by code with a fixed seed, random.Random(20260831), in plain Python, so every learner gets identical data. 06-shared-data.md holds the code and the fingerprints to check it.

NameSizeWhat it isMain use
MESSAGES1,800The inbox, 2 March to 30 August 2026, from templates with noise added on purposeTraining and every analysis
HARD_TEST80Hand-written messages: sarcasm, two intents, code-switching, slang, very short and very long. 40 English, 40 German, Spanish and French with reference translationsThe headline test set for every model
OOS60Out-of-scope messages that fit no intentAbstaining (Module 5)
HELP_CENTRE24 articlesKB01 to KB24, 155 to 182 words eachSearch, question answering
SEARCH_QUERIES60Queries with the article that answers eachModule 6
QA_PAIRS40Questions with an exact answer span; 8 cannot be answered from the articleModule 8
THREADS24Long email threads with a hand-written reference summary eachModules 8 and 9
TRANSLATIONS403 pairsEvery non-English message with its English referenceModule 9
POS_GOLD20 sentencesHand-tagged Universal POS tagsModule 3
W2V_CORPUS20,000 sentencesShort templated reviews and repair notesTraining word2vec and fastText (Module 6)
name_swapbuilt in Module 10Copies of test messages with names and pronouns swappedFairness check

Template messages flatter template-learnable models: a classifier trained and tested on MESSAGES scores far higher than it will on real mail. That is why HARD_TEST is the headline number, and Module 4 measures the gap rather than claiming it.

Dates

  • Course date: Wednesday 14 October 2026. Library versions, model names and prices were checked on this day or on the date shown beside them.
  • The data window: Monday 2 March to Sunday 30 August 2026, 26 weeks.
  • DATA_AS_OF = Monday 31 August 2026, the morning the inbox was exported. Code counts days to DATA_AS_OF, never to the computer's clock.
  • The project: Monday 7 September to Monday 16 November 2026. Module n is project week n. Lessons are told in the present tense, as if you are there.

Key events in the data

Fixed, so that every module tells the same story. All simulated.

WhenEventWhere it shows
6 to 19 April 2026A spam wave: fake "partnership", crypto and phishing messagesSpam is visible in the April data (Modules 1, 4, 5)
Tuesday 9 June 2026Tidewell emails Volt 2 owners about battery batch VB-0426Warranty faults and negative sentiment rise through June and July: the Module 5 "topics over time" spike, and the Hartley thread
Wednesday 1 July 2026Delivery to Germany, Spain and France startsNon-English messages go from about 5% to about 38% of the inbox; the train-before, test-after drift split (Modules 5 and 9)
15 to 28 July 2026Summer saleOrder-status messages spike; returns rise in the fortnight after
Monday 10 August 2026The courier changes from ParcelNorth to SwiftDropDelivery complaints rise ("attempted delivery")

The project weeks

WeekMondayModuleWhat happens
17 September1Rosa sets the five jobs. You load the export, clean it, pull out order numbers and dates, and build the rule router: the baseline
214 September2Tokenisation and word normalisation, measured on the router
321 September3Dev asks for the products, dates and order numbers in each booking: the entity extractor
428 September4The first trained intent classifier beats the rule router, and you measure how much of that is the templates
55 October5One evaluation report for every model; Rosa's first Monday report on what customers are unhappy about
612 October6Help-centre search for Ines
719 October7A fine-tuned DistilBERT against the TF-IDF model
826 October8Repair-booking records for Dev, an answer finder for Ines, thread summaries for Rosa
92 November9Multilingual routing for the July launch
109 November10The bake-off: every model, two hosted LLMs, a cost table, a hybrid router and a name-swap fairness check, presented to Rosa
1116 November11Capstone hand-over: the whole service, documented and tested, signed off by Rosa

Fixed names

So that modules fit together, these names do not change:

  • The repository is tidewell-inbox/; the package is inbox/; tests live in tests/.
  • inbox/data.py holds the shared data blocks from course-guide/06, copied exactly.
  • Every intent model, from the rule router to the LLM classifier, offers predict(texts: list[str]) -> list[str], returning one of the seven intents (or "abstain" once Module 5 adds abstaining). The bake-off calls every model the same way.
  • inbox/evaluate.py offers report(y_true, y_pred), which every module from 5 on uses to score a model on HARD_TEST.
  • inbox/llm.py holds the setup cell from course-guide/02 and ask(model, messages), created once.

One repository: which module adds which file

In Colab each lesson writes the files it needs with %%writefile and imports them; on a laptop the same files form the repository. Tests run with !pytest -q in Colab and pytest -q locally. Every lab from Module 2 on starts by checking that the earlier modules' files are present and writing back any that are missing, so you can start at any module.

ModuleAdds to tidewell-inbox/
1inbox/__init__.py, inbox/data.py (the shared data), inbox/clean.py (repair and normalise text), inbox/rules.py (field extraction with regular expressions, redaction, the keyword rule router); tests/test_clean.py, tests/test_rules.py; requirements.txt; .gitignore
2inbox/tokens.py (tokenisers, stop words, stemming and lemmatisation as switchable options); tests/test_tokens.py
3inbox/entities.py (the spaCy pipeline, noun phrases, negation scope, NER plus an EntityRuler for Tidewell products and order numbers); tests/test_entities.py
4inbox/features.py (bag of words, n-grams, TF-IDF), inbox/classify.py (naive Bayes and logistic regression intent classifiers); models/ for saved pipelines, git-ignored; tests/test_classify.py
5inbox/evaluate.py (one evaluation report for every model), inbox/abstain.py (Abstainer, the router that can answer "abstain"), inbox/sentiment.py (VADER, a trained model, aspect sentiment), inbox/topics.py (LDA and NMF, topics by week); reports/ for Rosa's Monday report; tests/test_evaluate.py, tests/test_sentiment.py
6inbox/embed.py (word and sentence embeddings), inbox/search.py (BM25 and dense help-centre search, recall@k and MRR); tests/test_search.py
7inbox/hf_classifier.py (pipelines, tokenisers, the fine-tuned DistilBERT intent model); the fine-tuned weights go in models/, git-ignored; tests/test_hf_classifier.py
8inbox/extract.py (repair-booking records validated with pydantic), inbox/qa.py (a help-centre reader), inbox/summarise.py (thread summaries); tests/test_extract.py (with the summary tests), tests/test_qa.py
9inbox/langid.py (language identification), inbox/translate.py (MarianMT and multilingual routing), inbox/gen_metrics.py (BLEU, chrF, ROUGE); tests/test_multilingual.py
10inbox/llm.py (one model client for three providers, and ask), inbox/llm_tasks.py (LLM classification and extraction), inbox/compare.py (the bake-off and the hybrid router), inbox/fairness.py (the name-swap check); cache/ for saved model replies, git-ignored; tests/test_llm_tasks.py, tests/test_fairness.py
11inbox/pipeline.py (the whole service end to end), README.md, WHAT_BROKE.md, tests/test_capstone.py; MODEL_CARD.md, generated by lab cells from the run's measured numbers

The finished inbox service

  • Clean, normalised text, with personal data redacted before storage
  • Order numbers, products, dates, money and faults extracted, validated and scored field by field
  • Every message routed to Ines, Dev or Callum, in four languages, with spam set aside in a spam folder and an "abstain" (sent to Ines) for what fits nowhere
  • One comparison table: rules, TF-IDF, embeddings, DistilBERT and two hosted LLMs on the same 80 hand-written messages, per class and per language, with cost and speed
  • A hybrid router that sends only the hard cases to a hosted model
  • Help-centre search and an answer finder for Ines, scored with recall@5, MRR and exact match
  • Rosa's Monday report: what customers are unhappy about, and whether it is getting worse
  • A name-swap fairness check, a model card and a list of what broke

The one idea

Measure the simple method first. A regular expression, a word count and a logistic regression are cheap, fast and explainable, and on many inbox jobs they are hard to beat. Every model in this course has to earn its place against them on the same 80 hand-written messages, and the capstone keeps the cheapest method that does each job well enough.