reportify-sdk 0.2.8__tar.gz → 0.2.10__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. {reportify_sdk-0.2.8/reportify_sdk.egg-info → reportify_sdk-0.2.10}/PKG-INFO +1 -1
  2. {reportify_sdk-0.2.8 → reportify_sdk-0.2.10}/pyproject.toml +1 -1
  3. {reportify_sdk-0.2.8 → reportify_sdk-0.2.10}/reportify_sdk/__init__.py +1 -1
  4. reportify_sdk-0.2.10/reportify_sdk/agent.py +213 -0
  5. reportify_sdk-0.2.10/reportify_sdk/channels.py +126 -0
  6. reportify_sdk-0.2.10/reportify_sdk/chat.py +107 -0
  7. {reportify_sdk-0.2.8 → reportify_sdk-0.2.10}/reportify_sdk/client.py +62 -180
  8. reportify_sdk-0.2.10/reportify_sdk/docs.py +516 -0
  9. {reportify_sdk-0.2.8 → reportify_sdk-0.2.10}/reportify_sdk/kb.py +15 -0
  10. reportify_sdk-0.2.10/reportify_sdk/search.py +357 -0
  11. {reportify_sdk-0.2.8 → reportify_sdk-0.2.10}/reportify_sdk/stock.py +203 -121
  12. {reportify_sdk-0.2.8 → reportify_sdk-0.2.10}/reportify_sdk/timeline.py +34 -0
  13. reportify_sdk-0.2.10/reportify_sdk/user.py +44 -0
  14. {reportify_sdk-0.2.8 → reportify_sdk-0.2.10/reportify_sdk.egg-info}/PKG-INFO +1 -1
  15. {reportify_sdk-0.2.8 → reportify_sdk-0.2.10}/reportify_sdk.egg-info/SOURCES.txt +5 -0
  16. reportify_sdk-0.2.8/reportify_sdk/docs.py +0 -173
  17. {reportify_sdk-0.2.8 → reportify_sdk-0.2.10}/LICENSE +0 -0
  18. {reportify_sdk-0.2.8 → reportify_sdk-0.2.10}/README.md +0 -0
  19. {reportify_sdk-0.2.8 → reportify_sdk-0.2.10}/reportify_sdk/concepts.py +0 -0
  20. {reportify_sdk-0.2.8 → reportify_sdk-0.2.10}/reportify_sdk/exceptions.py +0 -0
  21. {reportify_sdk-0.2.8 → reportify_sdk-0.2.10}/reportify_sdk/quant.py +0 -0
  22. {reportify_sdk-0.2.8 → reportify_sdk-0.2.10}/reportify_sdk.egg-info/dependency_links.txt +0 -0
  23. {reportify_sdk-0.2.8 → reportify_sdk-0.2.10}/reportify_sdk.egg-info/requires.txt +0 -0
  24. {reportify_sdk-0.2.8 → reportify_sdk-0.2.10}/reportify_sdk.egg-info/top_level.txt +0 -0
  25. {reportify_sdk-0.2.8 → reportify_sdk-0.2.10}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: reportify-sdk
3
- Version: 0.2.8
3
+ Version: 0.2.10
4
4
  Summary: Python SDK for Reportify API - Financial data and document search
5
5
  Author-email: Reportify <support@reportify.cn>
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "reportify-sdk"
7
- version = "0.2.8"
7
+ version = "0.2.10"
8
8
  description = "Python SDK for Reportify API - Financial data and document search"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -20,7 +20,7 @@ from reportify_sdk.exceptions import (
20
20
  APIError,
21
21
  )
22
22
 
