SSE for specifications
Browse files- app.py +30 -12
- classes.py +16 -2
- static/script.js +113 -21
app.py
CHANGED
@@ -74,7 +74,7 @@ def get_folder_name(working_group: str):
|
|
74 |
code, num = m.groups()
|
75 |
return (code, int(num))
|
76 |
else:
|
77 |
-
raise ValueError("
|
78 |
|
79 |
@app.get("/get_meetings/{working_group}")
|
80 |
def get_meetings(working_group: str):
|
@@ -98,7 +98,7 @@ def index_tdocs_wg_progress(req: IndexTDoc):
|
|
98 |
for content in tdoc_indexer.process_workgroup(folder, url):
|
99 |
yield content
|
100 |
tdoc_indexer.save_indexer()
|
101 |
-
yield "event: end\ndata: Indexation
|
102 |
return StreamingResponse(generate_events(), media_type="text/event-stream")
|
103 |
|
104 |
@app.post("/index_tdocs/meeting")
|
@@ -118,7 +118,7 @@ def index_tdocs_meeting_progress(req: IndexTDoc):
|
|
118 |
tdoc_indexer.process_meeting(meet, url)
|
119 |
yield f"event: progress\ndata: {i+1}\n\n"
|
120 |
tdoc_indexer.save_indexer()
|
121 |
-
yield "event: end\ndata: Indexation
|
122 |
return StreamingResponse(generate_events(), media_type="text/event-stream")
|
123 |
|
124 |
|
@@ -128,20 +128,38 @@ def index_all_tdocs_progress():
|
|
128 |
for content in tdoc_indexer.index_all_tdocs():
|
129 |
yield content
|
130 |
tdoc_indexer.save_indexer()
|
131 |
-
yield "event: end\ndata: Indexation
|
132 |
return StreamingResponse(generate_events(), media_type="text/event-stream")
|
133 |
|
134 |
|
135 |
@app.post("/index_specs/3gpp")
|
136 |
def index_3gpp_specs_progress():
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
141 |
|
142 |
@app.post("/index_specs/etsi")
|
143 |
def index_etsi_specs_progress():
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
code, num = m.groups()
|
75 |
return (code, int(num))
|
76 |
else:
|
77 |
+
raise ValueError("Unattended format")
|
78 |
|
79 |
@app.get("/get_meetings/{working_group}")
|
80 |
def get_meetings(working_group: str):
|
|
|
98 |
for content in tdoc_indexer.process_workgroup(folder, url):
|
99 |
yield content
|
100 |
tdoc_indexer.save_indexer()
|
101 |
+
yield "event: end\ndata: Indexation ended successfully !\n\n"
|
102 |
return StreamingResponse(generate_events(), media_type="text/event-stream")
|
103 |
|
104 |
@app.post("/index_tdocs/meeting")
|
|
|
118 |
tdoc_indexer.process_meeting(meet, url)
|
119 |
yield f"event: progress\ndata: {i+1}\n\n"
|
120 |
tdoc_indexer.save_indexer()
|
121 |
+
yield "event: end\ndata: Indexation ended successfully !\n\n"
|
122 |
return StreamingResponse(generate_events(), media_type="text/event-stream")
|
123 |
|
124 |
|
|
|
128 |
for content in tdoc_indexer.index_all_tdocs():
|
129 |
yield content
|
130 |
tdoc_indexer.save_indexer()
|
131 |
+
yield "event: end\ndata: Indexation ended successfully !\n\n"
|
132 |
return StreamingResponse(generate_events(), media_type="text/event-stream")
|
133 |
|
134 |
|
135 |
@app.post("/index_specs/3gpp")
|
136 |
def index_3gpp_specs_progress():
|
137 |
+
def generate_events():
|
138 |
+
for content in spec_3gpp_indexer.run():
|
139 |
+
yield content
|
140 |
+
yield "event: info\ndata: Saving index ...\n\n"
|
141 |
+
yield "event: get-maximum\ndata: 1\n\n"
|
142 |
+
yield "event: progress\ndata: 1\n\n"
|
143 |
+
spec_3gpp_indexer.save()
|
144 |
+
yield "event: info\ndata: Creating BM25 models ...\n\n"
|
145 |
+
yield "event: get-maximum\ndata: 1\n\n"
|
146 |
+
yield "event: progress\ndata: 1\n\n"
|
147 |
+
spec_3gpp_indexer.create_bm25_index()
|
148 |
+
yield "event: end\ndata: Indexation ended successfully !\n\n"
|
149 |
+
return StreamingResponse(generate_events(), media_type="text/event-stream")
|
150 |
|
151 |
@app.post("/index_specs/etsi")
|
152 |
def index_etsi_specs_progress():
|
153 |
+
def generate_events():
|
154 |
+
for content in spec_etsi_indexer.run():
|
155 |
+
yield content
|
156 |
+
yield "event: info\ndata: Saving index ...\n\n"
|
157 |
+
yield "event: get-maximum\ndata: 1\n\n"
|
158 |
+
yield "event: progress\ndata: 1\n\n"
|
159 |
+
spec_etsi_indexer.save()
|
160 |
+
yield "event: info\ndata: Creating BM25 models ...\n\n"
|
161 |
+
yield "event: get-maximum\ndata: 1\n\n"
|
162 |
+
yield "event: progress\ndata: 1\n\n"
|
163 |
+
spec_etsi_indexer.create_bm25_index()
|
164 |
+
yield "event: end\ndata: Indexation ended successfully !\n\n"
|
165 |
+
return StreamingResponse(generate_events(), media_type="text/event-stream")
|
classes.py
CHANGED
@@ -538,12 +538,19 @@ class Spec3GPPIndexer:
|
|
538 |
|
539 |
def run(self):
|
540 |
print("Fetching specification tables from 3GPP...")
|
|
|
541 |
specifications = self.fetch_spec_table()
|
542 |
self.total_count = len(specifications)
|
543 |
print(f"Processing {self.total_count} specs with {self.max_workers} threads...")
|
544 |
with concurrent.futures.ThreadPoolExecutor(max_workers=self.max_workers) as executor:
|
545 |
futures = [executor.submit(self.process_specification, spec) for spec in specifications]
|
546 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
547 |
if self.STOP_EVENT.is_set():
|
548 |
break
|
549 |
print("All specs processed.")
|
@@ -776,13 +783,20 @@ class SpecETSIIndexer:
|
|
776 |
|
777 |
def run(self):
|
778 |
print("Démarrage indexation ETSI…")
|
|
|
779 |
specifications = self.df.to_dict(orient="records")
|
780 |
self.total_count = len(specifications)
|
781 |
print(f"Traitement de {self.total_count} specs avec {self.max_workers} threads...\n")
|
782 |
|
783 |
with concurrent.futures.ThreadPoolExecutor(max_workers=self.max_workers) as executor:
|
784 |
futures = [executor.submit(self.process_specification, spec) for spec in specifications]
|
785 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
786 |
if self.STOP_EVENT.is_set():
|
787 |
break
|
788 |
|
|
|
538 |
|
539 |
def run(self):
|
540 |
print("Fetching specification tables from 3GPP...")
|
541 |
+
yield "event: info\ndata: Indexing 3GPP specs ...\n\n"
|
542 |
specifications = self.fetch_spec_table()
|
543 |
self.total_count = len(specifications)
|
544 |
print(f"Processing {self.total_count} specs with {self.max_workers} threads...")
|
545 |
with concurrent.futures.ThreadPoolExecutor(max_workers=self.max_workers) as executor:
|
546 |
futures = [executor.submit(self.process_specification, spec) for spec in specifications]
|
547 |
+
total = len(futures)
|
548 |
+
done_count = 0
|
549 |
+
yield f"event: get-maximum\ndata: {total}\n\n"
|
550 |
+
|
551 |
+
for future in concurrent.futures.as_completed(futures):
|
552 |
+
done_count += 1
|
553 |
+
yield f"event: progress\ndata: {done_count}\n\n"
|
554 |
if self.STOP_EVENT.is_set():
|
555 |
break
|
556 |
print("All specs processed.")
|
|
|
783 |
|
784 |
def run(self):
|
785 |
print("Démarrage indexation ETSI…")
|
786 |
+
yield "event: info\ndata: Indexing ETSI specs ...\n\n"
|
787 |
specifications = self.df.to_dict(orient="records")
|
788 |
self.total_count = len(specifications)
|
789 |
print(f"Traitement de {self.total_count} specs avec {self.max_workers} threads...\n")
|
790 |
|
791 |
with concurrent.futures.ThreadPoolExecutor(max_workers=self.max_workers) as executor:
|
792 |
futures = [executor.submit(self.process_specification, spec) for spec in specifications]
|
793 |
+
total = len(futures)
|
794 |
+
done_count = 0
|
795 |
+
yield f"event: get-maximum\ndata: {total}\n\n"
|
796 |
+
|
797 |
+
for future in concurrent.futures.as_completed(futures):
|
798 |
+
done_count += 1
|
799 |
+
yield f"event: progress\ndata: {done_count}\n\n"
|
800 |
if self.STOP_EVENT.is_set():
|
801 |
break
|
802 |
|
static/script.js
CHANGED
@@ -198,7 +198,7 @@ document.getElementById('tdocs-btn').addEventListener('click', async () => {
|
|
198 |
break;
|
199 |
case "end":
|
200 |
console.log("[end]", event.data);
|
201 |
-
document.getElementById('infoText').textContent =
|
202 |
break;
|
203 |
default:
|
204 |
if (event.data) {
|
@@ -211,30 +211,122 @@ document.getElementById('tdocs-btn').addEventListener('click', async () => {
|
|
211 |
enableButtons()
|
212 |
});
|
213 |
|
214 |
-
document.getElementById('spec-3gpp-btn').addEventListener('click', () => {
|
215 |
disableButtons()
|
216 |
-
fetch("/index_specs/3gpp", {
|
217 |
-
|
218 |
-
|
219 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
220 |
}
|
221 |
-
}
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
})
|
226 |
});
|
227 |
|
228 |
-
document.getElementById('spec-etsi-btn').addEventListener('click', () => {
|
229 |
disableButtons()
|
230 |
-
fetch("/index_specs/etsi", {
|
231 |
-
|
232 |
-
|
233 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
234 |
}
|
235 |
-
}
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
})
|
240 |
});
|
|
|
198 |
break;
|
199 |
case "end":
|
200 |
console.log("[end]", event.data);
|
201 |
+
document.getElementById('infoText').textContent = event.data;
|
202 |
break;
|
203 |
default:
|
204 |
if (event.data) {
|
|
|
211 |
enableButtons()
|
212 |
});
|
213 |
|
214 |
+
document.getElementById('spec-3gpp-btn').addEventListener('click', async () => {
|
215 |
disableButtons()
|
216 |
+
const response = await fetch("/index_specs/3gpp", {method: "POST", headers: {
|
217 |
+
"Content-Type": "application/json",
|
218 |
+
"Accept": "text/event-stream",
|
219 |
+
}});
|
220 |
+
const reader = response.body.getReader();
|
221 |
+
const decoder = new TextDecoder("utf-8");
|
222 |
+
let buffer = "";
|
223 |
+
|
224 |
+
while (true) {
|
225 |
+
const {
|
226 |
+
done,
|
227 |
+
value
|
228 |
+
} = await reader.read();
|
229 |
+
if (done) break;
|
230 |
+
|
231 |
+
buffer += decoder.decode(value, {
|
232 |
+
stream: true
|
233 |
+
});
|
234 |
+
|
235 |
+
let events = buffer.split("\n\n"); // séparer les événements
|
236 |
+
buffer = events.pop(); // garder le reste pour le prochain chunk
|
237 |
+
|
238 |
+
for (const rawEvent of events) {
|
239 |
+
const event = {};
|
240 |
+
rawEvent.split("\n").forEach((line) => {
|
241 |
+
const [key, ...rest] = line.split(":");
|
242 |
+
if (key) event[key.trim()] = rest.join(":").trim();
|
243 |
+
});
|
244 |
+
|
245 |
+
// dispatch selon event.event ou par défaut message
|
246 |
+
switch (event.event) {
|
247 |
+
case "progress":
|
248 |
+
console.log("[progress]", event.data);
|
249 |
+
progress.value = event.data;
|
250 |
+
break;
|
251 |
+
case "get-maximum":
|
252 |
+
console.log("[new-max]", event.data);
|
253 |
+
progress.max = event.data
|
254 |
+
break;
|
255 |
+
case "info":
|
256 |
+
console.log("[info]", event.data);
|
257 |
+
document.getElementById('infoText').textContent = event.data
|
258 |
+
break;
|
259 |
+
case "end":
|
260 |
+
console.log("[end]", event.data);
|
261 |
+
document.getElementById('infoText').textContent = event.data;
|
262 |
+
break;
|
263 |
+
default:
|
264 |
+
if (event.data) {
|
265 |
+
console.log("[message]", event.data);
|
266 |
+
};
|
267 |
}
|
268 |
+
}
|
269 |
+
}
|
270 |
+
|
271 |
+
enableButtons()
|
|
|
272 |
});
|
273 |
|
274 |
+
document.getElementById('spec-etsi-btn').addEventListener('click', async () => {
|
275 |
disableButtons()
|
276 |
+
const response = await fetch("/index_specs/etsi", {method: "POST", headers: {
|
277 |
+
"Content-Type": "application/json",
|
278 |
+
"Accept": "text/event-stream",
|
279 |
+
}});
|
280 |
+
const reader = response.body.getReader();
|
281 |
+
const decoder = new TextDecoder("utf-8");
|
282 |
+
let buffer = "";
|
283 |
+
|
284 |
+
while (true) {
|
285 |
+
const {
|
286 |
+
done,
|
287 |
+
value
|
288 |
+
} = await reader.read();
|
289 |
+
if (done) break;
|
290 |
+
|
291 |
+
buffer += decoder.decode(value, {
|
292 |
+
stream: true
|
293 |
+
});
|
294 |
+
|
295 |
+
let events = buffer.split("\n\n"); // séparer les événements
|
296 |
+
buffer = events.pop(); // garder le reste pour le prochain chunk
|
297 |
+
|
298 |
+
for (const rawEvent of events) {
|
299 |
+
const event = {};
|
300 |
+
rawEvent.split("\n").forEach((line) => {
|
301 |
+
const [key, ...rest] = line.split(":");
|
302 |
+
if (key) event[key.trim()] = rest.join(":").trim();
|
303 |
+
});
|
304 |
+
|
305 |
+
// dispatch selon event.event ou par défaut message
|
306 |
+
switch (event.event) {
|
307 |
+
case "progress":
|
308 |
+
console.log("[progress]", event.data);
|
309 |
+
progress.value = event.data;
|
310 |
+
break;
|
311 |
+
case "get-maximum":
|
312 |
+
console.log("[new-max]", event.data);
|
313 |
+
progress.max = event.data
|
314 |
+
break;
|
315 |
+
case "info":
|
316 |
+
console.log("[info]", event.data);
|
317 |
+
document.getElementById('infoText').textContent = event.data
|
318 |
+
break;
|
319 |
+
case "end":
|
320 |
+
console.log("[end]", event.data);
|
321 |
+
document.getElementById('infoText').textContent = event.data;
|
322 |
+
break;
|
323 |
+
default:
|
324 |
+
if (event.data) {
|
325 |
+
console.log("[message]", event.data);
|
326 |
+
};
|
327 |
}
|
328 |
+
}
|
329 |
+
}
|
330 |
+
|
331 |
+
enableButtons()
|
|
|
332 |
});
|