diff --git a/DEMARRAGE.md b/DEMARRAGE.md new file mode 100644 index 0000000..0e24a60 --- /dev/null +++ b/DEMARRAGE.md @@ -0,0 +1,62 @@ +# Guide de Démarrage - Priceflow + +## Problème détecté + +- ❌ Docker non installé/accessible +- ❌ WSL non installé +- ❌ Application non démarrée (port 8555 fermé) + +## Solutions possibles + +### Option 1 : Installer Docker Desktop (Recommandé) + +1. Télécharger Docker Desktop : https://www.docker.com/products/docker-desktop/ +2. Installer et démarrer Docker Desktop +3. Ouvrir un terminal PowerShell dans `C:\Users\Michael\Git\Priceflow` +4. Lancer l'application : + ```bash + docker compose up -d + ``` +5. Vérifier les logs : + ```bash + docker compose logs api | Select-String "site(s)" + ``` + Vous devriez voir : **"10 site(s) de recherche créé(s)"** + +### Option 2 : Installer WSL + Docker + +1. Installer WSL : + ```powershell + wsl --install + ``` +2. Redémarrer l'ordinateur +3. Installer Docker dans WSL +4. Suivre les étapes de l'Option 1 + +### Option 3 : Application déjà démarrée ailleurs + +Si l'application tourne déjà dans un conteneur ou processus différent : + +1. Vérifier les processus : + ```powershell + Get-Process | Where-Object {$_.ProcessName -like "*python*" -or $_.ProcessName -like "*uvicorn*"} + ``` + +2. Vérifier les ports ouverts : + ```powershell + netstat -ano | findstr :8555 + ``` + +## Prochaines étapes après démarrage + +1. ✅ Vérifier que 10 sites sont seedés (logs) +2. ✅ Tester via script : `docker compose exec api python verify_all_sites.py` +3. ✅ Tester via interface : http://localhost:8555/search + +## État actuel + +**Application : ❌ NON DÉMARRÉE** + +- Configuration : ✅ 10 sites ajoutés dans `search_config.py` +- Script de test : ✅ `verify_all_sites.py` créé +- Tests : ⏸️ En attente du démarrage de l'application diff --git a/frontend/src/pages/MultiSearch.jsx b/frontend/src/pages/MultiSearch.jsx index 728951b..a96cf94 100644 --- a/frontend/src/pages/MultiSearch.jsx +++ b/frontend/src/pages/MultiSearch.jsx @@ -2,12 +2,13 @@ import React, { useState, useEffect, useRef } from 'react'; import axios from 'axios'; import { toast } from 'sonner'; import { useTranslation } from 'react-i18next'; -import { Search as SearchIcon, Loader2, ExternalLink, TrendingUp, Package } from 'lucide-react'; +import { Search as SearchIcon, Loader2, ExternalLink, TrendingUp, Package, ChevronDown, ChevronUp } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'; import { Progress } from '@/components/ui/progress'; import { Badge } from '@/components/ui/badge'; +import { Checkbox } from '@/components/ui/checkbox'; const API_URL = '/api'; @@ -17,8 +18,67 @@ export default function MultiSearch() { const [isSearching, setIsSearching] = useState(false); const [progress, setProgress] = useState(null); const [results, setResults] = useState([]); + const [availableSites, setAvailableSites] = useState([]); + const [selectedSiteIds, setSelectedSiteIds] = useState([]); + const [showSiteSelector, setShowSiteSelector] = useState(false); const eventSourceRef = useRef(null); + // Fetch available sites on mount + useEffect(() => { + const fetchSites = async () => { + try { + const response = await axios.get(`${API_URL}/search-sites`); + const sites = response.data.filter(site => site.is_active); + setAvailableSites(sites); + + // Load selection from localStorage or select all by default + const savedSelection = localStorage.getItem('selectedSiteIds'); + if (savedSelection) { + setSelectedSiteIds(JSON.parse(savedSelection)); + } else { + setSelectedSiteIds(sites.map(s => s.id)); + } + } catch (error) { + console.error('Error fetching sites:', error); + toast.error('Erreur lors du chargement des sites'); + } + }; + fetchSites(); + }, []); + + // Save selection to localStorage + useEffect(() => { + if (selectedSiteIds.length > 0) { + localStorage.setItem('selectedSiteIds', JSON.stringify(selectedSiteIds)); + } + }, [selectedSiteIds]); + + const toggleSite = (siteId) => { + setSelectedSiteIds(prev => + prev.includes(siteId) + ? prev.filter(id => id !== siteId) + : [...prev, siteId] + ); + }; + + const selectAll = () => { + setSelectedSiteIds(availableSites.map(s => s.id)); + }; + + const deselectAll = () => { + setSelectedSiteIds([]); + }; + + // Group sites by category + const sitesByCategory = availableSites.reduce((acc, site) => { + const category = site.category || 'Autres'; + if (!acc[category]) { + acc[category] = []; + } + acc[category].push(site); + return acc; + }, {}); + const handleSearch = async (e) => { e.preventDefault(); if (!query.trim()) { @@ -26,6 +86,11 @@ export default function MultiSearch() { return; } + if (selectedSiteIds.length === 0) { + toast.error('Veuillez sélectionner au moins un site'); + return; + } + // Fermer l'EventSource précédent si existant if (eventSourceRef.current) { eventSourceRef.current.close(); @@ -35,10 +100,11 @@ export default function MultiSearch() { setResults([]); setProgress({ status: 'searching', total: 0, completed: 0 }); - // Construire l'URL - recherche sur TOUS les sites actifs + // Construire l'URL avec les sites sélectionnés const params = new URLSearchParams({ q: query.trim(), - max_results: 50, // Plus de résultats pour la comparaison + max_results: 50, + sites: selectedSiteIds.join(','), // Include selected sites }); // Créer l'EventSource pour SSE @@ -147,6 +213,65 @@ export default function MultiSearch() { + + {/* Site Selector */} +