23
- __version__ = "0.1.0"
23
+ __version__ = "0.2.10"
24
24
  __all__ = [
25
25
  "Reportify",
26
26
  "ReportifyError",
@@ -0,0 +1,213 @@
1
+ """
2
+ Agent Module
3
+
4
+ Provides access to AI agent conversations and workflow execution.
5
+ """
6
+
7
+ from typing import TYPE_CHECKING, Any, Iterator
8
+
9
+ if TYPE_CHECKING:
10
+ from reportify_sdk.client import Reportify
11
+
12
+
13
+ class AgentModule:
14
+ """
15
+ Agent module for AI-powered conversations and workflows
16
+
17
+ Access through the main client:
18
+ >>> client = Reportify(api_key="xxx")
19
+ >>> conv = client.agent.create_conversation(agent_id=11887655289749510)
20
+ """
21
+
22
+ def __init__(self, client: "Reportify"):
23
+ self._client = client
24
+
25
+ def _get(self, path: str, params: dict[str, Any] | None = None) -> dict[str, Any]:
26
+ return self._client._get(path, params=params)
27
+
28
+ def _post(self, path: str, json: dict[str, Any] | None = None) -> dict[str, Any]:
29
+ return self._client._post(path, json=json)
30
+
31
+ def create_conversation(
32
+ self,
33
+ agent_id: int,
34
+ *,
35
+ title: str | None = None,
36
+ ) -> dict[str, Any]:
37
+ """
38
+ Create a new agent conversation
39
+
40
+ Args:
41
+ agent_id: Agent ID
42
+ title: Conversation title (optional)
43
+
44
+ Returns:
45
+ Conversation details including id, user_id, agent_id, type, status, etc.
46
+
47
+ Example:
48
+ >>> conv = client.agent.create_conversation(
49
+ ... agent_id=11887655289749510,
50
+ ... title="NVIDIA analysis"
51
+ ... )
52
+ >>> print(conv["id"])
53
+ """
54
+ data: dict[str, Any] = {"agent_id": agent_id}
55
+ if title:
56
+ data["title"] = title
57
+
58
+ return self._post("/v1/agent/conversations", json=data)
59
+
60
+ def get_conversation(self, conversation_id: int) -> dict[str, Any]:
61
+ """
62
+ Get agent conversation details
63
+
64
+ Args:
65
+ conversation_id: Conversation ID
66
+
67
+ Returns:
68
+ Conversation details including messages, status, etc.
69
+ """
70
+ return self._get(f"/v1/agent/conversations/{conversation_id}")
71
+
72
+ def chat(
73
+ self,
74
+ conversation_id: int,
75
+ message: str,
76
+ *,
77
+ documents: list[dict[str, Any]] | None = None,
78
+ stream: bool = True,
79
+ ) -> dict[str, Any] | Iterator[dict[str, Any]]:
80
+ """
81
+ Chat with agent (streaming or non-streaming)
82
+
83
+ Args:
84
+ conversation_id: Conversation ID
85
+ message: User message content
86
+ documents: List of related documents (optional)
87
+ Each document should have: doc_id, doc_title, file_type (optional)
88
+ stream: Whether to use streaming response (default: True)
89
+
90
+ Returns:
91
+ For streaming: Iterator of WorkflowStreamEvent objects
92
+ For non-streaming: Response with message content
93
+
94
+ Example:
95
+ >>> # Non-streaming
96
+ >>> response = client.agent.chat(
97
+ ... conversation_id=123456,
98
+ ... message="Analyze NVIDIA's latest earnings",
99
+ ... stream=False
100
+ ... )
101
+
102
+ >>> # Streaming
103
+ >>> for event in client.agent.chat(conv_id, "Hello", stream=True):
104
+ ... print(event)
105
+ """
106
+ data: dict[str, Any] = {
107
+ "message": message,
108
+ "stream": stream,
109
+ }
110
+ if documents:
111
+ data["documents"] = documents
112
+
113
+ return self._post(
114
+ f"/v1/agent/conversations/{conversation_id}/chat",
115
+ json=data,
116
+ )
117
+
118
+ def list_messages(
119
+ self,
120
+ conversation_id: int,
121
+ *,
122
+ limit: int = 10,
123
+ before_message_id: int | None = None,
124
+ ) -> dict[str, Any]:
125
+ """
126
+ List agent conversation messages
127
+
128
+ Args:
129
+ conversation_id: Conversation ID
130
+ limit: Number of messages to return (default: 10, max: 100)
131
+ before_message_id: Fetch messages created before this message ID
132
+
133
+ Returns:
134
+ Dictionary with messages list
135
+ """
136
+ params: dict[str, Any] = {"limit": limit}
137
+ if before_message_id is not None:
138
+ params["before_message_id"] = before_message_id
139
+
140
+ return self._get(
141
+ f"/v1/agent/conversations/{conversation_id}/messages",
142
+ params=params,
143
+ )
144
+
145
+ def get_message_events(
146
+ self,
147
+ conversation_id: int,
148
+ assistant_message_id: str,
149
+ *,
150
+ stream: bool = True,
151
+ timeout: int = 1800,
152
+ from_offset: int = 0,
153
+ ) -> dict[str, Any] | Iterator[dict[str, Any]]:
154
+ """
155
+ Get assistant message events from a specific offset
156
+
157
+ Args:
158
+ conversation_id: Conversation ID
159
+ assistant_message_id: Assistant message ID (from chat response header)
160
+ stream: Whether to stream events via SSE (default: True)
161
+ timeout: Timeout in seconds for streaming mode (default: 1800)
162
+ from_offset: Start streaming from specific offset (default: 0)
163
+
164
+ Returns:
165
+ For streaming: Iterator of WorkflowStreamEvent objects
166
+ For non-streaming: Dictionary with assistant_events list
167
+ """
168
+ params: dict[str, Any] = {
169
+ "stream": stream,
170
+ "timeout": timeout,
171
+ "from_offset": from_offset,
172
+ }
173
+
174
+ return self._get(
175
+ f"/v1/agent/conversations/{conversation_id}/messages/{assistant_message_id}",
176
+ params=params,
177
+ )
178
+
179
+ def cancel_execution(
180
+ self,
181
+ conversation_id: int,
182
+ assistant_message_id: str,
183
+ ) -> dict[str, Any]:
184
+ """
185
+ Cancel agent execution
186
+
187
+ Args:
188
+ conversation_id: Conversation ID
189
+ assistant_message_id: Assistant message ID to cancel
190
+
191
+ Returns:
192
+ Dictionary with response_id and status
193
+ """
194
+ return self._post(
195
+ f"/v1/agent/conversations/{conversation_id}/messages/{assistant_message_id}/cancel"
196
+ )
197
+
198
+ def get_file(self, file_id: str) -> bytes:
199
+ """
200
+ Get agent generated file
201
+
202
+ Args:
203
+ file_id: Agent generated file ID
204
+
205
+ Returns:
206
+ File content as bytes
207
+
208
+ Example:
209
+ >>> file_content = client.agent.get_file("file_abc123")
210
+ >>> with open("output.xlsx", "wb") as f:
211
+ ... f.write(file_content)
212
+ """
213
+ return self._client._get_bytes(f"/v1/agent/files/{file_id}")
@@ -0,0 +1,126 @@
1
+ """
2
+ Channels Module
3
+
4
+ Provides access to channel management and following functionality.
5
+ """
6
+
7
+ from typing import TYPE_CHECKING, Any
8
+
9
+ if TYPE_CHECKING:
10
+ from reportify_sdk.client import Reportify
11
+
12
+
13
+ class ChannelsModule:
14
+ """
15
+ Channels module for searching and following channels
16
+
17
+ Access through the main client:
18
+ >>> client = Reportify(api_key="xxx")
19
+ >>> channels = client.channels.search("Goldman Sachs")
20
+ """
21
+
22
+ def __init__(self, client: "Reportify"):
23
+ self._client = client
24
+
25
+ def _get(self, path: str, params: dict[str, Any] | None = None) -> dict[str, Any]:
26
+ return self._client._get(path, params=params)
27
+
28
+ def _post(self, path: str, json: dict[str, Any] | None = None) -> dict[str, Any]:
29
+ return self._client._post(path, json=json)
30
+
31
+ def search(
32
+ self,
33
+ query: str,
34
+ *,
35
+ page_num: int = 1,
36
+ page_size: int = 10,
37
+ ) -> dict[str, Any]:
38
+ """
39
+ Search for channels by query string
40
+
41
+ Args:
42
+ query: Search query string or URL
43
+ page_num: Page number (default: 1)
44
+ page_size: Number of items per page (default: 10)
45
+
46
+ Returns:
47
+ Dictionary with channels list and pagination info
48
+
49
+ Example:
50
+ >>> result = client.channels.search("Goldman Sachs")
51
+ >>> for channel in result["channels"]:
52
+ ... print(channel["name"])
53
+ """
54
+ return self._post(
55
+ "/v1/channels/search",
56
+ json={"query": query, "page_num": page_num, "page_size": page_size},
57
+ )
58
+
59
+ def followings(
60
+ self,
61
+ *,
62
+ page_num: int = 1,
63
+ page_size: int = 10,
64
+ ) -> dict[str, Any]:
65
+ """
66
+ Get list of channels user is following
67
+
68
+ Args:
69
+ page_num: Page number (default: 1)
70
+ page_size: Number of items per page (default: 10)
71
+
72
+ Returns:
73
+ Dictionary with channels list and pagination info
74
+ """
75
+ return self._get(
76
+ "/v1/channels/followings",
77
+ params={"page_num": page_num, "page_size": page_size},
78
+ )
79
+
80
+ def follow(self, channel_id: str) -> dict[str, Any]:
81
+ """
82
+ Follow a specific channel
83
+
84
+ Args:
85
+ channel_id: Channel ID to follow
86
+
87
+ Returns:
88
+ Channel information with following status
89
+ """
90
+ return self._post(f"/v1/channels/{channel_id}/follow")
91
+
92
+ def unfollow(self, channel_id: str) -> dict[str, Any]:
93
+ """
94
+ Unfollow a specific channel
95
+
96
+ Args:
97
+ channel_id: Channel ID to unfollow
98
+
99
+ Returns:
100
+ Status message
101
+ """
102
+ return self._client._request("DELETE", f"/v1/channels/{channel_id}/unfollow")
103
+
104
+ def get_docs(
105
+ self,
106
+ *,
107
+ channel_ids: str | None = None,
108
+ page_num: int = 1,
109
+ page_size: int = 10,
110
+ ) -> dict[str, Any]:
111
+ """
112
+ Get documents from followed channels
113
+
114
+ Args:
115
+ channel_ids: Comma-separated channel IDs (optional, uses all followed if not provided)
116
+ page_num: Page number (default: 1)
117
+ page_size: Number of items per page (default: 10)
118
+
119
+ Returns:
120
+ Dictionary with documents list and pagination info
121
+ """
122
+ params: dict[str, Any] = {"page_num": page_num, "page_size": page_size}
123
+ if channel_ids:
124
+ params["channel_ids"] = channel_ids
125
+
126
+ return self._get("/v1/channels/followings/docs", params=params)
@@ -0,0 +1,107 @@
1
+ """
2
+ Chat Module
3
+
4
+ Provides chat completion functionality based on document content.
5
+ """
6
+
7
+ from typing import TYPE_CHECKING, Any, Iterator, Literal
8
+
9
+ if TYPE_CHECKING:
10
+ from reportify_sdk.client import Reportify
11
+
12
+
13
+ class ChatModule:
14
+ """
15
+ Chat module for document-based Q&A
16
+
17
+ Access through the main client:
18
+ >>> client = Reportify(api_key="xxx")
19
+ >>> response = client.chat.completion("What are Tesla's revenue?")
20
+ """
21
+
22
+ def __init__(self, client: "Reportify"):
23
+ self._client = client
24
+
25
+ def _post(self, path: str, json: dict[str, Any] | None = None) -> dict[str, Any]:
26
+ return self._client._post(path, json=json)
27
+
28
+ def completion(
29
+ self,
30
+ query: str,
31
+ *,
32
+ folder_ids: list[str] | None = None,
33
+ doc_ids: list[str] | None = None,
34
+ categories: list[str] | None = None,
35
+ markets: list[str] | None = None,
36
+ institutions: list[str] | None = None,
37
+ symbols: list[str] | None = None,
38
+ tags: dict[str, list] | None = None,
39
+ start_date: str | None = None,
40
+ end_date: str | None = None,
41
+ min_score: float | None = None,
42
+ extended_filters: list[dict] | None = None,
43
+ mode: Literal["concise", "comprehensive", "deepresearch"] = "concise",
44
+ session_id: str = "",
45
+ stream: bool = False,
46
+ ) -> dict[str, Any] | Iterator[dict[str, Any]]:
47
+ """
48
+ Chat completion based on document content
49
+
50
+ Args:
51
+ query: User question
52
+ folder_ids: Filter by folder IDs
53
+ doc_ids: Filter by document IDs
54
+ categories: Filter by document categories
55
+ markets: Filter by markets (cn, hk, us)
56
+ institutions: Filter by institutions
57
+ symbols: Filter by stock symbols
58
+ tags: Filter by tags
59
+ start_date: Start date filter (YYYY-MM-DD)
60
+ end_date: End date filter (YYYY-MM-DD)
61
+ min_score: Minimum relevance score
62
+ extended_filters: Extended filter conditions
63
+ mode: Response mode ("concise", "comprehensive", "deepresearch")
64
+ session_id: Session ID for conversation continuity
65
+ stream: Whether to stream the response
66
+
67
+ Returns:
68
+ Chat completion response with type, message_id, message, and extra
69
+
70
+ Example:
71
+ >>> response = client.chat.completion(
72
+ ... "What are Tesla's revenue projections?",
73
+ ... symbols=["US:TSLA"],
74
+ ... mode="comprehensive"
75
+ ... )
76
+ >>> print(response["message"])
77
+ """
78
+ data: dict[str, Any] = {
79
+ "query": query,
80
+ "mode": mode,
81
+ "session_id": session_id,
82
+ "stream": stream,
83
+ }
84
+ if folder_ids:
85
+ data["folder_ids"] = folder_ids
86
+ if doc_ids:
87
+ data["doc_ids"] = doc_ids
88
+ if categories:
89
+ data["categories"] = categories
90
+ if markets:
91
+ data["markets"] = markets
92
+ if institutions:
93
+ data["institutions"] = institutions
94
+ if symbols:
95
+ data["symbols"] = symbols
96
+ if tags:
97
+ data["tags"] = tags
98
+ if start_date:
99
+ data["start_date"] = start_date
100
+ if end_date:
101
+ data["end_date"] = end_date
102
+ if min_score is not None:
103
+ data["min_score"] = min_score
104
+ if extended_filters:
105
+ data["extended_filters"] = extended_filters
106
+
107
+ return self._post("/v1/chat/completion", json=data)