diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..43cc5fa Binary files /dev/null and b/.DS_Store differ diff --git a/QUICKSTART.md b/QUICKSTART.md new file mode 100644 index 0000000..4f5feb4 --- /dev/null +++ b/QUICKSTART.md @@ -0,0 +1,137 @@ +# 🚀 Guide de dĂ©marrage - immo-agent + +## Installation rapide + +```bash +# 1. Cloner et entrer dans le projet +git clone https://github.com/Arno37/immo-agent.git +cd immo-agent + +# 2. Configurer l'environnement +cp .env.example .env +# Éditer .env avec ta clĂ© MISTRAL_API_KEY + +# 3. Installer les dĂ©pendances +pip install -r requirements.txt +# ou pour dev : pip install -e ".[dev]" +``` + +## 🎯 Utiliser le projet + +### Option 1ïžâƒŁ : API Web (RecommandĂ©) +```bash +python scripts/run_api.py +``` +Puis ouvrez : **http://127.0.0.1:8000** + +### Option 2ïžâƒŁ : CLI interactive +```bash +python scripts/run_cli.py +``` + +### Option 3ïžâƒŁ : Importer comme module Python +```python +from immo_agent.runIA import outil_dvf_estimation + +# Estimer un bien +estimation = outil_dvf_estimation( + ville="Paris", + surface="120", + type_bien="Maison", + etat="bon" +) +print(estimation) +``` + +## 📁 Architecture du projet + +**Voir [STRUCTURE.md](STRUCTURE.md)** pour la description complĂšte + +Dossiers clĂ©s : +- 📩 **immo_agent/** → Code source (dĂ©veloppeurs) +- 🎯 **scripts/** → Points d'entrĂ©e (utilisateurs) +- 🎹 **frontend/** → Interface web +- 📊 **data/** → Bases de donnĂ©es +- đŸ§Ș **tests/** → Tests unitaires + +## ⚙ Configuration + +Les paramĂštres se trouvent dans 2 fichiers : + +1. **`.env`** (secrets) + ``` + MISTRAL_API_KEY=sk_... + GROQ_API_KEY=gsk_... + ``` + +2. **`config/settings.py`** (paramĂštres publics) + ```python + DB_PATH = "data/immo_ventes.db" + API_PORT = 8000 + DEFAULT_MODEL = "mistral-large-latest" + ``` + +## ✅ VĂ©rifier l'installation + +```bash +python immo_agent/check_setup.py +``` + +## đŸ§Ș Lancer les tests + +```bash +pytest tests/ +# ou avec couverture : pytest --cov=immo_agent tests/ +``` + +## 📚 Documentation + +- [STRUCTURE.md](STRUCTURE.md) - Organisation du projet +- [README.md](README.md) - Description gĂ©nĂ©rale +- [documentation/](documentation/) - SpĂ©cifications dĂ©taillĂ©es + +## 🐛 Troubleshooting + +| ProblĂšme | Solution | +|----------|----------| +| `ModuleNotFoundError: immo_agent` | Installer avec `pip install -e .` | +| Port 8000 occupĂ© | `python scripts/run_api.py --port 8001` | +| ClĂ© API manquante | CrĂ©er `.env` avec `MISTRAL_API_KEY=...` | +| BD non trouvĂ©e | Lancer `python immo_agent/csv_to_sqlite.py` | + +## 💡 DĂ©veloppement + +```bash +# Format le code +black immo_agent/ + +# VĂ©rifier les types +mypy immo_agent/ + +# Lint +flake8 immo_agent/ + +# DĂ©veloppement en mode auto-reload +python scripts/run_api.py # reload=True par dĂ©faut +``` + +## 📩 Structure recommandĂ©e pour ajouter du code + +```python +# immo_agent/features/ma_feature.py +from immo_agent.runIA import model +from config import DB_PATH + +def ma_fonction(): + """Ma nouvelle fonction bien organisĂ©e.""" + pass +``` + +Puis importer : +```python +from immo_agent.features import ma_fonction +``` + +--- + +**Besoin d'aide ?** Consultez [STRUCTURE.md](STRUCTURE.md) ou les docstrings du code. diff --git a/README.md b/README.md index 5846762..c6443b4 100644 --- a/README.md +++ b/README.md @@ -63,9 +63,10 @@ L'agent support les demandes comme : ``` immo-agent/ -├── runIA.py # DĂ©finition des outils IA (DVF, estimations) -├── api.py # API FastAPI web -├── main.py # CLI chat (WIP - dĂ©pendances manquantes) +├── immo_agent/ # code Python principal (package) +│ ├── runIA.py # DĂ©finition des outils IA (DVF, estimations) +│ ├── api.py # API FastAPI web +│ ├── main.py # CLI chat (WIP - dĂ©pendances manquantes) ├── frontend/ # Interface web React ├── data/ │ └── immo_ventes.db # Base de donnĂ©es SQLite diff --git a/STRUCTURE.md b/STRUCTURE.md new file mode 100644 index 0000000..70dabc7 --- /dev/null +++ b/STRUCTURE.md @@ -0,0 +1,100 @@ +# 📁 Structure du projet immo-agent + +``` +immo-agent/ +│ +├── immo_agent/ 📩 Package principal (code source) +│ ├── __init__.py +│ ├── runIA.py 🔧 DĂ©finition des outils IA & LLM +│ ├── api.py 🌐 API FastAPI +│ ├── main.py 💬 CLI interactive +│ ├── agent_memory.py 🧠 Gestion de la mĂ©moire (langgraph) +│ ├── api_auth.py 🔐 Authentification +│ ├── db_session.py đŸ’Ÿ Gestion sessions BD +│ ├── check_setup.py ✅ VĂ©rification configuration +│ ├── csv_to_sqlite.py 📊 Import donnĂ©es CSV +│ ├── init_and_run.py 🚀 Initialisation +│ ├── test_mcp.py đŸ§Ș Tests MCP +│ └── weather_mcp.py đŸŒ€ïž MCP serveur mĂ©tĂ©o +│ +├── scripts/ 🎯 Points d'entrĂ©e +│ ├── run_api.py → python scripts/run_api.py +│ └── run_cli.py → python scripts/run_cli.py +│ +├── frontend/ 🎹 Interface web +│ ├── index.html +│ ├── script.js +│ ├── style.css +│ └── auth.js +│ +├── data/ 📊 DonnĂ©es +│ ├── immo_ventes.db (SQLite - DVF data) +│ ├── memory.db (historique conversations) +│ ├── auth_system.db +│ └── ValeursFoncieres-2025-S1.csv +│ +├── documentation/ 📚 Documentation +│ ├── benchmark projIA.md +│ └── note-cadrage projIA.md +│ +├── exploration/ 🔍 Scripts d'exploration +│ ├── expl_mcp.py +│ ├── expl_mcp2.py +│ ├── expl_mcp_full.py +│ ├── explograph.py +│ ├── explograph2.py +│ └── explotools.py +│ +├── tests/ đŸ§Ș Tests unitaires +│ └── __init__.py +│ +├── config/ ⚙ Configuration +│ └── settings.py (paramĂštres globaux) +│ +├── .env.example (À copier en .env) +├── .gitignore +├── README.md (guide utilisateur) +├── pyproject.toml (configuration build/dependencies) +└── requirements.txt (dĂ©pendances pip) +``` + +## 🚀 Comment utiliser + +### Via API Web +```bash +python scripts/run_api.py +# → http://127.0.0.1:8000 +``` + +### Via CLI +```bash +python scripts/run_cli.py +``` + +### Importer le package +```python +from immo_agent.runIA import outil_dvf_historique, outil_dvf_estimation +from immo_agent.api import app +from immo_agent.main import chat_loop +``` + +## 📋 Organisation par rĂŽle + +| Dossier | Usage | Qui ? | +|---------|-------|-------| +| `immo_agent/` | Code mĂ©tier | DĂ©veloppeurs | +| `scripts/` | Lancer l'app | Utilisateurs finaux | +| `frontend/` | Interface | Frontend dev | +| `data/` | BD, donnĂ©es | DonnĂ©es scientifique | +| `tests/` | Validation | QA / CI-CD | +| `config/` | ParamĂštres | DevOps / Config | +| `documentation/` | SpĂ©cs | Analystes | +| `exploration/` | Prototypage | Recherche | + +## ✹ Avantages de cette structure + +✅ **Clair** : chaque dossier a un rĂŽle distinct +✅ **Scalable** : facile d'ajouter des modules +✅ **Professionnel** : suit les conventions Python +✅ **Maintenable** : organisation logique +✅ **Extensible** : prĂȘt pour CI/CD et tests diff --git a/add_gps_columns.py b/add_gps_columns.py new file mode 100644 index 0000000..49af1a9 --- /dev/null +++ b/add_gps_columns.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +"""Script pour ajouter les colonnes latitude et longitude Ă  la BD.""" + +import sqlite3 +import os + +db_path = "data/immo_ventes.db" + +if not os.path.exists(db_path): + print(f"❌ BD non trouvĂ©e: {db_path}") + exit(1) + +try: + conn = sqlite3.connect(db_path) + cursor = conn.cursor() + + # RĂ©cupĂ©rer le schĂ©ma actuel + cursor.execute("PRAGMA table_info(transactions)") + colonnes = [col[1] for col in cursor.fetchall()] + + print(f"📊 Colonnes existantes: {colonnes}\n") + + # Ajouter latitude si elle n'existe pas + if "latitude" not in colonnes: + print("➕ Ajout colonne: latitude") + cursor.execute("ALTER TABLE transactions ADD COLUMN latitude FLOAT") + print("✅ Colonne latitude ajoutĂ©e") + else: + print("✓ Colonne latitude existe dĂ©jĂ ") + + # Ajouter longitude si elle n'existe pas + if "longitude" not in colonnes: + print("➕ Ajout colonne: longitude") + cursor.execute("ALTER TABLE transactions ADD COLUMN longitude FLOAT") + print("✅ Colonne longitude ajoutĂ©e") + else: + print("✓ Colonne longitude existe dĂ©jĂ ") + + conn.commit() + conn.close() + + print("\n✅ BD mise Ă  jour avec succĂšs !") + +except sqlite3.OperationalError as e: + print(f"❌ Erreur: {e}") + print(" → La table 'transactions' n'existe peut-ĂȘtre pas") + print(" → VĂ©rifiez le nom exact de votre table dans la BD") + exit(1) +except Exception as e: + print(f"❌ Erreur: {e}") + exit(1) diff --git a/app/main.py b/app/main.py index 97a4a81..f538db4 100644 --- a/app/main.py +++ b/app/main.py @@ -9,9 +9,9 @@ app.include_router(IA_chat.router) -app.mount("/static", StaticFiles(directory="static"), name="static") -templates = Jinja2Templates(directory="templates") +app.mount("/static", StaticFiles(directory="frontend"), name="static") +templates = Jinja2Templates(directory="frontend") @app.get("/", response_class=HTMLResponse) def read_root(request: Request): - return templates.TemplateResponse("chat.html", {"request": request}) + return templates.TemplateResponse("index.html", {"request": request}) diff --git a/app/routers/IA_chat.py b/app/routers/IA_chat.py index 8df1eb9..bc59ca0 100644 --- a/app/routers/IA_chat.py +++ b/app/routers/IA_chat.py @@ -1,13 +1,29 @@ from fastapi import APIRouter, Request from fastapi.responses import HTMLResponse, JSONResponse +from pydantic import BaseModel +from app.services.agent import async_run_agent + router = APIRouter() -@router.get("/chat", response_class=HTMLResponse) -def chat_page(request: Request): - return JSONResponse({"message": "Bienvenue sur la page de chat!"}) +class ChatRequest(BaseModel): + message: str -@router.post("/chat") -def chat_post(request: Request): - # Ici, tu peux traiter le message utilisateur - return JSONResponse({"message": "Message reçu!"}) +@router.post("/api/chat") +async def chat_post(req: ChatRequest): + try: + # Appel Ă  la fonction run_agent asynchrone + # On utilise une session ("default") pour l'instant + result = await async_run_agent(req.message, "default_session") + + # Le retour est gĂ©nĂ©ralement un dict avec une clĂ© "messages" (langgraph) + reply_content = "" + if result and "messages" in result and len(result["messages"]) > 0: + last_msg = result["messages"][-1] + reply_content = last_msg.content if hasattr(last_msg, 'content') else str(last_msg) + else: + reply_content = str(result) + + return {"reply": reply_content} + except Exception as e: + return {"reply": f"⚠ Erreur cĂŽtĂ© serveur: {str(e)}"} diff --git a/app/services/agent.py b/app/services/agent.py index e4008d3..331e40e 100644 --- a/app/services/agent.py +++ b/app/services/agent.py @@ -17,8 +17,137 @@ class BienImmobilier(BaseModel): surface : float = Field(description="Surface area in square meters") rooms: int = Field(description="Number of rooms") type : str = Field(description="maison ou appartement") - +class HistoriqueVentesInput(BaseModel): + """Input for historical sales data queries.""" + location: str = Field(description="City name or coordinates") + years: int = Field(description="Number of past years to consider") + +class BienSimilairesInput(BaseModel): + """Input for searching similar properties within a range.""" + ville: str = Field(description="City name") + surface_min: float = Field(description="Minimum surface area in square meters") + surface_max: float = Field(description="Maximum surface area in square meters") + type_bien: str = Field(description="Type of property (maison or appartement)") + rayon_km: float = Field(description="Radius in kilometers to consider", default=10) + +@tool +def historique_ventes(input: HistoriqueVentesInput): + """RĂ©cupĂšre l'historique des ventes immobiliĂšres pour une localisation donnĂ©e et une pĂ©riode spĂ©cifiĂ©e. + Args: + input (HistoriqueVentesInput): Les critĂšres de recherche pour l'historique des ventes. + Returns: + list: Une liste d'enregistrements de ventes immobiliĂšres correspondant aux critĂšres. + """ + # Simuler une rĂ©ponse de la base de donnĂ©es DVF + ventes = [ + {"location": input.location, "surface": 70, "rooms": 3, "type": "appartement", "price": 350000, "date": "2023-05-10"}, + {"location": input.location, "surface": 120, "rooms": 5, "type": "maison", "price": 600000, "date": "2022-11-20"}, + # ... plus de donnĂ©es simulĂ©es + ] + return json.dumps(ventes) + +@tool +def biens_similaires(params: BienSimilairesInput): + """Trouve des biens immobiliers similaires dans un pĂ©rimĂštre donnĂ©. + + Cherche les biens qui ont la mĂȘme surface (±10%) et le mĂȘme type + Ă  moins de X km de la ville spĂ©cifiĂ©e. + """ + import sqlite3 + import requests + from math import radians, cos, sin, asin, sqrt + + # ÉTAPE 1: RĂ©cupĂ©rer les coordonnĂ©es de la ville + try: + response = requests.get( + "https://geo.api.gouv.fr/communes", + params={"nom": params.ville, "limit": 1} + ) + data = response.json() + if not data: + return f"❌ Ville '{params.ville}' non trouvĂ©e" + + ref_lat = data[0]["centre"]["coordinates"][1] + ref_lon = data[0]["centre"]["coordinates"][0] + except Exception as e: + return f"❌ Erreur gĂ©olocalisation: {e}" + + # ÉTAPE 2: Chercher en BD les biens similaires + try: + conn = sqlite3.connect("data/immo_ventes.db") + cursor = conn.cursor() + + # Biens avec surface similaire (±10%) + cursor.execute(""" + SELECT + Commune, + Voie, + "Valeur fonciere", + "Surface reelle bati", + latitude, + longitude + FROM transactions + WHERE "Type local" = ? + AND "Surface reelle bati" BETWEEN ? AND ? + AND latitude IS NOT NULL + AND longitude IS NOT NULL + LIMIT 100 + """, [ + params.type_bien.capitalize(), + params.surface_min * 0.9, + params.surface_max * 1.1 + ]) + + biens = cursor.fetchall() + conn.close() + + if not biens: + return f"❌ Aucun {params.type_bien} trouvĂ© avec surface {params.surface_min}-{params.surface_max}mÂČ" + + # ÉTAPE 3: Calculer les distances et filtrer + biens_proches = [] + + for commune, voie, prix, surface, lat, lon in biens: + # Formule Haversine + lat1, lon1, lat2, lon2 = map(radians, [ref_lat, ref_lon, lat, lon]) + dlat = lat2 - lat1 + dlon = lon2 - lon1 + a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2 + c = 2 * asin(sqrt(a)) + distance = c * 6371 # Rayon Terre en km + + # Garder seulement ceux dans le rayon + if distance <= params.rayon_km: + biens_proches.append({ + "commune": commune, + "adresse": voie, + "prix": prix, + "surface": surface, + "distance": round(distance, 1) + }) + + # ÉTAPE 4: Retourner rĂ©sultats formatĂ©s + if not biens_proches: + return f"❌ Aucun {params.type_bien} Ă  {params.surface_min}-{params.surface_max}mÂČ dans {params.rayon_km}km" + + # Trier par distance + biens_proches.sort(key=lambda x: x["distance"]) + + # Formatter le texte pour le LLM + resultat = f"✅ TrouvĂ© {len(biens_proches)} {params.type_bien}(s) similaire(s) Ă  {params.rayon_km}km de {params.ville}:\n\n" + + for i, bien in enumerate(biens_proches[:10], 1): + resultat += f"{i}. {bien['commune']} - {bien['adresse']}\n" + resultat += f" 💰 {int(bien['prix'])}€ | 📐 {bien['surface']}mÂČ | 📍 {bien['distance']}km\n\n" + + if len(biens_proches) > 10: + resultat += f"... et {len(biens_proches) - 10} autres" + + return resultat + + except Exception as e: + return f"❌ Erreur BD: {str(e)}" @tool def estimation_prix(bien: BienImmobilier): @@ -26,29 +155,86 @@ def estimation_prix(bien: BienImmobilier): Args: bien (BienImmobilier): Les caractĂ©ristiques du bien immobilier Ă  estimer. Returns: - float: Une estimation du prix du bien immobilier. + str: Une estimation du prix du bien immobilier. """ prix = bien.surface * 5000 if bien.type == "maison": prix *= 1.2 + + return f"Estimation du prix pour un {bien.type} de {bien.surface}mÂČ avec {bien.rooms} piĂšces Ă  {bien.location} : {int(prix)}€" - return prix - return f"Estimation du prix pour un {bien.type} de {bien.surface}mÂČ avec {bien.rooms} piĂšces Ă  {bien.location} : {prix}€ " llm = ChatMistralAI(model="mistral-large-latest") -system_prompt = """Tu es un assistant d'estimation de prix pour les biens immobiliers. Utilise les outils a ta disposition et n'invente aucune chiffre""" +def extract_last_city(thread_id): + """Extrait la derniĂšre ville mentionnĂ©e dans l'historique de la conversation.""" + try: + config = {"configurable": {"thread_id": thread_id}} + state = agent.get_state(config=config) + + if not state or not state.values.get("messages"): + return None + + # Parcourir les messages en ordre inverse pour trouver la derniĂšre ville mentionnĂ©e + messages = state.values.get("messages", []) + + villes_communes = [ + "Tours", "Paris", "Bordeaux", "Lyon", "Marseille", "Toulouse", + "Nice", "Nantes", "Strasbourg", "Montpellier", "Lille", "Rennes", + "Reims", "Le Havre", "Saint-Étienne", "Toulon", "Grenoble", "Angers", + "Saint-Denis", "Villeurbanne", "NĂźmes", "Clermont-Ferrand" + ] + + for msg in reversed(messages): + content = msg.content if hasattr(msg, 'content') else str(msg.get("content", "")) + for ville in villes_communes: + if ville.lower() in content.lower(): + return ville + + return None + except: + return None + + +system_prompt = """Tu es un assistant expert en biens immobiliers. Tu aides l'utilisateur Ă  rechercher des propriĂ©tĂ©s, estimer des prix et trouver des biens similaires. -# Ajout du tool estimation_prix -tools = [estimation_prix] +📋 RÈGLES IMPORTANTES : +1. Utilise TOUJOURS les outils disponibles pour rĂ©pondre aux requĂȘtes (estimation_prix, historique_ventes, biens_similaires) +2. N'invente JAMAIS de chiffres ou de prix +3. Si l'utilisateur ne mentionne pas une ville dans sa requĂȘte actuelle, utilise AUTOMATIQUEMENT la DERNIÈRE VILLE mentionnĂ©e dans la conversation +4. MĂ©morise chaque nouvelle ville mentionnĂ©e pour les requĂȘtes futures +5. Si aucune ville n'a Ă©tĂ© mentionnĂ©e, demande-la avant de rechercher + +📍 EXEMPLE : +- L'utilisateur dit : "Je cherche une maison Ă  Tours" +- Ensuite : "Je cherche une maison de 100mÂČ dans un rayon de 120km" +- → Tu dois utiliser Tours automatiquement, car c'est la derniĂšre ville mentionnĂ©e""" + +# Ajout des tools +tools = [estimation_prix, historique_ventes, biens_similaires] agent = create_agent(model=llm, tools=tools, system_prompt=system_prompt, checkpointer=InMemorySaver()) #agent_executor = AgentExecutor(agent=agent, tools=tools) #@traceable -async def async_run_agent(user_message,thread_id): +async def async_run_agent(user_message, thread_id): + """ExĂ©cute l'agent avec mĂ©moire de la derniĂšre ville mentionnĂ©e.""" config = {"configurable": {"thread_id": thread_id}} - messages = {"messages":[{"role":"user", "content": user_message}]} + + # Extraire la derniĂšre ville mentionnĂ©e pour l'ajouter au contexte si nĂ©cessaire + last_city = extract_last_city(thread_id) + + # Augmenter le message utilisateur si pas de ville mentionnĂ©e mais une existante + augmented_message = user_message + if last_city and not any( + city.lower() in user_message.lower() + for city in ["Tours", "Paris", "Bordeaux", "Lyon", "Marseille", "Toulouse", + "Nice", "Nantes", "Strasbourg", "Montpellier", "Lille", "Rennes", + "Reims", "Le Havre", "Saint-Étienne", "Toulon", "Grenoble", "Angers"] + ): + augmented_message = f"{user_message} (DerniĂšre ville mentionnĂ©e: {last_city})" + + messages = {"messages": [{"role": "user", "content": augmented_message}]} result = await agent.ainvoke(messages, config=config) return result diff --git a/app/templates/chat.html b/app/templates/chat.html new file mode 100644 index 0000000..350889c --- /dev/null +++ b/app/templates/chat.html @@ -0,0 +1,30 @@ + + + + Mon Agent Immo + + +

