nuclia 4.8.8__tar.gz → 4.8.10__tar.gz

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.
Files changed (98) hide show
  1. {nuclia-4.8.8 → nuclia-4.8.10}/CHANGELOG.md +12 -0
  2. nuclia-4.8.10/Makefile +12 -0
  3. {nuclia-4.8.8 → nuclia-4.8.10}/PKG-INFO +2 -2
  4. nuclia-4.8.10/VERSION +1 -0
  5. {nuclia-4.8.8 → nuclia-4.8.10}/docs/11-activity-log.md +13 -15
  6. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/lib/kb.py +43 -127
  7. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/lib/utils.py +57 -14
  8. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/sdk/logs.py +25 -59
  9. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/test_kb/test_logs.py +35 -20
  10. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia.egg-info/PKG-INFO +2 -2
  11. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia.egg-info/SOURCES.txt +0 -3
  12. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia.egg-info/requires.txt +1 -1
  13. {nuclia-4.8.8 → nuclia-4.8.10}/pyproject.toml +21 -1
  14. {nuclia-4.8.8 → nuclia-4.8.10}/uv.lock +890 -6
  15. nuclia-4.8.8/Makefile +0 -19
  16. nuclia-4.8.8/VERSION +0 -1
  17. nuclia-4.8.8/code-requirements.txt +0 -2
  18. nuclia-4.8.8/requirements.txt +0 -16
  19. nuclia-4.8.8/test-requirements.txt +0 -10
  20. {nuclia-4.8.8 → nuclia-4.8.10}/.gitignore +0 -0
  21. {nuclia-4.8.8 → nuclia-4.8.10}/LICENSE +0 -0
  22. {nuclia-4.8.8 → nuclia-4.8.10}/MANIFEST.in +0 -0
  23. {nuclia-4.8.8 → nuclia-4.8.10}/README.md +0 -0
  24. {nuclia-4.8.8 → nuclia-4.8.10}/docs/01-README.md +0 -0
  25. {nuclia-4.8.8 → nuclia-4.8.10}/docs/02-auth.md +0 -0
  26. {nuclia-4.8.8 → nuclia-4.8.10}/docs/03-kb.md +0 -0
  27. {nuclia-4.8.8 → nuclia-4.8.10}/docs/04-upload.md +0 -0
  28. {nuclia-4.8.8 → nuclia-4.8.10}/docs/05-search.md +0 -0
  29. {nuclia-4.8.8 → nuclia-4.8.10}/docs/06-read.md +0 -0
  30. {nuclia-4.8.8 → nuclia-4.8.10}/docs/07-nua.md +0 -0
  31. {nuclia-4.8.8 → nuclia-4.8.10}/docs/08-import-export.md +0 -0
  32. {nuclia-4.8.8 → nuclia-4.8.10}/docs/09-kb-backup.md +0 -0
  33. {nuclia-4.8.8 → nuclia-4.8.10}/docs/10-manage.md +0 -0
  34. {nuclia-4.8.8 → nuclia-4.8.10}/docs/12-da-agents.md +0 -0
  35. {nuclia-4.8.8 → nuclia-4.8.10}/docs/13-ai-agents.md +0 -0
  36. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/__init__.py +0 -0
  37. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/cli/__init__.py +0 -0
  38. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/cli/run.py +0 -0
  39. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/cli/utils.py +0 -0
  40. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/config.py +0 -0
  41. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/data.py +0 -0
  42. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/decorators.py +0 -0
  43. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/exceptions.py +0 -0
  44. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/lib/__init__.py +0 -0
  45. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/lib/conversations.py +0 -0
  46. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/lib/models.py +0 -0
  47. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/lib/nua.py +0 -0
  48. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/lib/nua_chat.py +0 -0
  49. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/lib/nua_responses.py +0 -0
  50. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/py.typed +0 -0
  51. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/sdk/__init__.py +0 -0
  52. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/sdk/accounts.py +0 -0
  53. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/sdk/agent.py +0 -0
  54. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/sdk/auth.py +0 -0
  55. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/sdk/backup.py +0 -0
  56. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/sdk/export_import.py +0 -0
  57. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/sdk/kb.py +0 -0
  58. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/sdk/kbs.py +0 -0
  59. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/sdk/logger.py +0 -0
  60. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/sdk/nua.py +0 -0
  61. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/sdk/nucliadb.py +0 -0
  62. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/sdk/predict.py +0 -0
  63. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/sdk/process.py +0 -0
  64. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/sdk/remi.py +0 -0
  65. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/sdk/resource.py +0 -0
  66. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/sdk/search.py +0 -0
  67. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/sdk/task.py +0 -0
  68. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/sdk/upload.py +0 -0
  69. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/sdk/zones.py +0 -0
  70. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/__init__.py +0 -0
  71. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/assets/conversation.json +0 -0
  72. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/conftest.py +0 -0
  73. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/fixtures.py +0 -0
  74. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/test_kb/test_backup.py +0 -0
  75. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/test_kb/test_conversation.py +0 -0
  76. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/test_kb/test_export_import.py +0 -0
  77. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/test_kb/test_graph.py +0 -0
  78. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/test_kb/test_labels.py +0 -0
  79. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/test_kb/test_remi.py +0 -0
  80. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/test_kb/test_resource.py +0 -0
  81. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/test_kb/test_search.py +0 -0
  82. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/test_kb/test_tasks.py +0 -0
  83. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/test_manage/__init__.py +0 -0
  84. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/test_manage/test_account.py +0 -0
  85. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/test_manage/test_auth.py +0 -0
  86. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/test_manage/test_kb.py +0 -0
  87. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/test_nua/__init__.py +0 -0
  88. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/test_nua/test_agent.py +0 -0
  89. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/test_nua/test_predict.py +0 -0
  90. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/test_nucliadb/__init__.py +0 -0
  91. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/test_nucliadb/test_crud.py +0 -0
  92. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/unit/__init__.py +0 -0
  93. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/unit/test_export_import.py +0 -0
  94. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia/tests/unit/test_nua_responses.py +0 -0
  95. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia.egg-info/dependency_links.txt +0 -0
  96. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia.egg-info/entry_points.txt +0 -0
  97. {nuclia-4.8.8 → nuclia-4.8.10}/nuclia.egg-info/top_level.txt +0 -0
  98. {nuclia-4.8.8 → nuclia-4.8.10}/setup.cfg +0 -0
