reportify-sdk 0.2.8__tar.gz → 0.2.9__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.
- {reportify_sdk-0.2.8/reportify_sdk.egg-info → reportify_sdk-0.2.9}/PKG-INFO +1 -1
- {reportify_sdk-0.2.8 → reportify_sdk-0.2.9}/pyproject.toml +1 -1
- {reportify_sdk-0.2.8 → reportify_sdk-0.2.9}/reportify_sdk/__init__.py +1 -1
- reportify_sdk-0.2.9/reportify_sdk/agent.py +213 -0
- reportify_sdk-0.2.9/reportify_sdk/channels.py +126 -0
- reportify_sdk-0.2.9/reportify_sdk/chat.py +107 -0
- reportify_sdk-0.2.9/reportify_sdk/client.py +580 -0
- reportify_sdk-0.2.9/reportify_sdk/docs.py +516 -0
- {reportify_sdk-0.2.8 → reportify_sdk-0.2.9}/reportify_sdk/kb.py +15 -0
- {reportify_sdk-0.2.8 → reportify_sdk-0.2.9}/reportify_sdk/stock.py +203 -121
- {reportify_sdk-0.2.8 → reportify_sdk-0.2.9}/reportify_sdk/timeline.py +34 -0
- reportify_sdk-0.2.9/reportify_sdk/user.py +44 -0
- {reportify_sdk-0.2.8 → reportify_sdk-0.2.9/reportify_sdk.egg-info}/PKG-INFO +1 -1
- {reportify_sdk-0.2.8 → reportify_sdk-0.2.9}/reportify_sdk.egg-info/SOURCES.txt +4 -0
- reportify_sdk-0.2.8/reportify_sdk/client.py +0 -380
- reportify_sdk-0.2.8/reportify_sdk/docs.py +0 -173
- {reportify_sdk-0.2.8 → reportify_sdk-0.2.9}/LICENSE +0 -0
- {reportify_sdk-0.2.8 → reportify_sdk-0.2.9}/README.md +0 -0
- {reportify_sdk-0.2.8 → reportify_sdk-0.2.9}/reportify_sdk/concepts.py +0 -0
- {reportify_sdk-0.2.8 → reportify_sdk-0.2.9}/reportify_sdk/exceptions.py +0 -0
- {reportify_sdk-0.2.8 → reportify_sdk-0.2.9}/reportify_sdk/quant.py +0 -0
- {reportify_sdk-0.2.8 → reportify_sdk-0.2.9}/reportify_sdk.egg-info/dependency_links.txt +0 -0
- {reportify_sdk-0.2.8 → reportify_sdk-0.2.9}/reportify_sdk.egg-info/requires.txt +0 -0
- {reportify_sdk-0.2.8 → reportify_sdk-0.2.9}/reportify_sdk.egg-info/top_level.txt +0 -0
- {reportify_sdk-0.2.8 → reportify_sdk-0.2.9}/setup.cfg +0 -0
|
@@ -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)
|