Bineta123/Domainexpert-api
0
1<!DOCTYPE html>
2<html lang="fr">
3<head>
4 <meta charset="UTF-8">
5 <title>🛒 {{ app_name if app_name else "Catégorisation de produits Auchan" }} — Accueil</title>
6 <meta name="viewport" content="width=device-width, initial-scale=1">
7
8 <style>
9 :root{
10 --primary:#0d47a1;
11 --primary2:#1e88e5;
12 --bgGlass: rgba(255,255,255,0.92);
13 --shadow: 0 10px 25px rgba(0,0,0,0.12);
14 --radius: 18px;
15 --success:#1b5e20;
16 --danger:#b71c1c;
17 --warn:#e65100;
18 }
19
20 body{
21 font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
22 background-image: url("{{ background_image }}");
23 background-size: cover;
24 background-attachment: fixed;
25 color:#222;
26 padding: 20px;
27 margin: 0;
28 }
29
30 .container{ max-width: 1100px; margin: 0 auto; }
31
32 /* NAVBAR */
33 .nav{
34 background: var(--bgGlass);
35 border-radius: var(--radius);
36 box-shadow: var(--shadow);
37 border: 1px solid rgba(255,255,255,0.6);
38 backdrop-filter: blur(6px);
39 padding: 12px 14px;
40 margin-bottom: 14px;
41
42 display:flex;
43 align-items:center;
44 justify-content: space-between;
45 gap: 10px;
46 flex-wrap: wrap;
47 }
48 .brand{
49 display:flex;
50 align-items:center;
51 gap:10px;
52 font-weight: 900;
53 color: var(--primary);
54 text-decoration: none;
55 }
56 .brand .dot{
57 width: 10px; height: 10px; border-radius: 50%;
58 background: linear-gradient(90deg, var(--primary2), #42a5f5);
59 box-shadow: 0 6px 14px rgba(66,165,245,0.35);
60 }
61 .navlinks{
62 display:flex;
63 gap: 10px;
64 flex-wrap: wrap;
65 align-items: center;
66 }
67 .navlinks a{
68 text-decoration:none;
69 font-weight: 800;
70 color: var(--primary);
71 padding: 8px 10px;
72 border-radius: 12px;
73 border: 1px solid rgba(13,71,161,0.12);
74 background: rgba(13,71,161,0.06);
75 transition: 0.15s;
76 }
77 .navlinks a:hover{ transform: translateY(-1px); }
78 .navlinks a.active{
79 color: #fff;
80 border-color: transparent;
81 background: linear-gradient(90deg, var(--primary2), #42a5f5);
82 }
83
84 .hero{
85 background: var(--bgGlass);
86 padding: 22px;
87 border-radius: var(--radius);
88 box-shadow: var(--shadow);
89 border: 1px solid rgba(255,255,255,0.6);
90 backdrop-filter: blur(6px);
91 margin-bottom: 16px;
92 }
93 .hero h1{
94 margin: 0 0 6px 0;
95 color: var(--primary);
96 text-shadow: 1px 1px 2px #ffffffaa;
97 font-size: 28px;
98 }
99 .hero p{
100 margin: 0;
101 color:#333;
102 line-height: 1.5;
103 }
104
105 .pill{
106 display:inline-block;
107 padding: 6px 10px;
108 border-radius: 999px;
109 background: rgba(13,71,161,0.08);
110 color: var(--primary);
111 font-weight: 800;
112 font-size: 12px;
113 border: 1px solid rgba(13,71,161,0.15);
114 }
115
116 .grid{
117 display: grid;
118 grid-template-columns: 1fr 1fr 1fr;
119 gap: 14px;
120 margin-bottom: 14px;
121 }
122
123 .card{
124 background: var(--bgGlass);
125 padding: 16px;
126 border-radius: var(--radius);
127 box-shadow: var(--shadow);
128 border: 1px solid rgba(255,255,255,0.6);
129 backdrop-filter: blur(6px);
130 }
131
132 .card h2{
133 margin: 0 0 8px 0;
134 color: var(--primary);
135 font-size: 18px;
136 }
137
138 .muted{ color:#555; font-size: 13px; line-height:1.45; }
139
140 .btnRow{
141 margin-top: 12px;
142 display:flex;
143 gap:10px;
144 flex-wrap: wrap;
145 align-items:center;
146 }
147
148 .btn{
149 padding: 11px 16px;
150 background: linear-gradient(90deg, var(--primary2), #42a5f5);
151 color: #fff;
152 border: none;
153 border-radius: 12px;
154 cursor: pointer;
155 font-weight: 800;
156 text-decoration: none;
157 display:inline-block;
158 transition: 0.2s;
159 }
160 .btn:hover{ transform: translateY(-1px); }
161
162 .btn.secondary{
163 background: #ffffff;
164 color: var(--primary);
165 border: 1px solid #bbdefb;
166 font-weight: 800;
167 }
168
169 .statusBox{
170 background: rgba(255,255,255,0.75);
171 border: 1px solid rgba(0,0,0,0.08);
172 border-radius: 14px;
173 padding: 12px;
174 margin-top: 12px;
175 }
176 .ok{ color: var(--success); font-weight: 900; }
177 .err{ color: var(--danger); font-weight: 900; }
178 .warn{ color: var(--warn); font-weight: 900; }
179
180 @media(max-width: 980px){
181 .grid{ grid-template-columns: 1fr; }
182 .nav{ justify-content: center; }
183 }
184 </style>
185</head>
186
187<body>
188<div class="container">
189
190 <!-- NAV -->
191 <div class="nav">
192 <a class="brand" href="/">
193 <span class="dot"></span>
194 <span>{{ app_name if app_name else "Catégorisation de produits Auchan" }}</span>
195 </a>
196
197 <div class="navlinks">
198 <a href="/" class="active">Accueil</a>
199 <a href="/playground">Playground</a>
200 <a href="/leaderboard">Leaderboard</a>
201 <a href="/project">Projet</a>
202 </div>
203 </div>
204
205 <!-- HERO -->
206 <div class="hero">
207 <h1>🛒 {{ app_name if app_name else "Catégorisation de produits Auchan" }}</h1>
208 <p>
209 Application de catégorisation e-commerce basée sur un <b>Domain Expert (XLM-R)</b> et une
210 <b>vérification LLM</b> (optionnelle) pour améliorer les cas ambigus.
211 <span class="pill" style="margin-left:8px;">Sortie = 1 catégorie finale</span>
212 </p>
213
214 <div class="statusBox" style="margin-top:14px;">
215 <div class="muted" style="margin-bottom:6px;"><b>Statut système</b> (auto)</div>
216 <div id="sysStatus" class="muted">Chargement…</div>
217 </div>
218
219 <div class="btnRow">
220 <a class="btn" href="/playground">🚀 Ouvrir le Playground</a>
221 <a class="btn secondary" href="/leaderboard">🏆 Voir le Leaderboard</a>
222 <a class="btn secondary" href="/project">📌 Lire le Projet</a>
223 </div>
224 </div>
225
226 <!-- QUICK CARDS -->
227 <div class="grid">
228 <div class="card">
229 <h2>🎛️ Playground</h2>
230 <div class="muted">
231 Tester la catégorisation sur <b>texte</b>, <b>image</b>, ou en <b>batch CSV</b>.
232 L’API renvoie uniquement la <b>catégorie finale</b>.
233 </div>
234 <div class="btnRow">
235 <a class="btn" href="/playground">Aller au Playground</a>
236 </div>
237 </div>
238
239 <div class="card">
240 <h2>🏆 Leaderboard</h2>
241 <div class="muted">
242 Comparer les modèles (Domain Expert vs Dual Expert) avec un <b>score composite</b> :
243 0.5·F1 + 0.3·Acc + 0.2·Top-10.
244 </div>
245 <div class="btnRow">
246 <a class="btn" href="/leaderboard">Ouvrir le Leaderboard</a>
247 </div>
248 </div>
249
250 <div class="card">
251 <h2>📌 Projet</h2>
252 <div class="muted">
253 Description du pipeline, objectifs, workflow, tâches et livrables (reproduction du Dual-Expert).
254 </div>
255 <div class="btnRow">
256 <a class="btn" href="/project">Voir la page Projet</a>
257 </div>
258 </div>
259 </div>
260
261 <div class="card">
262 <h2>🔌 Endpoints API</h2>
263 <div class="muted">
264 <span class="pill">POST</span> /api/predict (JSON: {"text": ...})
265 <span class="pill">POST</span> /api/predict_image (form-data: file)
266 <span class="pill">POST</span> /api/predict_batch (form-data: csv_file)
267 <span class="pill">GET</span> /api/export.csv
268 <span class="pill">GET</span> /api/leaderboard
269 </div>
270 </div>
271
272</div>
273
274<script>
275 async function loadStatus(){
276 const el = document.getElementById("sysStatus");
277 try{
278 const r = await fetch("/api/ping");
279 const d = await r.json();
280 if(!r.ok) throw new Error(d.error || "Erreur /api/ping");
281
282 const ready = d.model_ready ? "✅ prêt" : "⏳ non chargé";
283 const key = d.has_openai_key ? "✅ OK" : "⚠️ absente";
284 const device = d.device || "—";
285
286 el.innerHTML = `
287 Modèle : <b>${ready}</b> •
288 OpenAI key : <b>${key}</b> •
289 Device : <b>${device}</b>
290 `;
291 }catch(e){
292 el.innerHTML = `<span class="err">❌ ${e.message}</span>`;
293 }
294 }
295 loadStatus();
296</script>
297
298</body>
299</html>
300 