{"repo": "adamadham/fpl-assistant", "files": {"README.md": {"e4496b546c1920dcfc863ea801e00890ff84520e": {"t": 1785747291.283184, "n": 19996, "h": "6eaa5dacce9b5168", "c": "# ⚽ FPL Graph-RAG Assistant\n\n> **A Retrieval-Augmented Generation (RAG) system for intelligent Fantasy Premier League analysis using Neo4j knowledge graphs, semantic embeddings, and large language models.**\n\n---\n\n## 🎯 Overview\n\n**FPL Assistant** is an intelligent conversational system that answers Fantasy Premier League questions using a **retrieval-augmented generation (RAG)** approach. Instead of hallucinating answers, the system:\n\n1. **Classifies intent** β€” understands what the user is asking (e.g., player stats, comparisons)\n2. **Extracts entities** β€” identifies relevant players, teams, gameweeks, and statistics from the query\n3. **Retrieves context** β€” uses multiple retrieval strategies (deterministic Cypher queries, semantic vector search, or hybrid) to fetch facts from a Neo4j knowledge graph\n4. **Generates answers** β€” passes retrieved context to a language model (DeepSeek, Llama, or Gemma) to synthesize natural, conversational responses\n\nThe system supports queries like:\n\n- _\"Compare Salah and Haaland's total points\"_\n- _\"How many goals did Salah score against Wolves?\"_\n- _\"Which team did Salah score the least against in the 2022-23 season?\"_\n\n### Why This Approach?\n\nTraditional LLMs on FPL data are prone to hallucination (making up stats). RAG solves this by grounding responses in **actual data** from the knowledge graph, ensuring accuracy and factuality.\n\n---\n\n## ✨ Key Features\n\n| Feature | Description |\n| ----------------------------- | -------------------------------------------------------------------------------------------- |\n| **Multi-Model LLM Support** | DeepSeek (default), Llama, or Gemma for answer generation |\n| **Dual Embedding Models** | All-MiniLM-L6-v2 (fast, small) and All-MPNet-Base-V2 (high-quality) |\n| **Four Retrieval Strategies** | Baseline Cypher, Embeddings (Vector), Hybrid, and LLM-generated Cypher |\n| **Fuzzy Entity Matching** | Robust player/team name recognition despite typos and abbreviations |\n| **Comprehensive FPL Schema** | Covers players, teams, positions, gameweeks, seasons, and detailed performance stats |\n| **Interactive Web UI** | Streamlit-based interface with debug mode and real-time configuration |\n| **Evaluation Framework** | 30 test prompts Γ— 18 permutations = 540 experiments to benchmark retrieval + LLM performance |\n| **Two Seasons of Data** | 2021-22 and 2022-23 FPL data with player performance across all gameweeks |\n\n---\n\n## πŸ—οΈ System Architecture\n\n```\nUser Query\n ↓\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\nβ”‚ PREPROCESSING & UNDERSTANDING β”‚\nβ”‚ β€’ Intent Classification (LLM or Rule-based) β”‚\nβ”‚ β€’ Entity Extraction (NER + Fuzzy Matching) β”‚\nβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n ↓\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\nβ”‚ RETRIEVAL LAYER (Multi-Strategy) β”‚\nβ”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚\nβ”‚ β”‚ Cypher Baseline β”‚ β”‚ Vector Embeddingsβ”‚ β”‚\nβ”‚ β”‚ (Deterministic)β”‚ β”‚ (Semantic) β”‚ β”‚\nβ”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚\nβ”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚\nβ”‚ ↓ β”‚\nβ”‚ Neo4j Knowledge Graph β”‚\nβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n ↓\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\nβ”‚ CONTEXT ASSEMBLY β”‚\nβ”‚ β€’ Combine & deduplicate results β”‚\nβ”‚ β€’ Format for LLM consumption β”‚\nβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n ↓\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\nβ”‚ LLM ANSWER GENERATION β”‚\nβ”‚ β€’ DeepSeek / Llama / Gemma β”‚\nβ”‚ β€’ Grounded in retrieved facts β”‚\nβ”‚ β€’ Suggest follow-up questions β”‚\nβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n ↓\nNatural, Factual Answer\n```\n\n---\n\n## πŸš€ Quick Start\n\n### Prerequisites\n\n- **Python 3.12**\n- **Neo4j** (Desktop or Docker)\n- **4 GB+ RAM** (for embedding models + FAISS indexes)\n- **Internet connection** (for LLM API calls)\n\n### Step 1: Clone & Setup Environment\n\n```powershell\n# Create and activate virtual environment\npython -m venv .venv\n.\\venv\\Scripts\\Activate.ps1\n\n# Install dependencies\npip install -r requirements.txt\n```\n\n### Step 2: Configure Credentials\n\nCreate a `.env` file in the project root:\n\n```env\n# Neo4j Configuration\nNEO4J_URI=bolt://localhost:7687\nNEO4J_USERNAME=neo4j\nNEO4J_PASSWORD=\n\n# LLM API Keys\nDEEPSEEK_API_KEY=\nDEEPSEEK_API_URL=https://api.deepseek.com/chat/completions\nDEEPSEEK_MODEL=deepseek-chat\n\nHF_TOKEN=\n\n# Embedding Models\nMODEL_A_NAME=sentence-transformers/all-MiniLM-L6-v2\nMODEL_B_NAME=sentence-transformers/all-mpnet-base-v2\n\n# FAISS Index Paths\nFAISS_INDEX_A_PATH=./embeddings_out/faiss_index_modelA.index\nFAISS_INDEX_B_PATH=./embeddings_out/faiss_index_modelB.index\nMAPPING_A_PATH=./embeddings_out/idx_to_embedding_id_modelA.json\nMAPPING_B_PATH=./embeddings_out/idx_to_embedding_id_modelB.json\n\n# Output Directory\nOUTPUT_DIR=./embeddings_out\n```\n\n### Step 3: Populate Neo4j Knowledge Graph using `fpl_two_seasons.csv`\n\n```powershell\n# Start Neo4j Desktop and create/launch a local database\n\n# Run the knowledge graph creation script\npython .\\scripts\\create_kg.py\n```\n\nThis populates Neo4j with:\n\n- **Seasons**: 2021-22, 2022-23\n- **Players**: ~600 per season\n- **Teams**: 20 Premier League teams\n- **Fixtures**: 380 per season (38 gameweeks Γ— 20 teams)\n- **Performance Data**: Goals, assists, clean sheets, total points, etc.\n\n### Step 4: Load/Generate Embeddings\n\n#### Option A: Download Pre-computed Indexes (⚑ Fastest)\n\nDownload FAISS indexes and mappings from: [Google Drive Link](https://drive.google.com/drive/folders/1nyeVFgM-nb4q6_rRVhxmG5-gnQSjjBjp?usp=sharing)\n\nPlace files in `embeddings_out/`:\n\n```\nembeddings_out/\nβ”œβ”€β”€ faiss_index_modelA.index\nβ”œβ”€β”€ faiss_index_modelB.index\nβ”œβ”€β”€ idx_to_embedding_id_modelA.json\n└── idx_to_embedding_id_modelB.json\n```\n\n#### Option B: Generate From Scratch (⏱️ ~4 hours on CPU)\n\n```powershell\npython .\\scripts\\generate_embeddings.py\n```\n\nThis script:\n\n1. Fetches all player performance records from Neo4j\n2. Generates text descriptions (e.g., \"Haaland: 13 goals | assists: 1 | total_points: 10 | Position: FWD\")\n3. Encodes them using both embedding models\n4. Creates FAISS indexes for fast similarity search\n\n### Step 5: Run the Web UI\n\n```powershell\nstreamlit run main.py\n```\n\nOpen **http://localhost:8501** in your browser.\n\n---\n\n## πŸ“‚ Project Structure\n\n```\nfpl-assistant/\nβ”œβ”€β”€ main.py # Streamlit web UI entry point\nβ”œβ”€β”€ requirements.txt # Python dependencies\nβ”œβ”€β”€ README.md # This file\nβ”œβ”€β”€ STARTING.md # Minimal setup guide\nβ”œβ”€β”€ schema.md # Data schema documentation\nβ”œβ”€β”€ checklist.md # Project development phases\nβ”œβ”€β”€ .env.template # Environment variables template\nβ”‚\nβ”œβ”€β”€ config/ # Configuration & lookup tables\nβ”‚ β”œβ”€β”€ settings.py # Model options, defaults\nβ”‚ β”œβ”€β”€ template_library.py # 35 Cypher query templates\nβ”‚ β”œβ”€β”€ team_name_variants.py # Team abbreviation β†’ full name\nβ”‚ β”œβ”€β”€ stat_variants.py # Statistic name aliases\nβ”‚ β”œβ”€β”€ styles.py # Streamlit CSS styling\nβ”‚ └── FPLTrivia.md # Possible user queries\nβ”‚\nβ”œβ”€β”€ modules/ # Core application logic\nβ”‚ β”œβ”€β”€ preprocessing.py # Intent classification + entity extraction\nβ”‚ β”œβ”€β”€ cypher_retriever.py # Baseline retrieval via Cypher\nβ”‚ β”œβ”€β”€ vector_retriever.py # Semantic retrieval via embeddings\nβ”‚ β”œβ”€β”€ db_manager.py # Neo4j connection pool\nβ”‚ β”œβ”€β”€ llm_engine.py # LLM API calls (DeepSeek, Llama, Gemma)\nβ”‚ β”œβ”€β”€ llm_helper.py # Intent classification & Cypher Generator with LLM\nβ”‚ └── tests_llm_engine.py # `llm_engine.py` customized for performance testing\nβ”‚\nβ”œβ”€β”€ scripts/ # Data processing & setup\nβ”‚ β”œβ”€β”€ create_kg.py # Populate Neo4j from CSV\nβ”‚ β”œβ”€β”€ generate_embeddings.py # Create FAISS indexes\nβ”‚ β”œβ”€β”€ fpl_two_seasons.csv # Raw FPL data (2 seasons)\nβ”‚ └── config.txt # Neo4j connection configuration\nβ”‚\nβ”œβ”€β”€ embeddings_out/ # Pre-computed embeddings\nβ”‚ β”œβ”€β”€ faiss_index_modelA.index # Fast index for model A\nβ”‚ β”œβ”€β”€ faiss_index_modelB.index # Fast index for model B\nβ”‚ β”œβ”€β”€ idx_to_embedding_id_modelA.json\nβ”‚ └── idx_to_embedding_id_modelB.json\nβ”‚\nβ”œβ”€β”€ experiments/ # Evaluation framework\nβ”‚ β”œβ”€β”€ run_experiments.py # Execute all experiments\nβ”‚ β”œβ”€β”€ tests.json # 30 test prompts\nβ”‚ β”œβ”€β”€ results.json # Experimental results (540 trials)\nβ”‚ β”œβ”€β”€ validate_tests.json # Ground truth answers\nβ”‚ β”œβ”€β”€ cost_modify.py # Calculate LLM costs\nβ”‚ β”œβ”€β”€ viz.py # Visualize results using plots\nβ”‚ └── plots/ # Generated charts\nβ”‚\n└── logo.png # App logo\n```\n\n---\n\n## πŸ“š Module Documentation\n\n### 1. **preprocessing.py** β€” Intent & Entity Extraction\n\nConverts raw user text into structured data.\n\n**Key Functions:**\n\n- `extract_entities(query: str) β†’ dict` β€” Extracts players, teams, positions, gameweeks, seasons, stats\n\n**Features:**\n\n- **Spacy NER** for organization recognition (team names)\n- **Fuzzy matching** to handle typos and partial names\n- **Regex patterns** for gameweeks (e.g., \"GW10\"), positions, seasons\n- **Database lookups** for robustness\n\n**Example:**\n\n```python\nquery = \"How many goals did Haaland score in GW5 2022-23?\"\nentities = extract_entities(query)\n# Output:\n# {\n# \"players\": [\"Erling Haaland\"],\n# \"gameweeks\": [5],\n# \"seasons\": [\"2022-23\"],\n# \"statistics\": []\n# }\n```\n\n### 2. **cypher_retriever.py** β€” Baseline Deterministic Retrieval\n\nExecutes templated Cypher queries against Neo4j.\n\n**Key Functions:**\n\n- `retrieve_data_via_cypher(intent, entities, limit) β†’ dict` β€” Executes a Cypher template selected by intent\n\n**Template Examples:**\n\n- `PLAYER_STATS_GW_SEASON` β€” Get a player's stats in a specific gameweek\n- `COMPARE_PLAYERS_BY_TOTAL_POINTS` β€” Compare two players' total points\n- `PLAYER_CAREER_STATS_TOTALS` β€” Career aggregates\n- `TOP_PLAYERS_BY_POSITION` β€” Rank players by position\n- `TEAM_FIXTURE_SCHEDULE` β€” Get team's upcoming/past fixtures\n\n**Features:**\n\n- Parameter injection safety (parameterized + template rendering)\n- Missing parameter detection with fallbacks\n- JSON-friendly output\n\n### 3. **vector_retriever.py** β€” Semantic Embedding-Based Retrieval\n\nFinds players/fixtures using semantic similarity via embeddings.\n\n**Key Functions:**\n\n- `vector_search(entities, top_k, model_choice) β†’ dict` β€” Performs FAISS similarity search\n- `get_models_and_indexes()` β†’ Cached loading of models + FAISS indexes\n\n**Process:**\n\n1. Build query text from entities (e.g., \"Players: Haaland | Positions: FWD\")\n2. Encode query using SentenceTransformer\n3. Query FAISS index for top-k similar embeddings\n4. Fetch source nodes from Neo4j\n\n**Embedding Models:**\n\n- **Model A**: `all-MiniLM-L6-v2` (22M params, fast)\n- **Model B**: `all-mpnet-base-v2` (109M params, high-quality)\n\n### 4. **db_manager.py** β€” Neo4j Connection Management\n\nSingleton pattern for safe, pooled Neo4j access.\n\n```python\ndb = Neo4jGraph() # Singleton\nresults = db.execute_query(\"MATCH (p:Player) RETURN p LIMIT 5\")\n```\n\n### 5. **llm_engine.py** β€” Multi-Model LLM Answer Generation\n\nInterfaces with multiple LLM providers.\n\n**Supported Models:**\n\n- **DeepSeek** (default, most cost-effective)\n- **Llama** via Hugging Face Inference API\n- **Gemma** via Hugging Face Inference API\n\n**Functions:**\n\n- `deepseek_generate_answer(query, context) β†’ str`\n- `llama_generate_answer(query, context) β†’ str`\n- `gemma_generate_answer(query, context) β†’ str`\n\n**System Prompt:**\n\n```\nYou are an elite Fantasy Premier League analyst.\nAnswer the user's question using ONLY the data provided.\nDo NOT guess or hallucinate.\nKeep output concise and actionable.\nSuggest a follow-up question at the end.\n```\n\n### 6. **llm_helper.py** β€” Intent Classification & Prompt Engineering\n\n- High-level LLM utilities for understanding user intent.\n- Generating cypher queries.\n\n**Functions:**\n\n- `classify_with_deepseek(query, options) β†’ list` β€” Map query to up to 3 Cypher templates\n- Fallback: `local_intent_classify(query)` (rule-based, in `config/template_library.py`)\n- `create_query_with_deepseek(query: str, schema) -> cypher query` - Generate a consistent query for user's query with respect to KG schema.\n\n---\n\n## πŸ—„οΈ Knowledge Graph Schema\n\n### Node Types\n\n| Node | Properties | Purpose |\n| ------------- | ------------------------------------------ | ---------------------------------------- |\n| **Season** | `season_name` | Either 2021-22 or 2022-23 |\n| **Gameweek** | `season`, `GW_number` | 38 gameweeks per season |\n| **Fixture** | `season`, `fixture_number`, `kickoff_time` | Individual matches |\n| **Team** | `name` | 20 Premier League clubs per season |\n| **Player** | `player_name`, `player_element` | Individual players |\n| **Position** | `name` | FWD, MID, DEF, GK |\n| **Embedding** | `model`, `text`, `source_label` | Vector embeddings of player descriptions |\n\n### Relationships\n\n```\n- (Season) - [:HAS_GW]-> (Gameweek)\n- (Gameweek) - [:HAS_FIXTURE]-> (Fixture)\n- (Fixture) - [:HAS_HOME_TEAM]-> (Team)\n- (Fixture) - [:HAS_AWAY_TEAM]-> (Team)\n- (Player) - [:PLAYS_AS]-> (Position)\n- (Player) - [:PLAYED_IN]-> (Fixture)\n```\n\n### Performance Stats on `PLAYED_IN` Relationships\n\n```\nminutes, goals_scored, assists, total_points, bonus,\nclean_sheets, goals_conceded, own_goals, yellow_cards,\nred_cards, saves, penalties_saved, penalties_missed,\nbps, influence, creativity, threat, ict_index, form\n```\n\n---\n\n## πŸ” Retrieval Methods\n\nThe system supports **four retrieval strategies**, configurable from the UI sidebar:\n\n### 1. **Baseline (Cypher)** β€” Deterministic Graph Queries\n\n**When to use:** High-precision factual queries (stats, comparisons)\n\n**Process:**\n\n1. Classify intent (e.g., \"PLAYER_STATS_GW_SEASON\")\n2. Map entities to template parameters\n3. Execute Cypher query\n4. Return structured results\n\n**Pros:** Deterministic, precise, low latency \n**Cons:** Requires exact entity matching; limited flexibility\n\n### 2. **Embeddings (Vector)** β€” Semantic Similarity Search\n\n**When to use:** Exploratory queries, fuzzy matching (e.g., \"players similar to Salah\")\n\n**Process:**\n\n1. Encode query + entities as a text vector\n2. Query FAISS index for top-k similar embeddings\n3. Fetch corresponding nodes from Neo4j\n4. Return ranked results\n\n**Pros:** Robust to phrasing differences, discovers similar items \n**Cons:** Less precise; slower than Cypher; not practically useful for the FPL Knowledge Graph\n\n### 3. **Hybrid** β€” Best of Both Worlds\n\n**When to use:** Balance precision + recall\n\n**Process:**\n\n1. Run Cypher retrieval\n2. Run embedding search in parallel\n3. Combine results, deduplicate, rank by relevance\n\n**Pros:** High recall + precision \n**Cons:** Slower (executes both retrievers)\n\n### 4. **LLM-Generated Cypher** β€” Let the Model Write Queries\n\n**When to use:** Complex, unconventional questions\n\n**Process:**\n\n1. Prompt DeepSeek to generate Cypher queries\n2. Execute against Neo4j\n3. Return results\n\n**Pros:** Flexibility for novel queries \n**Cons:** Can generate invalid Cypher; slower; major cybersecurity threat\n\n---\n\n## πŸ€– LLM Comparison\n\n| Model | Provider | Speed | Quality | Cost |\n| --------------- | ------------ | ------- | ---------- | -------- |\n| **DeepSeek** | Deepseek API | ⚑ Fast | ⭐⭐⭐⭐ | πŸ’° Cheap |\n| **Llama 2 70B** | Hugging Face | 🐒 Slow | ⭐⭐⭐⭐⭐ | πŸ’°πŸ’° |\n| **Gemma 7B** | Hugging Face | ⚑ Fast | ⭐⭐⭐ | πŸ’° Cheap |\n\n---\n\n## πŸ“Š Experiments & Evaluation\n\n### Evaluation Framework\n\nThe project includes a comprehensive **evaluation suite** with:\n\n- **30 test prompts** across different query types\n- **18 permutations** per prompt (different retrieval modes Γ— LLM models Γ— embedding models)\n- **540 total experiments** to benchmark performance\n\n### Running Experiments\n\n```powershell\npython -m experiments.run_experiments\n```\n\n**Outputs:**\n\n- `experiments/results.json` β€” Detailed results for each trial\n- `experiments/plots/` β€” Generated visualizations\n- Summary metrics: latency, token usage, cost analysis\n\n### Test Prompt Categories\n\n1. **Player Performance** β€” Stats, comparisons, rankings\n2. **Team Analysis** β€” Fixture difficulty, form\n3. **Transfer Advice** β€” Form\n4. **Comparisons** β€” Head-to-head player metrics\n5. **Recommendations** β€” Top performers by position\n\n---\n\n## 🎨 UI Features\n\n### Streamlit Interface\n\n```\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\nβ”‚ FPL Graph-RAG Assistant β”‚\nβ”‚ Ask questions about Fantasy Premier League β”‚\nβ”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€\nβ”‚ SIDEBAR β”‚ MAIN CONTENT β”‚\nβ”‚ β”œβ”€ LLM Choice β”‚ β€’ Chat input β”‚\nβ”‚ β”œβ”€ Retrieval β”‚ β€’ Answer β”‚\nβ”‚ β”œβ”€ Embedding model β”‚ β€’ Graph visualization β”‚\nβ”‚ β”œβ”€ Top-K β”‚ β€’ Raw retrieval context β”‚\nβ”‚ └─ PL Logo β”‚ β€’ Debug & Transparency β”‚\nβ”‚ β”‚ β€’ Chat history β”‚\nβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n```\n\n### Color Palette (Official PL Colors)\n\n| Color | RGB | Use |\n| ------------------------------------------------------------------------ | -------------------- | ------------------- |\n| ● Cyan | `rgb(4, 245, 255)` | Highlights, accents |\n| ● Pink | `rgb(233, 0, 82)` | Warnings, important |\n| ● Green | `rgb(0, 255, 133)` | Success, positive |\n| ● Purple | `rgb(56, 0, 60)` | Background, muted |\n| ● White | `rgb(255, 255, 255)` | Text, primary |\n\n---\n\n## 🀝 Team & Contributing\n\nThis project was developed as part of **Advanced Computer Lab Milestone 3 course work** on AI tools at The German University in Cairo, CSEN 903.\n\n### Key Components Built By\n\n- **Graph Architecture** β€” Neo4j schema design, Cypher templates\n- **Preprocessing** β€” Intent classification, fuzzy entity extraction\n- **Retrieval Layer** β€” Cypher baseline, FAISS embeddings, hybrid approach\n- **LLM Integration** β€” Multi-model support, prompt engineering\n- **Evaluation** β€” Comprehensive benchmark suite with 540 trials\n\n### Future Work\n\n- [ ] Add `value`, `selected_by`, `transfer_balance` for actual FPL transfers recommendations\n- [ ] Add KG relations between Players & Teams\n- [ ] Optimize FAISS indexes for faster search\n- [ ] Add more LLM providers (Claude, GPT-4)\n- [ ] Cache common queries for faster responses\n- [ ] Implement streaming responses for long answers\n- [ ] Add user feedback loop for fine-tuning (PPO)\n\n"}, "166b83b5f4f493efdb7198087f27a6c153e00803": {"t": 1785772183.4316077, "n": 20088, "h": "fc5a9be0762bec09", "c": "# ⚽ FPL Graph-RAG Assistant\n\n> **A Retrieval-Augmented Generation (RAG) system for intelligent Fantasy Premier League analysis using Neo4j knowledge graphs, semantic embeddings, and large language models.**\n\n---\n\n## 🎯 Overview\n\n**FPL Assistant** is an intelligent conversational system that answers Fantasy Premier League questions using a **retrieval-augmented generation (RAG)** approach. Instead of hallucinating answers, the system:\n\n1. **Classifies intent** β€” understands what the user is asking (e.g., player stats, comparisons)\n2. **Extracts entities** β€” identifies relevant players, teams, gameweeks, and statistics from the query\n3. **Retrieves context** β€” uses multiple retrieval strategies (deterministic Cypher queries, semantic vector search, or hybrid) to fetch facts from a Neo4j knowledge graph\n4. **Generates answers** β€” passes retrieved context to a language model (DeepSeek, Llama, or Gemma) to synthesize natural, conversational responses\n\nThe system supports queries like:\n\n- _\"Compare Salah and Haaland's total points\"_\n- _\"How many goals did Salah score against Wolves?\"_\n- _\"Which team did Salah score the least against in the 2022-23 season?\"_\n\n### Why This Approach?\n\nTraditional LLMs on FPL data are prone to hallucination (making up stats). RAG solves this by grounding responses in **actual data** from the knowledge graph, ensuring accuracy and factuality.\n\n---\n\n## ✨ Key Features\n\n| Feature | Description |\n| ----------------------------- | -------------------------------------------------------------------------------------------- |\n| **Multi-Model LLM Support** | DeepSeek (default), Llama, or Gemma for answer generation |\n| **Dual Embedding Models** | All-MiniLM-L6-v2 (fast, small) and All-MPNet-Base-V2 (high-quality) |\n| **Four Retrieval Strategies** | Baseline Cypher, Embeddings (Vector), Hybrid, and LLM-generated Cypher |\n| **Fuzzy Entity Matching** | Robust player/team name recognition despite typos and abbreviations |\n| **Comprehensive FPL Schema** | Covers players, teams, positions, gameweeks, seasons, and detailed performance stats |\n| **Interactive Web UI** | Streamlit-based interface with debug mode and real-time configuration |\n| **Evaluation Framework** | 30 test prompts Γ— 18 permutations = 540 experiments to benchmark retrieval + LLM performance |\n| **Two Seasons of Data** | 2021-22 and 2022-23 FPL data with player performance across all gameweeks |\n\n---\n\n## πŸ—οΈ System Architecture\n\n```\nUser Query\n ↓\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\nβ”‚ PREPROCESSING & UNDERSTANDING β”‚\nβ”‚ β€’ Intent Classification (LLM or Rule-based) β”‚\nβ”‚ β€’ Entity Extraction (NER + Fuzzy Matching) β”‚\nβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n ↓\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\nβ”‚ RETRIEVAL LAYER (Multi-Strategy) β”‚\nβ”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚\nβ”‚ β”‚ Cypher Baseline β”‚ β”‚ Vector Embeddingsβ”‚ β”‚\nβ”‚ β”‚ (Deterministic)β”‚ β”‚ (Semantic) β”‚ β”‚\nβ”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚\nβ”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚\nβ”‚ ↓ β”‚\nβ”‚ Neo4j Knowledge Graph β”‚\nβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n ↓\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\nβ”‚ CONTEXT ASSEMBLY β”‚\nβ”‚ β€’ Combine & deduplicate results β”‚\nβ”‚ β€’ Format for LLM consumption β”‚\nβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n ↓\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\nβ”‚ LLM ANSWER GENERATION β”‚\nβ”‚ β€’ DeepSeek / Llama / Gemma β”‚\nβ”‚ β€’ Grounded in retrieved facts β”‚\nβ”‚ β€’ Suggest follow-up questions β”‚\nβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n ↓\nNatural, Factual Answer\n```\n\n---\n\n## πŸš€ Quick Start\n\n### Prerequisites\n\n- **Python 3.12**\n- **Neo4j** (Desktop or Docker)\n- **4 GB+ RAM** (for embedding models + FAISS indexes)\n- **Internet connection** (for LLM API calls)\n\n### Step 1: Clone & Setup Environment\n\n```powershell\n# Create and activate virtual environment\npython -m venv .venv\n.\\venv\\Scripts\\Activate.ps1\n\n# Install dependencies\npip install -r requirements.txt\n```\n\n### Step 2: Configure Credentials\n\nCreate a `.env` file in the project root:\n\n```env\n# Neo4j Configuration\nNEO4J_URI=bolt://localhost:7687\nNEO4J_USERNAME=neo4j\nNEO4J_PASSWORD=\n\n# LLM API Keys\nDEEPSEEK_API_KEY=\nDEEPSEEK_API_URL=https://api.deepseek.com/chat/completions\nDEEPSEEK_MODEL=deepseek-chat\n\nHF_TOKEN=\n\n# Embedding Models\nMODEL_A_NAME=sentence-transformers/all-MiniLM-L6-v2\nMODEL_B_NAME=sentence-transformers/all-mpnet-base-v2\n\n# FAISS Index Paths\nFAISS_INDEX_A_PATH=./embeddings_out/faiss_index_modelA.index\nFAISS_INDEX_B_PATH=./embeddings_out/faiss_index_modelB.index\nMAPPING_A_PATH=./embeddings_out/idx_to_embedding_id_modelA.json\nMAPPING_B_PATH=./embeddings_out/idx_to_embedding_id_modelB.json\n\n# Output Directory\nOUTPUT_DIR=./embeddings_out\n```\n\n### Step 3: Populate Neo4j Knowledge Graph using `fpl_two_seasons.csv`\n\n```powershell\n# Start Neo4j Desktop and create/launch a local database\n\n# Run the knowledge graph creation script\npython .\\scripts\\create_kg.py\n```\n\nThis populates Neo4j with:\n\n- **Seasons**: 2021-22, 2022-23\n- **Players**: ~600 per season\n- **Teams**: 20 Premier League teams\n- **Fixtures**: 380 per season (38 gameweeks Γ— 20 teams)\n- **Performance Data**: Goals, assists, clean sheets, total points, etc.\n\n### Step 4: Load/Generate Embeddings\n\n#### Option A: Download Pre-computed Indexes (⚑ Fastest)\n\nDownload FAISS indexes and mappings from: [Google Drive Link](https://drive.google.com/drive/folders/1nyeVFgM-nb4q6_rRVhxmG5-gnQSjjBjp?usp=sharing)\n\nPlace files in `embeddings_out/`:\n\n```\nembeddings_out/\nβ”œβ”€β”€ faiss_index_modelA.index\nβ”œβ”€β”€ faiss_index_modelB.index\nβ”œβ”€β”€ idx_to_embedding_id_modelA.json\n└── idx_to_embedding_id_modelB.json\n```\n\n#### Option B: Generate From Scratch (⏱️ ~4 hours on CPU)\n\n```powershell\npython .\\scripts\\generate_embeddings.py\n```\n\nThis script:\n\n1. Fetches all player performance records from Neo4j\n2. Generates text descriptions (e.g., \"Haaland: 13 goals | assists: 1 | total_points: 10 | Position: FWD\")\n3. Encodes them using both embedding models\n4. Creates FAISS indexes for fast similarity search\n\n### Step 5: Run the Web UI\n\n```powershell\nstreamlit run main.py\n```\n\nOpen **http://localhost:8501** in your browser.\n\n---\n\n## πŸ“‚ Project Structure\n\n```\nfpl-assistant/\nβ”œβ”€β”€ main.py # Streamlit web UI entry point\nβ”œβ”€β”€ requirements.txt # Python dependencies\nβ”œβ”€β”€ README.md # This file\nβ”œβ”€β”€ STARTING.md # Minimal setup guide\nβ”œβ”€β”€ schema.md # Data schema documentation\nβ”œβ”€β”€ checklist.md # Project development phases\nβ”œβ”€β”€ .env.template # Environment variables template\nβ”‚\nβ”œβ”€β”€ config/ # Configuration & lookup tables\nβ”‚ β”œβ”€β”€ settings.py # Model options, defaults\nβ”‚ β”œβ”€β”€ template_library.py # 35 Cypher query templates\nβ”‚ β”œβ”€β”€ team_name_variants.py # Team abbreviation β†’ full name\nβ”‚ β”œβ”€β”€ stat_variants.py # Statistic name aliases\nβ”‚ β”œβ”€β”€ styles.py # Streamlit CSS styling\nβ”‚ └── FPLTrivia.md # Possible user queries\nβ”‚\nβ”œβ”€β”€ modules/ # Core application logic\nβ”‚ β”œβ”€β”€ preprocessing.py # Intent classification + entity extraction\nβ”‚ β”œβ”€β”€ cypher_retriever.py # Baseline retrieval via Cypher\nβ”‚ β”œβ”€β”€ vector_retriever.py # Semantic retrieval via embeddings\nβ”‚ β”œβ”€β”€ db_manager.py # Neo4j connection pool\nβ”‚ β”œβ”€β”€ llm_engine.py # LLM API calls (DeepSeek, Llama, Gemma)\nβ”‚ β”œβ”€β”€ llm_helper.py # Intent classification & Cypher Generator with LLM\nβ”‚ └── tests_llm_engine.py # `llm_engine.py` customized for performance testing\nβ”‚\nβ”œβ”€β”€ scripts/ # Data processing & setup\nβ”‚ β”œβ”€β”€ create_kg.py # Populate Neo4j from CSV\nβ”‚ β”œβ”€β”€ generate_embeddings.py # Create FAISS indexes\nβ”‚ β”œβ”€β”€ fpl_two_seasons.csv # Raw FPL data (2 seasons)\nβ”‚ └── config.txt # Neo4j connection configuration\nβ”‚\nβ”œβ”€β”€ embeddings_out/ # Pre-computed embeddings\nβ”‚ β”œβ”€β”€ faiss_index_modelA.index # Fast index for model A\nβ”‚ β”œβ”€β”€ faiss_index_modelB.index # Fast index for model B\nβ”‚ β”œβ”€β”€ idx_to_embedding_id_modelA.json\nβ”‚ └── idx_to_embedding_id_modelB.json\nβ”‚\nβ”œβ”€β”€ experiments/ # Evaluation framework\nβ”‚ β”œβ”€β”€ run_experiments.py # Execute all experiments\nβ”‚ β”œβ”€β”€ tests.json # 30 test prompts\nβ”‚ β”œβ”€β”€ results.json # Experimental results (540 trials)\nβ”‚ β”œβ”€β”€ validate_tests.json # Ground truth answers\nβ”‚ β”œβ”€β”€ cost_modify.py # Calculate LLM costs\nβ”‚ β”œβ”€β”€ viz.py # Visualize results using plots\nβ”‚ └── plots/ # Generated charts\nβ”‚\n└── logo.png # App logo\n```\n\n---\n\n## πŸ“š Module Documentation\n\n### 1. **preprocessing.py** β€” Intent & Entity Extraction\n\nConverts raw user text into structured data.\n\n**Key Functions:**\n\n- `extract_entities(query: str) β†’ dict` β€” Extracts players, teams, positions, gameweeks, seasons, stats\n\n**Features:**\n\n- **Spacy NER** for organization recognition (team names)\n- **Fuzzy matching** to handle typos and partial names\n- **Regex patterns** for gameweeks (e.g., \"GW10\"), positions, seasons\n- **Database lookups** for robustness\n\n**Example:**\n\n```python\nquery = \"How many goals did Haaland score in GW5 2022-23?\"\nentities = extract_entities(query)\n# Output:\n# {\n# \"players\": [\"Erling Haaland\"],\n# \"gameweeks\": [5],\n# \"seasons\": [\"2022-23\"],\n# \"statistics\": []\n# }\n```\n\n### 2. **cypher_retriever.py** β€” Baseline Deterministic Retrieval\n\nExecutes templated Cypher queries against Neo4j.\n\n**Key Functions:**\n\n- `retrieve_data_via_cypher(intent, entities, limit) β†’ dict` β€” Executes a Cypher template selected by intent\n\n**Template Examples:**\n\n- `PLAYER_STATS_GW_SEASON` β€” Get a player's stats in a specific gameweek\n- `COMPARE_PLAYERS_BY_TOTAL_POINTS` β€” Compare two players' total points\n- `PLAYER_CAREER_STATS_TOTALS` β€” Career aggregates\n- `TOP_PLAYERS_BY_POSITION` β€” Rank players by position\n- `TEAM_FIXTURE_SCHEDULE` β€” Get team's upcoming/past fixtures\n\n**Features:**\n\n- Parameter injection safety (parameterized + template rendering)\n- Missing parameter detection with fallbacks\n- JSON-friendly output\n\n### 3. **vector_retriever.py** β€” Semantic Embedding-Based Retrieval\n\nFinds players/fixtures using semantic similarity via embeddings.\n\n**Key Functions:**\n\n- `vector_search(entities, top_k, model_choice) β†’ dict` β€” Performs FAISS similarity search\n- `get_models_and_indexes()` β†’ Cached loading of models + FAISS indexes\n\n**Process:**\n\n1. Build query text from entities (e.g., \"Players: Haaland | Positions: FWD\")\n2. Encode query using SentenceTransformer\n3. Query FAISS index for top-k similar embeddings\n4. Fetch source nodes from Neo4j\n\n**Embedding Models:**\n\n- **Model A**: `all-MiniLM-L6-v2` (22M params, fast)\n- **Model B**: `all-mpnet-base-v2` (109M params, high-quality)\n\n### 4. **db_manager.py** β€” Neo4j Connection Management\n\nSingleton pattern for safe, pooled Neo4j access.\n\n```python\ndb = Neo4jGraph() # Singleton\nresults = db.execute_query(\"MATCH (p:Player) RETURN p LIMIT 5\")\n```\n\n### 5. **llm_engine.py** β€” Multi-Model LLM Answer Generation\n\nInterfaces with multiple LLM providers.\n\n**Supported Models:**\n\n- **DeepSeek** (default, most cost-effective)\n- **Llama** via Hugging Face Inference API\n- **Gemma** via Hugging Face Inference API\n\n**Functions:**\n\n- `deepseek_generate_answer(query, context) β†’ str`\n- `llama_generate_answer(query, context) β†’ str`\n- `gemma_generate_answer(query, context) β†’ str`\n\n**System Prompt:**\n\n```\nYou are an elite Fantasy Premier League analyst.\nAnswer the user's question using ONLY the data provided.\nDo NOT guess or hallucinate.\nKeep output concise and actionable.\nSuggest a follow-up question at the end.\n```\n\n### 6. **llm_helper.py** β€” Intent Classification & Prompt Engineering\n\n- High-level LLM utilities for understanding user intent.\n- Generating cypher queries.\n\n**Functions:**\n\n- `classify_with_deepseek(query, options) β†’ list` β€” Map query to up to 3 Cypher templates\n- Fallback: `local_intent_classify(query)` (rule-based, in `config/template_library.py`)\n- `create_query_with_deepseek(query: str, schema) -> cypher query` - Generate a consistent query for user's query with respect to KG schema.\n\n---\n\n## πŸ—„οΈ Knowledge Graph Schema\n\n### Node Types\n\n| Node | Properties | Purpose |\n| ------------- | ------------------------------------------ | ---------------------------------------- |\n| **Season** | `season_name` | Either 2021-22 or 2022-23 |\n| **Gameweek** | `season`, `GW_number` | 38 gameweeks per season |\n| **Fixture** | `season`, `fixture_number`, `kickoff_time` | Individual matches |\n| **Team** | `name` | 20 Premier League clubs per season |\n| **Player** | `player_name`, `player_element` | Individual players |\n| **Position** | `name` | FWD, MID, DEF, GK |\n| **Embedding** | `model`, `text`, `source_label` | Vector embeddings of player descriptions |\n\n### Relationships\n\n```\n- (Season) - [:HAS_GW]-> (Gameweek)\n- (Gameweek) - [:HAS_FIXTURE]-> (Fixture)\n- (Fixture) - [:HAS_HOME_TEAM]-> (Team)\n- (Fixture) - [:HAS_AWAY_TEAM]-> (Team)\n- (Player) - [:PLAYS_AS]-> (Position)\n- (Player) - [:PLAYED_IN]-> (Fixture)\n```\n\n### Performance Stats on `PLAYED_IN` Relationships\n\n```\nminutes, goals_scored, assists, total_points, bonus,\nclean_sheets, goals_conceded, own_goals, yellow_cards,\nred_cards, saves, penalties_saved, penalties_missed,\nbps, influence, creativity, threat, ict_index, form\n```\n\n---\n\n## πŸ” Retrieval Methods\n\nThe system supports **four retrieval strategies**, configurable from the UI sidebar:\n\n### 1. **Baseline (Cypher)** β€” Deterministic Graph Queries\n\n**When to use:** High-precision factual queries (stats, comparisons)\n\n**Process:**\n\n1. Classify intent (e.g., \"PLAYER_STATS_GW_SEASON\")\n2. Map entities to template parameters\n3. Execute Cypher query\n4. Return structured results\n\n**Pros:** Deterministic, precise, low latency \n**Cons:** Requires exact entity matching; limited flexibility\n\n### 2. **Embeddings (Vector)** β€” Semantic Similarity Search\n\n**When to use:** Exploratory queries, fuzzy matching (e.g., \"players similar to Salah\")\n\n**Process:**\n\n1. Encode query + entities as a text vector\n2. Query FAISS index for top-k similar embeddings\n3. Fetch corresponding nodes from Neo4j\n4. Return ranked results\n\n**Pros:** Robust to phrasing differences, discovers similar items \n**Cons:** Less precise; slower than Cypher; not practically useful for the FPL Knowledge Graph\n\n### 3. **Hybrid** β€” Best of Both Worlds\n\n**When to use:** Balance precision + recall\n\n**Process:**\n\n1. Run Cypher retrieval\n2. Run embedding search in parallel\n3. Combine results, deduplicate, rank by relevance\n\n**Pros:** High recall + precision \n**Cons:** Slower (executes both retrievers)\n\n### 4. **LLM-Generated Cypher** β€” Let the Model Write Queries\n\n**When to use:** Complex, unconventional questions\n\n**Process:**\n\n1. Prompt DeepSeek to generate Cypher queries\n2. Execute against Neo4j\n3. Return results\n\n**Pros:** Flexibility for novel queries \n**Cons:** Can generate invalid Cypher; slower; major cybersecurity threat\n\n---\n\n## πŸ€– LLM Comparison\n\n| Model | Provider | Speed | Quality | Cost |\n| --------------- | ------------ | ------- | ---------- | -------- |\n| **DeepSeek** | Deepseek API | ⚑ Fast | ⭐⭐⭐⭐ | πŸ’° Cheap |\n| **Llama 2 70B** | Hugging Face | 🐒 Slow | ⭐⭐⭐⭐⭐ | πŸ’°πŸ’° |\n| **Gemma 7B** | Hugging Face | ⚑ Fast | ⭐⭐⭐ | πŸ’° Cheap |\n\n---\n\n## πŸ“Š Experiments & Evaluation\n\n### Evaluation Framework\n\nThe project includes a comprehensive **evaluation suite** with:\n\n- **30 test prompts** across different query types\n- **18 permutations** per prompt (different retrieval modes Γ— LLM models Γ— embedding models)\n- **540 total experiments** to benchmark performance\n\n### Running Experiments\n\n```powershell\npython -m experiments.run_experiments\n```\n\n**Outputs:**\n\n- `experiments/results.json` β€” Detailed results for each trial\n- `experiments/plots/` β€” Generated visualizations\n- Summary metrics: latency, token usage, cost analysis\n\n### Test Prompt Categories\n\n1. **Player Performance** β€” Stats, comparisons, rankings\n2. **Team Analysis** β€” Fixture difficulty, form\n3. **Transfer Advice** β€” Form\n4. **Comparisons** β€” Head-to-head player metrics\n5. **Recommendations** β€” Top performers by position\n\n---\n\n## 🎨 UI Features\n\n### Streamlit Interface\n\n```\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\nβ”‚ FPL Graph-RAG Assistant β”‚\nβ”‚ Ask questions about Fantasy Premier League β”‚\nβ”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€\nβ”‚ SIDEBAR β”‚ MAIN CONTENT β”‚\nβ”‚ β”œβ”€ LLM Choice β”‚ β€’ Chat input β”‚\nβ”‚ β”œβ”€ Retrieval β”‚ β€’ Answer β”‚\nβ”‚ β”œβ”€ Embedding model β”‚ β€’ Graph visualization β”‚\nβ”‚ β”œβ”€ Top-K β”‚ β€’ Raw retrieval context β”‚\nβ”‚ └─ PL Logo β”‚ β€’ Debug & Transparency β”‚\nβ”‚ β”‚ β€’ Chat history β”‚\nβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n```\n\n### Color Palette (Official PL Colors)\n\n| Color | RGB | Use |\n| ------------------------------------------------------------------------ | -------------------- | ------------------- |\n| ● Cyan | `rgb(4, 245, 255)` | Highlights, accents |\n| ● Pink | `rgb(233, 0, 82)` | Warnings, important |\n| ● Green | `rgb(0, 255, 133)` | Success, positive |\n| ● Purple | `rgb(56, 0, 60)` | Background, muted |\n| ● White | `rgb(255, 255, 255)` | Text, primary |\n\n---\n\n## 🀝 Team & Contributing\n\nThis project was developed as part of **Advanced Computer Lab Milestone 3 course work** on AI tools at The German University in Cairo, CSEN 903.\n\n### Key Components Built By\n\n- **Graph Architecture** β€” Neo4j schema design, Cypher templates\n- **Preprocessing** β€” Intent classification, fuzzy entity extraction\n- **Retrieval Layer** β€” Cypher baseline, FAISS embeddings, hybrid approach\n- **LLM Integration** β€” Multi-model support, prompt engineering\n- **Evaluation** β€” Comprehensive benchmark suite with 540 trials\n\n### Future Work\n\n- [ ] Add `value`, `selected_by`, `transfer_balance` for actual FPL transfers recommendations\n- [ ] Add KG relations between Players & Teams\n- [ ] Optimize FAISS indexes for faster search\n- [ ] Add more LLM providers (Claude, GPT-4)\n- [ ] Cache common queries for faster responses\n- [ ] Implement streaming responses for long answers\n- [ ] Add user feedback loop for fine-tuning (PPO)\n\n---\n\n## πŸ“„ License\n\nThis project is for educational purposes as part of ACL coursework.\n\n---\n"}, "64aca1c75d6470e252dbaf9f05c8deda1b34853e": {"t": 1785772188.5989442, "n": 20625, "h": "122dc93c83dd6446", "c": "# πŸ† FPL Graph-RAG Assistant\n\n> **A Retrieval-Augmented Generation (RAG) system for intelligent Fantasy Premier League analysis using Neo4j knowledge graphs, semantic embeddings, and large language models.**\n\n---\n\n## πŸ“– Table of Contents\n\n1. [Overview](#overview)\n2. [Key Features](#key-features)\n3. [System Architecture](#system-architecture)\n4. [Quick Start](#quick-start)\n5. [Project Structure](#project-structure)\n6. [Module Documentation](#module-documentation)\n7. [Knowledge Graph Schema](#knowledge-graph-schema)\n8. [Retrieval Methods](#retrieval-methods)\n9. [LLM Integration](#llm-integration)\n10. [Experiments & Evaluation](#experiments--evaluation)\n11. [Troubleshooting](#troubleshooting)\n12. [Team & Contributing](#team--contributing)\n\n---\n\n## 🎯 Overview\n\n**FPL Assistant** is an intelligent conversational system that answers Fantasy Premier League questions using a **retrieval-augmented generation (RAG)** approach. Instead of hallucinating answers, the system:\n\n1. **Classifies intent** β€” understands what the user is asking (e.g., player stats, comparisons)\n2. **Extracts entities** β€” identifies relevant players, teams, gameweeks, and statistics from the query\n3. **Retrieves context** β€” uses multiple retrieval strategies (deterministic Cypher queries, semantic vector search, or hybrid) to fetch facts from a Neo4j knowledge graph\n4. **Generates answers** β€” passes retrieved context to a language model (DeepSeek, Llama, or Gemma) to synthesize natural, conversational responses\n\nThe system supports queries like:\n\n- _\"Compare Salah and Haaland's total points\"_\n- _\"How many goals did Salah score against Wolves?\"_\n- _\"Which team did Salah score the least against in the 2022-23 season?\"_\n\n### Why This Approach?\n\nTraditional LLMs on FPL data are prone to hallucination (making up stats). RAG solves this by grounding responses in **actual data** from the knowledge graph, ensuring accuracy and factuality.\n\n---\n\n## ✨ Key Features\n\n| Feature | Description |\n| ----------------------------- | -------------------------------------------------------------------------------------------- |\n| **Multi-Model LLM Support** | DeepSeek (default), Llama, or Gemma for answer generation |\n| **Dual Embedding Models** | All-MiniLM-L6-v2 (fast, small) and All-MPNet-Base-V2 (high-quality) |\n| **Four Retrieval Strategies** | Baseline Cypher, Embeddings (Vector), Hybrid, and LLM-generated Cypher |\n| **Fuzzy Entity Matching** | Robust player/team name recognition despite typos and abbreviations |\n| **Comprehensive FPL Schema** | Covers players, teams, positions, gameweeks, seasons, and detailed performance stats |\n| **Interactive Web UI** | Streamlit-based interface with debug mode and real-time configuration |\n| **Evaluation Framework** | 30 test prompts Γ— 18 permutations = 540 experiments to benchmark retrieval + LLM performance |\n| **Two Seasons of Data** | 2021-22 and 2022-23 FPL data with player performance across all gameweeks |\n\n---\n\n## πŸ—οΈ System Architecture\n\n```\nUser Query\n ↓\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\nβ”‚ PREPROCESSING & UNDERSTANDING β”‚\nβ”‚ β€’ Intent Classification (LLM or Rule-based) β”‚\nβ”‚ β€’ Entity Extraction (NER + Fuzzy Matching) β”‚\nβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n ↓\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\nβ”‚ RETRIEVAL LAYER (Multi-Strategy) β”‚\nβ”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚\nβ”‚ β”‚ Cypher Baseline β”‚ β”‚ Vector Embeddingsβ”‚ β”‚\nβ”‚ β”‚ (Deterministic)β”‚ β”‚ (Semantic) β”‚ β”‚\nβ”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚\nβ”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚\nβ”‚ ↓ β”‚\nβ”‚ Neo4j Knowledge Graph β”‚\nβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n ↓\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\nβ”‚ CONTEXT ASSEMBLY β”‚\nβ”‚ β€’ Combine & deduplicate results β”‚\nβ”‚ β€’ Format for LLM consumption β”‚\nβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n ↓\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\nβ”‚ LLM ANSWER GENERATION β”‚\nβ”‚ β€’ DeepSeek / Llama / Gemma β”‚\nβ”‚ β€’ Grounded in retrieved facts β”‚\nβ”‚ β€’ Suggest follow-up questions β”‚\nβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n ↓\nNatural, Factual Answer\n```\n\n---\n\n## πŸš€ Quick Start\n\n### Prerequisites\n\n- **Python 3.12**\n- **Neo4j** (Desktop or Docker)\n- **4 GB+ RAM** (for embedding models + FAISS indexes)\n- **Internet connection** (for LLM API calls)\n\n### Step 1: Clone & Setup Environment\n\n```powershell\n# Create and activate virtual environment\npython -m venv .venv\n.\\venv\\Scripts\\Activate.ps1\n\n# Install dependencies\npip install -r requirements.txt\n```\n\n### Step 2: Configure Credentials\n\nCreate a `.env` file in the project root:\n\n```env\n# Neo4j Configuration\nNEO4J_URI=bolt://localhost:7687\nNEO4J_USERNAME=neo4j\nNEO4J_PASSWORD=\n\n# LLM API Keys\nDEEPSEEK_API_KEY=\nDEEPSEEK_API_URL=https://api.deepseek.com/chat/completions\nDEEPSEEK_MODEL=deepseek-chat\n\nHF_TOKEN=\n\n# Embedding Models\nMODEL_A_NAME=sentence-transformers/all-MiniLM-L6-v2\nMODEL_B_NAME=sentence-transformers/all-mpnet-base-v2\n\n# FAISS Index Paths\nFAISS_INDEX_A_PATH=./embeddings_out/faiss_index_modelA.index\nFAISS_INDEX_B_PATH=./embeddings_out/faiss_index_modelB.index\nMAPPING_A_PATH=./embeddings_out/idx_to_embedding_id_modelA.json\nMAPPING_B_PATH=./embeddings_out/idx_to_embedding_id_modelB.json\n\n# Output Directory\nOUTPUT_DIR=./embeddings_out\n```\n\n### Step 3: Populate Neo4j Knowledge Graph using `fpl_two_seasons.csv`\n\n```powershell\n# Start Neo4j Desktop and create/launch a local database\n\n# Run the knowledge graph creation script\npython .\\scripts\\create_kg.py\n```\n\nThis populates Neo4j with:\n\n- **Seasons**: 2021-22, 2022-23\n- **Players**: ~600 per season\n- **Teams**: 20 Premier League teams\n- **Fixtures**: 380 per season (38 gameweeks Γ— 20 teams)\n- **Performance Data**: Goals, assists, clean sheets, total points, etc.\n\n### Step 4: Load/Generate Embeddings\n\n#### Option A: Download Pre-computed Indexes (⚑ Fastest)\n\nDownload FAISS indexes and mappings from: [Google Drive Link](https://drive.google.com/drive/folders/1nyeVFgM-nb4q6_rRVhxmG5-gnQSjjBjp?usp=sharing)\n\nPlace files in `embeddings_out/`:\n\n```\nembeddings_out/\nβ”œβ”€β”€ faiss_index_modelA.index\nβ”œβ”€β”€ faiss_index_modelB.index\nβ”œβ”€β”€ idx_to_embedding_id_modelA.json\n└── idx_to_embedding_id_modelB.json\n```\n\n#### Option B: Generate From Scratch (⏱️ ~4 hours on CPU)\n\n```powershell\npython .\\scripts\\generate_embeddings.py\n```\n\nThis script:\n\n1. Fetches all player performance records from Neo4j\n2. Generates text descriptions (e.g., \"Haaland: 13 goals | assists: 1 | total_points: 10 | Position: FWD\")\n3. Encodes them using both embedding models\n4. Creates FAISS indexes for fast similarity search\n\n### Step 5: Run the Web UI\n\n```powershell\nstreamlit run main.py\n```\n\nOpen **http://localhost:8501** in your browser.\n\n---\n\n## πŸ“‚ Project Structure\n\n```\nfpl-assistant/\nβ”œβ”€β”€ main.py # Streamlit web UI entry point\nβ”œβ”€β”€ requirements.txt # Python dependencies\nβ”œβ”€β”€ README.md # This file\nβ”œβ”€β”€ STARTING.md # Minimal setup guide\nβ”œβ”€β”€ schema.md # Data schema documentation\nβ”œβ”€β”€ checklist.md # Project development phases\nβ”œβ”€β”€ .env.template # Environment variables template\nβ”‚\nβ”œβ”€β”€ config/ # Configuration & lookup tables\nβ”‚ β”œβ”€β”€ settings.py # Model options, defaults\nβ”‚ β”œβ”€β”€ template_library.py # 35 Cypher query templates\nβ”‚ β”œβ”€β”€ team_name_variants.py # Team abbreviation β†’ full name\nβ”‚ β”œβ”€β”€ stat_variants.py # Statistic name aliases\nβ”‚ β”œβ”€β”€ styles.py # Streamlit CSS styling\nβ”‚ └── FPLTrivia.md # Possible user queries\nβ”‚\nβ”œβ”€β”€ modules/ # Core application logic\nβ”‚ β”œβ”€β”€ preprocessing.py # Intent classification + entity extraction\nβ”‚ β”œβ”€β”€ cypher_retriever.py # Baseline retrieval via Cypher\nβ”‚ β”œβ”€β”€ vector_retriever.py # Semantic retrieval via embeddings\nβ”‚ β”œβ”€β”€ db_manager.py # Neo4j connection pool\nβ”‚ β”œβ”€β”€ llm_engine.py # LLM API calls (DeepSeek, Llama, Gemma)\nβ”‚ β”œβ”€β”€ llm_helper.py # Intent classification & Cypher Generator with LLM\nβ”‚ └── tests_llm_engine.py # `llm_engine.py` customized for performance testing\nβ”‚\nβ”œβ”€β”€ scripts/ # Data processing & setup\nβ”‚ β”œβ”€β”€ create_kg.py # Populate Neo4j from CSV\nβ”‚ β”œβ”€β”€ generate_embeddings.py # Create FAISS indexes\nβ”‚ β”œβ”€β”€ fpl_two_seasons.csv # Raw FPL data (2 seasons)\nβ”‚ └── config.txt # Neo4j connection configuration\nβ”‚\nβ”œβ”€β”€ embeddings_out/ # Pre-computed embeddings\nβ”‚ β”œβ”€β”€ faiss_index_modelA.index # Fast index for model A\nβ”‚ β”œβ”€β”€ faiss_index_modelB.index # Fast index for model B\nβ”‚ β”œβ”€β”€ idx_to_embedding_id_modelA.json\nβ”‚ └── idx_to_embedding_id_modelB.json\nβ”‚\nβ”œβ”€β”€ experiments/ # Evaluation framework\nβ”‚ β”œβ”€β”€ run_experiments.py # Execute all experiments\nβ”‚ β”œβ”€β”€ tests.json # 30 test prompts\nβ”‚ β”œβ”€β”€ results.json # Experimental results (540 trials)\nβ”‚ β”œβ”€β”€ validate_tests.json # Ground truth answers\nβ”‚ β”œβ”€β”€ cost_modify.py # Calculate LLM costs\nβ”‚ β”œβ”€β”€ viz.py # Visualize results using plots\nβ”‚ └── plots/ # Generated charts\nβ”‚\n└── logo.png # App logo\n```\n\n---\n\n## πŸ“š Module Documentation\n\n### 1. **preprocessing.py** β€” Intent & Entity Extraction\n\nConverts raw user text into structured data.\n\n**Key Functions:**\n\n- `extract_entities(query: str) β†’ dict` β€” Extracts players, teams, positions, gameweeks, seasons, stats\n\n**Features:**\n\n- **Spacy NER** for organization recognition (team names)\n- **Fuzzy matching** to handle typos and partial names\n- **Regex patterns** for gameweeks (e.g., \"GW10\"), positions, seasons\n- **Database lookups** for robustness\n\n**Example:**\n\n```python\nquery = \"How many goals did Haaland score in GW5 2022-23?\"\nentities = extract_entities(query)\n# Output:\n# {\n# \"players\": [\"Erling Haaland\"],\n# \"gameweeks\": [5],\n# \"seasons\": [\"2022-23\"],\n# \"statistics\": []\n# }\n```\n\n### 2. **cypher_retriever.py** β€” Baseline Deterministic Retrieval\n\nExecutes templated Cypher queries against Neo4j.\n\n**Key Functions:**\n\n- `retrieve_data_via_cypher(intent, entities, limit) β†’ dict` β€” Executes a Cypher template selected by intent\n\n**Template Examples:**\n\n- `PLAYER_STATS_GW_SEASON` β€” Get a player's stats in a specific gameweek\n- `COMPARE_PLAYERS_BY_TOTAL_POINTS` β€” Compare two players' total points\n- `PLAYER_CAREER_STATS_TOTALS` β€” Career aggregates\n- `TOP_PLAYERS_BY_POSITION` β€” Rank players by position\n- `TEAM_FIXTURE_SCHEDULE` β€” Get team's upcoming/past fixtures\n\n**Features:**\n\n- Parameter injection safety (parameterized + template rendering)\n- Missing parameter detection with fallbacks\n- JSON-friendly output\n\n### 3. **vector_retriever.py** β€” Semantic Embedding-Based Retrieval\n\nFinds players/fixtures using semantic similarity via embeddings.\n\n**Key Functions:**\n\n- `vector_search(entities, top_k, model_choice) β†’ dict` β€” Performs FAISS similarity search\n- `get_models_and_indexes()` β†’ Cached loading of models + FAISS indexes\n\n**Process:**\n\n1. Build query text from entities (e.g., \"Players: Haaland | Positions: FWD\")\n2. Encode query using SentenceTransformer\n3. Query FAISS index for top-k similar embeddings\n4. Fetch source nodes from Neo4j\n\n**Embedding Models:**\n\n- **Model A**: `all-MiniLM-L6-v2` (22M params, fast)\n- **Model B**: `all-mpnet-base-v2` (109M params, high-quality)\n\n### 4. **db_manager.py** β€” Neo4j Connection Management\n\nSingleton pattern for safe, pooled Neo4j access.\n\n```python\ndb = Neo4jGraph() # Singleton\nresults = db.execute_query(\"MATCH (p:Player) RETURN p LIMIT 5\")\n```\n\n### 5. **llm_engine.py** β€” Multi-Model LLM Answer Generation\n\nInterfaces with multiple LLM providers.\n\n**Supported Models:**\n\n- **DeepSeek** (default, most cost-effective)\n- **Llama** via Hugging Face Inference API\n- **Gemma** via Hugging Face Inference API\n\n**Functions:**\n\n- `deepseek_generate_answer(query, context) β†’ str`\n- `llama_generate_answer(query, context) β†’ str`\n- `gemma_generate_answer(query, context) β†’ str`\n\n**System Prompt:**\n\n```\nYou are an elite Fantasy Premier League analyst.\nAnswer the user's question using ONLY the data provided.\nDo NOT guess or hallucinate.\nKeep output concise and actionable.\nSuggest a follow-up question at the end.\n```\n\n### 6. **llm_helper.py** β€” Intent Classification & Prompt Engineering\n\n- High-level LLM utilities for understanding user intent.\n- Generating cypher queries.\n\n**Functions:**\n\n- `classify_with_deepseek(query, options) β†’ list` β€” Map query to up to 3 Cypher templates\n- Fallback: `local_intent_classify(query)` (rule-based, in `config/template_library.py`)\n- `create_query_with_deepseek(query: str, schema) -> cypher query` - Generate a consistent query for user's query with respect to KG schema.\n\n---\n\n## πŸ—„οΈ Knowledge Graph Schema\n\n### Node Types\n\n| Node | Properties | Purpose |\n| ------------- | ------------------------------------------ | ---------------------------------------- |\n| **Season** | `season_name` | Either 2021-22 or 2022-23 |\n| **Gameweek** | `season`, `GW_number` | 38 gameweeks per season |\n| **Fixture** | `season`, `fixture_number`, `kickoff_time` | Individual matches |\n| **Team** | `name` | 20 Premier League clubs per season |\n| **Player** | `player_name`, `player_element` | Individual players |\n| **Position** | `name` | FWD, MID, DEF, GK |\n| **Embedding** | `model`, `text`, `source_label` | Vector embeddings of player descriptions |\n\n### Relationships\n\n```\n- (Season) - [:HAS_GW]-> (Gameweek)\n- (Gameweek) - [:HAS_FIXTURE]-> (Fixture)\n- (Fixture) - [:HAS_HOME_TEAM]-> (Team)\n- (Fixture) - [:HAS_AWAY_TEAM]-> (Team)\n- (Player) - [:PLAYS_AS]-> (Position)\n- (Player) - [:PLAYED_IN]-> (Fixture)\n```\n\n### Performance Stats on `PLAYED_IN` Relationships\n\n```\nminutes, goals_scored, assists, total_points, bonus,\nclean_sheets, goals_conceded, own_goals, yellow_cards,\nred_cards, saves, penalties_saved, penalties_missed,\nbps, influence, creativity, threat, ict_index, form\n```\n\n---\n\n## πŸ” Retrieval Methods\n\nThe system supports **four retrieval strategies**, configurable from the UI sidebar:\n\n### 1. **Baseline (Cypher)** β€” Deterministic Graph Queries\n\n**When to use:** High-precision factual queries (stats, comparisons)\n\n**Process:**\n\n1. Classify intent (e.g., \"PLAYER_STATS_GW_SEASON\")\n2. Map entities to template parameters\n3. Execute Cypher query\n4. Return structured results\n\n**Pros:** Deterministic, precise, low latency \n**Cons:** Requires exact entity matching; limited flexibility\n\n### 2. **Embeddings (Vector)** β€” Semantic Similarity Search\n\n**When to use:** Exploratory queries, fuzzy matching (e.g., \"players similar to Salah\")\n\n**Process:**\n\n1. Encode query + entities as a text vector\n2. Query FAISS index for top-k similar embeddings\n3. Fetch corresponding nodes from Neo4j\n4. Return ranked results\n\n**Pros:** Robust to phrasing differences, discovers similar items \n**Cons:** Less precise; slower than Cypher; not practically useful for the FPL Knowledge Graph\n\n### 3. **Hybrid** β€” Best of Both Worlds\n\n**When to use:** Balance precision + recall\n\n**Process:**\n\n1. Run Cypher retrieval\n2. Run embedding search in parallel\n3. Combine results, deduplicate, rank by relevance\n\n**Pros:** High recall + precision \n**Cons:** Slower (executes both retrievers)\n\n### 4. **LLM-Generated Cypher** β€” Let the Model Write Queries\n\n**When to use:** Complex, unconventional questions\n\n**Process:**\n\n1. Prompt DeepSeek to generate Cypher queries\n2. Execute against Neo4j\n3. Return results\n\n**Pros:** Flexibility for novel queries \n**Cons:** Can generate invalid Cypher; slower; major cybersecurity threat\n\n---\n\n## πŸ€– LLM Comparison\n\n| Model | Provider | Speed | Quality | Cost |\n| --------------- | ------------ | ------- | ---------- | -------- |\n| **DeepSeek** | Deepseek API | ⚑ Fast | ⭐⭐⭐⭐ | πŸ’° Cheap |\n| **Llama 2 70B** | Hugging Face | 🐒 Slow | ⭐⭐⭐⭐⭐ | πŸ’°πŸ’° |\n| **Gemma 7B** | Hugging Face | ⚑ Fast | ⭐⭐⭐ | πŸ’° Cheap |\n\n---\n\n## πŸ“Š Experiments & Evaluation\n\n### Evaluation Framework\n\nThe project includes a comprehensive **evaluation suite** with:\n\n- **30 test prompts** across different query types\n- **18 permutations** per prompt (different retrieval modes Γ— LLM models Γ— embedding models)\n- **540 total experiments** to benchmark performance\n\n### Running Experiments\n\n```powershell\npython -m experiments.run_experiments\n```\n\n**Outputs:**\n\n- `experiments/results.json` β€” Detailed results for each trial\n- `experiments/plots/` β€” Generated visualizations\n- Summary metrics: latency, token usage, cost analysis\n\n### Test Prompt Categories\n\n1. **Player Performance** β€” Stats, comparisons, rankings\n2. **Team Analysis** β€” Fixture difficulty, form\n3. **Transfer Advice** β€” Form\n4. **Comparisons** β€” Head-to-head player metrics\n5. **Recommendations** β€” Top performers by position\n\n---\n\n## 🎨 UI Features\n\n### Streamlit Interface\n\n```\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\nβ”‚ FPL Graph-RAG Assistant β”‚\nβ”‚ Ask questions about Fantasy Premier League β”‚\nβ”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€\nβ”‚ SIDEBAR β”‚ MAIN CONTENT β”‚\nβ”‚ β”œβ”€ LLM Choice β”‚ β€’ Chat input β”‚\nβ”‚ β”œβ”€ Retrieval β”‚ β€’ Answer β”‚\nβ”‚ β”œβ”€ Embedding model β”‚ β€’ Graph visualization β”‚\nβ”‚ β”œβ”€ Top-K β”‚ β€’ Raw retrieval context β”‚\nβ”‚ └─ PL Logo β”‚ β€’ Debug & Transparency β”‚\nβ”‚ β”‚ β€’ Chat history β”‚\nβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n```\n\n### Color Palette (Official PL Colors)\n\n| Color | RGB | Use |\n| ------------------------------------------------------------------------ | -------------------- | ------------------- |\n| ● Cyan | `rgb(4, 245, 255)` | Highlights, accents |\n| ● Pink | `rgb(233, 0, 82)` | Warnings, important |\n| ● Green | `rgb(0, 255, 133)` | Success, positive |\n| ● Purple | `rgb(56, 0, 60)` | Background, muted |\n| ● White | `rgb(255, 255, 255)` | Text, primary |\n\n---\n\n## 🀝 Team & Contributing\n\nThis project was developed as part of **Advanced Computer Lab Milestone 3 course work** on AI tools at The German University in Cairo, CSEN 903.\n\n### Key Components Built By\n\n- **Graph Architecture** β€” Neo4j schema design, Cypher templates\n- **Preprocessing** β€” Intent classification, fuzzy entity extraction\n- **Retrieval Layer** β€” Cypher baseline, FAISS embeddings, hybrid approach\n- **LLM Integration** β€” Multi-model support, prompt engineering\n- **Evaluation** β€” Comprehensive benchmark suite with 540 trials\n\n### Future Work\n\n- [ ] Add `value`, `selected_by`, `transfer_balance` for actual FPL transfers recommendations\n- [ ] Add KG relations between Players & Teams\n- [ ] Optimize FAISS indexes for faster search\n- [ ] Add more LLM providers (Claude, GPT-4)\n- [ ] Cache common queries for faster responses\n- [ ] Implement streaming responses for long answers\n- [ ] Add user feedback loop for fine-tuning (PPO)\n\n---\n\n## πŸ“„ License\n\nThis project is for educational purposes as part of ACL coursework.\n\n---\n"}, "c6a930ec8d91b93d02f8ec0d5c3d8b67a3ec5a93": {"t": 1785772190.2287993, "n": 22359, "h": "6c424186b1192842", "c": "# πŸ† FPL Graph-RAG Assistant\n\n> **A Retrieval-Augmented Generation (RAG) system for intelligent Fantasy Premier League analysis using Neo4j knowledge graphs, semantic embeddings, and large language models.**\n\n---\n\n## πŸ“– Table of Contents\n\n1. [Overview](#overview)\n2. [Key Features](#key-features)\n3. [System Architecture](#system-architecture)\n4. [Quick Start](#quick-start)\n5. [Project Structure](#project-structure)\n6. [Module Documentation](#module-documentation)\n7. [Knowledge Graph Schema](#knowledge-graph-schema)\n8. [Retrieval Methods](#retrieval-methods)\n9. [LLM Integration](#llm-integration)\n10. [Experiments & Evaluation](#experiments--evaluation)\n11. [Troubleshooting](#troubleshooting)\n12. [Team & Contributing](#team--contributing)\n\n---\n\n## 🎯 Overview\n\n**FPL Assistant** is an intelligent conversational system that answers Fantasy Premier League questions using a **hybrid retrieval-augmented generation (RAG)** approach. Instead of hallucinating answers, the system:\n\n1. **Classifies intent** β€” understands what the user is asking (e.g., player stats, comparisons, recommendations)\n2. **Extracts entities** β€” identifies relevant players, teams, gameweeks, and statistics from the query\n3. **Retrieves context** β€” uses multiple retrieval strategies (deterministic Cypher queries, semantic vector search, or hybrid) to fetch facts from a Neo4j knowledge graph\n4. **Generates answers** β€” passes retrieved context to a language model (DeepSeek, Llama, or Gemma) to synthesize natural, conversational responses\n\nThe system supports queries like:\n\n- _\"Who should I captain for gameweek 10?\"_\n- _\"Compare Haaland and Son's assists per game\"_\n- _\"What are the top forwards under Β£6.5M?\"_\n- _\"Who are the most creative midfielders in the 2022-23 season?\"_\n\n### Why This Approach?\n\nTraditional LLMs on FPL data are prone to hallucination (making up stats). RAG solves this by grounding responses in **actual data** from the knowledge graph, ensuring accuracy and factuality.\n\n---\n\n## ✨ Key Features\n\n| Feature | Description |\n| ----------------------------- | -------------------------------------------------------------------------------------------- |\n| **Multi-Model LLM Support** | DeepSeek (default), Llama, or Gemma for answer generation |\n| **Dual Embedding Models** | All-MiniLM-L6-v2 (fast, small) and All-MPNet-Base-V2 (high-quality) |\n| **Four Retrieval Strategies** | Baseline Cypher, Embeddings (Vector), Hybrid, and LLM-generated Cypher |\n| **Fuzzy Entity Matching** | Robust player/team name recognition despite typos and abbreviations |\n| **Comprehensive FPL Schema** | Covers players, teams, positions, gameweeks, seasons, and detailed performance stats |\n| **Interactive Web UI** | Streamlit-based interface with debug mode and real-time configuration |\n| **Evaluation Framework** | 30 test prompts Γ— 18 permutations = 540 experiments to benchmark retrieval + LLM performance |\n| **Two Seasons of Data** | 2021-22 and 2022-23 FPL data with player performance across all gameweeks |\n\n---\n\n## πŸ—οΈ System Architecture\n\n```\nUser Query\n ↓\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\nβ”‚ PREPROCESSING & UNDERSTANDING β”‚\nβ”‚ β€’ Intent Classification (LLM or Rule-based) β”‚\nβ”‚ β€’ Entity Extraction (NER + Fuzzy Matching) β”‚\nβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n ↓\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\nβ”‚ RETRIEVAL LAYER (Multi-Strategy) β”‚\nβ”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚\nβ”‚ β”‚ Cypher Baseline β”‚ β”‚ Vector Embeddingsβ”‚ β”‚\nβ”‚ β”‚ (Deterministic)β”‚ β”‚ (Semantic) β”‚ β”‚\nβ”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚\nβ”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚\nβ”‚ ↓ β”‚\nβ”‚ Neo4j Knowledge Graph β”‚\nβ”‚ (2 seasons Γ— 38 gameweeks Γ— 20 teams) β”‚\nβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n ↓\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\nβ”‚ CONTEXT ASSEMBLY β”‚\nβ”‚ β€’ Combine & deduplicate results β”‚\nβ”‚ β€’ Format for LLM consumption β”‚\nβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n ↓\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\nβ”‚ LLM ANSWER GENERATION β”‚\nβ”‚ β€’ DeepSeek / Llama / Gemma β”‚\nβ”‚ β€’ Grounded in retrieved facts β”‚\nβ”‚ β€’ Suggest follow-up questions β”‚\nβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n ↓\nNatural, Factual Answer\n```\n\n---\n\n## πŸš€ Quick Start\n\n### Prerequisites\n\n- **Python 3.9+**\n- **Neo4j** (Desktop or Docker)\n- **4 GB+ RAM** (for embedding models + FAISS indexes)\n- **Internet connection** (for LLM API calls)\n\n### Step 1: Clone & Setup Environment\n\n```powershell\n# Create and activate virtual environment\npython -m venv .venv\n.\\venv\\Scripts\\Activate.ps1\n\n# Install dependencies\npip install -r requirements.txt\n```\n\n### Step 2: Configure Credentials\n\nCreate a `.env` file in the project root:\n\n```env\n# Neo4j Configuration\nNEO4J_URI=bolt://localhost:7687\nNEO4J_USERNAME=neo4j\nNEO4J_PASSWORD=\n\n# LLM API Keys\nDEEPSEEK_API_KEY=\nDEEPSEEK_API_URL=https://api.deepseek.com/chat/completions\nDEEPSEEK_MODEL=deepseek-chat\n\n# Embedding Models\nMODEL_A_NAME=sentence-transformers/all-MiniLM-L6-v2\nMODEL_B_NAME=sentence-transformers/all-mpnet-base-v2\n\n# FAISS Index Paths\nFAISS_INDEX_A_PATH=./embeddings_out/faiss_index_modelA.index\nFAISS_INDEX_B_PATH=./embeddings_out/faiss_index_modelB.index\nMAPPING_A_PATH=./embeddings_out/idx_to_embedding_id_modelA.json\nMAPPING_B_PATH=./embeddings_out/idx_to_embedding_id_modelB.json\n\n# Output Directory\nOUTPUT_DIR=./embeddings_out\n```\n\n### Step 3: Populate Neo4j Knowledge Graph\n\n#### Option A: Using Provided Data (Recommended)\n\n```powershell\n# Start Neo4j Desktop and create/launch a local database\n\n# Run the knowledge graph creation script\npython .\\scripts\\create_kg.py\n```\n\nThis populates Neo4j with:\n\n- **Seasons**: 2021-22, 2022-23\n- **Players**: ~600 per season\n- **Teams**: 20 Premier League teams\n- **Fixtures**: 380 per season (38 gameweeks Γ— 20 teams)\n- **Performance Data**: Goals, assists, clean sheets, total points, etc.\n\n### Step 4: Load/Generate Embeddings\n\n#### Option A: Download Pre-computed Indexes (⚑ Fastest)\n\nDownload FAISS indexes and mappings from: [Google Drive Link](https://drive.google.com/drive/folders/1nyeVFgM-nb4q6_rRVhxmG5-gnQSjjBjp?usp=sharing)\n\nPlace files in `embeddings_out/`:\n\n```\nembeddings_out/\nβ”œβ”€β”€ faiss_index_modelA.index\nβ”œβ”€β”€ faiss_index_modelB.index\nβ”œβ”€β”€ idx_to_embedding_id_modelA.json\n└── idx_to_embedding_id_modelB.json\n```\n\n#### Option B: Generate From Scratch (⏱️ ~4 hours on CPU)\n\n```powershell\npython .\\scripts\\generate_embeddings.py\n```\n\nThis script:\n\n1. Fetches all player performance records from Neo4j\n2. Generates text descriptions (e.g., \"Haaland (FWD): 13 goals, 5 assists, 195 points\")\n3. Encodes them using both embedding models\n4. Creates FAISS indexes for fast similarity search\n\n### Step 5: Run the Web UI\n\n```powershell\nstreamlit run main.py\n```\n\nOpen **http://localhost:8501** in your browser.\n\n---\n\n## πŸ“‚ Project Structure\n\n```\nfpl-assistant/\nβ”œβ”€β”€ main.py # Streamlit web UI entry point\nβ”œβ”€β”€ requirements.txt # Python dependencies\nβ”œβ”€β”€ README.md # This file\nβ”œβ”€β”€ STARTING.md # Minimal setup guide\nβ”œβ”€β”€ schema.md # Data schema documentation\nβ”œβ”€β”€ checklist.md # Project development phases\nβ”œβ”€β”€ .env.template # Environment variables template\nβ”‚\nβ”œβ”€β”€ config/ # Configuration & lookup tables\nβ”‚ β”œβ”€β”€ settings.py # Model options, defaults\nβ”‚ β”œβ”€β”€ template_library.py # 20+ Cypher query templates\nβ”‚ β”œβ”€β”€ team_name_variants.py # Team abbreviation β†’ full name\nβ”‚ β”œβ”€β”€ stat_variants.py # Statistic name aliases\nβ”‚ β”œβ”€β”€ styles.py # Streamlit CSS styling\nβ”‚ └── FPLTrivia.md # Fun FPL facts\nβ”‚\nβ”œβ”€β”€ modules/ # Core application logic\nβ”‚ β”œβ”€β”€ preprocessing.py # Intent classification + entity extraction\nβ”‚ β”œβ”€β”€ cypher_retriever.py # Baseline retrieval via Cypher\nβ”‚ β”œβ”€β”€ vector_retriever.py # Semantic retrieval via embeddings\nβ”‚ β”œβ”€β”€ db_manager.py # Neo4j connection pool\nβ”‚ β”œβ”€β”€ llm_engine.py # LLM API calls (DeepSeek, Llama, Gemma)\nβ”‚ β”œβ”€β”€ llm_helper.py # Intent classification with LLM\nβ”‚ └── tests_llm_engine.py # LLM testing utilities\nβ”‚\nβ”œβ”€β”€ scripts/ # Data processing & setup\nβ”‚ β”œβ”€β”€ create_kg.py # Populate Neo4j from CSV\nβ”‚ β”œβ”€β”€ generate_embeddings.py # Create FAISS indexes\nβ”‚ β”œβ”€β”€ fpl_two_seasons.csv # Raw FPL data (2 seasons)\nβ”‚ └── config.txt # Script configuration\nβ”‚\nβ”œβ”€β”€ embeddings_out/ # Pre-computed embeddings\nβ”‚ β”œβ”€β”€ faiss_index_modelA.index # Fast index for model A\nβ”‚ β”œβ”€β”€ faiss_index_modelB.index # Fast index for model B\nβ”‚ β”œβ”€β”€ idx_to_embedding_id_modelA.json\nβ”‚ └── idx_to_embedding_id_modelB.json\nβ”‚\nβ”œβ”€β”€ experiments/ # Evaluation framework\nβ”‚ β”œβ”€β”€ run_experiments.py # Execute all experiments\nβ”‚ β”œβ”€β”€ tests.json # 30 test prompts\nβ”‚ β”œβ”€β”€ results.json # Experimental results (540 trials)\nβ”‚ β”œβ”€β”€ validate_tests.json # Ground truth answers\nβ”‚ β”œβ”€β”€ cost_modify.py # Analyze token costs\nβ”‚ β”œβ”€β”€ viz.py # Visualize results\nβ”‚ └── plots/ # Generated charts\nβ”‚\n└── logo.png # App logo\n```\n\n---\n\n## πŸ“š Module Documentation\n\n### 1. **preprocessing.py** β€” Intent & Entity Extraction\n\nConverts raw user text into structured data.\n\n**Key Functions:**\n\n- `extract_entities(query: str) β†’ dict` β€” Extracts players, teams, positions, gameweeks, seasons, stats\n\n**Features:**\n\n- **Spacy NER** for organization recognition (team names)\n- **Fuzzy matching** to handle typos and partial names\n- **Regex patterns** for gameweeks (e.g., \"GW10\"), positions, seasons\n- **Database lookups** for robustness\n\n**Example:**\n\n```python\nquery = \"How many goals did Haaland score in GW5 2022-23?\"\nentities = extract_entities(query)\n# Output:\n# {\n# \"players\": [\"Erling Haaland\"],\n# \"gameweeks\": [5],\n# \"seasons\": [\"2022-23\"],\n# \"statistics\": []\n# }\n```\n\n### 2. **cypher_retriever.py** β€” Baseline Deterministic Retrieval\n\nExecutes templated Cypher queries against Neo4j.\n\n**Key Functions:**\n\n- `retrieve_data_via_cypher(intent, entities, limit) β†’ dict` β€” Executes a Cypher template selected by intent\n\n**Template Examples:**\n\n- `PLAYER_STATS_GW_SEASON` β€” Get a player's stats in a specific gameweek\n- `COMPARE_PLAYERS_BY_TOTAL_POINTS` β€” Compare two players' total points\n- `PLAYER_CAREER_STATS_TOTALS` β€” Career aggregates\n- `TOP_PLAYERS_BY_POSITION` β€” Rank players by position\n- `TEAM_FIXTURE_SCHEDULE` β€” Get team's upcoming/past fixtures\n\n**Features:**\n\n- Parameter injection safety (parameterized + template rendering)\n- Missing parameter detection with fallbacks\n- JSON-friendly output\n\n### 3. **vector_retriever.py** β€” Semantic Embedding-Based Retrieval\n\nFinds players/fixtures using semantic similarity via embeddings.\n\n**Key Functions:**\n\n- `vector_search(entities, top_k, model_choice) β†’ dict` β€” Performs FAISS similarity search\n- `get_models_and_indexes()` β†’ Cached loading of models + FAISS indexes\n\n**Process:**\n\n1. Build query text from entities (e.g., \"Players: Haaland | Positions: FWD\")\n2. Encode query using SentenceTransformer\n3. Query FAISS index for top-k similar embeddings\n4. Fetch source nodes from Neo4j\n\n**Embedding Models:**\n\n- **Model A**: `all-MiniLM-L6-v2` (22M params, fast)\n- **Model B**: `all-mpnet-base-v2` (109M params, high-quality)\n\n### 4. **db_manager.py** β€” Neo4j Connection Management\n\nSingleton pattern for safe, pooled Neo4j access.\n\n```python\ndb = Neo4jGraph() # Singleton\nresults = db.execute_query(\"MATCH (p:Player) RETURN p LIMIT 5\")\n```\n\n### 5. **llm_engine.py** β€” Multi-Model LLM Answer Generation\n\nInterfaces with multiple LLM providers.\n\n**Supported Models:**\n\n- **DeepSeek** (default, most cost-effective)\n- **Llama** via Hugging Face Inference API\n- **Gemma** via Hugging Face Inference API\n\n**Functions:**\n\n- `deepseek_generate_answer(query, context) β†’ str`\n- `llama_generate_answer(query, context) β†’ str`\n- `gemma_generate_answer(query, context) β†’ str`\n\n**System Prompt:**\n\n```\nYou are an elite Fantasy Premier League analyst.\nAnswer the user's question using ONLY the data provided.\nDo NOT guess or hallucinate.\nKeep output concise and actionable.\nSuggest a follow-up question at the end.\n```\n\n### 6. **llm_helper.py** β€” Intent Classification & Prompt Engineering\n\nHigh-level LLM utilities for understanding user intent.\n\n**Functions:**\n\n- `classify_with_deepseek(query, options) β†’ list` β€” Map query to up to 3 Cypher templates\n- Fallback: `local_intent_classify(query)` (rule-based, in `config/template_library.py`)\n\n---\n\n## πŸ—„οΈ Knowledge Graph Schema\n\n### Node Types\n\n| Node | Properties | Purpose |\n| ------------- | ------------------------------------------ | ---------------------------------------- |\n| **Season** | `season_name` | Group data by season (2021-22, 2022-23) |\n| **Gameweek** | `season`, `GW_number` | 38 gameweeks per season |\n| **Fixture** | `season`, `fixture_number`, `kickoff_time` | Individual matches |\n| **Team** | `name` | 20 Premier League clubs |\n| **Player** | `player_name`, `player_element` | Individual players |\n| **Position** | `name` | FWD, MID, DEF, GK |\n| **Embedding** | `model`, `text`, `source_label` | Vector embeddings of player descriptions |\n\n### Relationships\n\n```\n(Season) -[:HAS_GW]-> (Gameweek)\n ↓\n(Gameweek) -[:HAS_FIXTURE]-> (Fixture)\n ↓\n β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”\n ↓ ↓ ↓\n (Team) (Player) (Fixture properties)\n ↓\n(Player) -[:PLAYS_AS]-> (Position)\n(Player) -[:PLAYED_IN]-> (Fixture) [with performance data]\n\n(Embedding) -[:HAS_EMBEDDING]-> (Player or Team)\n```\n\n### Performance Stats on `PLAYED_IN` Relationships\n\n```\nminutes, goals_scored, assists, total_points, bonus,\nclean_sheets, goals_conceded, own_goals, yellow_cards,\nred_cards, saves, penalties_saved, penalties_missed,\nbps, influence, creativity, threat, ict_index, form\n```\n\n---\n\n## πŸ” Retrieval Methods\n\nThe system supports **four retrieval strategies**, configurable from the UI sidebar:\n\n### 1. **Baseline (Cypher)** β€” Deterministic Graph Queries\n\n**When to use:** High-precision factual queries (stats, comparisons)\n\n**Process:**\n\n1. Classify intent (e.g., \"PLAYER_STATS_GW_SEASON\")\n2. Map entities to template parameters\n3. Execute Cypher query\n4. Return structured results\n\n**Pros:** Deterministic, precise, low latency \n**Cons:** Requires exact entity matching; limited flexibility\n\n### 2. **Embeddings (Vector)** β€” Semantic Similarity Search\n\n**When to use:** Exploratory queries, fuzzy matching (e.g., \"players similar to Salah\")\n\n**Process:**\n\n1. Encode query + entities as a text vector\n2. Query FAISS index for top-k similar embeddings\n3. Fetch corresponding nodes from Neo4j\n4. Return ranked results\n\n**Pros:** Robust to phrasing differences, discovers similar items \n**Cons:** Less precise; slower than Cypher\n\n### 3. **Hybrid** β€” Best of Both Worlds\n\n**When to use:** Balance precision + recall\n\n**Process:**\n\n1. Run Cypher retrieval\n2. Run embedding search in parallel\n3. Combine results, deduplicate, rank by relevance\n\n**Pros:** High recall + precision \n**Cons:** Slower (executes both retrievers)\n\n### 4. **LLM-Generated Cypher** β€” Let the Model Write Queries\n\n**When to use:** Complex, unconventional questions\n\n**Process:**\n\n1. Prompt DeepSeek to generate Cypher queries\n2. Execute against Neo4j\n3. Return results\n\n**Pros:** Flexibility for novel queries \n**Cons:** Can generate invalid Cypher; slower\n\n---\n\n## πŸ€– LLM Integration\n\n### Supported Models\n\n| Model | Provider | Speed | Quality | Cost |\n| --------------- | ------------ | ------- | ---------- | -------- |\n| **DeepSeek** | Deepseek API | ⚑ Fast | ⭐⭐⭐⭐ | πŸ’° Cheap |\n| **Llama 2 70B** | Hugging Face | 🐒 Slow | ⭐⭐⭐⭐⭐ | πŸ’°πŸ’° |\n| **Gemma 7B** | Hugging Face | ⚑ Fast | ⭐⭐⭐ | πŸ’° Cheap |\n\n### Configuration\n\nSelect LLM and embedding model from **Streamlit sidebar**:\n\n```\nπŸŽ›οΈ Configuration\nβ”œβ”€ Choose LLM: [DeepSeek β–Ό]\nβ”œβ”€ Retrieval Mode: (Baseline (Cypher) β—― Embeddings β—― Hybrid)\nβ”œβ”€ Embedding Model: [all-MiniLM-L6-v2 β–Ό]\nβ”œβ”€ Top-K: [5]\n└─ Show debug info [☐]\n```\n\n### Example API Call\n\n```python\nfrom modules.llm_engine import deepseek_generate_answer\n\ncontext_data = {\n \"intent\": \"PLAYER_STATS_GW_SEASON\",\n \"results\": [\n {\"player\": \"Erling Haaland\", \"goals\": 5, \"assists\": 2, \"total_points\": 35}\n ]\n}\n\nanswer = deepseek_generate_answer(\n \"How did Haaland perform in GW5?\",\n context_data\n)\n```\n\n---\n\n## πŸ“Š Experiments & Evaluation\n\n### Evaluation Framework\n\nThe project includes a comprehensive **evaluation suite** with:\n\n- **30 test prompts** across different query types\n- **18 permutations** per prompt (different retrieval modes Γ— LLM models Γ— embedding models)\n- **540 total experiments** to benchmark performance\n\n### Running Experiments\n\n```powershell\npython -m experiments.run_experiments\n```\n\n**Outputs:**\n\n- `experiments/results.json` β€” Detailed results for each trial\n- `experiments/plots/` β€” Generated visualizations\n- Summary metrics: latency, token usage, cost analysis\n\n### Test Prompt Categories\n\n1. **Player Performance** β€” Stats, comparisons, rankings\n2. **Team Analysis** β€” Fixture difficulty, form\n3. **Transfer Advice** β€” Form\n4. **Comparisons** β€” Head-to-head player metrics\n5. **Recommendations** β€” Top performers by position\n\n---\n\n## 🎨 UI Features\n\n### Streamlit Interface\n\n```\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\nβ”‚ FPL Graph-RAG Assistant β”‚\nβ”‚ Ask questions about Fantasy Premier League β”‚\nβ”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€\nβ”‚ SIDEBAR β”‚ MAIN CONTENT β”‚\nβ”‚ β”œβ”€ LLM Choice β”‚ β€’ Chat input β”‚\nβ”‚ β”œβ”€ Retrieval β”‚ β€’ Message history β”‚\nβ”‚ β”œβ”€ Top-K β”‚ β€’ Context display (debug) β”‚\nβ”‚ β”œβ”€ Debug Toggle β”‚ β€’ Answer + follow-ups β”‚\nβ”‚ └─ Logo β”‚ β”‚\nβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n```\n\n### Color Palette (Official PL Colors)\n\n| Color | RGB | Use |\n| ------ | -------------------- | ------------------- |\n| Cyan | `rgb(4, 245, 255)` | Highlights, accents |\n| Pink | `rgb(233, 0, 82)` | Warnings, important |\n| Green | `rgb(0, 255, 133)` | Success, positive |\n| Purple | `rgb(56, 0, 60)` | Background, muted |\n| White | `rgb(255, 255, 255)` | Text, primary |\n\n---\n\n## πŸ› Troubleshooting\n\n### Issue: \"Neo4j connection failed\"\n\n**Cause:** Neo4j database not running or incorrect credentials\n\n**Solution:**\n\n```powershell\n# 1. Start Neo4j Desktop\n# 2. Verify .env has correct credentials\n# 3. Test connection:\npython -c \"from modules.db_manager import neo4j_graph; print('OK')\"\n```\n\n### Issue: \"Missing FAISS index files\"\n\n**Cause:** `embeddings_out/` directory is empty\n\n**Solution:**\n\n```powershell\n# Option 1: Download from Drive (fast)\n# Place files in embeddings_out/\n\n# Option 2: Generate from scratch (slow)\npython scripts/generate_embeddings.py\n```\n\n### Issue: \"spaCy model not found\"\n\n**Cause:** Transformer model not downloaded\n\n**Solution:**\n\n```powershell\npython -m spacy download en_core_web_trf\n# Fallback (smaller model):\npython -m spacy download en_core_web_sm\n```\n\n### Issue: \"LLM API key invalid\"\n\n**Cause:** Expired or incorrect API key in `.env`\n\n**Solution:**\n\n1. Check `DEEPSEEK_API_KEY` in `.env`\n2. Verify key is active on provider's dashboard\n3. Test with `curl` if possible\n\n### Issue: Memory errors with embedding models\n\n**Cause:** Insufficient RAM for both models + FAISS indexes\n\n**Solution:**\n\n- Use only one embedding model (set `MODEL_A_NAME` only)\n- Or reduce `top_k` parameter\n- Consider GPU acceleration with `pip install torch-cuda`\n\n### Issue: Slow vector search\n\n**Cause:** FAISS index not optimized or using CPU\n\n**Solution:**\n\n```python\n# In vector_retriever.py, use GPU-backed FAISS\n# index = faiss.index_gpu_to_cpu(gpu_index) # Convert after GPU search\n```\n\n---\n\n## 🀝 Team & Contributing\n\nThis project was developed as part of **ACL M3 course work** on advanced NLP & knowledge graphs.\n\n### Key Components Built By\n\n- **Graph Architecture** β€” Neo4j schema design, Cypher templates\n- **Preprocessing** β€” Intent classification, fuzzy entity extraction\n- **Retrieval Layer** β€” Cypher baseline, FAISS embeddings, hybrid approach\n- **LLM Integration** β€” Multi-model support, prompt engineering\n- **Evaluation** β€” Comprehensive benchmark suite with 540 trials\n\n### Future Work\n\n- [ ] Add captaincy prediction using form trends\n- [ ] Implement multi-turn conversation state\n- [ ] Optimize FAISS indexes for faster search\n- [ ] Add more LLM providers (Claude, GPT-4)\n- [ ] Cache common queries for faster responses\n- [ ] Implement streaming responses for long answers\n- [ ] Add user feedback loop for fine-tuning\n\n---\n\n## πŸ“„ License\n\nThis project is for educational purposes as part of ACL coursework.\n\n---\n\n## πŸ“ž Support\n\nFor issues, check:\n\n1. `STARTING.md` β€” Quick setup guide\n2. `schema.md` β€” Data structure documentation\n3. `checklist.md` β€” Development phases\n4. GitHub Issues (if applicable)\n\n---\n\n**Last Updated:** December 2025 \n**Status:** Active Development \n**Python Version:** 3.9+\n"}, "4b0314ca2e7f45e5c2a6f326a34b663d95fdf222": {"t": 1785772192.3720357, "n": 21403, "h": "d3c768a2619ac31b", "c": "# πŸ† FPL Graph-RAG Assistant\n\n> **A Retrieval-Augmented Generation (RAG) system for intelligent Fantasy Premier League analysis using Neo4j knowledge graphs, semantic embeddings, and large language models.**\n\n---\n\n## πŸ“– Table of Contents\n\n1. [Overview](#overview)\n2. [Key Features](#key-features)\n3. [System Architecture](#system-architecture)\n4. [Quick Start](#quick-start)\n5. [Project Structure](#project-structure)\n6. [Module Documentation](#module-documentation)\n7. [Knowledge Graph Schema](#knowledge-graph-schema)\n8. [Retrieval Methods](#retrieval-methods)\n9. [LLM Integration](#llm-integration)\n10. [Experiments & Evaluation](#experiments--evaluation)\n11. [Troubleshooting](#troubleshooting)\n12. [Team & Contributing](#team--contributing)\n\n---\n\n## 🎯 Overview\n\n**FPL Assistant** is an intelligent conversational system that answers Fantasy Premier League questions using a **hybrid retrieval-augmented generation (RAG)** approach. Instead of hallucinating answers, the system:\n\n1. **Classifies intent** β€” understands what the user is asking (e.g., player stats, comparisons, recommendations)\n2. **Extracts entities** β€” identifies relevant players, teams, gameweeks, and statistics from the query\n3. **Retrieves context** β€” uses multiple retrieval strategies (deterministic Cypher queries, semantic vector search, or hybrid) to fetch facts from a Neo4j knowledge graph\n4. **Generates answers** β€” passes retrieved context to a language model (DeepSeek, Llama, or Gemma) to synthesize natural, conversational responses\n\nThe system supports queries like:\n- *\"Who should I captain for gameweek 10?\"*\n- *\"Compare Haaland and Son's assists per game\"*\n- *\"What are the top forwards under Β£6.5M?\"*\n- *\"Who are the most creative midfielders in the 2022-23 season?\"*\n\n### Why This Approach?\n\nTraditional LLMs on FPL data are prone to hallucination (making up stats). RAG solves this by grounding responses in **actual data** from the knowledge graph, ensuring accuracy and factuality.\n\n---\n\n## ✨ Key Features\n\n| Feature | Description |\n|---------|-------------|\n| **Multi-Model LLM Support** | DeepSeek (default), Llama, or Gemma for answer generation |\n| **Dual Embedding Models** | All-MiniLM-L6-v2 (fast, small) and All-MPNet-Base-V2 (high-quality) |\n| **Four Retrieval Strategies** | Baseline Cypher, Embeddings (Vector), Hybrid, and LLM-generated Cypher |\n| **Fuzzy Entity Matching** | Robust player/team name recognition despite typos and abbreviations |\n| **Comprehensive FPL Schema** | Covers players, teams, positions, gameweeks, seasons, and detailed performance stats |\n| **Interactive Web UI** | Streamlit-based interface with debug mode and real-time configuration |\n| **Evaluation Framework** | 30 test prompts Γ— 18 permutations = 540 experiments to benchmark retrieval + LLM performance |\n| **Two Seasons of Data** | 2021-22 and 2022-23 FPL data with player performance across all gameweeks |\n\n---\n\n## πŸ—οΈ System Architecture\n\n```\nUser Query\n ↓\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\nβ”‚ PREPROCESSING & UNDERSTANDING β”‚\nβ”‚ β€’ Intent Classification (LLM or Rule-based) β”‚\nβ”‚ β€’ Entity Extraction (NER + Fuzzy Matching) β”‚\nβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n ↓\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\nβ”‚ RETRIEVAL LAYER (Multi-Strategy) β”‚\nβ”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚\nβ”‚ β”‚ Cypher Baseline β”‚ β”‚ Vector Embeddingsβ”‚ β”‚\nβ”‚ β”‚ (Deterministic)β”‚ β”‚ (Semantic) β”‚ β”‚\nβ”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚\nβ”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚\nβ”‚ ↓ β”‚\nβ”‚ Neo4j Knowledge Graph β”‚\nβ”‚ (2 seasons Γ— 38 gameweeks Γ— 20 teams) β”‚\nβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n ↓\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\nβ”‚ CONTEXT ASSEMBLY β”‚\nβ”‚ β€’ Combine & deduplicate results β”‚\nβ”‚ β€’ Format for LLM consumption β”‚\nβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n ↓\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\nβ”‚ LLM ANSWER GENERATION β”‚\nβ”‚ β€’ DeepSeek / Llama / Gemma β”‚\nβ”‚ β€’ Grounded in retrieved facts β”‚\nβ”‚ β€’ Suggest follow-up questions β”‚\nβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n ↓\nNatural, Factual Answer\n```\n\n---\n\n## πŸš€ Quick Start\n\n### Prerequisites\n\n- **Python 3.9+**\n- **Neo4j** (Desktop or Docker)\n- **4 GB+ RAM** (for embedding models + FAISS indexes)\n- **Internet connection** (for LLM API calls)\n\n### Step 1: Clone & Setup Environment\n\n```powershell\n# Create and activate virtual environment\npython -m venv .venv\n.\\venv\\Scripts\\Activate.ps1\n\n# Install dependencies\npip install -r requirements.txt\n```\n\n### Step 2: Configure Credentials\n\nCreate a `.env` file in the project root:\n\n```env\n# Neo4j Configuration\nNEO4J_URI=bolt://localhost:7687\nNEO4J_USERNAME=neo4j\nNEO4J_PASSWORD=\n\n# LLM API Keys\nDEEPSEEK_API_KEY=\nDEEPSEEK_API_URL=https://api.deepseek.com/chat/completions\nDEEPSEEK_MODEL=deepseek-chat\n\n# Embedding Models\nMODEL_A_NAME=sentence-transformers/all-MiniLM-L6-v2\nMODEL_B_NAME=sentence-transformers/all-mpnet-base-v2\n\n# FAISS Index Paths\nFAISS_INDEX_A_PATH=./embeddings_out/faiss_index_modelA.index\nFAISS_INDEX_B_PATH=./embeddings_out/faiss_index_modelB.index\nMAPPING_A_PATH=./embeddings_out/idx_to_embedding_id_modelA.json\nMAPPING_B_PATH=./embeddings_out/idx_to_embedding_id_modelB.json\n\n# Output Directory\nOUTPUT_DIR=./embeddings_out\n```\n\n### Step 3: Populate Neo4j Knowledge Graph\n\n#### Option A: Using Provided Data (Recommended)\n\n```powershell\n# Start Neo4j Desktop and create/launch a local database\n\n# Run the knowledge graph creation script\npython .\\scripts\\create_kg.py\n```\n\nThis populates Neo4j with:\n- **Seasons**: 2021-22, 2022-23\n- **Players**: ~600 per season\n- **Teams**: 20 Premier League teams\n- **Fixtures**: 380 per season (38 gameweeks Γ— 20 teams)\n- **Performance Data**: Goals, assists, clean sheets, total points, etc.\n\n### Step 4: Load/Generate Embeddings\n\n#### Option A: Download Pre-computed Indexes (⚑ Fastest)\n\nDownload FAISS indexes and mappings from: [Google Drive Link](https://drive.google.com/drive/folders/1nyeVFgM-nb4q6_rRVhxmG5-gnQSjjBjp?usp=sharing)\n\nPlace files in `embeddings_out/`:\n```\nembeddings_out/\nβ”œβ”€β”€ faiss_index_modelA.index\nβ”œβ”€β”€ faiss_index_modelB.index\nβ”œβ”€β”€ idx_to_embedding_id_modelA.json\n└── idx_to_embedding_id_modelB.json\n```\n\n#### Option B: Generate From Scratch (⏱️ ~4 hours on CPU)\n\n```powershell\npython .\\scripts\\generate_embeddings.py\n```\n\nThis script:\n1. Fetches all player performance records from Neo4j\n2. Generates text descriptions (e.g., \"Haaland (FWD): 13 goals, 5 assists, 195 points\")\n3. Encodes them using both embedding models\n4. Creates FAISS indexes for fast similarity search\n\n### Step 5: Run the Web UI\n\n```powershell\nstreamlit run main.py\n```\n\nOpen **http://localhost:8501** in your browser.\n\n---\n\n## πŸ“‚ Project Structure\n\n```\nfpl-assistant/\nβ”œβ”€β”€ main.py # Streamlit web UI entry point\nβ”œβ”€β”€ requirements.txt # Python dependencies\nβ”œβ”€β”€ README.md # This file\nβ”œβ”€β”€ STARTING.md # Minimal setup guide\nβ”œβ”€β”€ schema.md # Data schema documentation\nβ”œβ”€β”€ checklist.md # Project development phases\nβ”œβ”€β”€ .env.template # Environment variables template\nβ”‚\nβ”œβ”€β”€ config/ # Configuration & lookup tables\nβ”‚ β”œβ”€β”€ settings.py # Model options, defaults\nβ”‚ β”œβ”€β”€ template_library.py # 20+ Cypher query templates\nβ”‚ β”œβ”€β”€ team_name_variants.py # Team abbreviation β†’ full name\nβ”‚ β”œβ”€β”€ stat_variants.py # Statistic name aliases\nβ”‚ β”œβ”€β”€ styles.py # Streamlit CSS styling\nβ”‚ └── FPLTrivia.md # Fun FPL facts\nβ”‚\nβ”œβ”€β”€ modules/ # Core application logic\nβ”‚ β”œβ”€β”€ preprocessing.py # Intent classification + entity extraction\nβ”‚ β”œβ”€β”€ cypher_retriever.py # Baseline retrieval via Cypher\nβ”‚ β”œβ”€β”€ vector_retriever.py # Semantic retrieval via embeddings\nβ”‚ β”œβ”€β”€ db_manager.py # Neo4j connection pool\nβ”‚ β”œβ”€β”€ llm_engine.py # LLM API calls (DeepSeek, Llama, Gemma)\nβ”‚ β”œβ”€β”€ llm_helper.py # Intent classification with LLM\nβ”‚ └── tests_llm_engine.py # LLM testing utilities\nβ”‚\nβ”œβ”€β”€ scripts/ # Data processing & setup\nβ”‚ β”œβ”€β”€ create_kg.py # Populate Neo4j from CSV\nβ”‚ β”œβ”€β”€ generate_embeddings.py # Create FAISS indexes\nβ”‚ β”œβ”€β”€ fpl_two_seasons.csv # Raw FPL data (2 seasons)\nβ”‚ └── config.txt # Script configuration\nβ”‚\nβ”œβ”€β”€ embeddings_out/ # Pre-computed embeddings\nβ”‚ β”œβ”€β”€ faiss_index_modelA.index # Fast index for model A\nβ”‚ β”œβ”€β”€ faiss_index_modelB.index # Fast index for model B\nβ”‚ β”œβ”€β”€ idx_to_embedding_id_modelA.json\nβ”‚ └── idx_to_embedding_id_modelB.json\nβ”‚\nβ”œβ”€β”€ experiments/ # Evaluation framework\nβ”‚ β”œβ”€β”€ run_experiments.py # Execute all experiments\nβ”‚ β”œβ”€β”€ tests.json # 30 test prompts\nβ”‚ β”œβ”€β”€ results.json # Experimental results (540 trials)\nβ”‚ β”œβ”€β”€ validate_tests.json # Ground truth answers\nβ”‚ β”œβ”€β”€ cost_modify.py # Analyze token costs\nβ”‚ β”œβ”€β”€ viz.py # Visualize results\nβ”‚ └── plots/ # Generated charts\nβ”‚\n└── logo.png # App logo\n```\n\n---\n\n## πŸ“š Module Documentation\n\n### 1. **preprocessing.py** β€” Intent & Entity Extraction\n\nConverts raw user text into structured data.\n\n**Key Functions:**\n- `extract_entities(query: str) β†’ dict` β€” Extracts players, teams, positions, gameweeks, seasons, stats\n\n**Features:**\n- **Spacy NER** for organization recognition (team names)\n- **Fuzzy matching** to handle typos and partial names\n- **Regex patterns** for gameweeks (e.g., \"GW10\"), positions, seasons\n- **Database lookups** for robustness\n\n**Example:**\n```python\nquery = \"How many goals did Haaland score in GW5 2022-23?\"\nentities = extract_entities(query)\n# Output:\n# {\n# \"players\": [\"Erling Haaland\"],\n# \"gameweeks\": [5],\n# \"seasons\": [\"2022-23\"],\n# \"statistics\": []\n# }\n```\n\n### 2. **cypher_retriever.py** β€” Baseline Deterministic Retrieval\n\nExecutes templated Cypher queries against Neo4j.\n\n**Key Functions:**\n- `retrieve_data_via_cypher(intent, entities, limit) β†’ dict` β€” Executes a Cypher template selected by intent\n\n**Template Examples:**\n- `PLAYER_STATS_GW_SEASON` β€” Get a player's stats in a specific gameweek\n- `COMPARE_PLAYERS_BY_TOTAL_POINTS` β€” Compare two players' total points\n- `PLAYER_CAREER_STATS_TOTALS` β€” Career aggregates\n- `TOP_PLAYERS_BY_POSITION` β€” Rank players by position\n- `TEAM_FIXTURE_SCHEDULE` β€” Get team's upcoming/past fixtures\n\n**Features:**\n- Parameter injection safety (parameterized + template rendering)\n- Missing parameter detection with fallbacks\n- JSON-friendly output\n\n### 3. **vector_retriever.py** β€” Semantic Embedding-Based Retrieval\n\nFinds players/fixtures using semantic similarity via embeddings.\n\n**Key Functions:**\n- `vector_search(entities, top_k, model_choice) β†’ dict` β€” Performs FAISS similarity search\n- `get_models_and_indexes()` β†’ Cached loading of models + FAISS indexes\n\n**Process:**\n1. Build query text from entities (e.g., \"Players: Haaland | Positions: FWD\")\n2. Encode query using SentenceTransformer\n3. Query FAISS index for top-k similar embeddings\n4. Fetch source nodes from Neo4j\n\n**Embedding Models:**\n- **Model A**: `all-MiniLM-L6-v2` (22M params, fast)\n- **Model B**: `all-mpnet-base-v2` (109M params, high-quality)\n\n### 4. **db_manager.py** β€” Neo4j Connection Management\n\nSingleton pattern for safe, pooled Neo4j access.\n\n```python\ndb = Neo4jGraph() # Singleton\nresults = db.execute_query(\"MATCH (p:Player) RETURN p LIMIT 5\")\n```\n\n### 5. **llm_engine.py** β€” Multi-Model LLM Answer Generation\n\nInterfaces with multiple LLM providers.\n\n**Supported Models:**\n- **DeepSeek** (default, most cost-effective)\n- **Llama** via Hugging Face Inference API\n- **Gemma** via Hugging Face Inference API\n\n**Functions:**\n- `deepseek_generate_answer(query, context) β†’ str`\n- `llama_generate_answer(query, context) β†’ str`\n- `gemma_generate_answer(query, context) β†’ str`\n\n**System Prompt:**\n```\nYou are an elite Fantasy Premier League analyst.\nAnswer the user's question using ONLY the data provided.\nDo NOT guess or hallucinate.\nKeep output concise and actionable.\nSuggest a follow-up question at the end.\n```\n\n### 6. **llm_helper.py** β€” Intent Classification & Prompt Engineering\n\nHigh-level LLM utilities for understanding user intent.\n\n**Functions:**\n- `classify_with_deepseek(query, options) β†’ list` β€” Map query to up to 3 Cypher templates\n- Fallback: `local_intent_classify(query)` (rule-based, in `config/template_library.py`)\n\n---\n\n## πŸ—„οΈ Knowledge Graph Schema\n\n### Node Types\n\n| Node | Properties | Purpose |\n|------|-----------|---------|\n| **Season** | `season_name` | Group data by season (2021-22, 2022-23) |\n| **Gameweek** | `season`, `GW_number` | 38 gameweeks per season |\n| **Fixture** | `season`, `fixture_number`, `kickoff_time` | Individual matches |\n| **Team** | `name` | 20 Premier League clubs |\n| **Player** | `player_name`, `player_element` | Individual players |\n| **Position** | `name` | FWD, MID, DEF, GK |\n| **Embedding** | `model`, `text`, `source_label` | Vector embeddings of player descriptions |\n\n### Relationships\n\n```\n(Season) -[:HAS_GW]-> (Gameweek)\n ↓\n(Gameweek) -[:HAS_FIXTURE]-> (Fixture)\n ↓\n β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”\n ↓ ↓ ↓\n (Team) (Player) (Fixture properties)\n ↓\n(Player) -[:PLAYS_AS]-> (Position)\n(Player) -[:PLAYED_IN]-> (Fixture) [with performance data]\n\n(Embedding) -[:HAS_EMBEDDING]-> (Player or Team)\n```\n\n### Performance Stats on `PLAYED_IN` Relationships\n\n```\nminutes, goals_scored, assists, total_points, bonus,\nclean_sheets, goals_conceded, own_goals, yellow_cards,\nred_cards, saves, penalties_saved, penalties_missed,\nbps, influence, creativity, threat, ict_index, form\n```\n\n---\n\n## πŸ” Retrieval Methods\n\nThe system supports **four retrieval strategies**, configurable from the UI sidebar:\n\n### 1. **Baseline (Cypher)** β€” Deterministic Graph Queries\n\n**When to use:** High-precision factual queries (stats, comparisons)\n\n**Process:**\n1. Classify intent (e.g., \"PLAYER_STATS_GW_SEASON\")\n2. Map entities to template parameters\n3. Execute Cypher query\n4. Return structured results\n\n**Pros:** Deterministic, precise, low latency \n**Cons:** Requires exact entity matching; limited flexibility\n\n### 2. **Embeddings (Vector)** β€” Semantic Similarity Search\n\n**When to use:** Exploratory queries, fuzzy matching (e.g., \"players similar to Salah\")\n\n**Process:**\n1. Encode query + entities as a text vector\n2. Query FAISS index for top-k similar embeddings\n3. Fetch corresponding nodes from Neo4j\n4. Return ranked results\n\n**Pros:** Robust to phrasing differences, discovers similar items \n**Cons:** Less precise; slower than Cypher\n\n### 3. **Hybrid** β€” Best of Both Worlds\n\n**When to use:** Balance precision + recall\n\n**Process:**\n1. Run Cypher retrieval\n2. Run embedding search in parallel\n3. Combine results, deduplicate, rank by relevance\n\n**Pros:** High recall + precision \n**Cons:** Slower (executes both retrievers)\n\n### 4. **LLM-Generated Cypher** β€” Let the Model Write Queries\n\n**When to use:** Complex, unconventional questions\n\n**Process:**\n1. Prompt DeepSeek to generate Cypher queries\n2. Execute against Neo4j\n3. Return results\n\n**Pros:** Flexibility for novel queries \n**Cons:** Can generate invalid Cypher; slower\n\n---\n\n## πŸ€– LLM Integration\n\n### Supported Models\n\n| Model | Provider | Speed | Quality | Cost |\n|-------|----------|-------|---------|------|\n| **DeepSeek** | Deepseek API | ⚑ Fast | ⭐⭐⭐⭐ | πŸ’° Cheap |\n| **Llama 2 70B** | Hugging Face | 🐒 Slow | ⭐⭐⭐⭐⭐ | πŸ’°πŸ’° |\n| **Gemma 7B** | Hugging Face | ⚑ Fast | ⭐⭐⭐ | πŸ’° Cheap |\n\n### Configuration\n\nSelect LLM and embedding model from **Streamlit sidebar**:\n\n```\nπŸŽ›οΈ Configuration\nβ”œβ”€ Choose LLM: [DeepSeek β–Ό]\nβ”œβ”€ Retrieval Mode: (Baseline (Cypher) β—― Embeddings β—― Hybrid)\nβ”œβ”€ Embedding Model: [all-MiniLM-L6-v2 β–Ό]\nβ”œβ”€ Top-K: [5]\n└─ Show debug info [☐]\n```\n\n### Example API Call\n\n```python\nfrom modules.llm_engine import deepseek_generate_answer\n\ncontext_data = {\n \"intent\": \"PLAYER_STATS_GW_SEASON\",\n \"results\": [\n {\"player\": \"Erling Haaland\", \"goals\": 5, \"assists\": 2, \"total_points\": 35}\n ]\n}\n\nanswer = deepseek_generate_answer(\n \"How did Haaland perform in GW5?\",\n context_data\n)\n```\n\n---\n\n## πŸ“Š Experiments & Evaluation\n\n### Evaluation Framework\n\nThe project includes a comprehensive **evaluation suite** with:\n- **30 test prompts** across different query types\n- **18 permutations** per prompt (different retrieval modes Γ— LLM models Γ— embedding models)\n- **540 total experiments** to benchmark performance\n\n### Running Experiments\n\n```powershell\npython -m experiments.run_experiments\n```\n\n**Outputs:**\n- `experiments/results.json` β€” Detailed results for each trial\n- `experiments/plots/` β€” Generated visualizations\n- Summary metrics: latency, token usage, cost analysis\n\n### Test Prompt Categories\n\n1. **Player Performance** β€” Stats, comparisons, rankings\n2. **Team Analysis** β€” Fixture difficulty, form\n3. **Transfer Advice** β€” Budget constraints, captaincy\n4. **Comparisons** β€” Head-to-head player metrics\n5. **Recommendations** β€” Top performers by position, budget\n\n---\n\n## 🎨 UI Features\n\n### Streamlit Interface\n\n```\nβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”\nβ”‚ FPL Graph-RAG Assistant β”‚\nβ”‚ Ask questions about Fantasy Premier League β”‚\nβ”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€\nβ”‚ SIDEBAR β”‚ MAIN CONTENT β”‚\nβ”‚ β”œβ”€ LLM Choice β”‚ β€’ Chat input β”‚\nβ”‚ β”œβ”€ Retrieval β”‚ β€’ Message history β”‚\nβ”‚ β”œβ”€ Top-K β”‚ β€’ Context display (debug) β”‚\nβ”‚ β”œβ”€ Debug Toggle β”‚ β€’ Answer + follow-ups β”‚\nβ”‚ └─ Logo β”‚ β”‚\nβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n```\n\n### Color Palette (Official PL Colors)\n\n| Color | RGB | Use |\n|-------|-----|-----|\n| Cyan | `rgb(4, 245, 255)` | Highlights, accents |\n| Pink | `rgb(233, 0, 82)` | Warnings, important |\n| Green | `rgb(0, 255, 133)` | Success, positive |\n| Purple | `rgb(56, 0, 60)` | Background, muted |\n| White | `rgb(255, 255, 255)` | Text, primary |\n\n---\n\n## πŸ› Troubleshooting\n\n### Issue: \"Neo4j connection failed\"\n\n**Cause:** Neo4j database not running or incorrect credentials\n\n**Solution:**\n```powershell\n# 1. Start Neo4j Desktop\n# 2. Verify .env has correct credentials\n# 3. Test connection:\npython -c \"from modules.db_manager import neo4j_graph; print('OK')\"\n```\n\n### Issue: \"Missing FAISS index files\"\n\n**Cause:** `embeddings_out/` directory is empty\n\n**Solution:**\n```powershell\n# Option 1: Download from Drive (fast)\n# Place files in embeddings_out/\n\n# Option 2: Generate from scratch (slow)\npython scripts/generate_embeddings.py\n```\n\n### Issue: \"spaCy model not found\"\n\n**Cause:** Transformer model not downloaded\n\n**Solution:**\n```powershell\npython -m spacy download en_core_web_trf\n# Fallback (smaller model):\npython -m spacy download en_core_web_sm\n```\n\n### Issue: \"LLM API key invalid\"\n\n**Cause:** Expired or incorrect API key in `.env`\n\n**Solution:**\n1. Check `DEEPSEEK_API_KEY` in `.env`\n2. Verify key is active on provider's dashboard\n3. Test with `curl` if possible\n\n### Issue: Memory errors with embedding models\n\n**Cause:** Insufficient RAM for both models + FAISS indexes\n\n**Solution:**\n- Use only one embedding model (set `MODEL_A_NAME` only)\n- Or reduce `top_k` parameter\n- Consider GPU acceleration with `pip install torch-cuda`\n\n### Issue: Slow vector search\n\n**Cause:** FAISS index not optimized or using CPU\n\n**Solution:**\n```python\n# In vector_retriever.py, use GPU-backed FAISS\n# index = faiss.index_gpu_to_cpu(gpu_index) # Convert after GPU search\n```\n\n---\n\n## 🀝 Team & Contributing\n\nThis project was developed as part of **ACL M3 course work** on advanced NLP & knowledge graphs.\n\n### Key Components Built By\n\n- **Graph Architecture** β€” Neo4j schema design, Cypher templates\n- **Preprocessing** β€” Intent classification, fuzzy entity extraction\n- **Retrieval Layer** β€” Cypher baseline, FAISS embeddings, hybrid approach\n- **LLM Integration** β€” Multi-model support, prompt engineering\n- **Evaluation** β€” Comprehensive benchmark suite with 540 trials\n\n### Future Work\n\n- [ ] Add captaincy prediction using form trends\n- [ ] Implement multi-turn conversation state\n- [ ] Optimize FAISS indexes for faster search\n- [ ] Add more LLM providers (Claude, GPT-4)\n- [ ] Cache common queries for faster responses\n- [ ] Implement streaming responses for long answers\n- [ ] Add user feedback loop for fine-tuning\n\n---\n\n## πŸ“„ License\n\nThis project is for educational purposes as part of ACL coursework.\n\n---\n\n## πŸ“ž Support\n\nFor issues, check:\n1. `STARTING.md` β€” Quick setup guide\n2. `schema.md` β€” Data structure documentation\n3. `checklist.md` β€” Development phases\n4. GitHub Issues (if applicable)\n\n---\n\n**Last Updated:** December 2025 \n**Status:** Active Development \n**Python Version:** 3.9+\n"}, "13b81d833721b2205f8b2edb70ec70ea3cd31b2d": {"t": 1785772194.065687, "n": 2709, "h": "cc6d109ecd4ba05f", "c": "# FPL Graph-RAG β€” Project README\n\nThis repository contains an experimental Retrieval-Augmented Generation (RAG) assistant for Fantasy Premier League (FPL). The app combines a Neo4j graph knowledge base, template-based Cypher retrieval, semantic vector search (embeddings + FAISS), and a small LLM-driven orchestration layer to answer user questions about players, fixtures, comparisons, and transfer recommendations.\n\nThis README documents the repo layout, how to set up the project locally (Windows / PowerShell), runtime expectations, module responsibilities, and common troubleshooting steps for teammates.\n\n1. Create and activate a Python environment (recommended):\n\n```powershell\npython -m venv .venv\n.\\venv\\Scripts\\Activate.ps1\n```\n\n2. Install dependencies:\n\n```powershell\npip install -r requirements.txt\n```\n\n3. Provide environment variables.\n\n - Create a `.env` file in the root (Find a template in `.env.template`)\n\n4. Ensure Neo4j is running and populated with the expected schema and nodes.\n\n5. Populate `embeddings_out/` with FAISS index files and mapping JSON files from `https://drive.google.com/drive/folders/1nyeVFgM-nb4q6_rRVhxmG5-gnQSjjBjp?usp=sharing`. The `vector_retriever.py` currently expects:\n\n```\nembeddings_out/faiss_index_modelA.index\nembeddings_out/faiss_index_modelB.index\nembeddings_out/idx_to_embedding_id_modelA.json\nembeddings_out/idx_to_embedding_id_modelB.json\n```\n\nYou can generate these using the `scripts/generate_embeddings.py` script. Generating embeddings requires 4 hours (CPU).\n\n6. Run the app (PowerShell):\n\n```powershell\nstreamlit run main.py\n```\n\n7. Running quantitative experiments\n\n```powershell\npython -m experiments.run_experiments\n```\n\n36 test prompts\n18 permutations for each test prompt\n648 total test results\n\n## High-level architecture\n\n- UI (`main.py`) receives a user query.\n- Intent classification: tries `classify_with_deepseek` (remote LLM). On failure it falls back to `local_intent_classify` in `config/template_library.py`.\n- Entities are extracted with `preprocessing.extract_entities` (fuzzy matching uses DB lookups).\n- Retrieval options:\n - Baseline (Cypher): `cypher_retriever.retrieve_data_via_cypher(intent, entities, limit)` builds params and runs Cypher.\n - Embeddings (Vector): `vector_retriever.vector_search(entities, top_k)` encodes the query and queries FAISS, then fetches sources from Neo4j.\n - Hybrid: both are run and combined.\n- The assembled context is passed to `llm_helper.generate_answer` which calls the Deepseek/Gemma/Llama API and returns a response.\n\n## Premier league color pallette:\n\n- Cyan: rgb(4, 245, 255)\n- Pink: rgb(233, 0, 82)\n- White: rgb(255, 255, 255)\n- Green: rgb(0, 255, 133)\n- Purple: rgb(56, 0, 60)\n"}, "9f9dab083d374156d0f7a8f5f41d1519096cee20": {"t": 1785772197.4555295, "n": 2538, "h": "be99c1712f32e303", "c": "# FPL Graph-RAG β€” Project README\n\nThis repository contains an experimental Retrieval-Augmented Generation (RAG) assistant for Fantasy Premier League (FPL). The app combines a Neo4j graph knowledge base, template-based Cypher retrieval, semantic vector search (embeddings + FAISS), and a small LLM-driven orchestration layer to answer user questions about players, fixtures, comparisons, and transfer recommendations.\n\nThis README documents the repo layout, how to set up the project locally (Windows / PowerShell), runtime expectations, module responsibilities, and common troubleshooting steps for teammates.\n\n1. Create and activate a Python environment (recommended):\n\n```powershell\npython -m venv .venv\n.\\venv\\Scripts\\Activate.ps1\n```\n\n2. Install dependencies:\n\n```powershell\npip install -r requirements.txt\n```\n\n3. Provide environment variables.\n\n - Create a `.env` file in the root (Find a template in `.env.template`)\n\n4. Ensure Neo4j is running and populated with the expected schema and nodes.\n\n5. Populate `embeddings_out/` with FAISS index files and mapping JSON files from `https://drive.google.com/drive/folders/1nyeVFgM-nb4q6_rRVhxmG5-gnQSjjBjp?usp=sharing`. The `vector_retriever.py` currently expects:\n\n```\nembeddings_out/faiss_index_modelA.index\nembeddings_out/faiss_index_modelB.index\nembeddings_out/idx_to_embedding_id_modelA.json\nembeddings_out/idx_to_embedding_id_modelB.json\n```\n\nYou can generate these using the `scripts/generate_embeddings.py` script. Generating embeddings requires 4 hours (CPU).\n\n6. Run the app (PowerShell):\n\n```powershell\nstreamlit run main.py\n```\n\n## High-level architecture\n\n- UI (`main.py`) receives a user query.\n- Intent classification: tries `classify_with_deepseek` (remote LLM). On failure it falls back to `local_intent_classify` in `config/template_library.py`.\n- Entities are extracted with `preprocessing.extract_entities` (fuzzy matching uses DB lookups).\n- Retrieval options:\n - Baseline (Cypher): `cypher_retriever.retrieve_data_via_cypher(intent, entities, limit)` builds params and runs Cypher.\n - Embeddings (Vector): `vector_retriever.vector_search(entities, top_k)` encodes the query and queries FAISS, then fetches sources from Neo4j.\n - Hybrid: both are run and combined.\n- The assembled context is passed to `llm_helper.generate_answer` which calls the Deepseek/Gemma/Llama API and returns a response.\n\n## Premier league color pallette:\n\n- Cyan: rgb(4, 245, 255)\n- Pink: rgb(233, 0, 82)\n- White: rgb(255, 255, 255)\n- Green: rgb(0, 255, 133)\n- Purple: rgb(56, 0, 60)\n"}, "f1340e35742572a45deb94d1905288c6c1f4c19e": {"t": 1785772199.64663, "n": 9316, "h": "ae391ef69fe7b802", "c": "# FPL Graph-RAG β€” Project README\n\nThis repository contains an experimental Retrieval-Augmented Generation (RAG) assistant for Fantasy Premier League (FPL). The app combines a Neo4j graph knowledge base, template-based Cypher retrieval, semantic vector search (embeddings + FAISS), and a small LLM-driven orchestration layer to answer user questions about players, fixtures, comparisons, and transfer recommendations.\n\nThis README documents the repo layout, how to set up the project locally (Windows / PowerShell), runtime expectations, module responsibilities, and common troubleshooting steps for teammates.\n\n**Quick summary**: run the Streamlit UI with `streamlit run main.py` after installing dependencies and providing the required environment variables and data files (Neo4j DB, precomputed FAISS indexes, and optional Deepseek API keys).\n\n**Project status & notes**\n\n- The UI (`main.py`) includes a placeholder mode that activates when the `modules` package fails to import due to missing credentials/assets. This is deliberate for iterative development.\n- Some modules perform heavy initialization at import time (Neo4j driver, embedding models, FAISS indexes). See \"Runtime & initialization\" and \"Developer notes\" for recommendations to make imports safer (lazy init).\n\n**Repository layout (important files)**\n\n- `main.py` β€” Streamlit application entrypoint and UI wiring.\n- `requirements.txt` β€” Python dependencies (install with `pip install -r requirements.txt`).\n- `config/` β€” Configuration constants and the Cypher template library.\n - `config/settings.py` β€” global constants (model options, Neo4j defaults, paths).\n - `config/template_library.py` β€” Cypher templates used by the baseline retriever.\n- `modules/` β€” Core implementation pieces (each module documented below):\n - `modules/db_manager.py` β€” Neo4j driver singleton and `execute_query` helper.\n - `modules/preprocessing.py` β€” intent fallback rules, entity extraction, fuzzy matching.\n - `modules/cypher_retriever.py` β€” builds Cypher params, picks templates and returns DB results.\n - `modules/vector_retriever.py` β€” encodes queries, runs FAISS search, and fetches source nodes from Neo4j.\n - `modules/llm_helper.py` β€” thin HTTP client to Deepseek chat (classification + answer generation).\n - `modules/__init__.py` β€” package-level imports (note: currently imports submodules eagerly).\n- `scripts/` β€” helper scripts for dataset/embedding generation (e.g., `generate_embeddings.py`).\n- `embeddings_out/` β€” expected location for FAISS indexes and mapping files (modelA/modelB index files and mappings).\n\n## Getting started (Windows PowerShell)\n\n1. Create and activate a Python environment (recommended):\n\n```powershell\npython -m venv .venv\n.\\venv\\Scripts\\Activate.ps1\npip install --upgrade pip\n```\n\n2. Install dependencies:\n\n```powershell\npip install -r requirements.txt\n```\n\n3. Provide environment variables.\n - Create a `.env` file in the `project/` root (or set the variables system-wide). Example variables used across modules:\n\n```text\nNEO4J_URI=bolt://localhost:7687\nNEO4J_USERNAME=neo4j\nNEO4J_PASSWORD=your_password_here\nDEEPSEEK_API_KEY=...\nDEEPSEEK_API_URL=https://api.deepseek.example/v1/chat\nEMBEDDING_MODEL=A # or B β€” controls which precomputed FAISS index to load\n```\n\n4. Ensure Neo4j is running and populated with the expected schema and nodes. The modules expect node labels and properties such as `Player.player_name`, `Team.name`, `Embedding` nodes for vector sources, and `Gameweek` nodes.\n\n5. Populate `embeddings_out/` with FAISS index files and mapping JSON files. The `vector_retriever.py` currently expects:\n\n```\nembeddings_out/faiss_index_modelA.index\nembeddings_out/faiss_index_modelB.index\nembeddings_out/idx_to_embedding_id_modelA.json\nembeddings_out/idx_to_embedding_id_modelB.json\n```\n\nYou can generate these using the `scripts/generate_embeddings.py` script (see script for usage). Generating embeddings may require large models and GPU if you want reasonable speed.\n\n6. Run the app (PowerShell):\n\n```powershell\nstreamlit run main.py\n```\n\n## High-level architecture\n\n- UI (`main.py`) receives a user query.\n- Intent classification: tries `classify_with_deepseek` (remote LLM). On failure it falls back to `local_intent_classify` in `config/template_library.py`.\n- Entities are extracted with `preprocessing.extract_entities` (fuzzy matching uses DB lookups).\n- Retrieval options:\n - Baseline (Cypher): `cypher_retriever.retrieve_data_via_cypher(intent, entities, limit)` builds params and runs Cypher.\n - Embeddings (Vector): `vector_retriever.vector_search(entities, top_k)` encodes the query and queries FAISS, then fetches sources from Neo4j.\n - Hybrid: both are run and combined.\n- The assembled context is passed to `llm_helper.generate_answer` which calls the Deepseek chat API and returns a response.\n\n## Module responsibilities & important details\n\n- `modules/db_manager.py`:\n\n - Implements a `Neo4jGraph` singleton that initializes the Neo4j driver in `__new__` and exposes `execute_query(query, params)` that returns a list of dicts.\n - Note: current design instantiates a global `neo4j_graph = Neo4jGraph()` at module import time β€” this will raise if env vars are missing.\n\n- `modules/preprocessing.py`:\n\n - Extracts players, teams, positions, seasons, gameweeks and statistics using spaCy + regex + fuzzy matching.\n - Calls `fetch_all_names_from_db` (which uses `Neo4jGraph`) to fetch valid names for fuzzy matching.\n\n- `modules/cypher_retriever.py`:\n\n - Selects a Cypher template from `config.template_library.CYPHER_TEMPLATE_LIBRARY` using the `intent` key and fills params.\n - Returns a JSON-friendly payload including `intent`, `template_used`, `parameters` and `results`.\n - Important: if an `intent` key is missing from the template library the module will currently raise a KeyError β€” this can be made defensive.\n\n- `modules/vector_retriever.py`:\n\n - Loads a `SentenceTransformer` model and a FAISS index and mapping at import time (based on `EMBEDDING_MODEL` env var).\n - Encodes a constructed query text and runs FAISS `index.search` and then queries Neo4j for the embedding sources.\n - Heavy initialization is done at import; see the \"Developer notes\" section for a recommended lazy-init change to avoid import-time failures.\n\n- `modules/llm_helper.py`:\n - Calls an external chat API (Deepseek) for both intent classification and answer generation. It expects `DEEPSEEK_API_KEY` and `DEEPSEEK_API_URL` to be present in the environment.\n\n## Runtime & initialization considerations\n\n- Eager imports: both `modules/__init__.py` and many modules perform work at import time (driver creation, model loads, reading index files). This means a simple `import modules` in `main.py` can fail if Neo4j credentials, FAISS files, or model files are not present.\n- The app (`main.py`) partially anticipates this by catching `ModuleNotFoundError` during `from modules import ...` and falling back to placeholder behavior. However, other exceptions (like `RuntimeError` from missing env) may also be raised during import. To improve developer experience consider:\n - Lazy initialization in `db_manager` and `vector_retriever`.\n - Converting `modules/__init__.py` to a lazy loader (so submodules are imported only when referenced).\n - Catching general import exceptions in `main.py` and surfacing clear instructions to the user.\n\n## Troubleshooting\n\n- If the UI shows placeholder answers and an import error message, check for:\n\n - Missing `.env` values (`NEO4J_URI`, `NEO4J_USERNAME`, `NEO4J_PASSWORD`, `DEEPSEEK_API_KEY`, `DEEPSEEK_API_URL`).\n - Missing FAISS index files in `embeddings_out/`.\n - Missing Python packages (run `pip install -r requirements.txt`).\n - Neo4j not running or connection refused.\n\n- Common fixes:\n - Ensure `.env` is present and correct.\n - If you don't need embeddings immediately, set `EMBEDDING_MODEL` to a value that won't load FAISS, or edit `modules/vector_retriever.py` to guard index loading.\n - For API-related failures, inspect the raw HTTP error returned by `modules/llm_helper.py`.\n\n## Developer notes & recommended fixes\n\n1. Make `modules/__init__.py` lazy to avoid eager submodule imports. Example implementation:\n\n```python\n__all__ = [\"db_manager\", \"preprocessing\", \"cypher_retriever\", \"vector_retriever\"]\n\ndef __getattr__(name):\n\t\tif name in __all__:\n\t\t\t\timport importlib\n\t\t\t\tmod = importlib.import_module(f\"{__name__}.{name}\")\n\t\t\t\tglobals()[name] = mod\n\t\t\t\treturn mod\n\t\traise AttributeError(name)\n```\n\n2. In `modules/db_manager.py` consider removing the global instantiation `neo4j_graph = Neo4jGraph()` at module import time. Instead let callers instantiate `Neo4jGraph()` when needed or provide a `get_instance()` factory that initializes lazily.\n\n3. In `modules/vector_retriever.py` move heavy loads (SentenceTransformer, faiss.read_index, mapping loads) into an `_ensure_initialized()` function called on first `vector_search` invocation.\n\n4. Make `cypher_retriever.retrieve_data_via_cypher` defensive when the provided `intent` is not present in `CYPHER_TEMPLATE_LIBRARY`. Use `CYPHER_TEMPLATE_LIBRARY.get(intent)` and return a helpful error payload rather than crashing.\n\nPremier league color pallette:\n\nCyan: rgb(4, 245, 255)\n\nPink: rgb(233, 0, 82)\n\nWhite: rgb(255, 255, 255)\n\nGreen: rgb(0, 255, 133)\n\nPurple: rgb(56, 0, 60)\n"}, "1dcd1540beb3e1677e0009c134a4748a624c0af7": {"t": 1785772200.8722112, "n": 9161, "h": "3b27d9bf346d34af", "c": "# FPL Graph-RAG β€” Project README\n\nThis repository contains an experimental Retrieval-Augmented Generation (RAG) assistant for Fantasy Premier League (FPL). The app combines a Neo4j graph knowledge base, template-based Cypher retrieval, semantic vector search (embeddings + FAISS), and a small LLM-driven orchestration layer to answer user questions about players, fixtures, comparisons, and transfer recommendations.\n\nThis README documents the repo layout, how to set up the project locally (Windows / PowerShell), runtime expectations, module responsibilities, and common troubleshooting steps for teammates.\n\n**Quick summary**: run the Streamlit UI with `streamlit run main.py` after installing dependencies and providing the required environment variables and data files (Neo4j DB, precomputed FAISS indexes, and optional Deepseek API keys).\n\n**Project status & notes**\n\n- The UI (`main.py`) includes a placeholder mode that activates when the `modules` package fails to import due to missing credentials/assets. This is deliberate for iterative development.\n- Some modules perform heavy initialization at import time (Neo4j driver, embedding models, FAISS indexes). See \"Runtime & initialization\" and \"Developer notes\" for recommendations to make imports safer (lazy init).\n\n**Repository layout (important files)**\n\n- `main.py` β€” Streamlit application entrypoint and UI wiring.\n- `requirements.txt` β€” Python dependencies (install with `pip install -r requirements.txt`).\n- `config/` β€” Configuration constants and the Cypher template library.\n - `config/settings.py` β€” global constants (model options, Neo4j defaults, paths).\n - `config/template_library.py` β€” Cypher templates used by the baseline retriever.\n- `modules/` β€” Core implementation pieces (each module documented below):\n - `modules/db_manager.py` β€” Neo4j driver singleton and `execute_query` helper.\n - `modules/preprocessing.py` β€” intent fallback rules, entity extraction, fuzzy matching.\n - `modules/cypher_retriever.py` β€” builds Cypher params, picks templates and returns DB results.\n - `modules/vector_retriever.py` β€” encodes queries, runs FAISS search, and fetches source nodes from Neo4j.\n - `modules/llm_helper.py` β€” thin HTTP client to Deepseek chat (classification + answer generation).\n - `modules/__init__.py` β€” package-level imports (note: currently imports submodules eagerly).\n- `scripts/` β€” helper scripts for dataset/embedding generation (e.g., `generate_embeddings.py`).\n- `embeddings_out/` β€” expected location for FAISS indexes and mapping files (modelA/modelB index files and mappings).\n\n## Getting started (Windows PowerShell)\n\n1. Create and activate a Python environment (recommended):\n\n```powershell\npython -m venv .venv\n.\\venv\\Scripts\\Activate.ps1\npip install --upgrade pip\n```\n\n2. Install dependencies:\n\n```powershell\npip install -r requirements.txt\n```\n\n3. Provide environment variables.\n - Create a `.env` file in the `project/` root (or set the variables system-wide). Example variables used across modules:\n\n```text\nNEO4J_URI=bolt://localhost:7687\nNEO4J_USERNAME=neo4j\nNEO4J_PASSWORD=your_password_here\nDEEPSEEK_API_KEY=...\nDEEPSEEK_API_URL=https://api.deepseek.example/v1/chat\nEMBEDDING_MODEL=A # or B β€” controls which precomputed FAISS index to load\n```\n\n4. Ensure Neo4j is running and populated with the expected schema and nodes. The modules expect node labels and properties such as `Player.player_name`, `Team.name`, `Embedding` nodes for vector sources, and `Gameweek` nodes.\n\n5. Populate `embeddings_out/` with FAISS index files and mapping JSON files. The `vector_retriever.py` currently expects:\n\n```\nembeddings_out/faiss_index_modelA.index\nembeddings_out/faiss_index_modelB.index\nembeddings_out/idx_to_embedding_id_modelA.json\nembeddings_out/idx_to_embedding_id_modelB.json\n```\n\nYou can generate these using the `scripts/generate_embeddings.py` script (see script for usage). Generating embeddings may require large models and GPU if you want reasonable speed.\n\n6. Run the app (PowerShell):\n\n```powershell\nstreamlit run main.py\n```\n\n## High-level architecture\n\n- UI (`main.py`) receives a user query.\n- Intent classification: tries `classify_with_deepseek` (remote LLM). On failure it falls back to `local_intent_classify` in `config/template_library.py`.\n- Entities are extracted with `preprocessing.extract_entities` (fuzzy matching uses DB lookups).\n- Retrieval options:\n - Baseline (Cypher): `cypher_retriever.retrieve_data_via_cypher(intent, entities, limit)` builds params and runs Cypher.\n - Embeddings (Vector): `vector_retriever.vector_search(entities, top_k)` encodes the query and queries FAISS, then fetches sources from Neo4j.\n - Hybrid: both are run and combined.\n- The assembled context is passed to `llm_helper.generate_answer` which calls the Deepseek chat API and returns a response.\n\n## Module responsibilities & important details\n\n- `modules/db_manager.py`:\n\n - Implements a `Neo4jGraph` singleton that initializes the Neo4j driver in `__new__` and exposes `execute_query(query, params)` that returns a list of dicts.\n - Note: current design instantiates a global `neo4j_graph = Neo4jGraph()` at module import time β€” this will raise if env vars are missing.\n\n- `modules/preprocessing.py`:\n\n - Extracts players, teams, positions, seasons, gameweeks and statistics using spaCy + regex + fuzzy matching.\n - Calls `fetch_all_names_from_db` (which uses `Neo4jGraph`) to fetch valid names for fuzzy matching.\n\n- `modules/cypher_retriever.py`:\n\n - Selects a Cypher template from `config.template_library.CYPHER_TEMPLATE_LIBRARY` using the `intent` key and fills params.\n - Returns a JSON-friendly payload including `intent`, `template_used`, `parameters` and `results`.\n - Important: if an `intent` key is missing from the template library the module will currently raise a KeyError β€” this can be made defensive.\n\n- `modules/vector_retriever.py`:\n\n - Loads a `SentenceTransformer` model and a FAISS index and mapping at import time (based on `EMBEDDING_MODEL` env var).\n - Encodes a constructed query text and runs FAISS `index.search` and then queries Neo4j for the embedding sources.\n - Heavy initialization is done at import; see the \"Developer notes\" section for a recommended lazy-init change to avoid import-time failures.\n\n- `modules/llm_helper.py`:\n - Calls an external chat API (Deepseek) for both intent classification and answer generation. It expects `DEEPSEEK_API_KEY` and `DEEPSEEK_API_URL` to be present in the environment.\n\n## Runtime & initialization considerations\n\n- Eager imports: both `modules/__init__.py` and many modules perform work at import time (driver creation, model loads, reading index files). This means a simple `import modules` in `main.py` can fail if Neo4j credentials, FAISS files, or model files are not present.\n- The app (`main.py`) partially anticipates this by catching `ModuleNotFoundError` during `from modules import ...` and falling back to placeholder behavior. However, other exceptions (like `RuntimeError` from missing env) may also be raised during import. To improve developer experience consider:\n - Lazy initialization in `db_manager` and `vector_retriever`.\n - Converting `modules/__init__.py` to a lazy loader (so submodules are imported only when referenced).\n - Catching general import exceptions in `main.py` and surfacing clear instructions to the user.\n\n## Troubleshooting\n\n- If the UI shows placeholder answers and an import error message, check for:\n\n - Missing `.env` values (`NEO4J_URI`, `NEO4J_USERNAME`, `NEO4J_PASSWORD`, `DEEPSEEK_API_KEY`, `DEEPSEEK_API_URL`).\n - Missing FAISS index files in `embeddings_out/`.\n - Missing Python packages (run `pip install -r requirements.txt`).\n - Neo4j not running or connection refused.\n\n- Common fixes:\n - Ensure `.env` is present and correct.\n - If you don't need embeddings immediately, set `EMBEDDING_MODEL` to a value that won't load FAISS, or edit `modules/vector_retriever.py` to guard index loading.\n - For API-related failures, inspect the raw HTTP error returned by `modules/llm_helper.py`.\n\n## Developer notes & recommended fixes\n\n1. Make `modules/__init__.py` lazy to avoid eager submodule imports. Example implementation:\n\n```python\n__all__ = [\"db_manager\", \"preprocessing\", \"cypher_retriever\", \"vector_retriever\"]\n\ndef __getattr__(name):\n\t\tif name in __all__:\n\t\t\t\timport importlib\n\t\t\t\tmod = importlib.import_module(f\"{__name__}.{name}\")\n\t\t\t\tglobals()[name] = mod\n\t\t\t\treturn mod\n\t\traise AttributeError(name)\n```\n\n2. In `modules/db_manager.py` consider removing the global instantiation `neo4j_graph = Neo4jGraph()` at module import time. Instead let callers instantiate `Neo4jGraph()` when needed or provide a `get_instance()` factory that initializes lazily.\n\n3. In `modules/vector_retriever.py` move heavy loads (SentenceTransformer, faiss.read_index, mapping loads) into an `_ensure_initialized()` function called on first `vector_search` invocation.\n\n4. Make `cypher_retriever.retrieve_data_via_cypher` defensive when the provided `intent` is not present in `CYPHER_TEMPLATE_LIBRARY`. Use `CYPHER_TEMPLATE_LIBRARY.get(intent)` and return a helpful error payload rather than crashing.\n"}, "dacc9cf8042133c01d9526009cc3dfbee9834210": {"t": 1785772202.2821798, "n": 9162, "h": "cf7e0c17ecefd410", "c": "# FPL Graph-RAG β€” Project README\n\nThis repository contains an experimental Retrieval-Augmented Generation (RAG) assistant for Fantasy Premier League (FPL). The app combines a Neo4j graph knowledge base, template-based Cypher retrieval, semantic vector search (embeddings + FAISS), and a small LLM-driven orchestration layer to answer user questions about players, fixtures, comparisons, and transfer recommendations.\n\nThis README documents the repo layout, how to set up the project locally (Windows / PowerShell), runtime expectations, module responsibilities, and common troubleshooting steps for teammates.\n\n**Quick summary**: run the Streamlit UI with `streamlit run main.py` after installing dependencies and providing the required environment variables and data files (Neo4j DB, precomputed FAISS indexes, and optional Deepseek API keys).\n\n**Project status & notes**\n\n- The UI (`main.py`) includes a placeholder mode that activates when the `modules` package fails to import due to missing credentials/assets. This is deliberate for iterative development.\n- Some modules perform heavy initialization at import time (Neo4j driver, embedding models, FAISS indexes). See \"Runtime & initialization\" and \"Developer notes\" for recommendations to make imports safer (lazy init).\n\n**Repository layout (important files)**\n\n- `main.py` β€” Streamlit application entrypoint and UI wiring.\n- `requirements.txt` β€” Python dependencies (install with `pip install -r requirements.txt`).\n- `config/` β€” Configuration constants and the Cypher template library.\n - `config/settings.py` β€” global constants (model options, Neo4j defaults, paths).\n - `config/template_library.py` β€” Cypher templates used by the baseline retriever.\n- `modules/` β€” Core implementation pieces (each module documented below):\n - `modules/db_manager.py` β€” Neo4j driver singleton and `execute_query` helper.\n - `modules/preprocessing.py` β€” intent fallback rules, entity extraction, fuzzy matching.\n - `modules/cypher_retriever.py` β€” builds Cypher params, picks templates and returns DB results.\n - `modules/vector_retriever.py` β€” encodes queries, runs FAISS search, and fetches source nodes from Neo4j.\n - `modules/llm_helper.py` β€” thin HTTP client to Deepseek chat (classification + answer generation).\n - `modules/__init__.py` β€” package-level imports (note: currently imports submodules eagerly).\n- `scripts/` β€” helper scripts for dataset/embedding generation (e.g., `generate_embeddings.py`).\n- `embeddings_out/` β€” expected location for FAISS indexes and mapping files (modelA/modelB index files and mappings).\n\n## Getting started (Windows PowerShell)\n\n1. Create and activate a Python environment (recommended):\n\n```powershell\npython -m venv .venv\n.\\.venv\\Scripts\\Activate.ps1\npip install --upgrade pip\n```\n\n2. Install dependencies:\n\n```powershell\npip install -r requirements.txt\n```\n\n3. Provide environment variables.\n - Create a `.env` file in the `project/` root (or set the variables system-wide). Example variables used across modules:\n\n```text\nNEO4J_URI=bolt://localhost:7687\nNEO4J_USERNAME=neo4j\nNEO4J_PASSWORD=your_password_here\nDEEPSEEK_API_KEY=...\nDEEPSEEK_API_URL=https://api.deepseek.example/v1/chat\nEMBEDDING_MODEL=A # or B β€” controls which precomputed FAISS index to load\n```\n\n4. Ensure Neo4j is running and populated with the expected schema and nodes. The modules expect node labels and properties such as `Player.player_name`, `Team.name`, `Embedding` nodes for vector sources, and `Gameweek` nodes.\n\n5. Populate `embeddings_out/` with FAISS index files and mapping JSON files. The `vector_retriever.py` currently expects:\n\n```\nembeddings_out/faiss_index_modelA.index\nembeddings_out/faiss_index_modelB.index\nembeddings_out/idx_to_embedding_id_modelA.json\nembeddings_out/idx_to_embedding_id_modelB.json\n```\n\nYou can generate these using the `scripts/generate_embeddings.py` script (see script for usage). Generating embeddings may require large models and GPU if you want reasonable speed.\n\n6. Run the app (PowerShell):\n\n```powershell\nstreamlit run main.py\n```\n\n## High-level architecture\n\n- UI (`main.py`) receives a user query.\n- Intent classification: tries `classify_with_deepseek` (remote LLM). On failure it falls back to `local_intent_classify` in `config/template_library.py`.\n- Entities are extracted with `preprocessing.extract_entities` (fuzzy matching uses DB lookups).\n- Retrieval options:\n - Baseline (Cypher): `cypher_retriever.retrieve_data_via_cypher(intent, entities, limit)` builds params and runs Cypher.\n - Embeddings (Vector): `vector_retriever.vector_search(entities, top_k)` encodes the query and queries FAISS, then fetches sources from Neo4j.\n - Hybrid: both are run and combined.\n- The assembled context is passed to `llm_helper.generate_answer` which calls the Deepseek chat API and returns a response.\n\n## Module responsibilities & important details\n\n- `modules/db_manager.py`:\n\n - Implements a `Neo4jGraph` singleton that initializes the Neo4j driver in `__new__` and exposes `execute_query(query, params)` that returns a list of dicts.\n - Note: current design instantiates a global `neo4j_graph = Neo4jGraph()` at module import time β€” this will raise if env vars are missing.\n\n- `modules/preprocessing.py`:\n\n - Extracts players, teams, positions, seasons, gameweeks and statistics using spaCy + regex + fuzzy matching.\n - Calls `fetch_all_names_from_db` (which uses `Neo4jGraph`) to fetch valid names for fuzzy matching.\n\n- `modules/cypher_retriever.py`:\n\n - Selects a Cypher template from `config.template_library.CYPHER_TEMPLATE_LIBRARY` using the `intent` key and fills params.\n - Returns a JSON-friendly payload including `intent`, `template_used`, `parameters` and `results`.\n - Important: if an `intent` key is missing from the template library the module will currently raise a KeyError β€” this can be made defensive.\n\n- `modules/vector_retriever.py`:\n\n - Loads a `SentenceTransformer` model and a FAISS index and mapping at import time (based on `EMBEDDING_MODEL` env var).\n - Encodes a constructed query text and runs FAISS `index.search` and then queries Neo4j for the embedding sources.\n - Heavy initialization is done at import; see the \"Developer notes\" section for a recommended lazy-init change to avoid import-time failures.\n\n- `modules/llm_helper.py`:\n - Calls an external chat API (Deepseek) for both intent classification and answer generation. It expects `DEEPSEEK_API_KEY` and `DEEPSEEK_API_URL` to be present in the environment.\n\n## Runtime & initialization considerations\n\n- Eager imports: both `modules/__init__.py` and many modules perform work at import time (driver creation, model loads, reading index files). This means a simple `import modules` in `main.py` can fail if Neo4j credentials, FAISS files, or model files are not present.\n- The app (`main.py`) partially anticipates this by catching `ModuleNotFoundError` during `from modules import ...` and falling back to placeholder behavior. However, other exceptions (like `RuntimeError` from missing env) may also be raised during import. To improve developer experience consider:\n - Lazy initialization in `db_manager` and `vector_retriever`.\n - Converting `modules/__init__.py` to a lazy loader (so submodules are imported only when referenced).\n - Catching general import exceptions in `main.py` and surfacing clear instructions to the user.\n\n## Troubleshooting\n\n- If the UI shows placeholder answers and an import error message, check for:\n\n - Missing `.env` values (`NEO4J_URI`, `NEO4J_USERNAME`, `NEO4J_PASSWORD`, `DEEPSEEK_API_KEY`, `DEEPSEEK_API_URL`).\n - Missing FAISS index files in `embeddings_out/`.\n - Missing Python packages (run `pip install -r requirements.txt`).\n - Neo4j not running or connection refused.\n\n- Common fixes:\n - Ensure `.env` is present and correct.\n - If you don't need embeddings immediately, set `EMBEDDING_MODEL` to a value that won't load FAISS, or edit `modules/vector_retriever.py` to guard index loading.\n - For API-related failures, inspect the raw HTTP error returned by `modules/llm_helper.py`.\n\n## Developer notes & recommended fixes\n\n1. Make `modules/__init__.py` lazy to avoid eager submodule imports. Example implementation:\n\n```python\n__all__ = [\"db_manager\", \"preprocessing\", \"cypher_retriever\", \"vector_retriever\"]\n\ndef __getattr__(name):\n\t\tif name in __all__:\n\t\t\t\timport importlib\n\t\t\t\tmod = importlib.import_module(f\"{__name__}.{name}\")\n\t\t\t\tglobals()[name] = mod\n\t\t\t\treturn mod\n\t\traise AttributeError(name)\n```\n\n2. In `modules/db_manager.py` consider removing the global instantiation `neo4j_graph = Neo4jGraph()` at module import time. Instead let callers instantiate `Neo4jGraph()` when needed or provide a `get_instance()` factory that initializes lazily.\n\n3. In `modules/vector_retriever.py` move heavy loads (SentenceTransformer, faiss.read_index, mapping loads) into an `_ensure_initialized()` function called on first `vector_search` invocation.\n\n4. Make `cypher_retriever.retrieve_data_via_cypher` defensive when the provided `intent` is not present in `CYPHER_TEMPLATE_LIBRARY`. Use `CYPHER_TEMPLATE_LIBRARY.get(intent)` and return a helpful error payload rather than crashing.\n"}}}}