reportify-sdk 0.2.8__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/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.8",
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
- start_date: str | None = None,
151
- end_date: str | None = None,
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
- start_date: Start date filter (YYYY-MM-DD)
162
- end_date: End date filter (YYYY-MM-DD)
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 start_date:
181
- data["start_date"] = start_date
182
- if end_date:
183
- data["end_date"] = end_date
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
- start_date: str | None = None,
195
- end_date: str | None = None,
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
- start_date: Start date filter (YYYY-MM-DD)
205
- end_date: End date filter (YYYY-MM-DD)
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 start_date:
214
- data["start_date"] = start_date
215
- if end_date:
216
- data["end_date"] = end_date
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
- start_date: str | None = None,
228
- end_date: str | None = None,
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
- start_date: Start date filter (YYYY-MM-DD)
238
- end_date: End date filter (YYYY-MM-DD)
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 start_date:
247
- data["start_date"] = start_date
248
- if end_date:
249
- data["end_date"] = end_date
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
- symbols: list[str] | None = None,
260
- start_date: str | None = None,
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
- symbols: Filter by stock symbols
270
- start_date: Start date filter (YYYY-MM-DD)
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 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
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
- start_date: str | None = None,
294
- end_date: str | None = None,
393
+ start_datetime: str | None = None,
394
+ end_datetime: str | None = None,
295
395
  ) -> list[dict[str, Any]]:
296
396
  """
297
- Search earnings call transcripts
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
- start_date: Start date filter (YYYY-MM-DD)
304
- end_date: End date filter (YYYY-MM-DD)
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 start_date:
313
- data["start_date"] = start_date
314
- if end_date:
315
- data["end_date"] = end_date
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/conference-calls", json=data)
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()