nuclia 4.8.9__py3-none-any.whl → 4.9.0__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.
- nuclia/lib/kb.py +6 -90
- nuclia/lib/models.py +2 -2
- nuclia/sdk/logs.py +25 -59
- nuclia/sdk/search.py +56 -0
- nuclia/tests/fixtures.py +2 -2
- nuclia/tests/test_kb/test_conversation.py +0 -5
- nuclia/tests/test_kb/test_graph.py +40 -0
- nuclia/tests/test_kb/test_logs.py +35 -20
- {nuclia-4.8.9.dist-info → nuclia-4.9.0.dist-info}/METADATA +4 -4
- {nuclia-4.8.9.dist-info → nuclia-4.9.0.dist-info}/RECORD +14 -14
- {nuclia-4.8.9.dist-info → nuclia-4.9.0.dist-info}/WHEEL +1 -1
- {nuclia-4.8.9.dist-info → nuclia-4.9.0.dist-info}/entry_points.txt +0 -0
- {nuclia-4.8.9.dist-info → nuclia-4.9.0.dist-info}/licenses/LICENSE +0 -0
- {nuclia-4.8.9.dist-info → nuclia-4.9.0.dist-info}/top_level.txt +0 -0
nuclia/lib/kb.py
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
import base64
|
2
|
-
import csv
|
3
2
|
import os
|
4
3
|
from enum import Enum
|
5
4
|
from typing import Dict, Optional, Union
|
@@ -15,10 +14,10 @@ from tqdm import tqdm
|
|
15
14
|
from nuclia_models.events.activity_logs import ( # type: ignore
|
16
15
|
ActivityLogsQuery,
|
17
16
|
ActivityLogsSearchQuery,
|
18
|
-
|
17
|
+
ActivityLogsAskQuery,
|
19
18
|
DownloadActivityLogsQuery,
|
20
19
|
DownloadActivityLogsSearchQuery,
|
21
|
-
|
20
|
+
DownloadActivityLogsAskQuery,
|
22
21
|
EventType,
|
23
22
|
DownloadFormat,
|
24
23
|
)
|
@@ -46,11 +45,9 @@ DOWNLOAD_EXPORT_URL = "/export/{export_id}"
|
|
46
45
|
DOWNLOAD_URL = "/{uri}"
|
47
46
|
TUS_UPLOAD_RESOURCE_URL = "/resource/{rid}/file/{field}/tusupload"
|
48
47
|
TUS_UPLOAD_URL = "/tusupload"
|
49
|
-
LEGACY_ACTIVITY_LOG_URL = "/activity/download?type={type}&month={month}"
|
50
48
|
ACTIVITY_LOG_URL = "/activity/{type}/query/download"
|
51
49
|
ACTIVITY_LOG_DOWNLOAD_REQUEST_URL = "/activity/download_request/{request_id}"
|
52
50
|
ACTIVITY_LOG_QUERY_URL = "/activity/{type}/query"
|
53
|
-
FEEDBACK_LOG_URL = "/feedback/{month}"
|
54
51
|
NOTIFICATIONS = "/notifications"
|
55
52
|
REMI_QUERY_URL = "/remi/query"
|
56
53
|
REMI_EVENT_URL = "/remi/events/{event_id}"
|
@@ -73,23 +70,6 @@ class Environment(str, Enum):
|
|
73
70
|
OSS = "OSS"
|
74
71
|
|
75
72
|
|
76
|
-
class LogType(str, Enum):
|
77
|
-
# Nucliadb
|
78
|
-
VISITED = "visited"
|
79
|
-
MODIFIED = "modified"
|
80
|
-
DELETED = "deleted"
|
81
|
-
NEW = "new"
|
82
|
-
SEARCH = "search"
|
83
|
-
SUGGEST = "suggest"
|
84
|
-
INDEXED = "indexed"
|
85
|
-
CHAT = "chat"
|
86
|
-
# Tasks
|
87
|
-
STARTED = "started"
|
88
|
-
STOPPED = "stopped"
|
89
|
-
# Processor
|
90
|
-
PROCESSED = "processed"
|
91
|
-
|
92
|
-
|
93
73
|
class BaseNucliaDBClient:
|
94
74
|
environment: Environment
|
95
75
|
base_url: str
|
@@ -352,41 +332,10 @@ class NucliaDBClient(BaseNucliaDBClient):
|
|
352
332
|
handle_http_sync_errors(response)
|
353
333
|
return response
|
354
334
|
|
355
|
-
def logs(self, type: LogType, month: str) -> list[list[str]]:
|
356
|
-
if self.reader_session is None:
|
357
|
-
raise Exception("KB not configured")
|
358
|
-
|
359
|
-
if type != "feedback":
|
360
|
-
url = LEGACY_ACTIVITY_LOG_URL.format(type=type.value, month=month)
|
361
|
-
response: httpx.Response = self.reader_session.get(url)
|
362
|
-
handle_http_sync_errors(response)
|
363
|
-
return [row for row in csv.reader(response.iter_lines())]
|
364
|
-
else:
|
365
|
-
feedback_url = f"{self.url}{FEEDBACK_LOG_URL.format(month=month)}"
|
366
|
-
feedback_response: httpx.Response = self.reader_session.get(feedback_url)
|
367
|
-
handle_http_sync_errors(feedback_response)
|
368
|
-
feedbacks = [row for row in csv.reader(feedback_response.iter_lines())]
|
369
|
-
answers = self.logs(type=LogType.CHAT, month=month)
|
370
|
-
# first row with the columns headers
|
371
|
-
results = [[*feedbacks[0], *answers[0][:-1]]]
|
372
|
-
for feedback in feedbacks[1:]:
|
373
|
-
learning_id = feedback[1]
|
374
|
-
# search for the corresponding question/answer
|
375
|
-
# (the learning id is the same for both question/answer and feedback,
|
376
|
-
# and is the second column in the Q/A csv)
|
377
|
-
matching_answers = [
|
378
|
-
answer for answer in answers if answer[1] == learning_id
|
379
|
-
]
|
380
|
-
if len(matching_answers) > 0:
|
381
|
-
results.append([*feedback, *matching_answers[0][:-1]])
|
382
|
-
else:
|
383
|
-
results.append(feedback)
|
384
|
-
return results
|
385
|
-
|
386
335
|
def logs_query(
|
387
336
|
self,
|
388
337
|
type: EventType,
|
389
|
-
query: Union[ActivityLogsQuery, ActivityLogsSearchQuery,
|
338
|
+
query: Union[ActivityLogsQuery, ActivityLogsSearchQuery, ActivityLogsAskQuery],
|
390
339
|
) -> requests.Response:
|
391
340
|
if self.stream_session is None:
|
392
341
|
raise Exception("KB not configured")
|
@@ -405,7 +354,7 @@ class NucliaDBClient(BaseNucliaDBClient):
|
|
405
354
|
query: Union[
|
406
355
|
DownloadActivityLogsQuery,
|
407
356
|
DownloadActivityLogsSearchQuery,
|
408
|
-
|
357
|
+
DownloadActivityLogsAskQuery,
|
409
358
|
],
|
410
359
|
download_format: DownloadFormat,
|
411
360
|
):
|
@@ -709,43 +658,10 @@ class AsyncNucliaDBClient(BaseNucliaDBClient):
|
|
709
658
|
await handle_http_async_errors(response)
|
710
659
|
return response
|
711
660
|
|
712
|
-
async def logs(self, type: LogType, month: str) -> list[list[str]]:
|
713
|
-
if self.reader_session is None:
|
714
|
-
raise Exception("KB not configured")
|
715
|
-
|
716
|
-
if type != "feedback":
|
717
|
-
url = LEGACY_ACTIVITY_LOG_URL.format(type=type.value, month=month)
|
718
|
-
response: httpx.Response = await self.reader_session.get(url)
|
719
|
-
await handle_http_async_errors(response)
|
720
|
-
return [row for row in csv.reader(response.iter_lines())]
|
721
|
-
else:
|
722
|
-
feedback_url = f"{self.url}{FEEDBACK_LOG_URL.format(month=month)}"
|
723
|
-
feedback_response: httpx.Response = await self.reader_session.get(
|
724
|
-
feedback_url
|
725
|
-
)
|
726
|
-
await handle_http_async_errors(feedback_response)
|
727
|
-
feedbacks = [row for row in csv.reader(feedback_response.iter_lines())]
|
728
|
-
answers = await self.logs(type=LogType.CHAT, month=month)
|
729
|
-
# first row with the columns headers
|
730
|
-
results = [[*feedbacks[0], *answers[0][:-1]]]
|
731
|
-
for feedback in feedbacks[1:]:
|
732
|
-
learning_id = feedback[1]
|
733
|
-
# search for the corresponding question/answer
|
734
|
-
# (the learning id is the same for both question/answer and feedback,
|
735
|
-
# and is the second column in the Q/A csv)
|
736
|
-
matching_answers = [
|
737
|
-
answer for answer in answers if answer[1] == learning_id
|
738
|
-
]
|
739
|
-
if len(matching_answers) > 0:
|
740
|
-
results.append([*feedback, *matching_answers[0][:-1]])
|
741
|
-
else:
|
742
|
-
results.append(feedback)
|
743
|
-
return results
|
744
|
-
|
745
661
|
async def logs_query(
|
746
662
|
self,
|
747
663
|
type: EventType,
|
748
|
-
query: Union[ActivityLogsQuery, ActivityLogsSearchQuery,
|
664
|
+
query: Union[ActivityLogsQuery, ActivityLogsSearchQuery, ActivityLogsAskQuery],
|
749
665
|
) -> httpx.Response:
|
750
666
|
if self.reader_session is None:
|
751
667
|
raise Exception("KB not configured")
|
@@ -763,7 +679,7 @@ class AsyncNucliaDBClient(BaseNucliaDBClient):
|
|
763
679
|
query: Union[
|
764
680
|
DownloadActivityLogsQuery,
|
765
681
|
DownloadActivityLogsSearchQuery,
|
766
|
-
|
682
|
+
DownloadActivityLogsAskQuery,
|
767
683
|
],
|
768
684
|
download_format: DownloadFormat,
|
769
685
|
):
|
nuclia/lib/models.py
CHANGED
@@ -48,7 +48,7 @@ class GraphRelation(BaseModel):
|
|
48
48
|
destination: GraphEntity
|
49
49
|
|
50
50
|
def to_relation(self) -> Relation:
|
51
|
-
return Relation.
|
51
|
+
return Relation.model_validate(
|
52
52
|
{
|
53
53
|
"from": self.source.to_dict(),
|
54
54
|
"to": self.destination.to_dict(),
|
@@ -60,6 +60,6 @@ class GraphRelation(BaseModel):
|
|
60
60
|
|
61
61
|
def get_relation(relation: Union[GraphRelation, dict]) -> GraphRelation:
|
62
62
|
if isinstance(relation, dict):
|
63
|
-
return GraphRelation.
|
63
|
+
return GraphRelation.model_validate(relation)
|
64
64
|
else:
|
65
65
|
return relation
|
nuclia/sdk/logs.py
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
from nuclia.decorators import kb
|
2
|
-
from nuclia.lib.kb import
|
2
|
+
from nuclia.lib.kb import NucliaDBClient, AsyncNucliaDBClient
|
3
3
|
from nuclia_models.events.activity_logs import ( # type: ignore
|
4
4
|
ActivityLogsQuery,
|
5
|
-
|
5
|
+
ActivityLogsAskQuery,
|
6
6
|
ActivityLogsSearchQuery,
|
7
7
|
DownloadActivityLogsQuery,
|
8
|
-
|
8
|
+
DownloadActivityLogsAskQuery,
|
9
9
|
DownloadActivityLogsSearchQuery,
|
10
10
|
DownloadFormat,
|
11
11
|
EventType,
|
@@ -25,23 +25,6 @@ WAIT_FOR_DOWNLOAD_TIMEOUT = 120
|
|
25
25
|
|
26
26
|
|
27
27
|
class NucliaLogs:
|
28
|
-
@kb
|
29
|
-
def get(
|
30
|
-
self, *args, type: Union[LogType, str], month: str, **kwargs
|
31
|
-
) -> list[list[str]]:
|
32
|
-
"""
|
33
|
-
Download activity logs.
|
34
|
-
|
35
|
-
:param type: VISITED, MODIFIED, DELETED, NEW, SEARCH, SUGGEST, INDEXED, CHAT, STARTED, STOPPED, PROCESSED
|
36
|
-
:param month: YYYY-MM
|
37
|
-
"""
|
38
|
-
if isinstance(type, str):
|
39
|
-
type = LogType[type.upper()]
|
40
|
-
|
41
|
-
ndb: NucliaDBClient = kwargs["ndb"]
|
42
|
-
resp = ndb.logs(type=type, month=month)
|
43
|
-
return resp
|
44
|
-
|
45
28
|
@kb
|
46
29
|
def query(
|
47
30
|
self,
|
@@ -51,25 +34,25 @@ class NucliaLogs:
|
|
51
34
|
dict,
|
52
35
|
ActivityLogsQuery,
|
53
36
|
ActivityLogsSearchQuery,
|
54
|
-
|
37
|
+
ActivityLogsAskQuery,
|
55
38
|
],
|
56
39
|
**kwargs,
|
57
40
|
) -> ActivityLogsOutput:
|
58
41
|
"""
|
59
42
|
Query activity logs.
|
60
43
|
|
61
|
-
:param type: VISITED, MODIFIED, DELETED, NEW, SEARCH, SUGGEST, INDEXED, CHAT, STARTED, STOPPED, PROCESSED
|
44
|
+
:param type: VISITED, MODIFIED, DELETED, NEW, SEARCH, SUGGEST, INDEXED, CHAT, ASK, STARTED, STOPPED, PROCESSED
|
62
45
|
:param query: ActivityLogsQuery
|
63
46
|
"""
|
64
47
|
_type = EventType[type.upper()] if isinstance(type, str) else type
|
65
48
|
_query: Union[
|
66
49
|
ActivityLogsQuery,
|
67
50
|
ActivityLogsSearchQuery,
|
68
|
-
|
51
|
+
ActivityLogsAskQuery,
|
69
52
|
]
|
70
53
|
if isinstance(query, dict):
|
71
|
-
if _type
|
72
|
-
_query =
|
54
|
+
if _type in (EventType.ASK, EventType.CHAT): # TODO: deprecate chat event
|
55
|
+
_query = ActivityLogsAskQuery.model_validate(query)
|
73
56
|
elif type is EventType.SEARCH:
|
74
57
|
_query = ActivityLogsSearchQuery.model_validate(query)
|
75
58
|
else:
|
@@ -95,7 +78,7 @@ class NucliaLogs:
|
|
95
78
|
dict,
|
96
79
|
DownloadActivityLogsQuery,
|
97
80
|
DownloadActivityLogsSearchQuery,
|
98
|
-
|
81
|
+
DownloadActivityLogsAskQuery,
|
99
82
|
],
|
100
83
|
download_format: Union[DownloadFormat, str],
|
101
84
|
wait: bool = False,
|
@@ -104,8 +87,8 @@ class NucliaLogs:
|
|
104
87
|
"""
|
105
88
|
Download activity logs.
|
106
89
|
|
107
|
-
:param type:
|
108
|
-
:param
|
90
|
+
:param type: VISITED, MODIFIED, DELETED, NEW, SEARCH, SUGGEST, INDEXED, CHAT, ASK, STARTED, STOPPED, PROCESSED
|
91
|
+
:param download_format: NDJSON, CSV
|
109
92
|
:param query: DownloadActivityLogsQuery
|
110
93
|
"""
|
111
94
|
_type = EventType[type.upper()] if isinstance(type, str) else type
|
@@ -119,11 +102,11 @@ class NucliaLogs:
|
|
119
102
|
dict,
|
120
103
|
DownloadActivityLogsQuery,
|
121
104
|
DownloadActivityLogsSearchQuery,
|
122
|
-
|
105
|
+
DownloadActivityLogsAskQuery,
|
123
106
|
]
|
124
107
|
if isinstance(query, dict):
|
125
|
-
if _type
|
126
|
-
_query =
|
108
|
+
if _type in (EventType.ASK, EventType.CHAT): # TODO: deprecate chat event
|
109
|
+
_query = DownloadActivityLogsAskQuery.model_validate(query)
|
127
110
|
elif type is EventType.SEARCH:
|
128
111
|
_query = DownloadActivityLogsSearchQuery.model_validate(query)
|
129
112
|
else:
|
@@ -168,23 +151,6 @@ class NucliaLogs:
|
|
168
151
|
|
169
152
|
|
170
153
|
class AsyncNucliaLogs:
|
171
|
-
@kb
|
172
|
-
async def get(
|
173
|
-
self, *args, type: Union[LogType, str], month: str, **kwargs
|
174
|
-
) -> list[list[str]]:
|
175
|
-
"""
|
176
|
-
Download activity logs.
|
177
|
-
|
178
|
-
:param type: VISITED, MODIFIED, DELETED, NEW, SEARCH, SUGGEST, INDEXED, CHAT, STARTED, STOPPED, PROCESSED
|
179
|
-
:param month: YYYY-MM
|
180
|
-
"""
|
181
|
-
if isinstance(type, str):
|
182
|
-
type = LogType[type.upper()]
|
183
|
-
|
184
|
-
ndb: AsyncNucliaDBClient = kwargs["ndb"]
|
185
|
-
resp = await ndb.logs(type=type, month=month)
|
186
|
-
return resp
|
187
|
-
|
188
154
|
@kb
|
189
155
|
async def query(
|
190
156
|
self,
|
@@ -194,25 +160,25 @@ class AsyncNucliaLogs:
|
|
194
160
|
dict,
|
195
161
|
ActivityLogsQuery,
|
196
162
|
ActivityLogsSearchQuery,
|
197
|
-
|
163
|
+
ActivityLogsAskQuery,
|
198
164
|
],
|
199
165
|
**kwargs,
|
200
166
|
) -> ActivityLogsOutput:
|
201
167
|
"""
|
202
168
|
Query activity logs.
|
203
169
|
|
204
|
-
:param type: VISITED, MODIFIED, DELETED, NEW, SEARCH, SUGGEST, INDEXED, CHAT, STARTED, STOPPED, PROCESSED
|
170
|
+
:param type: VISITED, MODIFIED, DELETED, NEW, SEARCH, SUGGEST, INDEXED, CHAT, ASK, STARTED, STOPPED, PROCESSED
|
205
171
|
:param query: ActivityLogsQuery
|
206
172
|
"""
|
207
173
|
_type = EventType[type.upper()] if isinstance(type, str) else type
|
208
174
|
_query: Union[
|
209
175
|
ActivityLogsQuery,
|
210
176
|
ActivityLogsSearchQuery,
|
211
|
-
|
177
|
+
ActivityLogsAskQuery,
|
212
178
|
]
|
213
179
|
if isinstance(query, dict):
|
214
|
-
if _type
|
215
|
-
_query =
|
180
|
+
if _type in (EventType.ASK, EventType.CHAT): # TODO: deprecate chat event
|
181
|
+
_query = ActivityLogsAskQuery.model_validate(query)
|
216
182
|
elif type is EventType.SEARCH:
|
217
183
|
_query = ActivityLogsSearchQuery.model_validate(query)
|
218
184
|
else:
|
@@ -238,7 +204,7 @@ class AsyncNucliaLogs:
|
|
238
204
|
dict,
|
239
205
|
DownloadActivityLogsQuery,
|
240
206
|
DownloadActivityLogsSearchQuery,
|
241
|
-
|
207
|
+
DownloadActivityLogsAskQuery,
|
242
208
|
],
|
243
209
|
download_format: Union[DownloadFormat, str],
|
244
210
|
wait: bool = False,
|
@@ -247,8 +213,8 @@ class AsyncNucliaLogs:
|
|
247
213
|
"""
|
248
214
|
Download activity logs.
|
249
215
|
|
250
|
-
:param type:
|
251
|
-
:param
|
216
|
+
:param type: VISITED, MODIFIED, DELETED, NEW, SEARCH, SUGGEST, INDEXED, CHAT, ASK, STARTED, STOPPED, PROCESSED
|
217
|
+
:param download_format: NDJSON, CSV
|
252
218
|
:param query: DownloadActivityLogsQuery
|
253
219
|
"""
|
254
220
|
_type = EventType[type.upper()] if isinstance(type, str) else type
|
@@ -262,11 +228,11 @@ class AsyncNucliaLogs:
|
|
262
228
|
dict,
|
263
229
|
DownloadActivityLogsQuery,
|
264
230
|
DownloadActivityLogsSearchQuery,
|
265
|
-
|
231
|
+
DownloadActivityLogsAskQuery,
|
266
232
|
]
|
267
233
|
if isinstance(query, dict):
|
268
|
-
if _type
|
269
|
-
_query =
|
234
|
+
if _type in (EventType.ASK, EventType.CHAT): # TODO: deprecate chat event
|
235
|
+
_query = DownloadActivityLogsAskQuery.model_validate(query)
|
270
236
|
elif type is EventType.SEARCH:
|
271
237
|
_query = DownloadActivityLogsSearchQuery.model_validate(query)
|
272
238
|
else:
|
nuclia/sdk/search.py
CHANGED
@@ -20,6 +20,8 @@ from nucliadb_models.search import (
|
|
20
20
|
SyncAskResponse,
|
21
21
|
ChatModel,
|
22
22
|
)
|
23
|
+
from nucliadb_models.graph.requests import GraphSearchRequest
|
24
|
+
from nucliadb_models.graph.responses import GraphSearchResponse
|
23
25
|
from pydantic import ValidationError
|
24
26
|
|
25
27
|
from nuclia.data import get_async_auth, get_auth
|
@@ -331,6 +333,33 @@ class NucliaSearch:
|
|
331
333
|
result.tokens = ask_response.metadata.tokens.model_dump()
|
332
334
|
return result
|
333
335
|
|
336
|
+
@kb
|
337
|
+
def graph(
|
338
|
+
self,
|
339
|
+
*,
|
340
|
+
query: Union[dict, GraphSearchRequest],
|
341
|
+
**kwargs,
|
342
|
+
) -> GraphSearchResponse:
|
343
|
+
"""
|
344
|
+
Perform a graph path query.
|
345
|
+
|
346
|
+
See https://docs.nuclia.dev/docs/api#tag/Search/operation/graph_search_knowledgebox_kb__kbid__graph_post
|
347
|
+
"""
|
348
|
+
ndb: NucliaDBClient = kwargs["ndb"]
|
349
|
+
|
350
|
+
if isinstance(query, GraphSearchRequest):
|
351
|
+
req = query
|
352
|
+
elif isinstance(query, dict):
|
353
|
+
try:
|
354
|
+
req = GraphSearchRequest.model_validate(query)
|
355
|
+
except ValidationError:
|
356
|
+
logger.exception("Error validating query")
|
357
|
+
raise
|
358
|
+
else:
|
359
|
+
raise Exception(f"Invalid query: '{query}'")
|
360
|
+
|
361
|
+
return ndb.ndb.graph_search(req, kbid=ndb.kbid)
|
362
|
+
|
334
363
|
|
335
364
|
class AsyncNucliaSearch:
|
336
365
|
"""
|
@@ -659,3 +688,30 @@ class AsyncNucliaSearch:
|
|
659
688
|
else: # pragma: no cover
|
660
689
|
warnings.warn(f"Unknown ask stream item type: {ask_response_item.type}")
|
661
690
|
return result
|
691
|
+
|
692
|
+
@kb
|
693
|
+
async def graph(
|
694
|
+
self,
|
695
|
+
*,
|
696
|
+
query: Union[dict, GraphSearchRequest],
|
697
|
+
**kwargs,
|
698
|
+
) -> GraphSearchResponse:
|
699
|
+
"""
|
700
|
+
Perform a graph path query.
|
701
|
+
|
702
|
+
See https://docs.nuclia.dev/docs/api#tag/Search/operation/graph_search_knowledgebox_kb__kbid__graph_post
|
703
|
+
"""
|
704
|
+
ndb: AsyncNucliaDBClient = kwargs["ndb"]
|
705
|
+
|
706
|
+
if isinstance(query, GraphSearchRequest):
|
707
|
+
req = query
|
708
|
+
elif isinstance(query, dict):
|
709
|
+
try:
|
710
|
+
req = GraphSearchRequest.model_validate(query)
|
711
|
+
except ValidationError:
|
712
|
+
logger.exception("Error validating query")
|
713
|
+
raise
|
714
|
+
else:
|
715
|
+
raise Exception(f"Invalid query: '{query}'")
|
716
|
+
|
717
|
+
return await ndb.ndb.graph_search(req, kbid=ndb.kbid)
|
nuclia/tests/fixtures.py
CHANGED
@@ -49,8 +49,8 @@ def testing_config(testing_kb, testing_nua, testing_user):
|
|
49
49
|
nuclia_auth._config.set_default_kb(TESTING_KBID)
|
50
50
|
nuclia_auth._config.set_default_nua(client_id)
|
51
51
|
|
52
|
-
|
53
|
-
|
52
|
+
yield
|
53
|
+
reset_config_file()
|
54
54
|
|
55
55
|
|
56
56
|
@pytest.fixture(autouse=True)
|
@@ -2,7 +2,6 @@ import os
|
|
2
2
|
|
3
3
|
from nucliadb_sdk.v2.exceptions import NotFoundError
|
4
4
|
|
5
|
-
from nuclia.sdk.kb import NucliaKB
|
6
5
|
from nuclia.sdk.resource import NucliaResource
|
7
6
|
from nuclia.sdk.upload import NucliaUpload
|
8
7
|
|
@@ -10,7 +9,6 @@ path = f"{os.path.dirname(__file__)}/../assets/conversation.json"
|
|
10
9
|
|
11
10
|
|
12
11
|
def test_conversation(testing_config):
|
13
|
-
nkb = NucliaKB()
|
14
12
|
nresource = NucliaResource()
|
15
13
|
try:
|
16
14
|
res = nresource.get(slug="conversation1")
|
@@ -18,9 +16,6 @@ def test_conversation(testing_config):
|
|
18
16
|
except NotFoundError:
|
19
17
|
pass
|
20
18
|
|
21
|
-
res = nkb.list()
|
22
|
-
assert len(res.resources) == 2
|
23
|
-
|
24
19
|
nu = NucliaUpload()
|
25
20
|
nu.conversation(path=path, slug="conversation1", field="c1")
|
26
21
|
|
@@ -6,6 +6,13 @@ from time import sleep
|
|
6
6
|
|
7
7
|
def test_graph(testing_config):
|
8
8
|
nkb = NucliaKB()
|
9
|
+
|
10
|
+
# ensure KB is clean
|
11
|
+
try:
|
12
|
+
nkb.delete_graph(slug="graph1")
|
13
|
+
except NotFoundError:
|
14
|
+
pass
|
15
|
+
|
9
16
|
nkb.add_graph(
|
10
17
|
slug="graph1",
|
11
18
|
graph=[
|
@@ -28,6 +35,25 @@ def test_graph(testing_config):
|
|
28
35
|
)
|
29
36
|
relations = nkb.get_graph(slug="graph1")
|
30
37
|
assert len(relations) == 3
|
38
|
+
|
39
|
+
# XXX: sometimes, nucliadb needs some more time to index the graph. We retry
|
40
|
+
# some times and fail if that keeps hapenning
|
41
|
+
RETRIES = 5
|
42
|
+
DELAY = 0.5
|
43
|
+
for _ in range(RETRIES):
|
44
|
+
paths = nkb.search.graph(
|
45
|
+
query={"query": {"prop": "path", "source": {"value": "Alice"}}}
|
46
|
+
)
|
47
|
+
try:
|
48
|
+
assert len(paths.paths) == 2
|
49
|
+
except AssertionError:
|
50
|
+
# wait for a bit before retrying
|
51
|
+
print("Graph was not indexed yet, waiting a bit...")
|
52
|
+
sleep(DELAY)
|
53
|
+
else:
|
54
|
+
break
|
55
|
+
assert len(paths.paths) == 2
|
56
|
+
|
31
57
|
nkb.update_graph(
|
32
58
|
slug="graph1",
|
33
59
|
graph=[
|
@@ -40,6 +66,20 @@ def test_graph(testing_config):
|
|
40
66
|
)
|
41
67
|
relations = nkb.get_graph(slug="graph1")
|
42
68
|
assert len(relations) == 4
|
69
|
+
|
70
|
+
for _ in range(RETRIES):
|
71
|
+
paths = nkb.search.graph(
|
72
|
+
query={"query": {"prop": "path", "source": {"value": "Victor"}}}
|
73
|
+
)
|
74
|
+
try:
|
75
|
+
assert len(paths.paths) == 1
|
76
|
+
except AssertionError:
|
77
|
+
print("Graph was not indexed yet, waiting a bit...")
|
78
|
+
sleep(DELAY)
|
79
|
+
else:
|
80
|
+
break
|
81
|
+
assert len(paths.paths) == 1
|
82
|
+
|
43
83
|
nkb.delete_graph(slug="graph1")
|
44
84
|
try:
|
45
85
|
sleep(0.5)
|
@@ -1,24 +1,15 @@
|
|
1
1
|
from nuclia.sdk.kb import NucliaKB, AsyncNucliaKB
|
2
2
|
from nuclia.tests.fixtures import IS_PROD
|
3
|
-
from nuclia.lib.kb import LogType
|
4
3
|
from nuclia_models.events.activity_logs import (
|
5
4
|
ActivityLogsQuery,
|
6
5
|
Pagination,
|
7
6
|
DownloadActivityLogsQuery,
|
8
7
|
DownloadFormat,
|
8
|
+
EventType,
|
9
9
|
)
|
10
10
|
import pytest
|
11
11
|
|
12
12
|
|
13
|
-
def test_logs(testing_config):
|
14
|
-
if not IS_PROD:
|
15
|
-
assert True
|
16
|
-
return
|
17
|
-
nkb = NucliaKB()
|
18
|
-
logs = nkb.logs.get(type=LogType.NEW, month="2024-06")
|
19
|
-
assert len(logs) == 23
|
20
|
-
|
21
|
-
|
22
13
|
def test_activity_logs_query(testing_config):
|
23
14
|
if not IS_PROD:
|
24
15
|
assert True
|
@@ -30,7 +21,7 @@ def test_activity_logs_query(testing_config):
|
|
30
21
|
pagination=Pagination(limit=10),
|
31
22
|
)
|
32
23
|
nkb = NucliaKB()
|
33
|
-
output = nkb.logs.query(type=
|
24
|
+
output = nkb.logs.query(type=EventType.CHAT, query=query)
|
34
25
|
assert len(output.data) == 10
|
35
26
|
assert output.has_more
|
36
27
|
|
@@ -46,24 +37,48 @@ def test_activity_logs_download(testing_config):
|
|
46
37
|
)
|
47
38
|
nkb = NucliaKB()
|
48
39
|
output = nkb.logs.download(
|
49
|
-
type=
|
40
|
+
type=EventType.CHAT, query=query, download_format=DownloadFormat.NDJSON
|
50
41
|
)
|
51
42
|
assert output.request_id
|
52
43
|
assert output.download_url is None
|
53
44
|
|
54
45
|
|
55
46
|
@pytest.mark.asyncio
|
56
|
-
async def
|
47
|
+
async def test_activity_logs_query_async(testing_config):
|
57
48
|
if not IS_PROD:
|
58
49
|
assert True
|
59
50
|
return
|
51
|
+
query = ActivityLogsQuery(
|
52
|
+
year_month="2024-10",
|
53
|
+
show=["id", "date", "client_type", "total_duration"],
|
54
|
+
filters={},
|
55
|
+
pagination=Pagination(limit=10),
|
56
|
+
)
|
60
57
|
nkb = AsyncNucliaKB()
|
61
|
-
|
62
|
-
assert len(
|
58
|
+
output = await nkb.logs.query(type=EventType.CHAT, query=query)
|
59
|
+
assert len(output.data) == 10
|
60
|
+
assert output.has_more
|
63
61
|
|
64
62
|
|
65
63
|
@pytest.mark.asyncio
|
66
|
-
async def
|
64
|
+
async def test_activity_logs_download_async(testing_config):
|
65
|
+
if not IS_PROD:
|
66
|
+
assert True
|
67
|
+
return
|
68
|
+
query = DownloadActivityLogsQuery(
|
69
|
+
year_month="2024-10",
|
70
|
+
show=["id", "date", "client_type", "total_duration"],
|
71
|
+
filters={},
|
72
|
+
)
|
73
|
+
nkb = AsyncNucliaKB()
|
74
|
+
output = await nkb.logs.download(
|
75
|
+
type=EventType.CHAT, query=query, download_format=DownloadFormat.NDJSON
|
76
|
+
)
|
77
|
+
assert output.request_id
|
78
|
+
assert output.download_url is None
|
79
|
+
|
80
|
+
|
81
|
+
def test_activity_logs_ask_query(testing_config):
|
67
82
|
if not IS_PROD:
|
68
83
|
assert True
|
69
84
|
return
|
@@ -73,14 +88,14 @@ async def test_activity_logs_query_async(testing_config):
|
|
73
88
|
filters={},
|
74
89
|
pagination=Pagination(limit=10),
|
75
90
|
)
|
76
|
-
nkb =
|
77
|
-
output =
|
91
|
+
nkb = NucliaKB()
|
92
|
+
output = nkb.logs.query(type=EventType.ASK, query=query)
|
78
93
|
assert len(output.data) == 10
|
79
94
|
assert output.has_more
|
80
95
|
|
81
96
|
|
82
97
|
@pytest.mark.asyncio
|
83
|
-
async def
|
98
|
+
async def test_activity_logs_ask_download_async(testing_config):
|
84
99
|
if not IS_PROD:
|
85
100
|
assert True
|
86
101
|
return
|
@@ -91,7 +106,7 @@ async def test_activity_logs_download_async(testing_config):
|
|
91
106
|
)
|
92
107
|
nkb = AsyncNucliaKB()
|
93
108
|
output = await nkb.logs.download(
|
94
|
-
type=
|
109
|
+
type=EventType.ASK, query=query, download_format=DownloadFormat.NDJSON
|
95
110
|
)
|
96
111
|
assert output.request_id
|
97
112
|
assert output.download_url is None
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: nuclia
|
3
|
-
Version: 4.
|
3
|
+
Version: 4.9.0
|
4
4
|
Summary: Nuclia Python SDK
|
5
5
|
Author-email: Nuclia <info@nuclia.com>
|
6
6
|
License-Expression: MIT
|
@@ -24,9 +24,9 @@ Requires-Dist: requests
|
|
24
24
|
Requires-Dist: httpx
|
25
25
|
Requires-Dist: httpcore>=1.0.0
|
26
26
|
Requires-Dist: prompt_toolkit
|
27
|
-
Requires-Dist: nucliadb_sdk<7,>=6.
|
28
|
-
Requires-Dist: nucliadb_models<7,>=6.
|
29
|
-
Requires-Dist: nuclia-models>=0.
|
27
|
+
Requires-Dist: nucliadb_sdk<7,>=6.5
|
28
|
+
Requires-Dist: nucliadb_models<7,>=6.5
|
29
|
+
Requires-Dist: nuclia-models>=0.41.1
|
30
30
|
Requires-Dist: tqdm
|
31
31
|
Requires-Dist: aiofiles
|
32
32
|
Requires-Dist: backoff
|
@@ -9,8 +9,8 @@ nuclia/cli/run.py,sha256=B1hP0upSbSCqqT89WAwsd93ZxkAoF6ajVyLOdYmo8fU,1560
|
|
9
9
|
nuclia/cli/utils.py,sha256=iZ3P8juBdAGvaRUd2BGz7bpUXNDHdPrC5p876yyZ2Cs,1223
|
10
10
|
nuclia/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
11
|
nuclia/lib/conversations.py,sha256=M6qhL9NPEKroYF767S-Q2XWokRrjX02kpYTzRvZKwUE,149
|
12
|
-
nuclia/lib/kb.py,sha256=
|
13
|
-
nuclia/lib/models.py,sha256=
|
12
|
+
nuclia/lib/kb.py,sha256=jV-L8-a5oFVHIbFfeGO17hXf2IQk9UuW-9fq5D3LO6Y,28508
|
13
|
+
nuclia/lib/models.py,sha256=ekEQrVIFU3aFvt60yQh-zpWkGNORBMSc7c5Hd_VzPzI,1564
|
14
14
|
nuclia/lib/nua.py,sha256=sUVFdCjvLigTqUUhILywdHpiC0qKCtKPABn5kUXfuxQ,27064
|
15
15
|
nuclia/lib/nua_chat.py,sha256=ApL1Y1FWvAVUt-Y9a_8TUSJIhg8-UmBSy8TlDPn6tD8,3874
|
16
16
|
nuclia/lib/nua_responses.py,sha256=9WRGpvvhA2ZOyOv9kzX1zI7C3ypM8ySqciVYCSibUjo,12724
|
@@ -24,27 +24,27 @@ nuclia/sdk/export_import.py,sha256=y5cTOxhILwRPIvR2Ya12bk-ReGbeDzA3C9TPxgnOHD4,9
|
|
24
24
|
nuclia/sdk/kb.py,sha256=iDJimbzw_R9VeUu7a4F5wXoLdLxCim7W3UeEaAQ5dGI,26820
|
25
25
|
nuclia/sdk/kbs.py,sha256=nXEvg5ddZYdDS8Kie7TrN-s1meU9ecYLf9FlT5xr-ro,9131
|
26
26
|
nuclia/sdk/logger.py,sha256=UHB81eS6IGmLrsofKxLh8cmF2AsaTj_HXP0tGqMr_HM,57
|
27
|
-
nuclia/sdk/logs.py,sha256=
|
27
|
+
nuclia/sdk/logs.py,sha256=3jfORpo8fzZiXFFSbGY0o3Bre1ZgJaKQCXgxP1keNHw,9614
|
28
28
|
nuclia/sdk/nua.py,sha256=6t0m0Sx-UhqNU2Hx9v6vTwy0m3a30K4T0KmP9G43MzY,293
|
29
29
|
nuclia/sdk/nucliadb.py,sha256=bOESIppPgY7IrNqrYY7T3ESoxwttbOSTm5zj1xUS1jI,1288
|
30
30
|
nuclia/sdk/predict.py,sha256=KF7iT2aasaB9DIEAwqktXbOl2H_Y_ne-6-SEErN7YOk,9095
|
31
31
|
nuclia/sdk/process.py,sha256=WuNnqaWprp-EABWDC_z7O2woesGIlYWnDUKozh7Ibr4,2241
|
32
32
|
nuclia/sdk/remi.py,sha256=BEb3O9R2jOFlOda4vjFucKKGO1c2eTkqYZdFlIy3Zmo,4357
|
33
33
|
nuclia/sdk/resource.py,sha256=0lSvD4e1FpN5iM9W295dOKLJ8hsXfIe8HKdo0HsVg20,13976
|
34
|
-
nuclia/sdk/search.py,sha256=
|
34
|
+
nuclia/sdk/search.py,sha256=1mLJzDO-W3ObReDL1xK8zgjIxkdpuIhyf87-L4bISKQ,25180
|
35
35
|
nuclia/sdk/task.py,sha256=UawH-7IneRIGVOiLdDQ2vDBwe5eI51UXRbLRRVeu3C4,6095
|
36
36
|
nuclia/sdk/upload.py,sha256=ZBzYROF3yP-77HcaR06OBsFjJAbTOCvF-nlxaqQZsT4,22720
|
37
37
|
nuclia/sdk/zones.py,sha256=1ARWrTsTuzj8zguanpX3OaIw-3Qq_ULS_g4GG2mHxOA,342
|
38
38
|
nuclia/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
39
39
|
nuclia/tests/conftest.py,sha256=-Gv9Q20tBVQNNWqWHGNmzkXJpijmgTdcvNnaRAUluGk,115
|
40
|
-
nuclia/tests/fixtures.py,sha256=
|
40
|
+
nuclia/tests/fixtures.py,sha256=rcGGbtxQbGK9vR9efL7BsE1ugJl15QQDIxUyFZLfv-E,1795
|
41
41
|
nuclia/tests/assets/conversation.json,sha256=jLmVngHEW8QdAzSMa-MYgbJgYxOO8tHq6Ia029-CD0E,348
|
42
42
|
nuclia/tests/test_kb/test_backup.py,sha256=67fAw1C_NB363G-wuI9LnSH6nG_YrYs-uBcFyBx6Peg,2932
|
43
|
-
nuclia/tests/test_kb/test_conversation.py,sha256=
|
43
|
+
nuclia/tests/test_kb/test_conversation.py,sha256=plsWY_gEhK3P4CsIO9jkBmimZk3UDGeMYPu7YVFeuIQ,727
|
44
44
|
nuclia/tests/test_kb/test_export_import.py,sha256=lQEww2jFNHZYcudFJqcHhoWAPrmtvvnPvcFqrijxLbo,1019
|
45
|
-
nuclia/tests/test_kb/test_graph.py,sha256=
|
45
|
+
nuclia/tests/test_kb/test_graph.py,sha256=ecAB-lWqm3_796HUuF-fSpGzlhsXV9NGZnAjvxXANps,2540
|
46
46
|
nuclia/tests/test_kb/test_labels.py,sha256=IUdTq4mzv0OrOkwBWWy4UwKGKyJybtoHrgvXr676vyY,961
|
47
|
-
nuclia/tests/test_kb/test_logs.py,sha256=
|
47
|
+
nuclia/tests/test_kb/test_logs.py,sha256=Z9ELtiiU9NniITJzeWt92GCcERKYy9Nwc_fUVPboRU0,3121
|
48
48
|
nuclia/tests/test_kb/test_remi.py,sha256=OX5N-MHbgcwpLg6fBjrAK_KhqkMspJo_VKQHCBCayZ8,2080
|
49
49
|
nuclia/tests/test_kb/test_resource.py,sha256=05Xgmg5fwcPW2PZKnUSSjr6MPXp5w8XDgx8plfNcR68,1102
|
50
50
|
nuclia/tests/test_kb/test_search.py,sha256=bsQhfB6-NYFwY3gqkrVJJnru153UgZqEhV22ho4VeWM,4660
|
@@ -61,9 +61,9 @@ nuclia/tests/test_nucliadb/test_crud.py,sha256=GuY76HRvt2DFaNgioKm5n0Aco1HnG7zzV
|
|
61
61
|
nuclia/tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
62
62
|
nuclia/tests/unit/test_export_import.py,sha256=xo_wVbjUnNlVV65ZGH7LtZ38qy39EkJp2hjOuTHC1nU,980
|
63
63
|
nuclia/tests/unit/test_nua_responses.py,sha256=t_hIdVztTi27RWvpfTJUYcCL0lpKdZFegZIwLdaPNh8,319
|
64
|
-
nuclia-4.
|
65
|
-
nuclia-4.
|
66
|
-
nuclia-4.
|
67
|
-
nuclia-4.
|
68
|
-
nuclia-4.
|
69
|
-
nuclia-4.
|
64
|
+
nuclia-4.9.0.dist-info/licenses/LICENSE,sha256=Ops2LTti_HJtpmWcanuUTdTY3vKDR1myJ0gmGBKC0FA,1063
|
65
|
+
nuclia-4.9.0.dist-info/METADATA,sha256=ZHT0wCR1AhZtfnWdcD-uSmfNkb8QznVDuWRt_2f6yP8,2337
|
66
|
+
nuclia-4.9.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
67
|
+
nuclia-4.9.0.dist-info/entry_points.txt,sha256=iZHOyXPNS54r3eQmdi5So20xO1gudI9K2oP4sQsCJRw,46
|
68
|
+
nuclia-4.9.0.dist-info/top_level.txt,sha256=cqn_EitXOoXOSUvZnd4q6QGrhm04pg8tLAZtem-Zfdo,7
|
69
|
+
nuclia-4.9.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|