Automated Product Classification & Data Cleaning
I developed a small but useful Python script that reads product data from a CSV file, automatically assigns it to a suitable category, and optimizes the description. The idea was to test how well Large Language Models (LLMs) like gemma3:4b perform for such tasks.
I combine Pandas for data processing with a simple API connection to enrich product information. The script is not a complex AI system, but it shows how manual work steps can be automated with just a few lines of code — especially in e-commerce or for larger product catalogs.
The Technical Approach
In my approach, everything starts with the function that reads CSV data. Using Pandas and StringIO, I transform a simple CSV string into a DataFrame. This step is essential, as it allows me to further process the product data in a structured form.
1. LLM-Based Product Classification
The next part of the project revolves around classification. Here I used the ollama package to access the gemma3:4b model. In the classify_product_llm function, I first define a system prompt that gives the model clear instructions: it should take the product name and description and assign them to a predefined category schema (such as Electronics, Household Goods, Clothing, or Garden Items). It was important to me that the model returns only the category name to avoid misunderstandings.
2. Optimizing Product Descriptions
In parallel, I added another function: rewrite_description. This focuses on optimizing the product description. With a different system prompt, I ensure that the existing description is SEO-optimized while also being more engaging.
It was particularly important to me to find the balance between technical precision and natural, sales-promoting language. I wanted to avoid adding new details — the text should only be improved and made more readable.
3. Data Enrichment
To make the added value of the generated data visible, I wrote a function that iterates over all products in the DataFrame and applies both the classification and the text optimization. In enrich_data_with_classification, I collect the results and extend the dataset with the new columns PredictedCategory and new_descriptions.
The Code
In the main part of the program, I defined example CSV data, loaded it, and then ran it through the entire processing chain. The final step, saving the extended DataFrame to a CSV file, rounds off the project.
Here is the complete Python script:
import pandas as pd
from io import StringIO
from ollama import chat
def load_data(csv_data: str) -> pd.DataFrame:
"""
Reads CSV data from a string.
"""
df = pd.read_csv(StringIO(csv_data))
return df
def classify_product_llm(name: str, description: str) -> str:
"""
Uses the ollama package to access the model "gemma3:4b" and
determine a category based on a system prompt and the product
(name and description).
"""
system_prompt = (
"""
Du bist ein Experte für Produktklassifizierung. Ordne das Produkt in eine der folgenden Kategorien ein:
Elektronik: Computer, Smartphones, Fernseher, Audio-Geräte, Kameras, Wearables.
Haushaltswaren: Küchengeräte, Staubsauger, Bügeleisen, Waschmaschinen, Toaster, Lampen.
Kleidung: Schuhe, Jacken, T-Shirts, Hosen, Pullover.
Gartenartikel: Gartengeräte, Pflanzenzubehör, Rasenmäher, Heckenscheren.
Antworte ausschließlich mit dem Kategorienamen.
"""
)
user_prompt = f"Produktname: {name}\nBeschreibung: {description}"
# Send the messages to the model
response = chat(
model="gemma3:4b", # gemma3 references gemma3:4b by default
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt},
],
)
# Extract and clean the response
category = response.message.content.strip()
return category if category else "Unbekannt"
def rewrite_description(name: str, description: str) -> str:
"""
Uses the ollama package to access the model "gemma3:4b" and
rewrite the product description to be SEO-optimized and more engaging.
"""
system_prompt = (
"""
Du bist ein Experte für E-Commerce und SEO-optimierte Produktbeschreibungen.
Deine Aufgabe ist es, die gegebene Produktbeschreibung zu verbessern, indem du sie:
Leserfreundlich formulierst.
Relevante Keywords einbaust (ohne Keyword-Stuffing).
Eine emotionale und verkaufsstarke Sprache nutzt.
Erfinde keine Produktdetails – Es dürfen nur die vorhandenen Artikelinformationen angegeben werden, um zu verhindern, dass ausgedachte Details hinzugefügt werden.
Die Beschreibung leicht verständlich und ansprechend hälst.
Verwende eine natürliche, aber verkaufsstarke Tonalität, als würde ein professioneller Online-Shop sie schreiben.
Schreibe in kurzen Sätzen, verwende Bulletpoints bei vielen Vorteilen und formuliere den Text so, dass er die Kaufentscheidung positiv beeinflusst.
Gib nur die optimierte Beschreibung zurück, ohne weitere Erklärungen.
"""
)
user_prompt = f"Produktname: {name}\nBeschreibung: {description}"
# Send the messages to the model
response = chat(
model="gemma3:4b", # gemma3 references gemma3:4b by default
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt},
],
)
# Extract and clean the response
new_description = response.message.content.strip()
return new_description if new_description else "Unbekannt"
def enrich_data_with_classification(df: pd.DataFrame) -> pd.DataFrame:
"""
Iterates over the product list and calls the LLM-based classification for each item.
The result is stored in the new column 'PredictedCategory'.
"""
predicted_categories_list = []
new_descriptions_list = []
for idx, row in df.iterrows():
name = row.get("Name", "")
description = row.get("Description", "")
category = classify_product_llm(name, description)
new_description = rewrite_description(name, description)
print(f"Product '{name}' -> Predicted category: {category}")
predicted_categories_list.append(category)
new_descriptions_list.append(new_description)
df["PredictedCategory"] = predicted_categories_list
df["new_descriptions"] = new_descriptions_list
return df
def main():
# Example CSV data as string
csv_data = """
ArticleID,Name,Description,Manufacturer,Price,Stock
1,Smartphone,"Modernes Smartphone mit 6.5 Zoll Display und 128GB Speicher",TechCorp,699.99,50
2,T-Shirt,"Bequemes Baumwoll-T-Shirt in verschiedenen Farben",FashionCo,19.99,200
3,Kaffeemaschine,"Automatische Kaffeemaschine mit 12 Tassen Kapazität",HomeBrew,129.99,80
4,Gartenschere,"Hochwertige Gartenschere für präzises Schneiden",GardenPro,24.99,150
5,LED-Fernseher,"50 Zoll LED-Fernseher mit 4K Auflösung und Smart TV Funktionen",ElectroMax,499.99,30
6,Notebook,"Leistungsstarkes Notebook mit Intel i7 und 16GB RAM",CompuWorld,1299.99,20
7,Lederjacke,"Hochwertige Lederjacke aus echtem Leder",FashionCo,199.99,35
8,Toaster,"2-Schlitz-Toaster mit einstellbarer Bräunung",HomeBrew,34.99,100
9,Rasenmäher,"Elektrischer Rasenmäher mit 40cm Schnittbreite",GardenPro,299.99,40
10,Smartwatch,"Wasserdichte Smartwatch mit Fitness-Tracking",TechCorp,199.99,60
11,Hoodie,"Kapuzenpullover aus weichem Fleece-Material",FashionCo,39.99,120
12,Mikrowelle,"800W Mikrowelle mit Auftaufunktion",HomeBrew,89.99,75
13,Heckenschere,"Akku-Heckenschere für präzises Schneiden",GardenPro,179.99,50
14,Kopfhörer,"Kabellose Over-Ear-Kopfhörer mit Noise Cancelling",TechCorp,149.99,90
15,Winterjacke,"Gefütterte Winterjacke mit wasserabweisendem Material",FashionCo,129.99,45
16,Staubsauger,"Leistungsstarker Staubsauger mit HEPA-Filter",HomeBrew,199.99,55
17,Gartenlampe,"Solarbetriebene Gartenlampe mit Bewegungssensor",GardenPro,39.99,100
18,Bluetooth-Lautsprecher,"Wasserdichter Bluetooth-Lautsprecher mit 360° Sound",ElectroMax,79.99,85
19,Sneaker,"Bequeme Laufschuhe mit atmungsaktivem Material",FashionCo,89.99,150
20,Espressomaschine,"Hochwertige Espressomaschine mit Milchaufschäumer",HomeBrew,249.99,30
"""
# Load data
df = load_data(csv_data)
print("Original data:")
print(df, "\n")
# Run LLM-based classification
df = enrich_data_with_classification(df)
print("\nData with predicted categories:")
print(df)
# Optionally save result to CSV
output_file = "classified_products.csv"
df.to_csv(output_file, index=False)
print(f"\nResult saved to '{output_file}'.")
if __name__ == "__main__":
main()