|
24 | 24 | from collections.abc import Callable |
25 | 25 | from contextlib import asynccontextmanager |
26 | 26 | from functools import wraps |
27 | | -from threading import Event, Thread |
28 | 27 |
|
29 | 28 | from fastapi import FastAPI, Request |
30 | 29 | from nc_py_api import AsyncNextcloudApp, NextcloudApp |
|
59 | 58 | 'revision': '607a30d783dfa663caf39e06633721c8d4cfcd7e', |
60 | 59 | } |
61 | 60 | } if __download_models_from_hf else {} |
62 | | -app_enabled = Event() |
| 61 | +app_enabled = threading.Event() |
63 | 62 |
|
64 | 63 | def enabled_handler(enabled: bool, nc: NextcloudApp | AsyncNextcloudApp) -> str: |
65 | 64 | try: |
@@ -99,8 +98,6 @@ async def lifespan(app: FastAPI): |
99 | 98 | app_enabled.set() |
100 | 99 | start_bg_threads(app_config, app_enabled) |
101 | 100 | logger.info(f'App enable state at startup: {app_enabled.is_set()}') |
102 | | - t = Thread(target=background_thread_task, args=()) |
103 | | - t.start() |
104 | 101 | yield |
105 | 102 | vectordb_loader.offload() |
106 | 103 | wait_for_bg_threads() |
@@ -134,15 +131,6 @@ async def lifespan(app: FastAPI): |
134 | 131 | if not app_config.disable_aaa: |
135 | 132 | app.add_middleware(AppAPIAuthMiddleware) |
136 | 133 |
|
137 | | -# logger background thread |
138 | | - |
139 | | -def background_thread_task(): |
140 | | - # todo |
141 | | - # while(True): |
142 | | - # logger.info(f'Currently indexing {len(_indexing)} documents (filename, size): ', extra={'_indexing': _indexing}) |
143 | | - # sleep(10) |
144 | | - ... |
145 | | - |
146 | 134 | # exception handlers |
147 | 135 |
|
148 | 136 | @app.exception_handler(DbException) |
@@ -240,281 +228,3 @@ def download_logs() -> FileResponse: |
240 | 228 | if os.path.isfile(file_path): # Might be a folder (just skip it then) |
241 | 229 | zip_file.write(file_path) |
242 | 230 | return FileResponse(tmp.name, media_type='application/zip', filename='docker_logs.zip') |
243 | | - |
244 | | - |
245 | | -# @app.post('/updateAccessDeclarative') |
246 | | -# @enabled_guard(app) |
247 | | -# def _( |
248 | | -# userIds: Annotated[list[str], Body()], |
249 | | -# sourceId: Annotated[str, Body()], |
250 | | -# ): |
251 | | -# logger.debug('Update access declarative request:', extra={ |
252 | | -# 'user_ids': userIds, |
253 | | -# 'source_id': sourceId, |
254 | | -# }) |
255 | | - |
256 | | -# if len(userIds) == 0: |
257 | | -# return JSONResponse('Empty list of user ids', 400) |
258 | | - |
259 | | -# if not is_valid_source_id(sourceId): |
260 | | -# return JSONResponse('Invalid source id', 400) |
261 | | - |
262 | | -# exec_in_proc(target=decl_update_access, args=(vectordb_loader, userIds, sourceId)) |
263 | | - |
264 | | -# return JSONResponse('Access updated') |
265 | | - |
266 | | - |
267 | | -# @app.post('/updateAccess') |
268 | | -# @enabled_guard(app) |
269 | | -# def _( |
270 | | -# op: Annotated[UpdateAccessOp, Body()], |
271 | | -# userIds: Annotated[list[str], Body()], |
272 | | -# sourceId: Annotated[str, Body()], |
273 | | -# ): |
274 | | -# logger.debug('Update access request', extra={ |
275 | | -# 'op': op, |
276 | | -# 'user_ids': userIds, |
277 | | -# 'source_id': sourceId, |
278 | | -# }) |
279 | | - |
280 | | -# if len(userIds) == 0: |
281 | | -# return JSONResponse('Empty list of user ids', 400) |
282 | | - |
283 | | -# if not is_valid_source_id(sourceId): |
284 | | -# return JSONResponse('Invalid source id', 400) |
285 | | - |
286 | | -# exec_in_proc(target=update_access, args=(vectordb_loader, op, userIds, sourceId)) |
287 | | - |
288 | | -# return JSONResponse('Access updated') |
289 | | - |
290 | | - |
291 | | -# @app.post('/updateAccessProvider') |
292 | | -# @enabled_guard(app) |
293 | | -# def _( |
294 | | -# op: Annotated[UpdateAccessOp, Body()], |
295 | | -# userIds: Annotated[list[str], Body()], |
296 | | -# providerId: Annotated[str, Body()], |
297 | | -# ): |
298 | | -# logger.debug('Update access by provider request', extra={ |
299 | | -# 'op': op, |
300 | | -# 'user_ids': userIds, |
301 | | -# 'provider_id': providerId, |
302 | | -# }) |
303 | | - |
304 | | -# if len(userIds) == 0: |
305 | | -# return JSONResponse('Empty list of user ids', 400) |
306 | | - |
307 | | -# if not is_valid_provider_id(providerId): |
308 | | -# return JSONResponse('Invalid provider id', 400) |
309 | | - |
310 | | -# exec_in_proc(target=update_access_provider, args=(vectordb_loader, op, userIds, providerId)) |
311 | | - |
312 | | -# return JSONResponse('Access updated') |
313 | | - |
314 | | - |
315 | | -# @app.post('/deleteSources') |
316 | | -# @enabled_guard(app) |
317 | | -# def _(sourceIds: Annotated[list[str], Body(embed=True)]): |
318 | | -# logger.debug('Delete sources request', extra={ |
319 | | -# 'source_ids': sourceIds, |
320 | | -# }) |
321 | | - |
322 | | -# sourceIds = [source.strip() for source in sourceIds if source.strip() != ''] |
323 | | - |
324 | | -# if len(sourceIds) == 0: |
325 | | -# return JSONResponse('No sources provided', 400) |
326 | | - |
327 | | -# res = exec_in_proc(target=delete_by_source, args=(vectordb_loader, sourceIds)) |
328 | | -# if res is False: |
329 | | -# return JSONResponse('Error: VectorDB delete failed, check vectordb logs for more info.', 400) |
330 | | - |
331 | | -# return JSONResponse('All valid sources deleted') |
332 | | - |
333 | | - |
334 | | -# @app.post('/deleteProvider') |
335 | | -# @enabled_guard(app) |
336 | | -# def _(providerKey: str = Body(embed=True)): |
337 | | -# logger.debug('Delete sources by provider for all users request', extra={ 'provider_key': providerKey }) |
338 | | - |
339 | | -# if value_of(providerKey) is None: |
340 | | -# return JSONResponse('Invalid provider key provided', 400) |
341 | | - |
342 | | -# exec_in_proc(target=delete_by_provider, args=(vectordb_loader, providerKey)) |
343 | | - |
344 | | -# return JSONResponse('All valid sources deleted') |
345 | | - |
346 | | - |
347 | | -# @app.post('/deleteUser') |
348 | | -# @enabled_guard(app) |
349 | | -# def _(userId: str = Body(embed=True)): |
350 | | -# logger.debug('Remove access list for user, and orphaned sources', extra={ 'user_id': userId }) |
351 | | - |
352 | | -# if value_of(userId) is None: |
353 | | -# return JSONResponse('Invalid userId provided', 400) |
354 | | - |
355 | | -# exec_in_proc(target=delete_user, args=(vectordb_loader, userId)) |
356 | | - |
357 | | -# return JSONResponse('User deleted') |
358 | | - |
359 | | - |
360 | | -# @app.put('/loadSources') |
361 | | -# @enabled_guard(app) |
362 | | -# def _(sources: list[UploadFile]): |
363 | | -# global _indexing |
364 | | - |
365 | | -# if len(sources) == 0: |
366 | | -# return JSONResponse('No sources provided', 400) |
367 | | - |
368 | | -# for source in sources: |
369 | | -# if not value_of(source.filename): |
370 | | -# return JSONResponse(f'Invalid source filename for: {source.headers.get("title")}', 400) |
371 | | - |
372 | | -# with index_lock: |
373 | | -# if source.filename in _indexing: |
374 | | -# # this request will be retried by the client |
375 | | -# return JSONResponse( |
376 | | -# f'This source ({source.filename}) is already being processed in another request, try again later', |
377 | | -# 503, |
378 | | -# headers={'cc-retry': 'true'}, |
379 | | -# ) |
380 | | - |
381 | | -# if not ( |
382 | | -# value_of(source.headers.get('userIds')) |
383 | | -# and source.headers.get('title', None) is not None |
384 | | -# and value_of(source.headers.get('type')) |
385 | | -# and value_of(source.headers.get('modified')) |
386 | | -# and source.headers['modified'].isdigit() |
387 | | -# and value_of(source.headers.get('provider')) |
388 | | -# ): |
389 | | -# logger.error('Invalid/missing headers received', extra={ |
390 | | -# 'source_id': source.filename, |
391 | | -# 'title': source.headers.get('title'), |
392 | | -# 'headers': source.headers, |
393 | | -# }) |
394 | | -# return JSONResponse(f'Invaild/missing headers for:provider_ids {source.filename}', 400) |
395 | | - |
396 | | -# # wait for 10 minutes before failing the request |
397 | | -# semres = doc_parse_semaphore.acquire(block=True, timeout=10*60) |
398 | | -# if not semres: |
399 | | -# return JSONResponse( |
400 | | -# 'Document parser worker limit reached, try again in some time or consider increasing the limit', |
401 | | -# 503, |
402 | | -# headers={'cc-retry': 'true'} |
403 | | -# ) |
404 | | - |
405 | | -# with index_lock: |
406 | | -# for source in sources: |
407 | | -# _indexing[source.filename] = source.size |
408 | | - |
409 | | -# try: |
410 | | -# loaded_sources, not_added_sources = exec_in_proc( |
411 | | -# target=embed_sources, |
412 | | -# args=(vectordb_loader, app.extra['CONFIG'], sources) |
413 | | -# ) |
414 | | -# except (DbException, EmbeddingException): |
415 | | -# raise |
416 | | -# except Exception as e: |
417 | | -# raise DbException('Error: failed to load sources') from e |
418 | | -# finally: |
419 | | -# with index_lock: |
420 | | -# for source in sources: |
421 | | -# _indexing.pop(source.filename, None) |
422 | | -# doc_parse_semaphore.release() |
423 | | - |
424 | | -# if len(loaded_sources) != len(sources): |
425 | | -# logger.debug('Some sources were not loaded', extra={ |
426 | | -# 'Count of loaded sources': f'{len(loaded_sources)}/{len(sources)}', |
427 | | -# 'source_ids': loaded_sources, |
428 | | -# }) |
429 | | - |
430 | | -# # loaded sources include the existing sources that may only have their access updated |
431 | | -# return JSONResponse({'loaded_sources': loaded_sources, 'sources_to_retry': not_added_sources}) |
432 | | - |
433 | | - |
434 | | -# class Query(BaseModel): |
435 | | -# userId: str |
436 | | -# query: str |
437 | | -# useContext: bool = True |
438 | | -# scopeType: ScopeType | None = None |
439 | | -# scopeList: list[str] | None = None |
440 | | -# ctxLimit: int = 20 |
441 | | - |
442 | | -# @field_validator('userId', 'query', 'ctxLimit') |
443 | | -# @classmethod |
444 | | -# def check_empty_values(cls, value: Any, info: ValidationInfo): |
445 | | -# if value_of(value) is None: |
446 | | -# raise ValueError('Empty value for field', info.field_name) |
447 | | - |
448 | | -# return value |
449 | | - |
450 | | -# @field_validator('ctxLimit') |
451 | | -# @classmethod |
452 | | -# def at_least_one_context(cls, value: int): |
453 | | -# if value < 1: |
454 | | -# raise ValueError('Invalid context chunk limit') |
455 | | - |
456 | | -# return value |
457 | | - |
458 | | - |
459 | | -# def execute_query(query: Query, in_proc: bool = True) -> LLMOutput: |
460 | | -# llm: LLM = llm_loader.load() |
461 | | -# template = app.extra.get('LLM_TEMPLATE') |
462 | | -# no_ctx_template = app.extra['LLM_NO_CTX_TEMPLATE'] |
463 | | -# # todo: array |
464 | | -# end_separator = app.extra.get('LLM_END_SEPARATOR', '') |
465 | | - |
466 | | -# if query.useContext: |
467 | | -# target = process_context_query |
468 | | -# args=( |
469 | | -# query.userId, |
470 | | -# vectordb_loader, |
471 | | -# llm, |
472 | | -# app_config, |
473 | | -# query.query, |
474 | | -# query.ctxLimit, |
475 | | -# query.scopeType, |
476 | | -# query.scopeList, |
477 | | -# template, |
478 | | -# end_separator, |
479 | | -# ) |
480 | | -# else: |
481 | | -# target=process_query |
482 | | -# args=( |
483 | | -# query.userId, |
484 | | -# llm, |
485 | | -# app_config, |
486 | | -# query.query, |
487 | | -# no_ctx_template, |
488 | | -# end_separator, |
489 | | -# ) |
490 | | - |
491 | | -# if in_proc: |
492 | | -# return exec_in_proc(target=target, args=args) |
493 | | - |
494 | | -# return target(*args) # pyright: ignore |
495 | | - |
496 | | - |
497 | | -# @app.post('/query') |
498 | | -# @enabled_guard(app) |
499 | | -# def _(query: Query) -> LLMOutput: |
500 | | -# logger.debug('received query request', extra={ 'query': query.dict() }) |
501 | | - |
502 | | -# if app_config.llm[0] == 'nc_texttotext': |
503 | | -# return execute_query(query) |
504 | | - |
505 | | -# with llm_lock: |
506 | | -# return execute_query(query, in_proc=False) |
507 | | - |
508 | | - |
509 | | -# @app.post('/docSearch') |
510 | | -# @enabled_guard(app) |
511 | | -# def _(query: Query) -> list[SearchResult]: |
512 | | -# # useContext from Query is not used here |
513 | | -# return exec_in_proc(target=do_doc_search, args=( |
514 | | -# query.userId, |
515 | | -# query.query, |
516 | | -# vectordb_loader, |
517 | | -# query.ctxLimit, |
518 | | -# query.scopeType, |
519 | | -# query.scopeList, |
520 | | -# )) |
0 commit comments