@@ -1,6 +1,18 @@
1
1
  # Changelog
2
2
 
3
3
 
4
+ ## 4.8.10 (2025-05-28)
5
+
6
+
7
+ - Activity logs: Add event type `ASK` and deprecate `CHAT`
8
+
9
+
10
+ ## 4.8.9 (2025-05-15)
11
+
12
+
13
+ - Better http error handling
14
+
15
+
4
16
  ## 4.8.8 (2025-05-14)
5
17
 
6
18
 
nuclia-4.8.10/Makefile ADDED
@@ -0,0 +1,12 @@
1
+ lint:
2
+ ruff check nuclia
3
+ ruff format --check nuclia
4
+ mypy nuclia
5
+
6
+ fmt:
7
+ ruff check --fix nuclia
8
+ ruff format nuclia
9
+
10
+ test:
11
+ mypy nuclia
12
+ pytest --asyncio-mode=auto nuclia
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nuclia
3
- Version: 4.8.8
3
+ Version: 4.8.10
4
4
  Summary: Nuclia Python SDK
5
5
  Author-email: Nuclia <info@nuclia.com>
6
6
  License-Expression: MIT
@@ -26,7 +26,7 @@ Requires-Dist: httpcore>=1.0.0
26
26
  Requires-Dist: prompt_toolkit
27
27
  Requires-Dist: nucliadb_sdk<7,>=6.4
28
28
  Requires-Dist: nucliadb_models<7,>=6.4
29
- Requires-Dist: nuclia-models>=0.38.1
29
+ Requires-Dist: nuclia-models>=0.41.1
30
30
  Requires-Dist: tqdm
