1 line
150 KiB
JSON
1 line
150 KiB
JSON
{"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"}}}} |