#!/usr/bin/env python3 """ Test AI clustering with realistic fake articles """ from pymongo import MongoClient from datetime import datetime import sys # Connect to MongoDB client = MongoClient("mongodb://admin:changeme@mongodb:27017/") db = client["munich_news"] # Create test articles about the same Munich story from different sources test_articles = [ { "title": "München: Stadtrat beschließt neue Regelungen für Wohnungsbau", "content": """Der Münchner Stadtrat hat am Dienstag neue Regelungen für den Wohnungsbau beschlossen. Die Maßnahmen sollen den Bau von bezahlbarem Wohnraum in der bayerischen Landeshauptstadt fördern. Oberbürgermeister Dieter Reiter (SPD) sprach von einem wichtigen Schritt zur Lösung der Wohnungskrise. Die neuen Regelungen sehen vor, dass bei Neubauprojekten mindestens 40 Prozent der Wohnungen als Sozialwohnungen gebaut werden müssen. Zudem werden Bauvorschriften vereinfacht.""", "source": "abendzeitung-muenchen", "link": "https://example.com/az-wohnungsbau-1", "published_at": datetime.utcnow(), "category": "local", "word_count": 85 }, { "title": "Stadtrat München stimmt für neue Wohnungsbau-Verordnung", "content": """In einer Sitzung am Dienstag stimmte der Münchner Stadtrat für neue Wohnungsbau-Verordnungen. Die Beschlüsse zielen darauf ab, mehr bezahlbaren Wohnraum in München zu schaffen. OB Reiter bezeichnete die Entscheidung als Meilenstein im Kampf gegen die Wohnungsnot. Künftig müssen 40 Prozent aller Neubauwohnungen als Sozialwohnungen errichtet werden. Außerdem werden bürokratische Hürden beim Bauen abgebaut.""", "source": "sueddeutsche", "link": "https://example.com/sz-wohnungsbau-1", "published_at": datetime.utcnow(), "category": "local", "word_count": 72 }, { "title": "FC Bayern München verpflichtet neuen Stürmer aus Brasilien", "content": """Der FC Bayern München hat einen neuen Stürmer verpflichtet. Der 23-jährige Brasilianer wechselt für eine Ablösesumme von 50 Millionen Euro nach München. Sportdirektor Christoph Freund zeigte sich begeistert von der Verpflichtung. Der Spieler soll die Offensive verstärken.""", "source": "abendzeitung-muenchen", "link": "https://example.com/az-bayern-1", "published_at": datetime.utcnow(), "category": "sports", "word_count": 52 }, { "title": "Bayern München holt brasilianischen Angreifer", "content": """Der deutsche Rekordmeister Bayern München hat einen brasilianischen Stürmer unter Vertrag genommen. Für 50 Millionen Euro wechselt der 23-Jährige an die Isar. Sportdirektor Freund lobte den Transfer. Der Neuzugang soll die Münchner Offensive beleben und für mehr Torgefahr sorgen.""", "source": "sueddeutsche", "link": "https://example.com/sz-bayern-1", "published_at": datetime.utcnow(), "category": "sports", "word_count": 48 } ] print("Testing AI Clustering with Realistic Articles") print("=" * 70) print() # Clear previous test articles print("Cleaning up previous test articles...") db.articles.delete_many({"link": {"$regex": "^https://example.com/"}}) print("✓ Cleaned up") print() # Import clustering sys.path.insert(0, '/app') from ollama_client import OllamaClient from article_clustering import ArticleClusterer from config import Config # Initialize ollama_client = OllamaClient( base_url=Config.OLLAMA_BASE_URL, model=Config.OLLAMA_MODEL, enabled=Config.OLLAMA_ENABLED, timeout=30 ) clusterer = ArticleClusterer( ollama_client=ollama_client, similarity_threshold=0.50, time_window_hours=24 ) print("Processing articles with AI clustering...") print() clustered_articles = [] for i, article in enumerate(test_articles, 1): print(f"{i}. Processing: {article['title'][:60]}...") print(f" Source: {article['source']}") # Cluster with previously processed articles clustered = clusterer.cluster_article(article, clustered_articles) clustered_articles.append(clustered) print(f" → Cluster ID: {clustered['cluster_id']}") print(f" → Is Primary: {clustered['is_primary']}") # Insert into database db.articles.insert_one(clustered) print(f" ✓ Saved to database") print() print("=" * 70) print("Clustering Results:") print() # Analyze results clusters = {} for article in clustered_articles: cluster_id = article['cluster_id'] if cluster_id not in clusters: clusters[cluster_id] = [] clusters[cluster_id].append(article) for cluster_id, articles in clusters.items(): print(f"Cluster {cluster_id}: {len(articles)} article(s)") for article in articles: print(f" - [{article['source']}] {article['title'][:60]}...") print() # Expected results print("=" * 70) print("Expected Results:") print(" ✓ Articles 1&2 should be in same cluster (housing story)") print(" ✓ Articles 3&4 should be in same cluster (Bayern transfer)") print(" ✓ Total: 2 clusters with 2 articles each") print() # Actual results housing_cluster = [a for a in clustered_articles if 'Wohnungsbau' in a['title'] or 'Wohnungsbau' in a['title']] bayern_cluster = [a for a in clustered_articles if 'Bayern' in a['title'] or 'Stürmer' in a['title']] housing_cluster_ids = set(a['cluster_id'] for a in housing_cluster) bayern_cluster_ids = set(a['cluster_id'] for a in bayern_cluster) print("Actual Results:") if len(housing_cluster_ids) == 1: print(" ✓ Housing articles clustered together") else: print(f" ✗ Housing articles in {len(housing_cluster_ids)} different clusters") if len(bayern_cluster_ids) == 1: print(" ✓ Bayern articles clustered together") else: print(f" ✗ Bayern articles in {len(bayern_cluster_ids)} different clusters") if len(clusters) == 2: print(" ✓ Total clusters: 2 (correct)") else: print(f" ✗ Total clusters: {len(clusters)} (expected 2)") print() print("=" * 70) print("✓ Test complete! Check the results above.")