Step 1: Find and read the files
Open the inbox/ folder in the file tree. Twelve reviews, and three
things a real folder always has: a file that is not a review
(notes.md), an old subfolder (archive/) and a file with nothing in
it. Your script has to pick exactly the right files before any AI is
involved; a model that summarises the staff notes is a bug you cannot see.
Python's pathlib treats paths as objects rather than strings:
Path("inbox")is the folder.Path("inbox") / "review-01.txt"is a file inside it..glob("*.txt")finds the entries in that folder whose names end in.txt. It does not look inside subfolders (rglobwould)..read_text(encoding="utf-8")returns the whole file as a string. Say the encoding every time: without it Python uses the computer's default, which differs between machines and breaks on accented letters..nameis the file name without the folder:review-01.txt.
1. Write list_reviews(folder): return sorted(Path(folder).glob("*.txt")).
sorted gives the same order on every computer.
2. Write read_review(path): read the file as UTF-8 and .strip() it,
which removes spaces and blank lines at both ends. An empty file becomes
"".
3. Run. It lists each file with its word count and first words.
reviews.py, the file you edit63 lines
"""Turn a folder of customer reviews into one JSON file the shop can use."""
import json
from pathlib import Path
from openai import OpenAI
CLIENT = OpenAI()
MODEL = "meta/llama-3.1-8b-instruct"
SENTIMENTS = ("positive", "negative", "mixed")
# ---------- Step 1: find and read the files ----------
def list_reviews(folder):
"""Every .txt file directly inside `folder`, sorted by name, as Path objects."""
# TODO (Step 1): return sorted(Path(folder).glob("*.txt"))
raise NotImplementedError("Step 1: write list_reviews()")
def read_review(path):
"""The file's text with spaces and blank lines trimmed from both ends."""
# TODO (Step 1): read the file as UTF-8 text and strip whitespace from both ends.
raise NotImplementedError("Step 1: write read_review()")
# ---------- Step 2: one model call per file ----------
def summarise(text, client=None):
"""A one-sentence summary of one review."""
client = client or CLIENT
raise NotImplementedError("summarise() arrives in Step 2")
# ---------- Step 3: save and load JSON ----------
def save_json(data, path):
"""Write any list/dict to `path` as readable JSON (indented, accents kept as they are)."""
raise NotImplementedError("save_json() arrives in Step 3")
def load_json(path):
"""Read a JSON file back into Python lists and dicts."""
raise NotImplementedError("load_json() arrives in Step 3")
# ---------- Step 4: ask for JSON, and parse it defensively ----------
EXTRACT_PROMPT = """Read the customer review and reply with a JSON object only, no other text:
{"sentiment": "positive" | "negative" | "mixed", "topic": "<two or three words>", "mentions_price": true | false}"""
def parse_json_reply(reply):
"""Turn a model reply that should contain one JSON object into a dict.
Copes with ```json fences and with chatter before or after the object."""
raise NotImplementedError("parse_json_reply() arrives in Step 4")
def extract(text, client=None):
"""Ask the model for sentiment, topic and mentions_price; return them as a dict."""
client = client or CLIENT
raise NotImplementedError("extract() arrives in Step 4")
# ---------- Step 5: the whole folder, without one bad file stopping the rest ----------
def process_folder(folder, out_path, client=None):
"""One record per .txt file, written to out_path as a JSON list. Returns the list."""
raise NotImplementedError("process_folder() arrives in Step 5")inbox/archive/review-old-2019.txtinbox/notes.mdinbox/review-01.txtinbox/review-02.txtinbox/review-03.txtinbox/review-04.txtinbox/review-05.txtinbox/review-06.txtinbox/review-07.txtinbox/review-08.txtinbox/review-09.txtinbox/review-10.txtinbox/review-11.txtinbox/review-12.txttry_it.py