deepsights-api 1.2.2__tar.gz → 1.2.4__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.
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/CHANGELOG.md +8 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/PKG-INFO +1 -1
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/api/api.py +53 -8
- deepsights_api-1.2.4/deepsights/contentstore/resources/_download.py +51 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/contentstore/resources/_search.py +23 -15
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/contentstore/resources/news.py +12 -6
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/contentstore/resources/secondary.py +12 -5
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/pyproject.toml +1 -1
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/tests/contentstore/test_news_search.py +31 -31
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/tests/contentstore/test_secondary_search.py +27 -25
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/tests/data/test_data.json +3 -3
- deepsights_api-1.2.4/uv.lock +584 -0
- deepsights_api-1.2.2/uv.lock +0 -248
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/.github/workflows/build_docs.yml +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/.github/workflows/run_pylint.yml +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/.github/workflows/run_tests.yml +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/.gitignore +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/.pylintrc +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/.python-version +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/.vscode/settings.json +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/LICENSE +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/README.md +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/__init__.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/api/__init__.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/api/resource.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/contentstore/__init__.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/contentstore/contentstore.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/contentstore/resources/__init__.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/contentstore/resources/_model.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/deepsights/__init__.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/deepsights/_mip_identity.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/deepsights/deepsights.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/deepsights/resources/__init__.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/deepsights/resources/quota/__init__.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/deepsights/resources/quota/_model.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/deepsights/resources/quota/quota.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/documentstore/__init__.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/documentstore/documentstore.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/documentstore/resources/__init__.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/documentstore/resources/documents/__init__.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/documentstore/resources/documents/_cache.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/documentstore/resources/documents/_delete.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/documentstore/resources/documents/_download.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/documentstore/resources/documents/_list.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/documentstore/resources/documents/_load.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/documentstore/resources/documents/_model.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/documentstore/resources/documents/_search.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/documentstore/resources/documents/_segmenter.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/documentstore/resources/documents/_upload.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/documentstore/resources/documents/documents.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/userclient/__init__.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/userclient/resources/__init__.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/userclient/resources/_model.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/userclient/resources/answersV2/__init__.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/userclient/resources/answersV2/_model.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/userclient/resources/answersV2/answerV2.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/userclient/resources/reports/__init__.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/userclient/resources/reports/_model.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/userclient/resources/reports/report.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/userclient/userclient.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/utils/__init__.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/utils/_cache.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/utils/_ranking.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/utils/_utils.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/utils/model.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/docs/.gitkeep +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/main.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/requirements.txt +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/setup.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/tests/data/test_presentation.pdf +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/tests/data/test_text.txt +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/tests/deepsights/identity/test_mip_identity.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/tests/deepsights/quota/test_quota.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/tests/deepsights/userclient/test_userclient.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/tests/documentstore/test_download.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/tests/documentstore/test_lifecycle.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/tests/documentstore/test_list.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/tests/documentstore/test_load.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/tests/documentstore/test_search.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/tests/userclient/answersV2/test_answersV2.py +0 -0
- {deepsights_api-1.2.2 → deepsights_api-1.2.4}/tests/userclient/reports/test_reports.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deepsights-api
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.4
|
|
4
4
|
Summary: Python library for the DeepSights APIs
|
|
5
5
|
Project-URL: Documentation, https://marketlogicsoftware.github.io/deepsights-api/
|
|
6
6
|
Project-URL: Repository, https://github.com/marketlogicsoftware/deepsights-api
|
|
@@ -16,18 +16,19 @@
|
|
|
16
16
|
This module contains base API client classes.
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
|
-
import os
|
|
20
19
|
import logging
|
|
20
|
+
import os
|
|
21
21
|
from typing import Dict
|
|
22
|
+
|
|
23
|
+
from ratelimit import limits, sleep_and_retry
|
|
24
|
+
from requests import Session
|
|
25
|
+
from requests.exceptions import Timeout
|
|
22
26
|
from tenacity import (
|
|
23
27
|
retry,
|
|
28
|
+
retry_if_exception_type,
|
|
24
29
|
stop_after_attempt,
|
|
25
30
|
wait_random_exponential,
|
|
26
|
-
retry_if_exception_type,
|
|
27
31
|
)
|
|
28
|
-
from requests import Session
|
|
29
|
-
from requests.exceptions import Timeout
|
|
30
|
-
from ratelimit import limits, sleep_and_retry
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
#################################################
|
|
@@ -107,6 +108,50 @@ class API:
|
|
|
107
108
|
|
|
108
109
|
return response.json()
|
|
109
110
|
|
|
111
|
+
#######################################
|
|
112
|
+
@retry(
|
|
113
|
+
stop=stop_after_attempt(3),
|
|
114
|
+
wait=wait_random_exponential(max=5),
|
|
115
|
+
retry=retry_if_exception_type(Timeout),
|
|
116
|
+
)
|
|
117
|
+
@sleep_and_retry
|
|
118
|
+
@limits(calls=1000, period=60)
|
|
119
|
+
def get_content(
|
|
120
|
+
self, path: str, params: Dict = None, timeout=15, expected_statuscodes=[]
|
|
121
|
+
) -> bytes:
|
|
122
|
+
"""
|
|
123
|
+
Sends a GET request to the specified path and returns the raw response content.
|
|
124
|
+
|
|
125
|
+
This method is similar to get() but returns the raw response content instead of parsing it as JSON.
|
|
126
|
+
Useful for downloading binary data like files or images.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
path (str): The path to send the GET request to.
|
|
130
|
+
params (Dict, optional): Optional parameters to include in the request. Defaults to None.
|
|
131
|
+
timeout (int, optional): The timeout in seconds for the request. Defaults to 15.
|
|
132
|
+
expected_statuscodes (List[int], optional): List of expected status codes. Defaults to an empty list.
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
bytes: The raw content of the server's response.
|
|
136
|
+
|
|
137
|
+
Raises:
|
|
138
|
+
HTTPError: If the GET request fails with a non-200 status code and not in the expected_statuscodes list.
|
|
139
|
+
"""
|
|
140
|
+
response = self._session.get(
|
|
141
|
+
self._endpoint(path), params=params, timeout=timeout
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
if (
|
|
145
|
+
response.status_code != 200
|
|
146
|
+
and not response.status_code in expected_statuscodes
|
|
147
|
+
):
|
|
148
|
+
logging.error(
|
|
149
|
+
"GET %s failed with status code %s", path, response.status_code
|
|
150
|
+
)
|
|
151
|
+
response.raise_for_status()
|
|
152
|
+
|
|
153
|
+
return response.content.decode("utf-8")
|
|
154
|
+
|
|
110
155
|
#######################################
|
|
111
156
|
@retry(
|
|
112
157
|
stop=stop_after_attempt(3),
|
|
@@ -208,9 +253,9 @@ class APIKeyAPI(API):
|
|
|
208
253
|
super().__init__(endpoint_base)
|
|
209
254
|
|
|
210
255
|
# set api key
|
|
211
|
-
assert (
|
|
212
|
-
|
|
213
|
-
)
|
|
256
|
+
assert api_key or api_key_env_var, (
|
|
257
|
+
"Must provide either API key or environment variable"
|
|
258
|
+
)
|
|
214
259
|
if not api_key:
|
|
215
260
|
api_key = os.environ.get(api_key_env_var)
|
|
216
261
|
self._api_key = api_key
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Copyright 2024 Market Logic Software AG. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""
|
|
16
|
+
This module contains the base functions to download content from the ContentStore.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import os
|
|
20
|
+
import tempfile
|
|
21
|
+
import urllib.request
|
|
22
|
+
|
|
23
|
+
from deepsights.api import APIResource
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
#################################################
|
|
27
|
+
def contentstore_download(resource: APIResource, item_id: str) -> str:
|
|
28
|
+
"""
|
|
29
|
+
Downloads and returns the extracted text content of an item from the ContentStore.
|
|
30
|
+
|
|
31
|
+
This function retrieves a signed download link for the specified item's extracted text content
|
|
32
|
+
from the ContentStore API, downloads the content to a temporary file, reads the text content,
|
|
33
|
+
and returns it as a string. The temporary file is automatically cleaned up after use.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
resource (APIResource): An instance of the DeepSights API resource used to make API calls
|
|
37
|
+
to the ContentStore service.
|
|
38
|
+
item_id (str): The unique identifier of the item whose content should be downloaded.
|
|
39
|
+
|
|
40
|
+
Raises:
|
|
41
|
+
ValueError: If the download fails for any reason, such as network errors, invalid item ID,
|
|
42
|
+
or issues reading the downloaded content.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
str: The extracted text content of the downloaded item as a string.
|
|
46
|
+
"""
|
|
47
|
+
return str(
|
|
48
|
+
resource.api.get_content(
|
|
49
|
+
f"/item-service/items/{item_id}/_download-content-extracted-text",
|
|
50
|
+
)
|
|
51
|
+
)
|
|
@@ -16,9 +16,11 @@
|
|
|
16
16
|
This module contains the base functions to search the ContentStore.
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
|
-
from typing import List
|
|
20
19
|
from datetime import datetime
|
|
20
|
+
from typing import List
|
|
21
|
+
|
|
21
22
|
from pydantic import BaseModel
|
|
23
|
+
|
|
22
24
|
from deepsights.api import API
|
|
23
25
|
from deepsights.utils import (
|
|
24
26
|
promote_exact_matches,
|
|
@@ -96,9 +98,9 @@ def contentstore_hybrid_search(
|
|
|
96
98
|
assert 0 <= vector_fraction <= 1, "Vector fraction must be between 0 and 1"
|
|
97
99
|
assert 0 <= vector_weight <= 1, "Vector weught must be between 0 and 1"
|
|
98
100
|
assert 0 < max_results <= 250, "Maximum results must be between 1 and 250."
|
|
99
|
-
assert (
|
|
100
|
-
|
|
101
|
-
)
|
|
101
|
+
assert recency_weight is None or 0 <= recency_weight <= 1, (
|
|
102
|
+
"Recency weight must be between 0 and 1."
|
|
103
|
+
)
|
|
102
104
|
|
|
103
105
|
body = {
|
|
104
106
|
"query": query,
|
|
@@ -171,9 +173,9 @@ def contentstore_vector_search(
|
|
|
171
173
|
assert len(query_embedding) == 1536, "The 'query_embedding' must be of length 1536."
|
|
172
174
|
assert 0 <= min_score <= 1, "Minimum score must be between 0 and 1."
|
|
173
175
|
assert 0 < max_results <= 100, "Maximum results must be between 1 and 100."
|
|
174
|
-
assert (
|
|
175
|
-
|
|
176
|
-
)
|
|
176
|
+
assert recency_weight is None or 0 <= recency_weight <= 1, (
|
|
177
|
+
"Recency weight must be between 0 and 1."
|
|
178
|
+
)
|
|
177
179
|
|
|
178
180
|
body = {
|
|
179
181
|
"vector": query_embedding,
|
|
@@ -206,7 +208,7 @@ def contentstore_text_search(
|
|
|
206
208
|
max_results: int = 50,
|
|
207
209
|
offset: int = 0,
|
|
208
210
|
languages: List[str] = None,
|
|
209
|
-
|
|
211
|
+
sort_descending: bool = True,
|
|
210
212
|
search_from_timestamp: datetime = None,
|
|
211
213
|
search_to_timestamp: datetime = None,
|
|
212
214
|
search_only_ai_allowed_content: bool = True,
|
|
@@ -223,7 +225,7 @@ def contentstore_text_search(
|
|
|
223
225
|
max_results (int, optional): The maximum number of results to return. Defaults to 50.
|
|
224
226
|
offset (int, optional): The offset to start the search from. Defaults to 0.
|
|
225
227
|
languages (List[str], optional): The languages to search for. Defaults to None.
|
|
226
|
-
|
|
228
|
+
most_recent_first (bool, optional): Whether to sort results by most recent first. Defaults to True.
|
|
227
229
|
search_from_timestamp (datetime, optional): The start timestamp for the search. Defaults to None.
|
|
228
230
|
search_to_timestamp (datetime, optional): The end timestamp for the search. Defaults to None.
|
|
229
231
|
search_only_ai_allowed_content (bool, optional): Whether to search only AI-allowed content. Defaults to True.
|
|
@@ -233,21 +235,24 @@ def contentstore_text_search(
|
|
|
233
235
|
List[BaseModel]: The re-ranked search results.
|
|
234
236
|
"""
|
|
235
237
|
assert 0 < max_results <= 100, "Maximum results must be between 1 and 100."
|
|
236
|
-
assert (
|
|
237
|
-
recency_weight is None or 0 <= recency_weight <= 1
|
|
238
|
-
), "Recency weight must be between 0 and 1."
|
|
239
238
|
|
|
240
239
|
# force proper empty search
|
|
241
240
|
if query is not None and len(query.strip()) == 0:
|
|
242
241
|
query = None
|
|
243
242
|
|
|
243
|
+
# determine sort order
|
|
244
|
+
if query is not None:
|
|
245
|
+
sort_order = "RELEVANCY_DESC" if sort_descending else "RELEVANCY_ASC"
|
|
246
|
+
else:
|
|
247
|
+
sort_order = "PUBLISHED_AT_DESC" if sort_descending else "PUBLISHED_AT_ASC"
|
|
248
|
+
|
|
244
249
|
body = {
|
|
245
250
|
"query": query,
|
|
246
251
|
"source_items_type": item_type,
|
|
247
252
|
"content_restrictions": "NONE",
|
|
248
253
|
"limit": max_results,
|
|
249
254
|
"offset": offset,
|
|
250
|
-
"sort":
|
|
255
|
+
"sort": sort_order,
|
|
251
256
|
"languages": languages,
|
|
252
257
|
"published_at": _get_time_filter(search_from_timestamp, search_to_timestamp),
|
|
253
258
|
"content_restrictions": (
|
|
@@ -259,5 +264,8 @@ def contentstore_text_search(
|
|
|
259
264
|
# parse
|
|
260
265
|
results = [search_result(i) for i in response["items"]]
|
|
261
266
|
|
|
262
|
-
#
|
|
263
|
-
|
|
267
|
+
# record rank
|
|
268
|
+
for rank, result in enumerate(results):
|
|
269
|
+
result.rank = rank + 1
|
|
270
|
+
|
|
271
|
+
return results
|
|
@@ -16,19 +16,19 @@
|
|
|
16
16
|
This module defines the resource to retrieve news content from the DeepSights API.
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
|
-
from typing import List
|
|
20
19
|
from datetime import datetime
|
|
20
|
+
from typing import List
|
|
21
21
|
|
|
22
22
|
from deepsights.api import APIResource
|
|
23
|
+
from deepsights.contentstore.resources._download import contentstore_download
|
|
23
24
|
from deepsights.contentstore.resources._model import ContentStoreSearchResult
|
|
24
25
|
from deepsights.contentstore.resources._search import (
|
|
26
|
+
contentstore_hybrid_search,
|
|
25
27
|
contentstore_text_search,
|
|
26
28
|
contentstore_vector_search,
|
|
27
|
-
contentstore_hybrid_search,
|
|
28
29
|
)
|
|
29
30
|
|
|
30
31
|
|
|
31
|
-
|
|
32
32
|
#################################################
|
|
33
33
|
class NewsSearchResult(ContentStoreSearchResult):
|
|
34
34
|
"""
|
|
@@ -42,6 +42,12 @@ class NewsResource(APIResource):
|
|
|
42
42
|
Represents a resource for retrieving news articles from the DeepSights content store.
|
|
43
43
|
"""
|
|
44
44
|
|
|
45
|
+
def download(self, item_id: str) -> str:
|
|
46
|
+
"""
|
|
47
|
+
Download the extracted text content of an item from the ContentStore.
|
|
48
|
+
"""
|
|
49
|
+
return contentstore_download(self, item_id)
|
|
50
|
+
|
|
45
51
|
#################################################
|
|
46
52
|
def vector_search(
|
|
47
53
|
self,
|
|
@@ -93,7 +99,7 @@ class NewsResource(APIResource):
|
|
|
93
99
|
max_results: int = 30,
|
|
94
100
|
offset: int = 0,
|
|
95
101
|
languages: List[str] = None,
|
|
96
|
-
|
|
102
|
+
sort_descending: bool = True,
|
|
97
103
|
search_from_timestamp: datetime = None,
|
|
98
104
|
search_to_timestamp: datetime = None,
|
|
99
105
|
):
|
|
@@ -106,7 +112,7 @@ class NewsResource(APIResource):
|
|
|
106
112
|
max_results (int, optional): The maximum number of search results to return. Defaults to 30.
|
|
107
113
|
offset (int, optional): The offset to start the search from. Defaults to 0.
|
|
108
114
|
languages (List[str], optional): The list of languages to search for. Defaults to None.
|
|
109
|
-
|
|
115
|
+
sort_descending (bool, optional): Whether to sort the results in descending order. Defaults to True.
|
|
110
116
|
search_from_timestamp (datetime, optional): The start timestamp for the search. Defaults to None.
|
|
111
117
|
search_to_timestamp (datetime, optional): The end timestamp for the search. Defaults to None.
|
|
112
118
|
|
|
@@ -122,7 +128,7 @@ class NewsResource(APIResource):
|
|
|
122
128
|
),
|
|
123
129
|
query=query,
|
|
124
130
|
max_results=max_results,
|
|
125
|
-
|
|
131
|
+
sort_descending=sort_descending,
|
|
126
132
|
languages=languages,
|
|
127
133
|
offset=offset,
|
|
128
134
|
search_from_timestamp=search_from_timestamp,
|
{deepsights_api-1.2.2 → deepsights_api-1.2.4}/deepsights/contentstore/resources/secondary.py
RENAMED
|
@@ -16,15 +16,16 @@
|
|
|
16
16
|
This module contains the resource to retrieve secondary reports from the DeepSights content store.
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
|
-
from typing import List
|
|
20
19
|
from datetime import datetime
|
|
20
|
+
from typing import List
|
|
21
21
|
|
|
22
22
|
from deepsights.api import APIResource
|
|
23
|
+
from deepsights.contentstore.resources._download import contentstore_download
|
|
23
24
|
from deepsights.contentstore.resources._model import ContentStoreSearchResult
|
|
24
25
|
from deepsights.contentstore.resources._search import (
|
|
26
|
+
contentstore_hybrid_search,
|
|
25
27
|
contentstore_text_search,
|
|
26
28
|
contentstore_vector_search,
|
|
27
|
-
contentstore_hybrid_search,
|
|
28
29
|
)
|
|
29
30
|
|
|
30
31
|
|
|
@@ -41,6 +42,12 @@ class SecondaryResource(APIResource):
|
|
|
41
42
|
Represents a resource for retrieving secondary reports from the DeepSights content store.
|
|
42
43
|
"""
|
|
43
44
|
|
|
45
|
+
def download(self, item_id: str) -> str:
|
|
46
|
+
"""
|
|
47
|
+
Download the extracted text content of an item from the ContentStore.
|
|
48
|
+
"""
|
|
49
|
+
return contentstore_download(self, item_id)
|
|
50
|
+
|
|
44
51
|
#################################################
|
|
45
52
|
def vector_search(
|
|
46
53
|
self,
|
|
@@ -92,7 +99,7 @@ class SecondaryResource(APIResource):
|
|
|
92
99
|
max_results: int = 50,
|
|
93
100
|
offset: int = 0,
|
|
94
101
|
languages: List[str] = None,
|
|
95
|
-
|
|
102
|
+
sort_descending: bool = True,
|
|
96
103
|
search_from_timestamp: datetime = None,
|
|
97
104
|
search_to_timestamp: datetime = None,
|
|
98
105
|
):
|
|
@@ -105,7 +112,7 @@ class SecondaryResource(APIResource):
|
|
|
105
112
|
max_results (int, optional): The maximum number of search results to return. Defaults to 50.
|
|
106
113
|
offset (int, optional): The offset to start the search from. Defaults to 0.
|
|
107
114
|
languages (List[str], optional): The languages to search for. Defaults to None.
|
|
108
|
-
|
|
115
|
+
sort_descending (bool, optional): Whether to sort the results in descending order. Defaults to True.
|
|
109
116
|
search_from_timestamp (datetime, optional): The start timestamp for the search. Defaults to None.
|
|
110
117
|
search_to_timestamp (datetime, optional): The end timestamp for the search. Defaults to None.
|
|
111
118
|
|
|
@@ -123,7 +130,7 @@ class SecondaryResource(APIResource):
|
|
|
123
130
|
max_results=max_results,
|
|
124
131
|
offset=offset,
|
|
125
132
|
languages=languages,
|
|
126
|
-
|
|
133
|
+
sort_descending=sort_descending,
|
|
127
134
|
search_from_timestamp=search_from_timestamp,
|
|
128
135
|
search_to_timestamp=search_to_timestamp,
|
|
129
136
|
)
|
|
@@ -79,6 +79,17 @@ def test_news_text_empty_search():
|
|
|
79
79
|
assert result.publication_date <= results[ix - 1].publication_date
|
|
80
80
|
|
|
81
81
|
|
|
82
|
+
def test_news_download():
|
|
83
|
+
""" """
|
|
84
|
+
results = ds.contentstore.news.text_search(
|
|
85
|
+
query="",
|
|
86
|
+
max_results=1,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
content = ds.contentstore.news.download(results[0].id)
|
|
90
|
+
assert len(content) > 0
|
|
91
|
+
|
|
92
|
+
|
|
82
93
|
def test_news_text_search_offset():
|
|
83
94
|
"""
|
|
84
95
|
Test the news text search function with an offset.
|
|
@@ -152,51 +163,43 @@ def test_news_text_search_with_date():
|
|
|
152
163
|
assert result.publication_date <= end and result.publication_date >= start
|
|
153
164
|
|
|
154
165
|
|
|
155
|
-
def
|
|
166
|
+
def test_news_text_search_descending():
|
|
156
167
|
"""
|
|
157
|
-
Test
|
|
158
|
-
|
|
159
|
-
This test verifies that the news text search function returns results
|
|
160
|
-
when the recency weight is set to a low value. It checks that the
|
|
161
|
-
returned results have valid IDs, ranks, score ranks, and age ranks,
|
|
162
|
-
and that the final rank is identical to the score rank.
|
|
163
|
-
|
|
164
|
-
Note: This test assumes the existence of a `test_query` variable.
|
|
168
|
+
Test news text search with descending publication date sort order.
|
|
169
|
+
Verifies results have valid IDs, sequential ranks, and descending dates.
|
|
165
170
|
"""
|
|
166
|
-
|
|
167
171
|
results = ds.contentstore.news.text_search(
|
|
168
|
-
query=
|
|
172
|
+
query=None,
|
|
169
173
|
max_results=10,
|
|
170
|
-
|
|
174
|
+
sort_descending=True,
|
|
171
175
|
)
|
|
172
176
|
|
|
173
177
|
assert len(results) > 0
|
|
174
178
|
for ix, result in enumerate(results):
|
|
175
179
|
assert result.id is not None
|
|
176
180
|
assert result.rank == ix + 1
|
|
181
|
+
if ix < len(results) - 1:
|
|
182
|
+
assert result.publication_date >= results[ix + 1].publication_date
|
|
177
183
|
|
|
178
184
|
|
|
179
|
-
def
|
|
185
|
+
def test_news_text_search_ascending():
|
|
180
186
|
"""
|
|
181
|
-
Test
|
|
182
|
-
|
|
183
|
-
This test verifies that the news text search function returns results
|
|
184
|
-
when the recency weight is set to a high value. It checks that the
|
|
185
|
-
returned results have valid IDs, ranks, score ranks, and age ranks,
|
|
186
|
-
and that the final rank is identical to the age rank.
|
|
187
|
-
|
|
188
|
-
Note: This test assumes the existence of a `test_query` variable.
|
|
187
|
+
Test news text search with ascending publication date sort order.
|
|
188
|
+
Verifies results have valid IDs, sequential ranks, and ascending dates.
|
|
189
189
|
"""
|
|
190
|
+
|
|
190
191
|
results = ds.contentstore.news.text_search(
|
|
191
|
-
query=
|
|
192
|
+
query=None,
|
|
192
193
|
max_results=10,
|
|
193
|
-
|
|
194
|
+
sort_descending=False,
|
|
194
195
|
)
|
|
195
196
|
|
|
196
197
|
assert len(results) > 0
|
|
197
198
|
for ix, result in enumerate(results):
|
|
198
199
|
assert result.id is not None
|
|
199
200
|
assert result.rank == ix + 1
|
|
201
|
+
if ix < len(results) - 1:
|
|
202
|
+
assert result.publication_date <= results[ix + 1].publication_date
|
|
200
203
|
|
|
201
204
|
|
|
202
205
|
def test_news_vector_search():
|
|
@@ -349,9 +352,7 @@ def test_news_hybrid_search_only_text():
|
|
|
349
352
|
)
|
|
350
353
|
|
|
351
354
|
text_results = ds.contentstore.news.text_search(
|
|
352
|
-
query=test_query,
|
|
353
|
-
max_results=results,
|
|
354
|
-
recency_weight=0.0,
|
|
355
|
+
query=test_query, max_results=results
|
|
355
356
|
)
|
|
356
357
|
|
|
357
358
|
assert len(hybrid_results) == results
|
|
@@ -439,19 +440,19 @@ def test_news_hybrid_search_with_vector_high():
|
|
|
439
440
|
"""
|
|
440
441
|
hybrid_results = ds.contentstore.news.search(
|
|
441
442
|
query=test_query,
|
|
442
|
-
max_results=
|
|
443
|
-
vector_weight=0.
|
|
443
|
+
max_results=5,
|
|
444
|
+
vector_weight=0.9999999999,
|
|
444
445
|
vector_fraction=1.0,
|
|
445
446
|
recency_weight=0.0,
|
|
446
447
|
)
|
|
447
448
|
|
|
448
449
|
vector_results = ds.contentstore.news.vector_search(
|
|
449
450
|
query_embedding=test_embedding,
|
|
450
|
-
max_results=
|
|
451
|
+
max_results=5,
|
|
451
452
|
recency_weight=0.0,
|
|
452
453
|
)
|
|
453
454
|
|
|
454
|
-
assert len(hybrid_results) ==
|
|
455
|
+
assert len(hybrid_results) == 5
|
|
455
456
|
for ix, result in enumerate(hybrid_results):
|
|
456
457
|
assert equal_results(result, vector_results[ix])
|
|
457
458
|
|
|
@@ -476,7 +477,6 @@ def test_news_hybrid_search_with_vector_low():
|
|
|
476
477
|
text_results = ds.contentstore.news.text_search(
|
|
477
478
|
query=test_query,
|
|
478
479
|
max_results=results,
|
|
479
|
-
recency_weight=0.0,
|
|
480
480
|
)
|
|
481
481
|
|
|
482
482
|
assert len(hybrid_results) == results
|
|
@@ -80,6 +80,17 @@ def test_secondary_text_empty_search():
|
|
|
80
80
|
assert result.publication_date <= results[ix - 1].publication_date
|
|
81
81
|
|
|
82
82
|
|
|
83
|
+
def test_news_download():
|
|
84
|
+
""" """
|
|
85
|
+
results = ds.contentstore.secondary.text_search(
|
|
86
|
+
query="",
|
|
87
|
+
max_results=1,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
content = ds.contentstore.secondary.download(results[0].id)
|
|
91
|
+
assert len(content) > 0
|
|
92
|
+
|
|
93
|
+
|
|
83
94
|
def test_secondary_text_search_offset():
|
|
84
95
|
"""
|
|
85
96
|
Test the secondary text search function with an offset.
|
|
@@ -153,51 +164,43 @@ def test_secondary_text_search_with_date():
|
|
|
153
164
|
assert result.publication_date <= end and result.publication_date >= start
|
|
154
165
|
|
|
155
166
|
|
|
156
|
-
def
|
|
167
|
+
def test_secondary_text_search_descending():
|
|
157
168
|
"""
|
|
158
|
-
Test
|
|
159
|
-
|
|
160
|
-
This test verifies that the secondary text search function returns results
|
|
161
|
-
when the recency weight is set to a low value. It checks that the
|
|
162
|
-
returned results have valid IDs, ranks, score ranks, and age ranks,
|
|
163
|
-
and that the final rank is identical to the score rank.
|
|
164
|
-
|
|
165
|
-
Note: This test assumes the existence of a `test_query` variable.
|
|
169
|
+
Test secondary text search with descending publication date sort order.
|
|
170
|
+
Verifies results have valid IDs, sequential ranks, and descending dates.
|
|
166
171
|
"""
|
|
167
|
-
|
|
168
172
|
results = ds.contentstore.secondary.text_search(
|
|
169
|
-
query=
|
|
173
|
+
query=None,
|
|
170
174
|
max_results=10,
|
|
171
|
-
|
|
175
|
+
sort_descending=True,
|
|
172
176
|
)
|
|
173
177
|
|
|
174
178
|
assert len(results) > 0
|
|
175
179
|
for ix, result in enumerate(results):
|
|
176
180
|
assert result.id is not None
|
|
177
181
|
assert result.rank == ix + 1
|
|
182
|
+
if ix < len(results) - 1:
|
|
183
|
+
assert result.publication_date >= results[ix + 1].publication_date
|
|
178
184
|
|
|
179
185
|
|
|
180
|
-
def
|
|
186
|
+
def test_secondary_text_search_ascending():
|
|
181
187
|
"""
|
|
182
|
-
Test
|
|
183
|
-
|
|
184
|
-
This test verifies that the secondary text search function returns results
|
|
185
|
-
when the recency weight is set to a high value. It checks that the
|
|
186
|
-
returned results have valid IDs, ranks, score ranks, and age ranks,
|
|
187
|
-
and that the final rank is identical to the age rank.
|
|
188
|
-
|
|
189
|
-
Note: This test assumes the existence of a `test_query` variable.
|
|
188
|
+
Test secondary text search with ascending publication date sort order.
|
|
189
|
+
Verifies results have valid IDs, sequential ranks, and ascending dates.
|
|
190
190
|
"""
|
|
191
|
+
|
|
191
192
|
results = ds.contentstore.secondary.text_search(
|
|
192
|
-
query=
|
|
193
|
+
query=None,
|
|
193
194
|
max_results=10,
|
|
194
|
-
|
|
195
|
+
sort_descending=False,
|
|
195
196
|
)
|
|
196
197
|
|
|
197
198
|
assert len(results) > 0
|
|
198
199
|
for ix, result in enumerate(results):
|
|
199
200
|
assert result.id is not None
|
|
200
201
|
assert result.rank == ix + 1
|
|
202
|
+
if ix < len(results) - 1:
|
|
203
|
+
assert result.publication_date <= results[ix + 1].publication_date
|
|
201
204
|
|
|
202
205
|
|
|
203
206
|
def test_secondary_vector_search():
|
|
@@ -348,7 +351,6 @@ def test_secondary_hybrid_search_only_text():
|
|
|
348
351
|
text_results = ds.contentstore.secondary.text_search(
|
|
349
352
|
query=test_query,
|
|
350
353
|
max_results=5,
|
|
351
|
-
recency_weight=0.0,
|
|
352
354
|
)
|
|
353
355
|
|
|
354
356
|
assert len(hybrid_results) == 5
|
|
@@ -480,7 +482,7 @@ def test_secondary_text_search_with_title_promotion():
|
|
|
480
482
|
This test case verifies that the hybrid search function returns the expected results
|
|
481
483
|
when searching for secondary articles based on a query with title promotion enabled.
|
|
482
484
|
"""
|
|
483
|
-
query = "consumer
|
|
485
|
+
query = "shopping consumer"
|
|
484
486
|
|
|
485
487
|
# first find top 10 results without title promotion and hard recency weight
|
|
486
488
|
hybrid_results_no_promotion = ds.contentstore.secondary.search(
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"comment": "text-ada-002 embedding for 'What are emerging food moments with Gen Z consumers?'",
|
|
3
3
|
"question": "What are emerging food moments with Gen Z consumers?",
|
|
4
|
-
"document_id": "
|
|
5
|
-
"document_page_id": "
|
|
6
|
-
"report_id": "
|
|
4
|
+
"document_id": "b3d728a6-6ef8-4c31-9949-dcc49439f4f1",
|
|
5
|
+
"document_page_id": "319eb5ab-e701-402e-881f-be3ccede65b3",
|
|
6
|
+
"report_id": "44126fc2-2aff-47c0-ac3f-d86bd6afcca2",
|
|
7
7
|
"answerV2_id": "7511f5dd-bb5d-4082-8799-0d1733d61afc",
|
|
8
8
|
"embedding": [
|
|
9
9
|
-0.0012380050029605627,
|