Interface de Chat - Agent Immobilier

+
+
+ + + + + + \ No newline at end of file diff --git a/config/__init__.py b/config/__init__.py new file mode 100644 index 0000000..4cfc7d2 --- /dev/null +++ b/config/__init__.py @@ -0,0 +1,2 @@ +"""Configuration module for immo_agent""" +from .settings import * diff --git a/config/settings.py b/config/settings.py new file mode 100644 index 0000000..c1a61cb --- /dev/null +++ b/config/settings.py @@ -0,0 +1,21 @@ +"""Configuration file for immo_agent project settings""" + +# Database +DB_PATH = "data/immo_ventes.db" +MEMORY_DB_PATH = "data/memory.db" + +# API +API_HOST = "127.0.0.1" +API_PORT = 8000 +API_TITLE = "Solenhya Immo Agent API" + +# Frontend +FRONTEND_DIR = "frontend" + +# Tools +DVF_TOOLS_ENABLED = True +MAX_TOOL_ITERATIONS = 5 + +# LLM Models +DEFAULT_MODEL = "mistral-large-latest" +TEMPERATURE = 0 diff --git a/cookies.txt b/cookies.txt new file mode 100644 index 0000000..5c85344 --- /dev/null +++ b/cookies.txt @@ -0,0 +1,5 @@ +# Netscape HTTP Cookie File +# https://curl.se/docs/http-cookies.html +# This file was generated by libcurl! Edit at your own risk. + +#HttpOnly_127.0.0.1 FALSE / FALSE 1775917241 session_id 24a446b5-499c-4555-b94a-d94de98e481e diff --git a/cookies_mistral.txt b/cookies_mistral.txt new file mode 100644 index 0000000..6b96416 --- /dev/null +++ b/cookies_mistral.txt @@ -0,0 +1,5 @@ +# Netscape HTTP Cookie File +# https://curl.se/docs/http-cookies.html +# This file was generated by libcurl! Edit at your own risk. + +#HttpOnly_127.0.0.1 FALSE / FALSE 1775919227 session_id 083b53d2-fea0-4f89-ab62-676809399e3e diff --git a/cookies_test.txt b/cookies_test.txt new file mode 100644 index 0000000..8fb70d0 --- /dev/null +++ b/cookies_test.txt @@ -0,0 +1,5 @@ +# Netscape HTTP Cookie File +# https://curl.se/docs/http-cookies.html +# This file was generated by libcurl! Edit at your own risk. + +#HttpOnly_127.0.0.1 FALSE / FALSE 1775917150 session_id 0c68b8a4-c0ba-42f5-b6d8-7bd8252ede43 diff --git a/documentation/note-cadrage projIA.md b/documentation/note-cadrage projIA.md index dfdc028..6e665b1 100644 --- a/documentation/note-cadrage projIA.md +++ b/documentation/note-cadrage projIA.md @@ -153,9 +153,63 @@ A dĂ©cider "product owner" (responsable de l'intĂ©gritĂ© du produit) --- -## 7. CritĂšres de succĂšs +## 7. Sources de donnĂ©es - Évaluation -### 7.1 Minimum Viable Product (MVP) +### 7.1 API DVF (Demandes de Valeurs FonciĂšres) + +| CritĂšre | Évaluation | +|:---|:---| +| **URL / AccĂšs** | https://www.data.gouv.fr/fr/datasets/demandes-de-valeurs-foncieres/ | +| **Type d'accĂšs** | ☑ TĂ©lĂ©chargement de fichiers | +| **Format des donnĂ©es** | ☑ CSV | +| **DonnĂ©es disponibles** | Historique complet des transactions immobiliĂšres en France : prix, surface, type de bien, localisation, date de mutation, etc. | +| **Limitations** | Mise Ă  jour mensuelle/trimestrielle ; donnĂ©es anonymisĂ©es ; ~2-3 mois de dĂ©lai avant intĂ©gration | +| **QualitĂ© des donnĂ©es** | ☑ Excellente - Source officielle (DGFIP) | +| **Mise Ă  jour / FraĂźcheur** | DonnĂ©es actualisĂ©es tous les 1-2 mois ; derniĂšre mise Ă  jour 2025 S1 | +| **Documentation** | ☑ Excellente - Dictionnaire complet et guides d'utilisation fournis | +| **DifficultĂ© d'intĂ©gration** | ☑ Facile - CSV standardisĂ©, importable directement en SQLite | + +### 7.2 Autre source 1 : API Communes (geo.api.gouv.fr) + +| CritĂšre | Évaluation | +|:---|:---| +| **URL / AccĂšs** | https://geo.api.gouv.fr | +| **Type d'accĂšs** | ☑ API REST | +| **Format des donnĂ©es** | ☑ JSON | +| **DonnĂ©es disponibles** | Population, gĂ©olocalisation, code postal, rĂ©gion, dĂ©partement de chaque commune française | +| **Limitations** | Pas de rate limit documentĂ© ; rĂ©ponses rapides (<100ms) | +| **QualitĂ© des donnĂ©es** | ☑ Excellente - Source officielle INSEE | +| **Mise Ă  jour / FraĂźcheur** | Mise Ă  jour annuelle ; donnĂ©es 2024 actuelles | +| **Documentation** | ☑ Excellente - API simple et bien documentĂ©e | +| **DifficultĂ© d'intĂ©gration** | ☑ TrĂšs facile - Appels REST directs, pas d'authentification | + +### 7.3 Autre source 2 : [À dĂ©terminer - MĂ©tĂ©o / Transports / Commerces] + +| CritĂšre | Évaluation | +|:---|:---| +| **URL / AccĂšs** | À dĂ©finir selon besoin futur | +| **Type d'accĂšs** | ☐ API REST ☐ TĂ©lĂ©chargement ☐ Base de donnĂ©es ☐ Autre | +| **Format des donnĂ©es** | À dĂ©finir | +| **DonnĂ©es disponibles** | ComplĂ©ments potentiels : donnĂ©es mĂ©tĂ©o, rĂ©seau transport, commerces proches | +| **Limitations** | À Ă©valuer | +| **QualitĂ© des donnĂ©es** | À Ă©valuer | +| **Mise Ă  jour / FraĂźcheur** | À Ă©valuer | +| **Documentation** | À Ă©valuer | +| **DifficultĂ© d'intĂ©gration** | À Ă©valuer | + +### 7.4 SynthĂšse des sources retenues + +| Source | DonnĂ©es utilisĂ©es | MĂ©thode d'intĂ©gration | PrioritĂ© | +|:---|:---|:---|:---| +| **DVF** | Prix au mÂČ, historique ventes, types bien | Import CSV → SQLite (`csv_to_sqlite.py`) | ☑ **Haute** | +| **API Communes** | Population, gĂ©olocalisation | Appels API REST directs (outil `outil_infos_ville`) | ☑ **Haute** | +| **MĂ©tadonnĂ©es** | DonnĂ©es utilisateur, historique conversations | SQLite (sessions, memory.db) | ☑ **Haute** | + +--- + +## 8. CritĂšres de succĂšs + +### 8.1 Minimum Viable Product (MVP) *Ce que vous considĂ©rez comme le "minimum acceptable" pour vendredi :* @@ -164,7 +218,7 @@ A dĂ©cider "product owner" (responsable de l'intĂ©gritĂ© du produit) - [ ] Agent utilise outil estimation - [ ] Interface utilisateur -### 7.2 FonctionnalitĂ©s "nice to have" (si temps) +### 8.2 FonctionnalitĂ©s "nice to have" (si temps) - [ ] Autres outils : MCP gouv, - [ ] Enregistrement conversation @@ -174,7 +228,7 @@ A dĂ©cider "product owner" (responsable de l'intĂ©gritĂ© du produit) --- -## 8. Validation +## 9. Validation | | Nom | Date | Signature | |:---|:---|:---|:---| @@ -184,7 +238,7 @@ A dĂ©cider "product owner" (responsable de l'intĂ©gritĂ© du produit) --- -## 9. Annexes +## 10. Annexes *Liens utiles, ressources, documentation, etc.* diff --git a/frontend/auth.js b/frontend/auth.js new file mode 100644 index 0000000..f50c7f0 --- /dev/null +++ b/frontend/auth.js @@ -0,0 +1,29 @@ +// Fonction pour se connecter +async function login(email) { + const response = await fetch('/api/login', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ email: email }) + }); + const data = await response.json(); + if(data.status === "success") { + console.log("ConnectĂ© ! Le cookie est maintenant dans le navigateur."); + } +} + +// Fonction d'envoi de message (Le navigateur enverra le cookie automatiquement) +async function sendMessage(text) { + const response = await fetch('/api/chat', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ message: text }) // Pas besoin d'envoyer l'ID, il est dans le cookie ! + }); + + if (response.status === 401) { + alert("Veuillez vous connecter d'abord."); + return; + } + + const data = await response.json(); + return data.reply; +} diff --git a/frontend/index.html b/frontend/index.html index a0c22b9..5a35bf0 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -13,6 +13,8 @@
+ +