reportify-sdk 0.2.8__py3-none-any.whl → 0.2.10__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.
- reportify_sdk/__init__.py +1 -1
- reportify_sdk/agent.py +213 -0
- reportify_sdk/channels.py +126 -0
- reportify_sdk/chat.py +107 -0
- reportify_sdk/client.py +62 -180
- reportify_sdk/docs.py +351 -8
- reportify_sdk/kb.py +15 -0
- reportify_sdk/search.py +357 -0
- reportify_sdk/stock.py +203 -121
- reportify_sdk/timeline.py +34 -0
- reportify_sdk/user.py +44 -0
- {reportify_sdk-0.2.8.dist-info → reportify_sdk-0.2.10.dist-info}/METADATA +1 -1
- reportify_sdk-0.2.10.dist-info/RECORD +19 -0
- {reportify_sdk-0.2.8.dist-info → reportify_sdk-0.2.10.dist-info}/WHEEL +1 -1
- reportify_sdk-0.2.8.dist-info/RECORD +0 -14
- {reportify_sdk-0.2.8.dist-info → reportify_sdk-0.2.10.dist-info}/licenses/LICENSE +0 -0
- {reportify_sdk-0.2.8.dist-info → reportify_sdk-0.2.10.dist-info}/top_level.txt +0 -0
reportify_sdk/client.py
CHANGED
|
@@ -63,13 +63,18 @@ class Reportify:
|
|
|
63
63
|
self._tools = None
|
|
64
64
|
self._quant = None
|
|
65
65
|
self._concepts = None
|
|
66
|
+
self._channels = None
|
|
67
|
+
self._chat = None
|
|
68
|
+
self._agent = None
|
|
69
|
+
self._user = None
|
|
70
|
+
self._search = None
|
|
66
71
|
|
|
67
72
|
def _get_headers(self) -> dict[str, str]:
|
|
68
73
|
"""Get default headers for API requests"""
|
|
69
74
|
return {
|
|
70
75
|
"Authorization": f"Bearer {self.api_key}",
|
|
71
76
|
"Content-Type": "application/json",
|
|
72
|
-
"User-Agent": "reportify-sdk-python/0.2.
|
|
77
|
+
"User-Agent": "reportify-sdk-python/0.2.10",
|
|
73
78
|
}
|
|
74
79
|
|
|
75
80
|
def _request(
|
|
@@ -136,191 +141,36 @@ class Reportify:
|
|
|
136
141
|
"""Make a POST request"""
|
|
137
142
|
return self._request("POST", path, json=json)
|
|
138
143
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
Args:
|
|
157
|
-
query: Search query string
|
|
158
|
-
num: Number of results to return (default: 10, max: 100)
|
|
159
|
-
categories: Filter by document categories
|
|
160
|
-
symbols: Filter by stock symbols (e.g., ["US:AAPL", "HK:0700"])
|
|
161
|
-
start_date: Start date filter (YYYY-MM-DD)
|
|
162
|
-
end_date: End date filter (YYYY-MM-DD)
|
|
163
|
-
|
|
164
|
-
Returns:
|
|
165
|
-
List of matching documents
|
|
166
|
-
|
|
167
|
-
Example:
|
|
168
|
-
>>> docs = client.search("Tesla earnings", num=10)
|
|
169
|
-
>>> for doc in docs:
|
|
170
|
-
... print(doc["title"])
|
|
171
|
-
"""
|
|
172
|
-
data = {
|
|
173
|
-
"query": query,
|
|
174
|
-
"num": num,
|
|
175
|
-
}
|
|
176
|
-
if categories:
|
|
177
|
-
data["categories"] = categories
|
|
178
|
-
if symbols:
|
|
179
|
-
data["symbols"] = symbols
|
|
180
|
-
if start_date:
|
|
181
|
-
data["start_date"] = start_date
|
|
182
|
-
if end_date:
|
|
183
|
-
data["end_date"] = end_date
|
|
184
|
-
|
|
185
|
-
response = self._post("/v2/search", json=data)
|
|
186
|
-
return response.get("docs", [])
|
|
187
|
-
|
|
188
|
-
def search_news(
|
|
189
|
-
self,
|
|
190
|
-
query: str,
|
|
191
|
-
*,
|
|
192
|
-
num: int = 10,
|
|
193
|
-
symbols: list[str] | None = None,
|
|
194
|
-
start_date: str | None = None,
|
|
195
|
-
end_date: str | None = None,
|
|
196
|
-
) -> list[dict[str, Any]]:
|
|
197
|
-
"""
|
|
198
|
-
Search news articles
|
|
199
|
-
|
|
200
|
-
Args:
|
|
201
|
-
query: Search query string
|
|
202
|
-
num: Number of results to return
|
|
203
|
-
symbols: Filter by stock symbols
|
|
204
|
-
start_date: Start date filter (YYYY-MM-DD)
|
|
205
|
-
end_date: End date filter (YYYY-MM-DD)
|
|
206
|
-
|
|
207
|
-
Returns:
|
|
208
|
-
List of news articles
|
|
209
|
-
"""
|
|
210
|
-
data = {"query": query, "num": num}
|
|
211
|
-
if symbols:
|
|
212
|
-
data["symbols"] = symbols
|
|
213
|
-
if start_date:
|
|
214
|
-
data["start_date"] = start_date
|
|
215
|
-
if end_date:
|
|
216
|
-
data["end_date"] = end_date
|
|
217
|
-
|
|
218
|
-
response = self._post("/v2/search/news", json=data)
|
|
219
|
-
return response.get("docs", [])
|
|
220
|
-
|
|
221
|
-
def search_reports(
|
|
222
|
-
self,
|
|
223
|
-
query: str,
|
|
224
|
-
*,
|
|
225
|
-
num: int = 10,
|
|
226
|
-
symbols: list[str] | None = None,
|
|
227
|
-
start_date: str | None = None,
|
|
228
|
-
end_date: str | None = None,
|
|
229
|
-
) -> list[dict[str, Any]]:
|
|
230
|
-
"""
|
|
231
|
-
Search research reports
|
|
232
|
-
|
|
233
|
-
Args:
|
|
234
|
-
query: Search query string
|
|
235
|
-
num: Number of results to return
|
|
236
|
-
symbols: Filter by stock symbols
|
|
237
|
-
start_date: Start date filter (YYYY-MM-DD)
|
|
238
|
-
end_date: End date filter (YYYY-MM-DD)
|
|
239
|
-
|
|
240
|
-
Returns:
|
|
241
|
-
List of research reports
|
|
242
|
-
"""
|
|
243
|
-
data = {"query": query, "num": num}
|
|
244
|
-
if symbols:
|
|
245
|
-
data["symbols"] = symbols
|
|
246
|
-
if start_date:
|
|
247
|
-
data["start_date"] = start_date
|
|
248
|
-
if end_date:
|
|
249
|
-
data["end_date"] = end_date
|
|
250
|
-
|
|
251
|
-
response = self._post("/v2/search/reports", json=data)
|
|
252
|
-
return response.get("docs", [])
|
|
253
|
-
|
|
254
|
-
def search_filings(
|
|
255
|
-
self,
|
|
256
|
-
query: str,
|
|
257
|
-
*,
|
|
258
|
-
num: int = 10,
|
|
259
|
-
symbols: list[str] | None = None,
|
|
260
|
-
start_date: str | None = None,
|
|
261
|
-
end_date: str | None = None,
|
|
262
|
-
) -> list[dict[str, Any]]:
|
|
263
|
-
"""
|
|
264
|
-
Search company filings and announcements
|
|
265
|
-
|
|
266
|
-
Args:
|
|
267
|
-
query: Search query string
|
|
268
|
-
num: Number of results to return
|
|
269
|
-
symbols: Filter by stock symbols
|
|
270
|
-
start_date: Start date filter (YYYY-MM-DD)
|
|
271
|
-
end_date: End date filter (YYYY-MM-DD)
|
|
272
|
-
|
|
273
|
-
Returns:
|
|
274
|
-
List of filings
|
|
275
|
-
"""
|
|
276
|
-
data = {"query": query, "num": num}
|
|
277
|
-
if symbols:
|
|
278
|
-
data["symbols"] = symbols
|
|
279
|
-
if start_date:
|
|
280
|
-
data["start_date"] = start_date
|
|
281
|
-
if end_date:
|
|
282
|
-
data["end_date"] = end_date
|
|
283
|
-
|
|
284
|
-
response = self._post("/v2/search/filings", json=data)
|
|
285
|
-
return response.get("docs", [])
|
|
286
|
-
|
|
287
|
-
def search_transcripts(
|
|
288
|
-
self,
|
|
289
|
-
query: str,
|
|
290
|
-
*,
|
|
291
|
-
num: int = 10,
|
|
292
|
-
symbols: list[str] | None = None,
|
|
293
|
-
start_date: str | None = None,
|
|
294
|
-
end_date: str | None = None,
|
|
295
|
-
) -> list[dict[str, Any]]:
|
|
296
|
-
"""
|
|
297
|
-
Search earnings call transcripts
|
|
298
|
-
|
|
299
|
-
Args:
|
|
300
|
-
query: Search query string
|
|
301
|
-
num: Number of results to return
|
|
302
|
-
symbols: Filter by stock symbols
|
|
303
|
-
start_date: Start date filter (YYYY-MM-DD)
|
|
304
|
-
end_date: End date filter (YYYY-MM-DD)
|
|
305
|
-
|
|
306
|
-
Returns:
|
|
307
|
-
List of transcripts
|
|
308
|
-
"""
|
|
309
|
-
data = {"query": query, "num": num}
|
|
310
|
-
if symbols:
|
|
311
|
-
data["symbols"] = symbols
|
|
312
|
-
if start_date:
|
|
313
|
-
data["start_date"] = start_date
|
|
314
|
-
if end_date:
|
|
315
|
-
data["end_date"] = end_date
|
|
144
|
+
def _get_bytes(self, path: str) -> bytes:
|
|
145
|
+
"""Make a GET request and return raw bytes (for file downloads)"""
|
|
146
|
+
try:
|
|
147
|
+
response = self._client.get(path)
|
|
148
|
+
response.raise_for_status()
|
|
149
|
+
return response.content
|
|
150
|
+
except httpx.HTTPStatusError as e:
|
|
151
|
+
status_code = e.response.status_code
|
|
152
|
+
if status_code == 401:
|
|
153
|
+
raise AuthenticationError("Invalid API key")
|
|
154
|
+
elif status_code == 404:
|
|
155
|
+
raise NotFoundError(f"Resource not found: {path}")
|
|
156
|
+
elif status_code == 429:
|
|
157
|
+
raise RateLimitError("Rate limit exceeded")
|
|
158
|
+
else:
|
|
159
|
+
raise APIError(f"API error: {status_code}")
|
|
316
160
|
|
|
317
|
-
response = self._post("/v2/search/conference-calls", json=data)
|
|
318
|
-
return response.get("docs", [])
|
|
319
161
|
|
|
320
162
|
# -------------------------------------------------------------------------
|
|
321
163
|
# Sub-modules (lazy loading)
|
|
322
164
|
# -------------------------------------------------------------------------
|
|
323
165
|
|
|
166
|
+
@property
|
|
167
|
+
def search(self):
|
|
168
|
+
"""Search module for document search across all categories"""
|
|
169
|
+
if self._search is None:
|
|
170
|
+
from reportify_sdk.search import SearchModule
|
|
171
|
+
self._search = SearchModule(self)
|
|
172
|
+
return self._search
|
|
173
|
+
|
|
324
174
|
@property
|
|
325
175
|
def stock(self):
|
|
326
176
|
"""Stock data module for financial statements, prices, etc."""
|
|
@@ -369,6 +219,38 @@ class Reportify:
|
|
|
369
219
|
self._concepts = ConceptsModule(self)
|
|
370
220
|
return self._concepts
|
|
371
221
|
|
|
222
|
+
@property
|
|
223
|
+
def channels(self):
|
|
224
|
+
"""Channels module for searching and following channels"""
|
|
225
|
+
if self._channels is None:
|
|
226
|
+
from reportify_sdk.channels import ChannelsModule
|
|
227
|
+
self._channels = ChannelsModule(self)
|
|
228
|
+
return self._channels
|
|
229
|
+
|
|
230
|
+
@property
|
|
231
|
+
def chat(self):
|
|
232
|
+
"""Chat module for document-based Q&A"""
|
|
233
|
+
if self._chat is None:
|
|
234
|
+
from reportify_sdk.chat import ChatModule
|
|
235
|
+
self._chat = ChatModule(self)
|
|
236
|
+
return self._chat
|
|
237
|
+
|
|
238
|
+
@property
|
|
239
|
+
def agent(self):
|
|
240
|
+
"""Agent module for AI-powered conversations and workflows"""
|
|
241
|
+
if self._agent is None:
|
|
242
|
+
from reportify_sdk.agent import AgentModule
|
|
243
|
+
self._agent = AgentModule(self)
|
|
244
|
+
return self._agent
|
|
245
|
+
|
|
246
|
+
@property
|
|
247
|
+
def user(self):
|
|
248
|
+
"""User module for user-related tools and data"""
|
|
249
|
+
if self._user is None:
|
|
250
|
+
from reportify_sdk.user import UserModule
|
|
251
|
+
self._user = UserModule(self)
|
|
252
|
+
return self._user
|
|
253
|
+
|
|
372
254
|
def close(self):
|
|
373
255
|
"""Close the HTTP client"""
|
|
374
256
|
self._client.close()
|
reportify_sdk/docs.py
CHANGED
|
@@ -86,21 +86,33 @@ class DocsModule:
|
|
|
86
86
|
*,
|
|
87
87
|
symbols: list[str] | None = None,
|
|
88
88
|
categories: list[str] | None = None,
|
|
89
|
+
markets: list[str] | None = None,
|
|
90
|
+
institutions: list[str] | None = None,
|
|
91
|
+
tags: dict[str, list] | None = None,
|
|
92
|
+
folder_ids: list[str] | None = None,
|
|
89
93
|
start_date: str | None = None,
|
|
90
94
|
end_date: str | None = None,
|
|
91
|
-
|
|
92
|
-
|
|
95
|
+
min_score: float | None = None,
|
|
96
|
+
extended_filters: list[dict] | None = None,
|
|
97
|
+
page_num: int = 1,
|
|
98
|
+
page_size: int = 10,
|
|
93
99
|
) -> dict[str, Any]:
|
|
94
100
|
"""
|
|
95
101
|
List documents with filters
|
|
96
102
|
|
|
97
103
|
Args:
|
|
98
104
|
symbols: Filter by stock symbols
|
|
99
|
-
categories: Filter by document categories
|
|
105
|
+
categories: Filter by document categories (financials, transcripts, reports, news, files, filings, socials)
|
|
106
|
+
markets: Filter by markets (cn, hk, us)
|
|
107
|
+
institutions: Filter by institutions
|
|
108
|
+
tags: Filter by tags (dict with key-value pairs)
|
|
109
|
+
folder_ids: Filter by folder IDs
|
|
100
110
|
start_date: Start date filter (YYYY-MM-DD)
|
|
101
111
|
end_date: End date filter (YYYY-MM-DD)
|
|
102
|
-
|
|
103
|
-
|
|
112
|
+
min_score: Minimum relevance score
|
|
113
|
+
extended_filters: Extended filter conditions
|
|
114
|
+
page_num: Page number (default: 1)
|
|
115
|
+
page_size: Number of items per page (default: 10)
|
|
104
116
|
|
|
105
117
|
Returns:
|
|
106
118
|
Dictionary with documents list and pagination info
|
|
@@ -111,17 +123,29 @@ class DocsModule:
|
|
|
111
123
|
... print(doc["title"])
|
|
112
124
|
"""
|
|
113
125
|
data: dict[str, Any] = {
|
|
114
|
-
"page_num":
|
|
126
|
+
"page_num": page_num,
|
|
115
127
|
"page_size": page_size,
|
|
116
128
|
}
|
|
117
129
|
if symbols:
|
|
118
130
|
data["symbols"] = symbols
|
|
119
131
|
if categories:
|
|
120
132
|
data["categories"] = categories
|
|
133
|
+
if markets:
|
|
134
|
+
data["markets"] = markets
|
|
135
|
+
if institutions:
|
|
136
|
+
data["institutions"] = institutions
|
|
137
|
+
if tags:
|
|
138
|
+
data["tags"] = tags
|
|
139
|
+
if folder_ids:
|
|
140
|
+
data["folder_ids"] = folder_ids
|
|
121
141
|
if start_date:
|
|
122
142
|
data["start_date"] = start_date
|
|
123
143
|
if end_date:
|
|
124
144
|
data["end_date"] = end_date
|
|
145
|
+
if min_score is not None:
|
|
146
|
+
data["min_score"] = min_score
|
|
147
|
+
if extended_filters:
|
|
148
|
+
data["extended_filters"] = extended_filters
|
|
125
149
|
|
|
126
150
|
return self._post("/v1/docs", json=data)
|
|
127
151
|
|
|
@@ -131,9 +155,19 @@ class DocsModule:
|
|
|
131
155
|
*,
|
|
132
156
|
symbols: list[str] | None = None,
|
|
133
157
|
categories: list[str] | None = None,
|
|
158
|
+
markets: list[str] | None = None,
|
|
159
|
+
institutions: list[str] | None = None,
|
|
160
|
+
tags: dict[str, list] | None = None,
|
|
161
|
+
folder_ids: list[str] | None = None,
|
|
162
|
+
doc_ids: list[str] | None = None,
|
|
134
163
|
start_date: str | None = None,
|
|
135
164
|
end_date: str | None = None,
|
|
165
|
+
min_score: float | None = None,
|
|
166
|
+
extended_filters: list[dict] | None = None,
|
|
136
167
|
num: int = 10,
|
|
168
|
+
include_doc_extra_details: bool = False,
|
|
169
|
+
refine_question: bool = False,
|
|
170
|
+
date_range: str | None = None,
|
|
137
171
|
) -> list[dict[str, Any]]:
|
|
138
172
|
"""
|
|
139
173
|
Search document chunks semantically
|
|
@@ -143,10 +177,20 @@ class DocsModule:
|
|
|
143
177
|
Args:
|
|
144
178
|
query: Search query string
|
|
145
179
|
symbols: Filter by stock symbols
|
|
146
|
-
categories: Filter by document categories
|
|
180
|
+
categories: Filter by document categories (financials, transcripts, reports, news, filings, socials)
|
|
181
|
+
markets: Filter by markets (cn, hk, us)
|
|
182
|
+
institutions: Filter by institutions
|
|
183
|
+
tags: Filter by tags (dict with key-value pairs)
|
|
184
|
+
folder_ids: Filter by folder IDs
|
|
185
|
+
doc_ids: Filter by document IDs
|
|
147
186
|
start_date: Start date filter (YYYY-MM-DD)
|
|
148
187
|
end_date: End date filter (YYYY-MM-DD)
|
|
149
|
-
|
|
188
|
+
min_score: Minimum relevance score
|
|
189
|
+
extended_filters: Extended filter conditions
|
|
190
|
+
num: Number of results to return (default: 10)
|
|
191
|
+
include_doc_extra_details: Include extra document details
|
|
192
|
+
refine_question: Refine the search question
|
|
193
|
+
date_range: Date range filter (h, d, w, m, y)
|
|
150
194
|
|
|
151
195
|
Returns:
|
|
152
196
|
List of matching chunks with document info
|
|
@@ -164,10 +208,309 @@ class DocsModule:
|
|
|
164
208
|
data["symbols"] = symbols
|
|
165
209
|
if categories:
|
|
166
210
|
data["categories"] = categories
|
|
211
|
+
if markets:
|
|
212
|
+
data["markets"] = markets
|
|
213
|
+
if institutions:
|
|
214
|
+
data["institutions"] = institutions
|
|
215
|
+
if tags:
|
|
216
|
+
data["tags"] = tags
|
|
217
|
+
if folder_ids:
|
|
218
|
+
data["folder_ids"] = folder_ids
|
|
219
|
+
if doc_ids:
|
|
220
|
+
data["doc_ids"] = doc_ids
|
|
167
221
|
if start_date:
|
|
168
222
|
data["start_date"] = start_date
|
|
169
223
|
if end_date:
|
|
170
224
|
data["end_date"] = end_date
|
|
225
|
+
if min_score is not None:
|
|
226
|
+
data["min_score"] = min_score
|
|
227
|
+
if extended_filters:
|
|
228
|
+
data["extended_filters"] = extended_filters
|
|
229
|
+
if include_doc_extra_details:
|
|
230
|
+
data["include_doc_extra_details"] = include_doc_extra_details
|
|
231
|
+
if refine_question:
|
|
232
|
+
data["refine_question"] = refine_question
|
|
233
|
+
if date_range:
|
|
234
|
+
data["date_range"] = date_range
|
|
171
235
|
|
|
172
236
|
response = self._post("/v1/search/chunks", json=data)
|
|
173
237
|
return response.get("chunks", [])
|
|
238
|
+
|
|
239
|
+
def query_by_symbols(
|
|
240
|
+
self,
|
|
241
|
+
symbols: list[str],
|
|
242
|
+
*,
|
|
243
|
+
categories: list[str] | None = None,
|
|
244
|
+
markets: list[str] | None = None,
|
|
245
|
+
start_date: str | None = None,
|
|
246
|
+
end_date: str | None = None,
|
|
247
|
+
page_num: int = 1,
|
|
248
|
+
page_size: int = 10,
|
|
249
|
+
) -> dict[str, Any]:
|
|
250
|
+
"""
|
|
251
|
+
Query documents by stock symbols
|
|
252
|
+
|
|
253
|
+
Args:
|
|
254
|
+
symbols: Stock symbols to filter by (required)
|
|
255
|
+
categories: Filter by document categories
|
|
256
|
+
markets: Filter by markets (cn, hk, us)
|
|
257
|
+
start_date: Start date filter (YYYY-MM-DD)
|
|
258
|
+
end_date: End date filter (YYYY-MM-DD)
|
|
259
|
+
page_num: Page number (default: 1)
|
|
260
|
+
page_size: Number of items per page (default: 10)
|
|
261
|
+
|
|
262
|
+
Returns:
|
|
263
|
+
Dictionary with documents list and pagination info
|
|
264
|
+
"""
|
|
265
|
+
data: dict[str, Any] = {
|
|
266
|
+
"symbols": symbols,
|
|
267
|
+
"page_num": page_num,
|
|
268
|
+
"page_size": page_size,
|
|
269
|
+
}
|
|
270
|
+
if categories:
|
|
271
|
+
data["categories"] = categories
|
|
272
|
+
if markets:
|
|
273
|
+
data["markets"] = markets
|
|
274
|
+
if start_date:
|
|
275
|
+
data["start_date"] = start_date
|
|
276
|
+
if end_date:
|
|
277
|
+
data["end_date"] = end_date
|
|
278
|
+
|
|
279
|
+
return self._post("/v1/docs/symbols", json=data)
|
|
280
|
+
|
|
281
|
+
def query_by_tags(
|
|
282
|
+
self,
|
|
283
|
+
tags: dict[str, list],
|
|
284
|
+
*,
|
|
285
|
+
categories: list[str] | None = None,
|
|
286
|
+
markets: list[str] | None = None,
|
|
287
|
+
start_date: str | None = None,
|
|
288
|
+
end_date: str | None = None,
|
|
289
|
+
page_num: int = 1,
|
|
290
|
+
page_size: int = 10,
|
|
291
|
+
) -> dict[str, Any]:
|
|
292
|
+
"""
|
|
293
|
+
Query documents by tags
|
|
294
|
+
|
|
295
|
+
Args:
|
|
296
|
+
tags: Tags to filter by (required, dict with key-value pairs)
|
|
297
|
+
categories: Filter by document categories
|
|
298
|
+
markets: Filter by markets (cn, hk, us)
|
|
299
|
+
start_date: Start date filter (YYYY-MM-DD)
|
|
300
|
+
end_date: End date filter (YYYY-MM-DD)
|
|
301
|
+
page_num: Page number (default: 1)
|
|
302
|
+
page_size: Number of items per page (default: 10)
|
|
303
|
+
|
|
304
|
+
Returns:
|
|
305
|
+
Dictionary with documents list and pagination info
|
|
306
|
+
"""
|
|
307
|
+
data: dict[str, Any] = {
|
|
308
|
+
"tags": tags,
|
|
309
|
+
"page_num": page_num,
|
|
310
|
+
"page_size": page_size,
|
|
311
|
+
}
|
|
312
|
+
if categories:
|
|
313
|
+
data["categories"] = categories
|
|
314
|
+
if markets:
|
|
315
|
+
data["markets"] = markets
|
|
316
|
+
if start_date:
|
|
317
|
+
data["start_date"] = start_date
|
|
318
|
+
if end_date:
|
|
319
|
+
data["end_date"] = end_date
|
|
320
|
+
|
|
321
|
+
return self._post("/v1/docs/tags", json=data)
|
|
322
|
+
|
|
323
|
+
def search(
|
|
324
|
+
self,
|
|
325
|
+
*,
|
|
326
|
+
query: str | None = None,
|
|
327
|
+
symbols: list[str] | None = None,
|
|
328
|
+
categories: list[str] | None = None,
|
|
329
|
+
markets: list[str] | None = None,
|
|
330
|
+
institutions: list[str] | None = None,
|
|
331
|
+
tags: dict[str, list] | None = None,
|
|
332
|
+
folder_ids: list[str] | None = None,
|
|
333
|
+
start_date: str | None = None,
|
|
334
|
+
end_date: str | None = None,
|
|
335
|
+
min_score: float | None = None,
|
|
336
|
+
extended_filters: list[dict] | None = None,
|
|
337
|
+
page_num: int = 1,
|
|
338
|
+
page_size: int = 10,
|
|
339
|
+
mode: str = "smart",
|
|
340
|
+
sort: str = "smart",
|
|
341
|
+
should_highlight: bool = False,
|
|
342
|
+
) -> dict[str, Any]:
|
|
343
|
+
"""
|
|
344
|
+
Search documents (v1 API)
|
|
345
|
+
|
|
346
|
+
Args:
|
|
347
|
+
query: Search query string
|
|
348
|
+
symbols: Filter by stock symbols
|
|
349
|
+
categories: Filter by document categories
|
|
350
|
+
markets: Filter by markets (cn, hk, us)
|
|
351
|
+
institutions: Filter by institutions
|
|
352
|
+
tags: Filter by tags
|
|
353
|
+
folder_ids: Filter by folder IDs
|
|
354
|
+
start_date: Start date filter (YYYY-MM-DD)
|
|
355
|
+
end_date: End date filter (YYYY-MM-DD)
|
|
356
|
+
min_score: Minimum relevance score
|
|
357
|
+
extended_filters: Extended filter conditions
|
|
358
|
+
page_num: Page number (default: 1)
|
|
359
|
+
page_size: Number of items per page (default: 10)
|
|
360
|
+
mode: Search mode ("smart", "semantic", "keywords")
|
|
361
|
+
sort: Sort order ("smart", "latest")
|
|
362
|
+
should_highlight: Whether to highlight matches
|
|
363
|
+
|
|
364
|
+
Returns:
|
|
365
|
+
Dictionary with documents list and pagination info
|
|
366
|
+
"""
|
|
367
|
+
data: dict[str, Any] = {
|
|
368
|
+
"page_num": page_num,
|
|
369
|
+
"page_size": page_size,
|
|
370
|
+
"mode": mode,
|
|
371
|
+
"sort": sort,
|
|
372
|
+
"should_highlight": should_highlight,
|
|
373
|
+
}
|
|
374
|
+
if query:
|
|
375
|
+
data["query"] = query
|
|
376
|
+
if symbols:
|
|
377
|
+
data["symbols"] = symbols
|
|
378
|
+
if categories:
|
|
379
|
+
data["categories"] = categories
|
|
380
|
+
if markets:
|
|
381
|
+
data["markets"] = markets
|
|
382
|
+
if institutions:
|
|
383
|
+
data["institutions"] = institutions
|
|
384
|
+
if tags:
|
|
385
|
+
data["tags"] = tags
|
|
386
|
+
if folder_ids:
|
|
387
|
+
data["folder_ids"] = folder_ids
|
|
388
|
+
if start_date:
|
|
389
|
+
data["start_date"] = start_date
|
|
390
|
+
if end_date:
|
|
391
|
+
data["end_date"] = end_date
|
|
392
|
+
if min_score is not None:
|
|
393
|
+
data["min_score"] = min_score
|
|
394
|
+
if extended_filters:
|
|
395
|
+
data["extended_filters"] = extended_filters
|
|
396
|
+
|
|
397
|
+
return self._post("/v1/search", json=data)
|
|
398
|
+
|
|
399
|
+
# -------------------------------------------------------------------------
|
|
400
|
+
# Folder Management
|
|
401
|
+
# -------------------------------------------------------------------------
|
|
402
|
+
|
|
403
|
+
def create_folder(self, name: str) -> dict[str, Any]:
|
|
404
|
+
"""
|
|
405
|
+
Create a new folder
|
|
406
|
+
|
|
407
|
+
Args:
|
|
408
|
+
name: Folder name
|
|
409
|
+
|
|
410
|
+
Returns:
|
|
411
|
+
Dictionary with folder_id
|
|
412
|
+
"""
|
|
413
|
+
return self._post("/v1/docs/folder/create", json={"name": name})
|
|
414
|
+
|
|
415
|
+
def delete_folder(self, folder_id: str) -> dict[str, Any]:
|
|
416
|
+
"""
|
|
417
|
+
Delete a folder and all files in it
|
|
418
|
+
|
|
419
|
+
Args:
|
|
420
|
+
folder_id: Folder ID to delete
|
|
421
|
+
|
|
422
|
+
Returns:
|
|
423
|
+
Dictionary with deleted doc_ids and folder_id
|
|
424
|
+
"""
|
|
425
|
+
return self._client._request(
|
|
426
|
+
"DELETE", "/v1/docs/folder/delete", json={"folder_id": folder_id}
|
|
427
|
+
)
|
|
428
|
+
|
|
429
|
+
# -------------------------------------------------------------------------
|
|
430
|
+
# Document Upload
|
|
431
|
+
# -------------------------------------------------------------------------
|
|
432
|
+
|
|
433
|
+
def upload(
|
|
434
|
+
self,
|
|
435
|
+
docs: list[dict[str, Any]],
|
|
436
|
+
*,
|
|
437
|
+
folder_id: str | None = None,
|
|
438
|
+
pdf_parsing_mode: int = 1,
|
|
439
|
+
) -> dict[str, Any]:
|
|
440
|
+
"""
|
|
441
|
+
Upload documents by URL
|
|
442
|
+
|
|
443
|
+
Args:
|
|
444
|
+
docs: List of document objects with url, name, metadatas, published_at, tags
|
|
445
|
+
folder_id: Folder ID to upload to (optional, uses default folder if not provided)
|
|
446
|
+
pdf_parsing_mode: PDF parsing mode (1: by page, 3: by logic)
|
|
447
|
+
|
|
448
|
+
Returns:
|
|
449
|
+
Dictionary with uploaded document IDs
|
|
450
|
+
|
|
451
|
+
Example:
|
|
452
|
+
>>> result = client.docs.upload([
|
|
453
|
+
... {"url": "https://example.com/doc.pdf", "name": "My Doc"}
|
|
454
|
+
... ])
|
|
455
|
+
"""
|
|
456
|
+
data: dict[str, Any] = {
|
|
457
|
+
"docs": docs,
|
|
458
|
+
"pdf_parsing_mode": pdf_parsing_mode,
|
|
459
|
+
}
|
|
460
|
+
if folder_id:
|
|
461
|
+
data["folder_id"] = folder_id
|
|
462
|
+
|
|
463
|
+
return self._post("/v1/docs/upload", json=data)
|
|
464
|
+
|
|
465
|
+
def upload_async(
|
|
466
|
+
self,
|
|
467
|
+
docs: list[dict[str, Any]],
|
|
468
|
+
*,
|
|
469
|
+
folder_id: str | None = None,
|
|
470
|
+
pdf_parsing_mode: int = 1,
|
|
471
|
+
) -> dict[str, Any]:
|
|
472
|
+
"""
|
|
473
|
+
Upload documents asynchronously by URL
|
|
474
|
+
|
|
475
|
+
Args:
|
|
476
|
+
docs: List of document objects with url, name, metadatas, published_at, tags
|
|
477
|
+
folder_id: Folder ID to upload to (optional)
|
|
478
|
+
pdf_parsing_mode: PDF parsing mode (1: by page, 3: by logic)
|
|
479
|
+
|
|
480
|
+
Returns:
|
|
481
|
+
Dictionary with uploaded document IDs
|
|
482
|
+
"""
|
|
483
|
+
data: dict[str, Any] = {
|
|
484
|
+
"docs": docs,
|
|
485
|
+
"pdf_parsing_mode": pdf_parsing_mode,
|
|
486
|
+
}
|
|
487
|
+
if folder_id:
|
|
488
|
+
data["folder_id"] = folder_id
|
|
489
|
+
|
|
490
|
+
return self._post("/v1/docs/upload/async", json=data)
|
|
491
|
+
|
|
492
|
+
def get_upload_status(self, doc_id: str) -> dict[str, Any]:
|
|
493
|
+
"""
|
|
494
|
+
Get document upload status
|
|
495
|
+
|
|
496
|
+
Args:
|
|
497
|
+
doc_id: Document ID
|
|
498
|
+
|
|
499
|
+
Returns:
|
|
500
|
+
Dictionary with id and status (pending, processing, completed)
|
|
501
|
+
"""
|
|
502
|
+
return self._get(f"/v1/docs/{doc_id}/upload/status")
|
|
503
|
+
|
|
504
|
+
def delete(self, doc_ids: list[str]) -> dict[str, Any]:
|
|
505
|
+
"""
|
|
506
|
+
Delete documents
|
|
507
|
+
|
|
508
|
+
Args:
|
|
509
|
+
doc_ids: List of document IDs to delete
|
|
510
|
+
|
|
511
|
+
Returns:
|
|
512
|
+
Dictionary with deleted doc_ids
|
|
513
|
+
"""
|
|
514
|
+
return self._client._request(
|
|
515
|
+
"DELETE", "/v1/docs/delete", json={"doc_ids": doc_ids}
|
|
516
|
+
)
|