nucliadb 6.2.1.post2949__py3-none-any.whl → 6.2.1.post2971__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nucliadb/search/predict.py +6 -4
- nucliadb/search/search/chat/ask.py +46 -13
- nucliadb/search/search/chat/query.py +4 -4
- {nucliadb-6.2.1.post2949.dist-info → nucliadb-6.2.1.post2971.dist-info}/METADATA +5 -5
- {nucliadb-6.2.1.post2949.dist-info → nucliadb-6.2.1.post2971.dist-info}/RECORD +9 -9
- {nucliadb-6.2.1.post2949.dist-info → nucliadb-6.2.1.post2971.dist-info}/WHEEL +0 -0
- {nucliadb-6.2.1.post2949.dist-info → nucliadb-6.2.1.post2971.dist-info}/entry_points.txt +0 -0
- {nucliadb-6.2.1.post2949.dist-info → nucliadb-6.2.1.post2971.dist-info}/top_level.txt +0 -0
- {nucliadb-6.2.1.post2949.dist-info → nucliadb-6.2.1.post2971.dist-info}/zip-safe +0 -0
nucliadb/search/predict.py
CHANGED
@@ -21,7 +21,7 @@ import json
|
|
21
21
|
import os
|
22
22
|
import random
|
23
23
|
from enum import Enum
|
24
|
-
from typing import Any,
|
24
|
+
from typing import Any, AsyncGenerator, Optional
|
25
25
|
from unittest.mock import AsyncMock, Mock
|
26
26
|
|
27
27
|
import aiohttp
|
@@ -121,12 +121,14 @@ class AnswerStatusCode(str, Enum):
|
|
121
121
|
SUCCESS = "0"
|
122
122
|
ERROR = "-1"
|
123
123
|
NO_CONTEXT = "-2"
|
124
|
+
NO_RETRIEVAL_DATA = "-3"
|
124
125
|
|
125
126
|
def prettify(self) -> str:
|
126
127
|
return {
|
127
128
|
AnswerStatusCode.SUCCESS: "success",
|
128
129
|
AnswerStatusCode.ERROR: "error",
|
129
130
|
AnswerStatusCode.NO_CONTEXT: "no_context",
|
131
|
+
AnswerStatusCode.NO_RETRIEVAL_DATA: "no_retrieval_data",
|
130
132
|
}[self]
|
131
133
|
|
132
134
|
|
@@ -266,7 +268,7 @@ class PredictEngine:
|
|
266
268
|
@predict_observer.wrap({"type": "chat_ndjson"})
|
267
269
|
async def chat_query_ndjson(
|
268
270
|
self, kbid: str, item: ChatModel
|
269
|
-
) -> tuple[str, str,
|
271
|
+
) -> tuple[str, str, AsyncGenerator[GenerativeChunk, None]]:
|
270
272
|
"""
|
271
273
|
Chat query using the new stream format
|
272
274
|
Format specs: https://github.com/ndjson/ndjson-spec
|
@@ -442,7 +444,7 @@ class DummyPredictEngine(PredictEngine):
|
|
442
444
|
|
443
445
|
async def chat_query_ndjson(
|
444
446
|
self, kbid: str, item: ChatModel
|
445
|
-
) -> tuple[str, str,
|
447
|
+
) -> tuple[str, str, AsyncGenerator[GenerativeChunk, None]]:
|
446
448
|
self.calls.append(("chat_query_ndjson", item))
|
447
449
|
|
448
450
|
async def generate():
|
@@ -553,7 +555,7 @@ def get_answer_generator(response: aiohttp.ClientResponse):
|
|
553
555
|
|
554
556
|
def get_chat_ndjson_generator(
|
555
557
|
response: aiohttp.ClientResponse,
|
556
|
-
) ->
|
558
|
+
) -> AsyncGenerator[GenerativeChunk, None]:
|
557
559
|
async def _parse_generative_chunks(gen):
|
558
560
|
async for chunk in gen:
|
559
561
|
try:
|
@@ -49,6 +49,7 @@ from nucliadb.search.search.chat.query import (
|
|
49
49
|
ChatAuditor,
|
50
50
|
get_find_results,
|
51
51
|
get_relations_results,
|
52
|
+
maybe_audit_chat,
|
52
53
|
rephrase_query,
|
53
54
|
sorted_prompt_context_list,
|
54
55
|
tokens_to_chars,
|
@@ -128,7 +129,7 @@ class AskResult:
|
|
128
129
|
main_results: KnowledgeboxFindResults,
|
129
130
|
prequeries_results: Optional[list[PreQueryResult]],
|
130
131
|
nuclia_learning_id: Optional[str],
|
131
|
-
predict_answer_stream: AsyncGenerator[GenerativeChunk, None],
|
132
|
+
predict_answer_stream: Optional[AsyncGenerator[GenerativeChunk, None]],
|
132
133
|
prompt_context: PromptContext,
|
133
134
|
prompt_context_order: PromptContextOrder,
|
134
135
|
auditor: ChatAuditor,
|
@@ -395,6 +396,9 @@ class AskResult:
|
|
395
396
|
This method does not assume any order in the stream of items, but it assumes that at least
|
396
397
|
the answer text is streamed in order.
|
397
398
|
"""
|
399
|
+
if self.predict_answer_stream is None:
|
400
|
+
# In some cases, clients may want to skip the answer generation step
|
401
|
+
return
|
398
402
|
async for generative_chunk in self.predict_answer_stream:
|
399
403
|
item = generative_chunk.chunk
|
400
404
|
if isinstance(item, TextGenerativeResponse):
|
@@ -433,14 +437,14 @@ class NotEnoughContextAskResult(AskResult):
|
|
433
437
|
"""
|
434
438
|
yield self._ndjson_encode(RetrievalAskResponseItem(results=self.main_results))
|
435
439
|
yield self._ndjson_encode(AnswerAskResponseItem(text=NOT_ENOUGH_CONTEXT_ANSWER))
|
436
|
-
status = AnswerStatusCode.
|
440
|
+
status = AnswerStatusCode.NO_RETRIEVAL_DATA
|
437
441
|
yield self._ndjson_encode(StatusAskResponseItem(code=status.value, status=status.prettify()))
|
438
442
|
|
439
443
|
async def json(self) -> str:
|
440
444
|
return SyncAskResponse(
|
441
445
|
answer=NOT_ENOUGH_CONTEXT_ANSWER,
|
442
446
|
retrieval_results=self.main_results,
|
443
|
-
status=AnswerStatusCode.
|
447
|
+
status=AnswerStatusCode.NO_RETRIEVAL_DATA.prettify(),
|
444
448
|
).model_dump_json()
|
445
449
|
|
446
450
|
|
@@ -487,6 +491,31 @@ async def ask(
|
|
487
491
|
resource=resource,
|
488
492
|
)
|
489
493
|
except NoRetrievalResultsError as err:
|
494
|
+
try:
|
495
|
+
rephrase_time = metrics.elapsed("rephrase")
|
496
|
+
except KeyError:
|
497
|
+
# Not all ask requests have a rephrase step
|
498
|
+
rephrase_time = None
|
499
|
+
|
500
|
+
maybe_audit_chat(
|
501
|
+
kbid=kbid,
|
502
|
+
user_id=user_id,
|
503
|
+
client_type=client_type,
|
504
|
+
origin=origin,
|
505
|
+
generative_answer_time=0,
|
506
|
+
generative_answer_first_chunk_time=0,
|
507
|
+
rephrase_time=rephrase_time,
|
508
|
+
user_query=user_query,
|
509
|
+
rephrased_query=rephrased_query,
|
510
|
+
text_answer=b"",
|
511
|
+
status_code=AnswerStatusCode.NO_RETRIEVAL_DATA,
|
512
|
+
chat_history=chat_history,
|
513
|
+
query_context={},
|
514
|
+
query_context_order={},
|
515
|
+
learning_id=None,
|
516
|
+
model=ask_request.generative_model,
|
517
|
+
)
|
518
|
+
|
490
519
|
# If a retrieval was attempted but no results were found,
|
491
520
|
# early return the ask endpoint without querying the generative model
|
492
521
|
return NotEnoughContextAskResult(
|
@@ -536,14 +565,18 @@ async def ask(
|
|
536
565
|
rerank_context=False,
|
537
566
|
top_k=ask_request.top_k,
|
538
567
|
)
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
568
|
+
|
569
|
+
nuclia_learning_id = None
|
570
|
+
nuclia_learning_model = None
|
571
|
+
predict_answer_stream = None
|
572
|
+
if ask_request.generate_answer:
|
573
|
+
with metrics.time("stream_start"):
|
574
|
+
predict = get_predict()
|
575
|
+
(
|
576
|
+
nuclia_learning_id,
|
577
|
+
nuclia_learning_model,
|
578
|
+
predict_answer_stream,
|
579
|
+
) = await predict.chat_query_ndjson(kbid, chat_model)
|
547
580
|
|
548
581
|
auditor = ChatAuditor(
|
549
582
|
kbid=kbid,
|
@@ -564,13 +597,13 @@ async def ask(
|
|
564
597
|
main_results=retrieval_results.main_query,
|
565
598
|
prequeries_results=retrieval_results.prequeries,
|
566
599
|
nuclia_learning_id=nuclia_learning_id,
|
567
|
-
predict_answer_stream=predict_answer_stream,
|
600
|
+
predict_answer_stream=predict_answer_stream,
|
568
601
|
prompt_context=prompt_context,
|
569
602
|
prompt_context_order=prompt_context_order,
|
570
603
|
auditor=auditor,
|
571
604
|
metrics=metrics,
|
572
605
|
best_matches=retrieval_results.best_matches,
|
573
|
-
debug_chat_model=
|
606
|
+
debug_chat_model=chat_model,
|
574
607
|
)
|
575
608
|
|
576
609
|
|
@@ -285,8 +285,8 @@ def maybe_audit_chat(
|
|
285
285
|
chat_history: list[ChatContextMessage],
|
286
286
|
query_context: PromptContext,
|
287
287
|
query_context_order: PromptContextOrder,
|
288
|
-
learning_id: str,
|
289
|
-
model: str,
|
288
|
+
learning_id: Optional[str],
|
289
|
+
model: Optional[str],
|
290
290
|
):
|
291
291
|
audit = get_audit()
|
292
292
|
if audit is None:
|
@@ -324,7 +324,7 @@ def maybe_audit_chat(
|
|
324
324
|
|
325
325
|
|
326
326
|
def parse_audit_answer(raw_text_answer: bytes, status_code: AnswerStatusCode) -> Optional[str]:
|
327
|
-
if status_code == AnswerStatusCode.NO_CONTEXT:
|
327
|
+
if status_code == AnswerStatusCode.NO_CONTEXT or status_code == AnswerStatusCode.NO_RETRIEVAL_DATA:
|
328
328
|
# We don't want to audit "Not enough context to answer this." and instead set a None.
|
329
329
|
return None
|
330
330
|
return raw_text_answer.decode()
|
@@ -349,7 +349,7 @@ class ChatAuditor:
|
|
349
349
|
learning_id: Optional[str],
|
350
350
|
query_context: PromptContext,
|
351
351
|
query_context_order: PromptContextOrder,
|
352
|
-
model: str,
|
352
|
+
model: Optional[str],
|
353
353
|
):
|
354
354
|
self.kbid = kbid
|
355
355
|
self.user_id = user_id
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: nucliadb
|
3
|
-
Version: 6.2.1.
|
3
|
+
Version: 6.2.1.post2971
|
4
4
|
Home-page: https://docs.nuclia.dev/docs/management/nucliadb/intro
|
5
5
|
Author: NucliaDB Community
|
6
6
|
Author-email: nucliadb@nuclia.com
|
@@ -22,10 +22,10 @@ Classifier: Programming Language :: Python :: 3.12
|
|
22
22
|
Classifier: Programming Language :: Python :: 3 :: Only
|
23
23
|
Requires-Python: >=3.9, <4
|
24
24
|
Description-Content-Type: text/markdown
|
25
|
-
Requires-Dist: nucliadb-telemetry[all]>=6.2.1.
|
26
|
-
Requires-Dist: nucliadb-utils[cache,fastapi,storages]>=6.2.1.
|
27
|
-
Requires-Dist: nucliadb-protos>=6.2.1.
|
28
|
-
Requires-Dist: nucliadb-models>=6.2.1.
|
25
|
+
Requires-Dist: nucliadb-telemetry[all]>=6.2.1.post2971
|
26
|
+
Requires-Dist: nucliadb-utils[cache,fastapi,storages]>=6.2.1.post2971
|
27
|
+
Requires-Dist: nucliadb-protos>=6.2.1.post2971
|
28
|
+
Requires-Dist: nucliadb-models>=6.2.1.post2971
|
29
29
|
Requires-Dist: nucliadb-admin-assets>=1.0.0.post1224
|
30
30
|
Requires-Dist: nucliadb-node-binding>=2.26.0
|
31
31
|
Requires-Dist: nuclia-models>=0.24.2
|
@@ -189,7 +189,7 @@ nucliadb/search/__init__.py,sha256=tnypbqcH4nBHbGpkINudhKgdLKpwXQCvDtPchUlsyY4,1
|
|
189
189
|
nucliadb/search/app.py,sha256=6UV7rO0f3w5bNFXLdQM8bwUwXayMGnM4hF6GGv7WPv4,4260
|
190
190
|
nucliadb/search/lifecycle.py,sha256=DW8v4WUi4rZqc7xTOi3rE67W7877WG7fH9oTZbolHdE,2099
|
191
191
|
nucliadb/search/openapi.py,sha256=t3Wo_4baTrfPftg2BHsyLWNZ1MYn7ZRdW7ht-wFOgRs,1016
|
192
|
-
nucliadb/search/predict.py,sha256=
|
192
|
+
nucliadb/search/predict.py,sha256=EWOiWVUX9U_TE19Cl6bpCr6Mjs7hjuvCcG26C7e6KnQ,20919
|
193
193
|
nucliadb/search/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
194
194
|
nucliadb/search/run.py,sha256=aFb-CXRi_C8YMpP_ivNj8KW1BYhADj88y8K9Lr_nUPI,1402
|
195
195
|
nucliadb/search/settings.py,sha256=vem3EcyYlTPSim0kEK-xe-erF4BZg0CT_LAb8ZRQAE8,1684
|
@@ -234,11 +234,11 @@ nucliadb/search/search/shards.py,sha256=mM2aCHWhl_gwkCENXDShPukS-_qnB5tFS3UAJuzM
|
|
234
234
|
nucliadb/search/search/summarize.py,sha256=ksmYPubEQvAQgfPdZHfzB_rR19B2ci4IYZ6jLdHxZo8,4996
|
235
235
|
nucliadb/search/search/utils.py,sha256=iF2tbBA56gRMJH1TlE2hMrqeXqjoeOPt4KgRdp2m9Ek,3313
|
236
236
|
nucliadb/search/search/chat/__init__.py,sha256=cp15ZcFnHvpcu_5-aK2A4uUyvuZVV_MJn4bIXMa20ks,835
|
237
|
-
nucliadb/search/search/chat/ask.py,sha256=
|
237
|
+
nucliadb/search/search/chat/ask.py,sha256=tE1Q5V58oLMCo-T9s0N6Kko-1RWn1e4kHfbbPBsD2uU,36266
|
238
238
|
nucliadb/search/search/chat/exceptions.py,sha256=Siy4GXW2L7oPhIR86H3WHBhE9lkV4A4YaAszuGGUf54,1356
|
239
239
|
nucliadb/search/search/chat/images.py,sha256=PA8VWxT5_HUGfW1ULhKTK46UBsVyINtWWqEM1ulzX1E,3095
|
240
240
|
nucliadb/search/search/chat/prompt.py,sha256=r2JTiRWH3YHPdeRAG5w6gD0g0fWVxdTjYIR86qAVa7k,47106
|
241
|
-
nucliadb/search/search/chat/query.py,sha256=
|
241
|
+
nucliadb/search/search/chat/query.py,sha256=y7W5VuKl1XiZuNsxZIcxxHcFXSG6It2W5CoftZ-ekAc,15428
|
242
242
|
nucliadb/search/search/query_parser/__init__.py,sha256=cp15ZcFnHvpcu_5-aK2A4uUyvuZVV_MJn4bIXMa20ks,835
|
243
243
|
nucliadb/search/search/query_parser/exceptions.py,sha256=tuzl7ZyvVsRz6u0_3zMe60vx39nd3pi641prs-5nC0E,872
|
244
244
|
nucliadb/search/search/query_parser/models.py,sha256=-VlCDXUCgOroAZw1Leqhj2VMgRv_CD2w40PXXOBLaUM,2332
|
@@ -340,9 +340,9 @@ nucliadb/writer/tus/local.py,sha256=7jYa_w9b-N90jWgN2sQKkNcomqn6JMVBOVeDOVYJHto,
|
|
340
340
|
nucliadb/writer/tus/s3.py,sha256=vF0NkFTXiXhXq3bCVXXVV-ED38ECVoUeeYViP8uMqcU,8357
|
341
341
|
nucliadb/writer/tus/storage.py,sha256=ToqwjoYnjI4oIcwzkhha_MPxi-k4Jk3Lt55zRwaC1SM,2903
|
342
342
|
nucliadb/writer/tus/utils.py,sha256=MSdVbRsRSZVdkaum69_0wku7X3p5wlZf4nr6E0GMKbw,2556
|
343
|
-
nucliadb-6.2.1.
|
344
|
-
nucliadb-6.2.1.
|
345
|
-
nucliadb-6.2.1.
|
346
|
-
nucliadb-6.2.1.
|
347
|
-
nucliadb-6.2.1.
|
348
|
-
nucliadb-6.2.1.
|
343
|
+
nucliadb-6.2.1.post2971.dist-info/METADATA,sha256=Ftcrf80Q8tp56jdibzPDOdTJq2jG0aEGuC-bMD-4418,4689
|
344
|
+
nucliadb-6.2.1.post2971.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
345
|
+
nucliadb-6.2.1.post2971.dist-info/entry_points.txt,sha256=XqGfgFDuY3zXQc8ewXM2TRVjTModIq851zOsgrmaXx4,1268
|
346
|
+
nucliadb-6.2.1.post2971.dist-info/top_level.txt,sha256=hwYhTVnX7jkQ9gJCkVrbqEG1M4lT2F_iPQND1fCzF80,20
|
347
|
+
nucliadb-6.2.1.post2971.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
348
|
+
nucliadb-6.2.1.post2971.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|