Files

1 line
150 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"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=<your_password>\n\n# LLM API Keys\nDEEPSEEK_API_KEY=<your_deepseek_key>\nDEEPSEEK_API_URL=https://api.deepseek.com/chat/completions\nDEEPSEEK_MODEL=deepseek-chat\n\nHF_TOKEN=<your_huggingface_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| <span style=\"color:rgb(4, 245, 255); font-weight:bold;\">● Cyan</span> | `rgb(4, 245, 255)` | Highlights, accents |\n| <span style=\"color:rgb(233, 0, 82); font-weight:bold;\">● Pink</span> | `rgb(233, 0, 82)` | Warnings, important |\n| <span style=\"color:rgb(0, 255, 133); font-weight:bold;\">● Green</span> | `rgb(0, 255, 133)` | Success, positive |\n| <span style=\"color:rgb(56, 0, 60); font-weight:bold;\">● Purple</span> | `rgb(56, 0, 60)` | Background, muted |\n| <span style=\"color:rgb(255, 255, 255); font-weight:bold;\">● White</span> | `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=<your_password>\n\n# LLM API Keys\nDEEPSEEK_API_KEY=<your_deepseek_key>\nDEEPSEEK_API_URL=https://api.deepseek.com/chat/completions\nDEEPSEEK_MODEL=deepseek-chat\n\nHF_TOKEN=<your_huggingface_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| <span style=\"color:rgb(4, 245, 255); font-weight:bold;\">● Cyan</span> | `rgb(4, 245, 255)` | Highlights, accents |\n| <span style=\"color:rgb(233, 0, 82); font-weight:bold;\">● Pink</span> | `rgb(233, 0, 82)` | Warnings, important |\n| <span style=\"color:rgb(0, 255, 133); font-weight:bold;\">● Green</span> | `rgb(0, 255, 133)` | Success, positive |\n| <span style=\"color:rgb(56, 0, 60); font-weight:bold;\">● Purple</span> | `rgb(56, 0, 60)` | Background, muted |\n| <span style=\"color:rgb(255, 255, 255); font-weight:bold;\">● White</span> | `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=<your_password>\n\n# LLM API Keys\nDEEPSEEK_API_KEY=<your_deepseek_key>\nDEEPSEEK_API_URL=https://api.deepseek.com/chat/completions\nDEEPSEEK_MODEL=deepseek-chat\n\nHF_TOKEN=<your_huggingface_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| <span style=\"color:rgb(4, 245, 255); font-weight:bold;\">● Cyan</span> | `rgb(4, 245, 255)` | Highlights, accents |\n| <span style=\"color:rgb(233, 0, 82); font-weight:bold;\">● Pink</span> | `rgb(233, 0, 82)` | Warnings, important |\n| <span style=\"color:rgb(0, 255, 133); font-weight:bold;\">● Green</span> | `rgb(0, 255, 133)` | Success, positive |\n| <span style=\"color:rgb(56, 0, 60); font-weight:bold;\">● Purple</span> | `rgb(56, 0, 60)` | Background, muted |\n| <span style=\"color:rgb(255, 255, 255); font-weight:bold;\">● White</span> | `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=<your_password>\n\n# LLM API Keys\nDEEPSEEK_API_KEY=<your_deepseek_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=<your_password>\n\n# LLM API Keys\nDEEPSEEK_API_KEY=<your_deepseek_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"}}}}