reportify-sdk 0.2.7__py3-none-any.whl → 0.2.9__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 +257 -57
- reportify_sdk/docs.py +351 -8
- reportify_sdk/kb.py +15 -0
- reportify_sdk/stock.py +231 -126
- reportify_sdk/timeline.py +34 -0
- reportify_sdk/user.py +44 -0
- {reportify_sdk-0.2.7.dist-info → reportify_sdk-0.2.9.dist-info}/METADATA +1 -1
- reportify_sdk-0.2.9.dist-info/RECORD +18 -0
- reportify_sdk-0.2.7.dist-info/RECORD +0 -14
- {reportify_sdk-0.2.7.dist-info → reportify_sdk-0.2.9.dist-info}/WHEEL +0 -0
- {reportify_sdk-0.2.7.dist-info → reportify_sdk-0.2.9.dist-info}/licenses/LICENSE +0 -0
- {reportify_sdk-0.2.7.dist-info → reportify_sdk-0.2.9.dist-info}/top_level.txt +0 -0
reportify_sdk/client.py
CHANGED
|
@@ -63,13 +63,17 @@ 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
|
|
66
70
|
|
|
67
71
|
def _get_headers(self) -> dict[str, str]:
|
|
68
72
|
"""Get default headers for API requests"""
|
|
69
73
|
return {
|
|
70
74
|
"Authorization": f"Bearer {self.api_key}",
|
|
71
75
|
"Content-Type": "application/json",
|
|
72
|
-
"User-Agent": "reportify-sdk-python/0.2.
|
|
76
|
+
"User-Agent": "reportify-sdk-python/0.2.9",
|
|
73
77
|
}
|
|
74
78
|
|
|
75
79
|
def _request(
|
|
@@ -136,6 +140,23 @@ class Reportify:
|
|
|
136
140
|
"""Make a POST request"""
|
|
137
141
|
return self._request("POST", path, json=json)
|
|
138
142
|
|
|
143
|
+
def _get_bytes(self, path: str) -> bytes:
|
|
144
|
+
"""Make a GET request and return raw bytes (for file downloads)"""
|
|
145
|
+
try:
|
|
146
|
+
response = self._client.get(path)
|
|
147
|
+
response.raise_for_status()
|
|
148
|
+
return response.content
|
|
149
|
+
except httpx.HTTPStatusError as e:
|
|
150
|
+
status_code = e.response.status_code
|
|
151
|
+
if status_code == 401:
|
|
152
|
+
raise AuthenticationError("Invalid API key")
|
|
153
|
+
elif status_code == 404:
|
|
154
|
+
raise NotFoundError(f"Resource not found: {path}")
|
|
155
|
+
elif status_code == 429:
|
|
156
|
+
raise RateLimitError("Rate limit exceeded")
|
|
157
|
+
else:
|
|
158
|
+
raise APIError(f"API error: {status_code}")
|
|
159
|
+
|
|
139
160
|
# -------------------------------------------------------------------------
|
|
140
161
|
# Search Methods
|
|
141
162
|
# -------------------------------------------------------------------------
|
|
@@ -145,10 +166,11 @@ class Reportify:
|
|
|
145
166
|
query: str,
|
|
146
167
|
*,
|
|
147
168
|
num: int = 10,
|
|
148
|
-
categories: list[str] | None = None,
|
|
149
169
|
symbols: list[str] | None = None,
|
|
150
|
-
|
|
151
|
-
|
|
170
|
+
industries: list[str] | None = None,
|
|
171
|
+
channel_ids: list[str] | None = None,
|
|
172
|
+
start_datetime: str | None = None,
|
|
173
|
+
end_datetime: str | None = None,
|
|
152
174
|
) -> list[dict[str, Any]]:
|
|
153
175
|
"""
|
|
154
176
|
Search documents across all categories
|
|
@@ -156,10 +178,11 @@ class Reportify:
|
|
|
156
178
|
Args:
|
|
157
179
|
query: Search query string
|
|
158
180
|
num: Number of results to return (default: 10, max: 100)
|
|
159
|
-
categories: Filter by document categories
|
|
160
181
|
symbols: Filter by stock symbols (e.g., ["US:AAPL", "HK:0700"])
|
|
161
|
-
|
|
162
|
-
|
|
182
|
+
industries: Filter by industries
|
|
183
|
+
channel_ids: Filter by channel IDs
|
|
184
|
+
start_datetime: Start datetime filter (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)
|
|
185
|
+
end_datetime: End datetime filter (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)
|
|
163
186
|
|
|
164
187
|
Returns:
|
|
165
188
|
List of matching documents
|
|
@@ -169,18 +192,20 @@ class Reportify:
|
|
|
169
192
|
>>> for doc in docs:
|
|
170
193
|
... print(doc["title"])
|
|
171
194
|
"""
|
|
172
|
-
data = {
|
|
195
|
+
data: dict[str, Any] = {
|
|
173
196
|
"query": query,
|
|
174
197
|
"num": num,
|
|
175
198
|
}
|
|
176
|
-
if categories:
|
|
177
|
-
data["categories"] = categories
|
|
178
199
|
if symbols:
|
|
179
200
|
data["symbols"] = symbols
|
|
180
|
-
if
|
|
181
|
-
data["
|
|
182
|
-
if
|
|
183
|
-
data["
|
|
201
|
+
if industries:
|
|
202
|
+
data["industries"] = industries
|
|
203
|
+
if channel_ids:
|
|
204
|
+
data["channel_ids"] = channel_ids
|
|
205
|
+
if start_datetime:
|
|
206
|
+
data["start_datetime"] = start_datetime
|
|
207
|
+
if end_datetime:
|
|
208
|
+
data["end_datetime"] = end_datetime
|
|
184
209
|
|
|
185
210
|
response = self._post("/v2/search", json=data)
|
|
186
211
|
return response.get("docs", [])
|
|
@@ -191,8 +216,9 @@ class Reportify:
|
|
|
191
216
|
*,
|
|
192
217
|
num: int = 10,
|
|
193
218
|
symbols: list[str] | None = None,
|
|
194
|
-
|
|
195
|
-
|
|
219
|
+
channel_ids: list[str] | None = None,
|
|
220
|
+
start_datetime: str | None = None,
|
|
221
|
+
end_datetime: str | None = None,
|
|
196
222
|
) -> list[dict[str, Any]]:
|
|
197
223
|
"""
|
|
198
224
|
Search news articles
|
|
@@ -201,19 +227,22 @@ class Reportify:
|
|
|
201
227
|
query: Search query string
|
|
202
228
|
num: Number of results to return
|
|
203
229
|
symbols: Filter by stock symbols
|
|
204
|
-
|
|
205
|
-
|
|
230
|
+
channel_ids: Filter by channel IDs
|
|
231
|
+
start_datetime: Start datetime filter (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)
|
|
232
|
+
end_datetime: End datetime filter (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)
|
|
206
233
|
|
|
207
234
|
Returns:
|
|
208
235
|
List of news articles
|
|
209
236
|
"""
|
|
210
|
-
data = {"query": query, "num": num}
|
|
237
|
+
data: dict[str, Any] = {"query": query, "num": num}
|
|
211
238
|
if symbols:
|
|
212
239
|
data["symbols"] = symbols
|
|
213
|
-
if
|
|
214
|
-
data["
|
|
215
|
-
if
|
|
216
|
-
data["
|
|
240
|
+
if channel_ids:
|
|
241
|
+
data["channel_ids"] = channel_ids
|
|
242
|
+
if start_datetime:
|
|
243
|
+
data["start_datetime"] = start_datetime
|
|
244
|
+
if end_datetime:
|
|
245
|
+
data["end_datetime"] = end_datetime
|
|
217
246
|
|
|
218
247
|
response = self._post("/v2/search/news", json=data)
|
|
219
248
|
return response.get("docs", [])
|
|
@@ -224,8 +253,10 @@ class Reportify:
|
|
|
224
253
|
*,
|
|
225
254
|
num: int = 10,
|
|
226
255
|
symbols: list[str] | None = None,
|
|
227
|
-
|
|
228
|
-
|
|
256
|
+
industries: list[str] | None = None,
|
|
257
|
+
channel_ids: list[str] | None = None,
|
|
258
|
+
start_datetime: str | None = None,
|
|
259
|
+
end_datetime: str | None = None,
|
|
229
260
|
) -> list[dict[str, Any]]:
|
|
230
261
|
"""
|
|
231
262
|
Search research reports
|
|
@@ -234,19 +265,25 @@ class Reportify:
|
|
|
234
265
|
query: Search query string
|
|
235
266
|
num: Number of results to return
|
|
236
267
|
symbols: Filter by stock symbols
|
|
237
|
-
|
|
238
|
-
|
|
268
|
+
industries: Filter by industries
|
|
269
|
+
channel_ids: Filter by channel IDs
|
|
270
|
+
start_datetime: Start datetime filter (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)
|
|
271
|
+
end_datetime: End datetime filter (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)
|
|
239
272
|
|
|
240
273
|
Returns:
|
|
241
274
|
List of research reports
|
|
242
275
|
"""
|
|
243
|
-
data = {"query": query, "num": num}
|
|
276
|
+
data: dict[str, Any] = {"query": query, "num": num}
|
|
244
277
|
if symbols:
|
|
245
278
|
data["symbols"] = symbols
|
|
246
|
-
if
|
|
247
|
-
data["
|
|
248
|
-
if
|
|
249
|
-
data["
|
|
279
|
+
if industries:
|
|
280
|
+
data["industries"] = industries
|
|
281
|
+
if channel_ids:
|
|
282
|
+
data["channel_ids"] = channel_ids
|
|
283
|
+
if start_datetime:
|
|
284
|
+
data["start_datetime"] = start_datetime
|
|
285
|
+
if end_datetime:
|
|
286
|
+
data["end_datetime"] = end_datetime
|
|
250
287
|
|
|
251
288
|
response = self._post("/v2/search/reports", json=data)
|
|
252
289
|
return response.get("docs", [])
|
|
@@ -254,67 +291,198 @@ class Reportify:
|
|
|
254
291
|
def search_filings(
|
|
255
292
|
self,
|
|
256
293
|
query: str,
|
|
294
|
+
symbols: list[str],
|
|
257
295
|
*,
|
|
258
296
|
num: int = 10,
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
end_date: str | None = None,
|
|
297
|
+
start_datetime: str | None = None,
|
|
298
|
+
end_datetime: str | None = None,
|
|
262
299
|
) -> list[dict[str, Any]]:
|
|
263
300
|
"""
|
|
264
301
|
Search company filings and announcements
|
|
265
302
|
|
|
266
303
|
Args:
|
|
267
304
|
query: Search query string
|
|
305
|
+
symbols: Stock symbols to filter by (required)
|
|
268
306
|
num: Number of results to return
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
end_date: End date filter (YYYY-MM-DD)
|
|
307
|
+
start_datetime: Start datetime filter (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)
|
|
308
|
+
end_datetime: End datetime filter (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)
|
|
272
309
|
|
|
273
310
|
Returns:
|
|
274
311
|
List of filings
|
|
275
312
|
"""
|
|
276
|
-
data = {"query": query, "num": num}
|
|
277
|
-
if
|
|
278
|
-
data["
|
|
279
|
-
if
|
|
280
|
-
data["
|
|
281
|
-
if end_date:
|
|
282
|
-
data["end_date"] = end_date
|
|
313
|
+
data: dict[str, Any] = {"query": query, "symbols": symbols, "num": num}
|
|
314
|
+
if start_datetime:
|
|
315
|
+
data["start_datetime"] = start_datetime
|
|
316
|
+
if end_datetime:
|
|
317
|
+
data["end_datetime"] = end_datetime
|
|
283
318
|
|
|
284
319
|
response = self._post("/v2/search/filings", json=data)
|
|
285
320
|
return response.get("docs", [])
|
|
286
321
|
|
|
287
322
|
def search_transcripts(
|
|
323
|
+
self,
|
|
324
|
+
query: str,
|
|
325
|
+
symbols: list[str],
|
|
326
|
+
*,
|
|
327
|
+
num: int = 10,
|
|
328
|
+
start_datetime: str | None = None,
|
|
329
|
+
end_datetime: str | None = None,
|
|
330
|
+
) -> list[dict[str, Any]]:
|
|
331
|
+
"""
|
|
332
|
+
Search earnings call transcripts (conference calls)
|
|
333
|
+
|
|
334
|
+
Args:
|
|
335
|
+
query: Search query string
|
|
336
|
+
symbols: Stock symbols to filter by (required)
|
|
337
|
+
num: Number of results to return
|
|
338
|
+
start_datetime: Start datetime filter (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)
|
|
339
|
+
end_datetime: End datetime filter (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)
|
|
340
|
+
|
|
341
|
+
Returns:
|
|
342
|
+
List of transcripts
|
|
343
|
+
"""
|
|
344
|
+
data: dict[str, Any] = {"query": query, "symbols": symbols, "num": num}
|
|
345
|
+
if start_datetime:
|
|
346
|
+
data["start_datetime"] = start_datetime
|
|
347
|
+
if end_datetime:
|
|
348
|
+
data["end_datetime"] = end_datetime
|
|
349
|
+
|
|
350
|
+
response = self._post("/v2/search/conference-calls", json=data)
|
|
351
|
+
return response.get("docs", [])
|
|
352
|
+
|
|
353
|
+
def search_earnings_pack(
|
|
354
|
+
self,
|
|
355
|
+
query: str,
|
|
356
|
+
symbols: list[str],
|
|
357
|
+
*,
|
|
358
|
+
num: int = 10,
|
|
359
|
+
start_datetime: str | None = None,
|
|
360
|
+
end_datetime: str | None = None,
|
|
361
|
+
) -> list[dict[str, Any]]:
|
|
362
|
+
"""
|
|
363
|
+
Search earnings pack documents
|
|
364
|
+
|
|
365
|
+
Includes financial reports, earnings call transcripts,
|
|
366
|
+
presentation materials, and press releases.
|
|
367
|
+
|
|
368
|
+
Args:
|
|
369
|
+
query: Search query string
|
|
370
|
+
symbols: Stock symbols to filter by (required)
|
|
371
|
+
num: Number of results to return
|
|
372
|
+
start_datetime: Start datetime filter (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)
|
|
373
|
+
end_datetime: End datetime filter (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)
|
|
374
|
+
|
|
375
|
+
Returns:
|
|
376
|
+
List of earnings pack documents
|
|
377
|
+
"""
|
|
378
|
+
data: dict[str, Any] = {"query": query, "symbols": symbols, "num": num}
|
|
379
|
+
if start_datetime:
|
|
380
|
+
data["start_datetime"] = start_datetime
|
|
381
|
+
if end_datetime:
|
|
382
|
+
data["end_datetime"] = end_datetime
|
|
383
|
+
|
|
384
|
+
response = self._post("/v2/search/earnings-pack", json=data)
|
|
385
|
+
return response.get("docs", [])
|
|
386
|
+
|
|
387
|
+
def search_minutes(
|
|
288
388
|
self,
|
|
289
389
|
query: str,
|
|
290
390
|
*,
|
|
291
391
|
num: int = 10,
|
|
292
392
|
symbols: list[str] | None = None,
|
|
293
|
-
|
|
294
|
-
|
|
393
|
+
start_datetime: str | None = None,
|
|
394
|
+
end_datetime: str | None = None,
|
|
295
395
|
) -> list[dict[str, Any]]:
|
|
296
396
|
"""
|
|
297
|
-
Search
|
|
397
|
+
Search minutes transcripts
|
|
398
|
+
|
|
399
|
+
Includes conference calls and IR (Investor Relations) meetings.
|
|
298
400
|
|
|
299
401
|
Args:
|
|
300
402
|
query: Search query string
|
|
301
403
|
num: Number of results to return
|
|
302
404
|
symbols: Filter by stock symbols
|
|
303
|
-
|
|
304
|
-
|
|
405
|
+
start_datetime: Start datetime filter (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)
|
|
406
|
+
end_datetime: End datetime filter (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)
|
|
305
407
|
|
|
306
408
|
Returns:
|
|
307
|
-
List of transcripts
|
|
409
|
+
List of minutes transcripts
|
|
308
410
|
"""
|
|
309
|
-
data = {"query": query, "num": num}
|
|
411
|
+
data: dict[str, Any] = {"query": query, "num": num}
|
|
310
412
|
if symbols:
|
|
311
413
|
data["symbols"] = symbols
|
|
312
|
-
if
|
|
313
|
-
data["
|
|
314
|
-
if
|
|
315
|
-
data["
|
|
414
|
+
if start_datetime:
|
|
415
|
+
data["start_datetime"] = start_datetime
|
|
416
|
+
if end_datetime:
|
|
417
|
+
data["end_datetime"] = end_datetime
|
|
316
418
|
|
|
317
|
-
response = self._post("/v2/search/
|
|
419
|
+
response = self._post("/v2/search/minutes", json=data)
|
|
420
|
+
return response.get("docs", [])
|
|
421
|
+
|
|
422
|
+
def search_socials(
|
|
423
|
+
self,
|
|
424
|
+
query: str,
|
|
425
|
+
*,
|
|
426
|
+
num: int = 10,
|
|
427
|
+
symbols: list[str] | None = None,
|
|
428
|
+
channel_ids: list[str] | None = None,
|
|
429
|
+
start_datetime: str | None = None,
|
|
430
|
+
end_datetime: str | None = None,
|
|
431
|
+
) -> list[dict[str, Any]]:
|
|
432
|
+
"""
|
|
433
|
+
Search social media content and market sentiment
|
|
434
|
+
|
|
435
|
+
Args:
|
|
436
|
+
query: Search query string
|
|
437
|
+
num: Number of results to return
|
|
438
|
+
symbols: Filter by stock symbols
|
|
439
|
+
channel_ids: Filter by channel IDs
|
|
440
|
+
start_datetime: Start datetime filter (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)
|
|
441
|
+
end_datetime: End datetime filter (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)
|
|
442
|
+
|
|
443
|
+
Returns:
|
|
444
|
+
List of social media content
|
|
445
|
+
"""
|
|
446
|
+
data: dict[str, Any] = {"query": query, "num": num}
|
|
447
|
+
if symbols:
|
|
448
|
+
data["symbols"] = symbols
|
|
449
|
+
if channel_ids:
|
|
450
|
+
data["channel_ids"] = channel_ids
|
|
451
|
+
if start_datetime:
|
|
452
|
+
data["start_datetime"] = start_datetime
|
|
453
|
+
if end_datetime:
|
|
454
|
+
data["end_datetime"] = end_datetime
|
|
455
|
+
|
|
456
|
+
response = self._post("/v2/search/socials", json=data)
|
|
457
|
+
return response.get("docs", [])
|
|
458
|
+
|
|
459
|
+
def search_webpages(
|
|
460
|
+
self,
|
|
461
|
+
query: str,
|
|
462
|
+
*,
|
|
463
|
+
num: int = 10,
|
|
464
|
+
start_datetime: str | None = None,
|
|
465
|
+
end_datetime: str | None = None,
|
|
466
|
+
) -> list[dict[str, Any]]:
|
|
467
|
+
"""
|
|
468
|
+
Search webpage content
|
|
469
|
+
|
|
470
|
+
Args:
|
|
471
|
+
query: Search query string
|
|
472
|
+
num: Number of results to return
|
|
473
|
+
start_datetime: Start datetime filter (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)
|
|
474
|
+
end_datetime: End datetime filter (YYYY-MM-DD or YYYY-MM-DD HH:MM:SS)
|
|
475
|
+
|
|
476
|
+
Returns:
|
|
477
|
+
List of webpage content
|
|
478
|
+
"""
|
|
479
|
+
data: dict[str, Any] = {"query": query, "num": num}
|
|
480
|
+
if start_datetime:
|
|
481
|
+
data["start_datetime"] = start_datetime
|
|
482
|
+
if end_datetime:
|
|
483
|
+
data["end_datetime"] = end_datetime
|
|
484
|
+
|
|
485
|
+
response = self._post("/v2/search/webpages", json=data)
|
|
318
486
|
return response.get("docs", [])
|
|
319
487
|
|
|
320
488
|
# -------------------------------------------------------------------------
|
|
@@ -369,6 +537,38 @@ class Reportify:
|
|
|
369
537
|
self._concepts = ConceptsModule(self)
|
|
370
538
|
return self._concepts
|
|
371
539
|
|
|
540
|
+
@property
|
|
541
|
+
def channels(self):
|
|
542
|
+
"""Channels module for searching and following channels"""
|
|
543
|
+
if self._channels is None:
|
|
544
|
+
from reportify_sdk.channels import ChannelsModule
|
|
545
|
+
self._channels = ChannelsModule(self)
|
|
546
|
+
return self._channels
|
|
547
|
+
|
|
548
|
+
@property
|
|
549
|
+
def chat(self):
|
|
550
|
+
"""Chat module for document-based Q&A"""
|
|
551
|
+
if self._chat is None:
|
|
552
|
+
from reportify_sdk.chat import ChatModule
|
|
553
|
+
self._chat = ChatModule(self)
|
|
554
|
+
return self._chat
|
|
555
|
+
|
|
556
|
+
@property
|
|
557
|
+
def agent(self):
|
|
558
|
+
"""Agent module for AI-powered conversations and workflows"""
|
|
559
|
+
if self._agent is None:
|
|
560
|
+
from reportify_sdk.agent import AgentModule
|
|
561
|
+
self._agent = AgentModule(self)
|
|
562
|
+
return self._agent
|
|
563
|
+
|
|
564
|
+
@property
|
|
565
|
+
def user(self):
|
|
566
|
+
"""User module for user-related tools and data"""
|
|
567
|
+
if self._user is None:
|
|
568
|
+
from reportify_sdk.user import UserModule
|
|
569
|
+
self._user = UserModule(self)
|
|
570
|
+
return self._user
|
|
571
|
+
|
|
372
572
|
def close(self):
|
|
373
573
|
"""Close the HTTP client"""
|
|
374
574
|
self._client.close()
|