31
31
  Requires-Dist: aiofiles
32
32
  Requires-Dist: backoff
nuclia-4.8.10/VERSION ADDED
@@ -0,0 +1 @@
1
+ 4.8.10
@@ -35,7 +35,7 @@ See the examples for more information
35
35
 
36
36
  #### Event-Specific Fields
37
37
  - `SEARCH` events: Common fields + `question`, `resources_count`, `filter`, `learning_id`
38
- - `CHAT` events: Common fields + Search fields + `rephrased_question`, `answer`, `retrieved_context`, `chat_history`, `feedback_good`, `feedback_comment`, `model`, `rag_strategies_names`, `rag_strategies`, `status`, `time_to_first_char`
38
+ - `ASK` events: Common fields + Search fields + `rephrased_question`, `answer`, `retrieved_context`, `chat_history`, `feedback_good`, `feedback_comment`, `model`, `rag_strategies_names`, `rag_strategies`, `status`, `time_to_first_char`
39
39
 
40
40
 
41
41
  ### Query Examples
@@ -43,7 +43,7 @@ See the examples for more information
43
43
  #### CLI Example
44
44
 
45
45
  ```bash
46
- nuclia kb logs query --type=CHAT --query='{
46
+ nuclia kb logs query --type=ASK --query='{
47
47
  "year_month": "2024-10",
48
48
  "show": ["id", "date", "question", "answer", "feedback_good"],
49
49
  "filters": {
@@ -58,11 +58,10 @@ nuclia kb logs query --type=CHAT --query='{
58
58
 
59
59
  ```python
60
60
  from nuclia import sdk
61
- from nuclia.lib.kb import LogType
62
- from nuclia_models.events.activity_logs import ActivityLogsChatQuery, Pagination
61
+ from nuclia_models.events.activity_logs import ActivityLogsAskQuery, EventType, Pagination
63
62
 
64
63
  kb = sdk.NucliaKB()
65
- query = ActivityLogsChatQuery(
64
+ query = ActivityLogsAskQuery(
66
65
  year_month="2024-10",
67
66
  show=["id", "date", "question", "answer"],
68
67
  filters={
@@ -71,7 +70,7 @@ query = ActivityLogsChatQuery(
71
70
  },
72
71
  pagination=Pagination(limit=10)
73
72
  )
74
- kb.logs.query(type=LogType.CHAT, query=query)
73
+ kb.logs.query(type=EventType.ASK, query=query)
75
74
  ```
76
75
  ### Special Field: `audit_metadata`
77
76
  The `audit_metadata` field is a customizable dictionary. Use the `key` operator to target specific keys within the dictionary.
@@ -103,7 +102,7 @@ The `audit_metadata` field is a customizable dictionary. Use the `key` operator
103
102
  Request download and wait until the download url is generated
104
103
 
105
104
  ```bash
106
- >>> nuclia kb logs download --wait --type=CHAT --format=NDJSON --query='{
105
+ >>> nuclia kb logs download --wait --type=ASK --format=NDJSON --query='{
107
106
  "year_month": "2024-10",
108
107
  "show": ["id", "date", "question", "answer", "feedback_good"],
109
108
  "filters": {
@@ -119,7 +118,7 @@ download_url=https://your-download-url
119
118
 
120
119
  Request download and ask to be notified
121
120
  ```bash
122
- >>> nuclia kb logs download --type=CHAT --format=NDJSON --query='{
121
+ >>> nuclia kb logs download --type=ASK --format=NDJSON --query='{
123
122
  "year_month": "2024-10",
124
123
  "show": ["id", "date", "question", "answer", "feedback_good"],
125
124
  "filters": {
@@ -136,7 +135,7 @@ download_url=null
136
135
  ```
137
136
  Request download and poll for the status
138
137
  ```bash
139
- >>> nuclia kb logs download --type=CHAT --format=NDJSON --query='{
138
+ >>> nuclia kb logs download --type=ASK --format=NDJSON --query='{
140
139
  "year_month": "2024-10",
141
140
  "show": ["id", "date", "question", "answer", "feedback_good"],
142
141
  "filters": {
@@ -159,11 +158,10 @@ download_url=https://your-download-url
159
158
 
160
159
  ```python
161
160
  from nuclia import sdk
162
- from nuclia.lib.kb import LogType
163
- from nuclia_models.events.activity_logs import DownloadActivityLogsChatQuery
161
+ from nuclia_models.events.activity_logs import DownloadActivityLogsAskQuery, EventType
164
162
 
165
163
  kb = sdk.NucliaKB()
166
- query = DownloadActivityLogsChatQuery(
164
+ query = DownloadActivityLogsAskQuery(
167
165
  year_month="2024-10",
168
166
  show=["id", "date", "question", "answer"],
169
167
  filters={
@@ -171,7 +169,7 @@ query = DownloadActivityLogsChatQuery(
171
169
  "feedback_good": {"eq": True}
172
170
  },
173
171
  )
174
- request = kb.logs.download(type=LogType.CHAT, query=query, wait=True)
172
+ request = kb.logs.download(type=EventType.ASK, query=query, wait=True)
175
173
  return request.download_url
176
174
  ```
177
175
 
@@ -182,7 +180,7 @@ The REMi module provides tools to monitor the quality of your RAG pipeline to ge
182
180
 
183
181
  ## REMi Query
184
182
 
185
- Use `remi query` to retrieve a list of chat activity logs that match specified criteria for REMi scores.
183
+ Use `remi query` to retrieve a list of ask activity logs that match specified criteria for REMi scores.
186
184
 
187
185
  ### Basic Query
188
186
 
@@ -284,7 +282,7 @@ kb.remi.query(
284
282
 
285
283
  ### REMi Get
286
284
 
287
- Use `remi get_event` to fetch detailed information for a specific chat activity log. This command is useful for retrieving full context and score details of an entry obtained from a previous REMi query.
285
+ Use `remi get_event` to fetch detailed information for a specific ask activity log. This command is useful for retrieving full context and score details of an entry obtained from a previous REMi query.
288
286
 
289
287
  #### CLI Example
290
288
  ```bash
@@ -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,17 +14,17 @@ from tqdm import tqdm
15
14
  from nuclia_models.events.activity_logs import ( # type: ignore
16
15
  ActivityLogsQuery,
17
16
  ActivityLogsSearchQuery,
18
- ActivityLogsChatQuery,
17
+ ActivityLogsAskQuery,
19
18
  DownloadActivityLogsQuery,
20
19
  DownloadActivityLogsSearchQuery,
21
- DownloadActivityLogsChatQuery,
20
+ DownloadActivityLogsAskQuery,
22
21
  EventType,
23
22
  DownloadFormat,
24
23
  )
25
24
  from nuclia_models.events.remi import RemiQuery
26
25
  from nuclia_models.worker.tasks import TaskStartKB
27
26
  from nuclia.exceptions import RateLimitError
28
- from nuclia.lib.utils import handle_http_errors
27
+ from nuclia.lib.utils import handle_http_sync_errors, handle_http_async_errors
29
28
  from datetime import datetime
30
29
  from nuclia.lib.utils import build_httpx_client, build_httpx_async_client, USER_AGENT
31
30
 
@@ -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
@@ -220,7 +200,7 @@ class NucliaDBClient(BaseNucliaDBClient):
220
200
  raise Exception("KB not configured")
221
201
  url = f"{self.url}{NOTIFICATIONS}"
222
202
  response = self.stream_session.get(url, stream=True, timeout=3660)
223
- handle_http_errors(response)
203
+ handle_http_sync_errors(response)
224
204
  return response
225
205
 
226
206
  def ask(self, request: AskRequest, timeout: int = 1000):
@@ -233,7 +213,7 @@ class NucliaDBClient(BaseNucliaDBClient):
233
213
  stream=True,
234
214
  timeout=timeout,
235
215
  )
236
- handle_http_errors(response)
216
+ handle_http_sync_errors(response)
237
217
  return response
238
218
 
239
219
  def download_export(self, export_id: str, path: str, chunk_size: int):
@@ -276,7 +256,7 @@ class NucliaDBClient(BaseNucliaDBClient):
276
256
  new_uri = "/".join(uri_parts[3:])
277
257
  url = DOWNLOAD_URL.format(uri=new_uri)
278
258
  response: httpx.Response = self.reader_session.get(url)
279
- handle_http_errors(response)
259
+ handle_http_sync_errors(response)
280
260
  return response.content
281
261
 
282
262
  @backoff.on_exception(
@@ -320,7 +300,7 @@ class NucliaDBClient(BaseNucliaDBClient):
320
300
  headers["x-extract-strategy"] = extract_strategy
321
301
 
322
302
  response: httpx.Response = self.writer_session.post(url, headers=headers)
323
- handle_http_errors(response)
303
+ handle_http_sync_errors(response)
324
304
  return response.headers.get("Location")
325
305
 
326
306
  def patch_tus_upload(self, upload_url: str, data: bytes, offset: int) -> int:
@@ -338,7 +318,7 @@ class NucliaDBClient(BaseNucliaDBClient):
338
318
  response: httpx.Response = self.writer_session.patch(
339
319
  url, headers=headers, content=data
340
320
  )
341
- handle_http_errors(response)
321
+ handle_http_sync_errors(response)
342
322
  return int(response.headers.get("Upload-Offset"))
343
323
 
344
324
  def summarize(self, request: SummarizeRequest, timeout: int = 1000):
@@ -349,44 +329,13 @@ class NucliaDBClient(BaseNucliaDBClient):
349
329
  response = self.reader_session.post(
350
330
  url, json=request.model_dump(), timeout=timeout
351
331
  )
352
- handle_http_errors(response)
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_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_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, ActivityLogsChatQuery],
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")
@@ -396,7 +345,7 @@ class NucliaDBClient(BaseNucliaDBClient):
396
345
  json=query.model_dump(mode="json", exclude_unset=True),
397
346
  stream=True,
398
347
  )
399
- handle_http_errors(response)
348
+ handle_http_sync_errors(response)
400
349
  return response
401
350
 
402
351
  def logs_download(
@@ -405,7 +354,7 @@ class NucliaDBClient(BaseNucliaDBClient):
405
354
  query: Union[
406
355
  DownloadActivityLogsQuery,
407
356
  DownloadActivityLogsSearchQuery,
408
- DownloadActivityLogsChatQuery,
357
+ DownloadActivityLogsAskQuery,
409
358
  ],
410
359
  download_format: DownloadFormat,
411
360
  ):
@@ -420,7 +369,7 @@ class NucliaDBClient(BaseNucliaDBClient):
420
369
  json=query.model_dump(mode="json", exclude_unset=True),
421
370
  headers={"accept": format_header_value},
422
371
  )
423
- handle_http_errors(response)
372
+ handle_http_sync_errors(response)
424
373
  return response
425
374
 
426
375
  def get_download_request(
@@ -431,7 +380,7 @@ class NucliaDBClient(BaseNucliaDBClient):
431
380
  raise Exception("KB not configured")
432
381
  download_request_url = f"{self.url}{ACTIVITY_LOG_DOWNLOAD_REQUEST_URL.format(request_id=request_id)}"
433
382
  response: httpx.Response = self.reader_session.get(download_request_url)
434
- handle_http_errors(response)
383
+ handle_http_sync_errors(response)
435
384
  return response
436
385
 
437
386
  def remi_query(
@@ -446,7 +395,7 @@ class NucliaDBClient(BaseNucliaDBClient):
446
395
  json=query.model_dump(mode="json", exclude_unset=True),
447
396
  timeout=10,
448
397
  )
449
- handle_http_errors(response)
398
+ handle_http_sync_errors(response)
450
399
  return response
451
400
 
452
401
  def get_remi_event(
@@ -459,7 +408,7 @@ class NucliaDBClient(BaseNucliaDBClient):
459
408
  response: httpx.Response = self.reader_session.get(
460
409
  f"{self.url}{REMI_EVENT_URL.format(event_id=event_id)}"
461
410
  )
462
- handle_http_errors(response)
411
+ handle_http_sync_errors(response)
463
412
  return response
464
413
 
465
414
  def get_remi_scores(
@@ -476,7 +425,7 @@ class NucliaDBClient(BaseNucliaDBClient):
476
425
  response: httpx.Response = self.reader_session.get(
477
426
  f"{self.url}{REMI_SCORES_URL}", params=params, timeout=10
478
427
  )
479
- handle_http_errors(response)
428
+ handle_http_sync_errors(response)
480
429
  return response
481
430
 
482
431
  def list_tasks(self) -> httpx.Response:
@@ -484,7 +433,7 @@ class NucliaDBClient(BaseNucliaDBClient):
484
433
  raise Exception("KB not configured")
485
434
 
486
435
  response: httpx.Response = self.reader_session.get(f"{self.url}{LIST_TASKS}")
487
- handle_http_errors(response)
436
+ handle_http_sync_errors(response)
488
437
  return response
489
438
 
490
439
  def start_task(self, body: TaskStartKB) -> httpx.Response:
@@ -495,7 +444,7 @@ class NucliaDBClient(BaseNucliaDBClient):
495
444
  f"{self.url}{START_TASK}",
496
445
  json=body.model_dump(mode="json", exclude_unset=True),
497
446
  )
498
- handle_http_errors(response)
447
+ handle_http_sync_errors(response)
499
448
  return response
500
449
 
501
450
  def delete_task(self, task_id: str) -> httpx.Response:
@@ -505,7 +454,7 @@ class NucliaDBClient(BaseNucliaDBClient):
505
454
  response: httpx.Response = self.writer_session.delete(
506
455
  f"{self.url}{DELETE_TASK.format(task_id=task_id)}",
507
456
  )
508
- handle_http_errors(response)
457
+ handle_http_sync_errors(response)
509
458
  return response
510
459
 
511
460
  def stop_task(self, task_id: str) -> httpx.Response:
@@ -515,7 +464,7 @@ class NucliaDBClient(BaseNucliaDBClient):
515
464
  response: httpx.Response = self.writer_session.post(
516
465
  f"{self.url}{STOP_TASK.format(task_id=task_id)}",
517
466
  )
518
- handle_http_errors(response)
467
+ handle_http_sync_errors(response)
519
468
  return response
520
469
 
521
470
  def get_task(self, task_id: str) -> httpx.Response:
@@ -525,7 +474,7 @@ class NucliaDBClient(BaseNucliaDBClient):
525
474
  response: httpx.Response = self.reader_session.get(
526
475
  f"{self.url}{GET_TASK.format(task_id=task_id)}",
527
476
  )
528
- handle_http_errors(response)
477
+ handle_http_sync_errors(response)
529
478
  return response
530
479
 
531
480
  def restart_task(self, task_id: str) -> httpx.Response:
@@ -535,7 +484,7 @@ class NucliaDBClient(BaseNucliaDBClient):
535
484
  response: httpx.Response = self.writer_session.post(
536
485
  f"{self.url}{RESTART_TASK.format(task_id=task_id)}",
537
486
  )
538
- handle_http_errors(response)
487
+ handle_http_sync_errors(response)
539
488
  return response
540
489
 
541
490
 
@@ -583,7 +532,7 @@ class AsyncNucliaDBClient(BaseNucliaDBClient):
583
532
  url = f"{self.url}{NOTIFICATIONS}"
584
533
  req = self.reader_session.build_request("GET", url, timeout=3660)
585
534
  response = await self.reader_session.send(req, stream=True)
586
- handle_http_errors(response)
535
+ await handle_http_async_errors(response)
587
536
  return response
588
537
 
589
538
  async def ask(self, request: AskRequest, timeout: int = 1000):
@@ -594,7 +543,7 @@ class AsyncNucliaDBClient(BaseNucliaDBClient):
594
543
  "POST", url, json=request.model_dump(), timeout=timeout
595
544
  )
596
545
  response = await self.reader_session.send(req, stream=True)
597
- handle_http_errors(response)
546
+ await handle_http_async_errors(response)
598
547
  return response
599
548
 
600
549
  async def download_export(self, export_id: str, path: str, chunk_size: int):
@@ -635,7 +584,7 @@ class AsyncNucliaDBClient(BaseNucliaDBClient):
635
584
  new_uri = "/".join(uri_parts[3:])
636
585
  url = DOWNLOAD_URL.format(uri=new_uri)
637
586
  response = await self.reader_session.get(url)
638
- handle_http_errors(response)
587
+ await handle_http_async_errors(response)
639
588
  return response.content
640
589
 
641
590
  @backoff.on_exception(
@@ -679,7 +628,7 @@ class AsyncNucliaDBClient(BaseNucliaDBClient):
679
628
  headers["x-extract-strategy"] = extract_strategy
680
629
 
681
630
  response = await self.writer_session.post(url, headers=headers)
682
- handle_http_errors(response)
631
+ await handle_http_async_errors(response)
683
632
  return response.headers.get("Location")
684
633
 
685
634
  async def patch_tus_upload(self, upload_url: str, data: bytes, offset: int) -> int:
@@ -695,7 +644,7 @@ class AsyncNucliaDBClient(BaseNucliaDBClient):
695
644
  url = httpx.URL("/".join(url.path.split("/")[3:]))
696
645
 
697
646
  response = await self.writer_session.patch(url, headers=headers, content=data)
698
- handle_http_errors(response)
647
+ await handle_http_async_errors(response)
699
648
  return int(response.headers.get("Upload-Offset"))
700
649
 
701
650
  async def summarize(self, request: SummarizeRequest, timeout: int = 1000):
@@ -706,46 +655,13 @@ class AsyncNucliaDBClient(BaseNucliaDBClient):
706
655
  response = await self.reader_session.post(
707
656
  url, json=request.model_dump(), timeout=timeout
708
657
  )
709
- handle_http_errors(response)
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
- handle_http_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
- handle_http_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, ActivityLogsChatQuery],
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")
@@ -754,7 +670,7 @@ class AsyncNucliaDBClient(BaseNucliaDBClient):
754
670
  f"{self.url}{ACTIVITY_LOG_QUERY_URL.format(type=type.value)}",
755
671
  json=query.model_dump(mode="json", exclude_unset=True),
756
672
  )
757
- handle_http_errors(response)
673
+ await handle_http_async_errors(response)
758
674
  return response
759
675
 
760
676
  async def logs_download(
@@ -763,7 +679,7 @@ class AsyncNucliaDBClient(BaseNucliaDBClient):
763
679
  query: Union[
764
680
  DownloadActivityLogsQuery,
765
681
  DownloadActivityLogsSearchQuery,
766
- DownloadActivityLogsChatQuery,
682
+ DownloadActivityLogsAskQuery,
767
683
  ],
768
684
  download_format: DownloadFormat,
769
685
  ):
@@ -778,7 +694,7 @@ class AsyncNucliaDBClient(BaseNucliaDBClient):
778
694
  json=query.model_dump(mode="json", exclude_unset=True),
779
695
  headers={"accept": format_header_value},
780
696
  )
781
- handle_http_errors(response)
697
+ await handle_http_async_errors(response)
782
698
  return response
783
699
 
784
700
  async def get_download_request(
@@ -789,7 +705,7 @@ class AsyncNucliaDBClient(BaseNucliaDBClient):
789
705
  raise Exception("KB not configured")
790
706
  download_request_url = f"{self.url}{ACTIVITY_LOG_DOWNLOAD_REQUEST_URL.format(request_id=request_id)}"
791
707
  response: httpx.Response = await self.reader_session.get(download_request_url)
792
- handle_http_errors(response)
708
+ await handle_http_async_errors(response)
793
709
  return response
794
710
 
795
711
  async def remi_query(
@@ -804,7 +720,7 @@ class AsyncNucliaDBClient(BaseNucliaDBClient):
804
720
  json=query.model_dump(mode="json", exclude_unset=True),
805
721
  timeout=10,
806
722
  )
807
- handle_http_errors(response)
723
+ await handle_http_async_errors(response)
808
724
  return response
809
725
 
810
726
  async def get_remi_event(
@@ -817,7 +733,7 @@ class AsyncNucliaDBClient(BaseNucliaDBClient):
817
733
  response: httpx.Response = await self.reader_session.get(
818
734
  f"{self.url}{REMI_EVENT_URL.format(event_id=event_id)}"
819
735
  )
820
- handle_http_errors(response)
736
+ await handle_http_async_errors(response)
821
737
  return response
822
738
 
823
739
  async def get_remi_scores(
@@ -834,7 +750,7 @@ class AsyncNucliaDBClient(BaseNucliaDBClient):
834
750
  response: httpx.Response = await self.reader_session.get(
835
751
  f"{self.url}{REMI_SCORES_URL}", params=params, timeout=10
836
752
  )
837
- handle_http_errors(response)
753
+ await handle_http_async_errors(response)
838
754
  return response
839
755
 
840
756
  async def list_tasks(self) -> httpx.Response:
@@ -844,7 +760,7 @@ class AsyncNucliaDBClient(BaseNucliaDBClient):
844
760
  response: httpx.Response = await self.reader_session.get(
845
761
  f"{self.url}{LIST_TASKS}"
846
762
  )
847
- handle_http_errors(response)
763
+ await handle_http_async_errors(response)
848
764
  return response
849
765
 
850
766
  async def start_task(self, body: TaskStartKB) -> httpx.Response:
@@ -855,7 +771,7 @@ class AsyncNucliaDBClient(BaseNucliaDBClient):
855
771
  f"{self.url}{START_TASK}",
856
772
  json=body.model_dump(mode="json", exclude_unset=True),
857
773
  )
858
- handle_http_errors(response)
774
+ await handle_http_async_errors(response)
859
775
  return response
860
776
 
861
777
  async def delete_task(self, task_id: str) -> httpx.Response:
@@ -865,7 +781,7 @@ class AsyncNucliaDBClient(BaseNucliaDBClient):
865
781
  response: httpx.Response = await self.writer_session.delete(
866
782
  f"{self.url}{DELETE_TASK.format(task_id=task_id)}",
867
783
  )
868
- handle_http_errors(response)
784
+ await handle_http_async_errors(response)
869
785
  return response
870
786
 
871
787
  async def stop_task(self, task_id: str) -> httpx.Response:
@@ -875,7 +791,7 @@ class AsyncNucliaDBClient(BaseNucliaDBClient):
875
791
  response: httpx.Response = await self.writer_session.post(
876
792
  f"{self.url}{STOP_TASK.format(task_id=task_id)}",
877
793
  )
878
- handle_http_errors(response)
794
+ await handle_http_async_errors(response)
879
795
  return response
880
796
 
881
797
  async def get_task(self, task_id: str) -> httpx.Response:
@@ -885,7 +801,7 @@ class AsyncNucliaDBClient(BaseNucliaDBClient):
885
801
  response: httpx.Response = await self.reader_session.get(
886
802
  f"{self.url}{GET_TASK.format(task_id=task_id)}",
887
803
  )
888
- handle_http_errors(response)
804
+ await handle_http_async_errors(response)
889
805
  return response
890
806
 
891
807
  async def restart_task(self, task_id: str) -> httpx.Response:
@@ -895,5 +811,5 @@ class AsyncNucliaDBClient(BaseNucliaDBClient):
895
811
  response: httpx.Response = await self.writer_session.post(
896
812
  f"{self.url}{RESTART_TASK.format(task_id=task_id)}",
897
813
  )
898
- handle_http_errors(response)
814
+ await handle_http_async_errors(response)
899
815
  return response