kbot-py-client 2.0.2__tar.gz → 2.0.4__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.
- {kbot_py_client-2.0.2/kbot_py_client.egg-info → kbot_py_client-2.0.4}/PKG-INFO +33 -2
- {kbot_py_client-2.0.2 → kbot_py_client-2.0.4}/README.md +32 -1
- kbot_py_client-2.0.4/kbot_client/chat_client.py +178 -0
- {kbot_py_client-2.0.2 → kbot_py_client-2.0.4}/kbot_client/client.py +8 -4
- {kbot_py_client-2.0.2 → kbot_py_client-2.0.4}/kbot_client/client.recording.py +1 -3
- {kbot_py_client-2.0.2 → kbot_py_client-2.0.4/kbot_py_client.egg-info}/PKG-INFO +33 -2
- {kbot_py_client-2.0.2 → kbot_py_client-2.0.4}/kbot_py_client.egg-info/SOURCES.txt +1 -0
- {kbot_py_client-2.0.2 → kbot_py_client-2.0.4}/setup.py +1 -1
- {kbot_py_client-2.0.2 → kbot_py_client-2.0.4}/.gitignore +0 -0
- {kbot_py_client-2.0.2 → kbot_py_client-2.0.4}/LICENSE +0 -0
- {kbot_py_client-2.0.2 → kbot_py_client-2.0.4}/kbot_client/__init__.py +0 -0
- {kbot_py_client-2.0.2 → kbot_py_client-2.0.4}/kbot_client/client_group.py +0 -0
- {kbot_py_client-2.0.2 → kbot_py_client-2.0.4}/kbot_client/folder_sync.py +0 -0
- {kbot_py_client-2.0.2 → kbot_py_client-2.0.4}/kbot_client/test.py +0 -0
- {kbot_py_client-2.0.2 → kbot_py_client-2.0.4}/kbot_py_client.egg-info/dependency_links.txt +0 -0
- {kbot_py_client-2.0.2 → kbot_py_client-2.0.4}/kbot_py_client.egg-info/requires.txt +0 -0
- {kbot_py_client-2.0.2 → kbot_py_client-2.0.4}/kbot_py_client.egg-info/top_level.txt +0 -0
- {kbot_py_client-2.0.2 → kbot_py_client-2.0.4}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: kbot-py-client
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.4
|
|
4
4
|
Summary: Client for Konverso Kbot
|
|
5
5
|
Home-page: https://www.konverso.ai
|
|
6
6
|
Author: Konverso
|
|
@@ -146,6 +146,37 @@ In this example, we create a conversation between the logged in user and the bot
|
|
|
146
146
|
else:
|
|
147
147
|
print("Could not create conversation due to: ", r.text)
|
|
148
148
|
|
|
149
|
+
## Uploading one file to kbot
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
### Prerequisites
|
|
153
|
+
* A local file that you wish to send
|
|
154
|
+
* The UUID of the folder that will receive the files you want to upload
|
|
155
|
+
|
|
156
|
+
### Code sample
|
|
157
|
+
```
|
|
158
|
+
current_top_folder = "uuid-of-a-folder"
|
|
159
|
+
filepath = "/tmp/test.pdf"
|
|
160
|
+
filename = os.path.basename(filepath)
|
|
161
|
+
|
|
162
|
+
# Upload to remote filemanager
|
|
163
|
+
with open(filepath, "rb") as fd:
|
|
164
|
+
files = {
|
|
165
|
+
"upload_files": fd
|
|
166
|
+
}
|
|
167
|
+
params= {
|
|
168
|
+
"override": False
|
|
169
|
+
}
|
|
170
|
+
data = {
|
|
171
|
+
"folder": current_top_folder,
|
|
172
|
+
"name": file_name,
|
|
173
|
+
}
|
|
174
|
+
response = self.client.post_file("attachment",
|
|
175
|
+
data=data,
|
|
176
|
+
params=params,
|
|
177
|
+
files=files)
|
|
178
|
+
```
|
|
179
|
+
|
|
149
180
|
## Uploading a batch of files to the file manager
|
|
150
181
|
|
|
151
182
|
### Prerequisites
|
|
@@ -162,5 +193,5 @@ In this example, we simply upload the content of a directory to a folder in the
|
|
|
162
193
|
client = Client("mybot.konverso.ai", api_key="17ebXXXXXXXXXXXXXXXXXXXXX")
|
|
163
194
|
|
|
164
195
|
syncer = FolderSync(client)
|
|
165
|
-
syncer.sync("/tmp/my_source_folder/", "
|
|
196
|
+
syncer.sync("/tmp/my_source_folder/", "1831f-XXXXXXXXXXXXXXXXXXXXXXX")
|
|
166
197
|
print("Syncing is done :)")
|
|
@@ -131,6 +131,37 @@ In this example, we create a conversation between the logged in user and the bot
|
|
|
131
131
|
else:
|
|
132
132
|
print("Could not create conversation due to: ", r.text)
|
|
133
133
|
|
|
134
|
+
## Uploading one file to kbot
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
### Prerequisites
|
|
138
|
+
* A local file that you wish to send
|
|
139
|
+
* The UUID of the folder that will receive the files you want to upload
|
|
140
|
+
|
|
141
|
+
### Code sample
|
|
142
|
+
```
|
|
143
|
+
current_top_folder = "uuid-of-a-folder"
|
|
144
|
+
filepath = "/tmp/test.pdf"
|
|
145
|
+
filename = os.path.basename(filepath)
|
|
146
|
+
|
|
147
|
+
# Upload to remote filemanager
|
|
148
|
+
with open(filepath, "rb") as fd:
|
|
149
|
+
files = {
|
|
150
|
+
"upload_files": fd
|
|
151
|
+
}
|
|
152
|
+
params= {
|
|
153
|
+
"override": False
|
|
154
|
+
}
|
|
155
|
+
data = {
|
|
156
|
+
"folder": current_top_folder,
|
|
157
|
+
"name": file_name,
|
|
158
|
+
}
|
|
159
|
+
response = self.client.post_file("attachment",
|
|
160
|
+
data=data,
|
|
161
|
+
params=params,
|
|
162
|
+
files=files)
|
|
163
|
+
```
|
|
164
|
+
|
|
134
165
|
## Uploading a batch of files to the file manager
|
|
135
166
|
|
|
136
167
|
### Prerequisites
|
|
@@ -147,5 +178,5 @@ In this example, we simply upload the content of a directory to a folder in the
|
|
|
147
178
|
client = Client("mybot.konverso.ai", api_key="17ebXXXXXXXXXXXXXXXXXXXXX")
|
|
148
179
|
|
|
149
180
|
syncer = FolderSync(client)
|
|
150
|
-
syncer.sync("/tmp/my_source_folder/", "
|
|
181
|
+
syncer.sync("/tmp/my_source_folder/", "1831f-XXXXXXXXXXXXXXXXXXXXXXX")
|
|
151
182
|
print("Syncing is done :)")
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import time
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
|
|
4
|
+
class ChatClient(ABC):
|
|
5
|
+
def __init__(self, client,
|
|
6
|
+
render_types=("text", "html"),
|
|
7
|
+
prompt="{sender}> {message}",
|
|
8
|
+
user_prompt = "User> ",
|
|
9
|
+
bye = "Bye, hope to see you again soon",
|
|
10
|
+
exit_commands = ("stop", "exit")):
|
|
11
|
+
|
|
12
|
+
self._client = client
|
|
13
|
+
self._render_types = render_types
|
|
14
|
+
self._prompt = prompt
|
|
15
|
+
self._user_prompt = user_prompt
|
|
16
|
+
self._bye = bye
|
|
17
|
+
self._exit_commands = exit_commands
|
|
18
|
+
|
|
19
|
+
# Create a new conversation
|
|
20
|
+
#
|
|
21
|
+
response = self._client.post("conversation", data={"username": "bot"})
|
|
22
|
+
response.raise_for_status()
|
|
23
|
+
|
|
24
|
+
# Print the first welcome message
|
|
25
|
+
#
|
|
26
|
+
self._process_new_messages(response.json(), context="welcome")
|
|
27
|
+
|
|
28
|
+
# Loop waiting for user questions and then waiting for the bot response
|
|
29
|
+
#
|
|
30
|
+
self._start_question_answer_loop(response.json().get("id"))
|
|
31
|
+
|
|
32
|
+
def _process_new_messages(self, messages_json, context):
|
|
33
|
+
"""Given a JSON response from the bot, extract two key information:
|
|
34
|
+
- sender: The name of the bot
|
|
35
|
+
- messages: A list of the JSON matching the type constraints such as:
|
|
36
|
+
|
|
37
|
+
Arguments:
|
|
38
|
+
- context: One of "welcome" or "response"
|
|
39
|
+
|
|
40
|
+
The input json of a Welcome (conversation creation) is expected to have format such as:
|
|
41
|
+
{
|
|
42
|
+
"sender": {...}
|
|
43
|
+
"messages": [{
|
|
44
|
+
"type": "message",
|
|
45
|
+
"message": [{
|
|
46
|
+
"format": "text",
|
|
47
|
+
"value": "Hello John",
|
|
48
|
+
...
|
|
49
|
+
|
|
50
|
+
The input json of a Response (conversation response) is expected to have format such as:
|
|
51
|
+
[{
|
|
52
|
+
"sender": {...}
|
|
53
|
+
"type": "message",
|
|
54
|
+
"message": [{
|
|
55
|
+
"format": "text",
|
|
56
|
+
"value": "Hello John",
|
|
57
|
+
...
|
|
58
|
+
|
|
59
|
+
Returns a tuple of two elements: sender, messages
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
stop = False
|
|
63
|
+
if context == "welcome":
|
|
64
|
+
self._sender = messages_json.get("sender").get("name")
|
|
65
|
+
|
|
66
|
+
for message in messages_json.get("messages"):
|
|
67
|
+
message_type = message.get("type")
|
|
68
|
+
|
|
69
|
+
if message.get("type") != "message":
|
|
70
|
+
continue
|
|
71
|
+
|
|
72
|
+
for message_content in message.get("message"):
|
|
73
|
+
if message_content.get("format") in self._render_types:
|
|
74
|
+
self._display_response(message_content)
|
|
75
|
+
|
|
76
|
+
elif context == "response":
|
|
77
|
+
#print(messages_json)
|
|
78
|
+
|
|
79
|
+
for one_message in messages_json.get("messages"):
|
|
80
|
+
self._sender = one_message.get("sender").get("name")
|
|
81
|
+
message_type = one_message.get("type")
|
|
82
|
+
|
|
83
|
+
if message_type == "stop_topic":
|
|
84
|
+
stop = True
|
|
85
|
+
|
|
86
|
+
if one_message.get("type") != "message":
|
|
87
|
+
continue
|
|
88
|
+
|
|
89
|
+
for message_content in one_message.get("message"):
|
|
90
|
+
if message_content.get("format") in self._render_types:
|
|
91
|
+
self._display_response(message_content)
|
|
92
|
+
|
|
93
|
+
return stop
|
|
94
|
+
|
|
95
|
+
def _display_response(self, message):
|
|
96
|
+
"""Display to the user the message. The message argument is a json in the format:
|
|
97
|
+
{
|
|
98
|
+
"format": "text",
|
|
99
|
+
"value": "Hello John",
|
|
100
|
+
...
|
|
101
|
+
"""
|
|
102
|
+
print(self._prompt.format(sender=self._sender, message=message.get('value')))
|
|
103
|
+
|
|
104
|
+
def _start_question_answer_loop(self, conversation_id):
|
|
105
|
+
|
|
106
|
+
# Start the chatbot, in a loop
|
|
107
|
+
# We stop when user type "exit" or EOF (Ctrl D)
|
|
108
|
+
while True:
|
|
109
|
+
|
|
110
|
+
# Get the user sentence and check for the stop conditions
|
|
111
|
+
#
|
|
112
|
+
try:
|
|
113
|
+
question = input(self._user_prompt)
|
|
114
|
+
except EOFError:
|
|
115
|
+
print(self._bye)
|
|
116
|
+
break
|
|
117
|
+
|
|
118
|
+
if not question:
|
|
119
|
+
continue
|
|
120
|
+
|
|
121
|
+
if question.lower() in self._exit_commands:
|
|
122
|
+
print(self._bye)
|
|
123
|
+
break
|
|
124
|
+
|
|
125
|
+
self._send_question(question, conversation_id)
|
|
126
|
+
self._get_response(conversation_id)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _send_question(self, question, conversation_id):
|
|
130
|
+
# Send the user question to Kbot.
|
|
131
|
+
#
|
|
132
|
+
data = {
|
|
133
|
+
"conversation_id": conversation_id,
|
|
134
|
+
"type":"message",
|
|
135
|
+
"message": question,
|
|
136
|
+
"fromUser": True,
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
response = self._client.post(f"conversation/{conversation_id}/message", data=data)
|
|
140
|
+
response.raise_for_status()
|
|
141
|
+
|
|
142
|
+
@abstractmethod
|
|
143
|
+
def _get_response(self, conversation_id):
|
|
144
|
+
"""Collect the kbot response"""
|
|
145
|
+
|
|
146
|
+
class AsyncChatClient(ChatClient):
|
|
147
|
+
"""A Chatbot client that will pull for updates and display responses
|
|
148
|
+
as they come
|
|
149
|
+
"""
|
|
150
|
+
def __init__(self, client, pull_interval=0.5, pull_timeout=10, **kwargs):
|
|
151
|
+
self._pull_interval = pull_interval
|
|
152
|
+
self._pull_timeout = pull_timeout
|
|
153
|
+
super().__init__(client,**kwargs)
|
|
154
|
+
|
|
155
|
+
def _get_response(self, conversation_id):
|
|
156
|
+
# Wait for the response(s)
|
|
157
|
+
#
|
|
158
|
+
while True:
|
|
159
|
+
time.sleep(self._pull_interval)
|
|
160
|
+
response = self._client.get(f"conversation/{conversation_id}/messages", params={"timeout": self._pull_timeout})
|
|
161
|
+
response.raise_for_status()
|
|
162
|
+
|
|
163
|
+
stop = self._process_new_messages(response.json(), context="response")
|
|
164
|
+
if stop:
|
|
165
|
+
# Time to ask for a new question
|
|
166
|
+
break
|
|
167
|
+
|
|
168
|
+
class SyncChatClient(ChatClient):
|
|
169
|
+
"""A Chatbot client that will wait for full response from the bot before displaying to the user
|
|
170
|
+
"""
|
|
171
|
+
|
|
172
|
+
def _get_response(self, conversation_id):
|
|
173
|
+
# Wait for the response(s)
|
|
174
|
+
#
|
|
175
|
+
params = {"wait": "true"}
|
|
176
|
+
response = self._client.get(f"conversation/{conversation_id}/messages", params=params)
|
|
177
|
+
response.raise_for_status()
|
|
178
|
+
self._process_new_messages(response.json(), context="response")
|
|
@@ -176,7 +176,11 @@ class Client:
|
|
|
176
176
|
self.__reset_headers(r.json())
|
|
177
177
|
|
|
178
178
|
def __request(self, method: str, uri : str = None, data: dict = None, params: dict = None, files: dict = None, attempt=0):
|
|
179
|
-
|
|
179
|
+
if files:
|
|
180
|
+
# For file upload, the data must be a dictionnary
|
|
181
|
+
dump_data = data
|
|
182
|
+
else:
|
|
183
|
+
dump_data = json.dumps(data or {})
|
|
180
184
|
|
|
181
185
|
if files:
|
|
182
186
|
headers = self._headers.copy()
|
|
@@ -185,7 +189,7 @@ class Client:
|
|
|
185
189
|
else:
|
|
186
190
|
headers = self._headers
|
|
187
191
|
|
|
188
|
-
r = requests.request(method.upper(), self.url + '/api/%s/' % (uri), params=params, data=dump_data, headers=headers, verify=self.verify)
|
|
192
|
+
r = requests.request(method.upper(), self.url + '/api/%s/' % (uri), params=params, data=dump_data, headers=headers, files=files, verify=self.verify)
|
|
189
193
|
|
|
190
194
|
if r.status_code == 401:
|
|
191
195
|
# Refresh the token
|
|
@@ -204,8 +208,8 @@ class Client:
|
|
|
204
208
|
|
|
205
209
|
return r
|
|
206
210
|
|
|
207
|
-
def request(self, method: str, uri: str, data: dict = None, params: dict = None):
|
|
208
|
-
return self.__request(method, uri=uri, data=data, params=params)
|
|
211
|
+
def request(self, method: str, uri: str, data: dict = None, params: dict = None, files: dict = None):
|
|
212
|
+
return self.__request(method, uri=uri, data=data, params=params, files=files)
|
|
209
213
|
|
|
210
214
|
def unit(self, name: str, params=None) -> dict:
|
|
211
215
|
r = self.get(name, params)
|
|
@@ -28,9 +28,7 @@ class Client:
|
|
|
28
28
|
else:
|
|
29
29
|
proto = 'http'
|
|
30
30
|
|
|
31
|
-
if
|
|
32
|
-
self.url = "%s://%s" % (proto, server)
|
|
33
|
-
elif proto == "https" and port == 443:
|
|
31
|
+
if port in (80, 443):
|
|
34
32
|
self.url = "%s://%s" % (proto, server)
|
|
35
33
|
else:
|
|
36
34
|
self.url = "%s://%s:%s" % (proto, server, port)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: kbot-py-client
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.4
|
|
4
4
|
Summary: Client for Konverso Kbot
|
|
5
5
|
Home-page: https://www.konverso.ai
|
|
6
6
|
Author: Konverso
|
|
@@ -146,6 +146,37 @@ In this example, we create a conversation between the logged in user and the bot
|
|
|
146
146
|
else:
|
|
147
147
|
print("Could not create conversation due to: ", r.text)
|
|
148
148
|
|
|
149
|
+
## Uploading one file to kbot
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
### Prerequisites
|
|
153
|
+
* A local file that you wish to send
|
|
154
|
+
* The UUID of the folder that will receive the files you want to upload
|
|
155
|
+
|
|
156
|
+
### Code sample
|
|
157
|
+
```
|
|
158
|
+
current_top_folder = "uuid-of-a-folder"
|
|
159
|
+
filepath = "/tmp/test.pdf"
|
|
160
|
+
filename = os.path.basename(filepath)
|
|
161
|
+
|
|
162
|
+
# Upload to remote filemanager
|
|
163
|
+
with open(filepath, "rb") as fd:
|
|
164
|
+
files = {
|
|
165
|
+
"upload_files": fd
|
|
166
|
+
}
|
|
167
|
+
params= {
|
|
168
|
+
"override": False
|
|
169
|
+
}
|
|
170
|
+
data = {
|
|
171
|
+
"folder": current_top_folder,
|
|
172
|
+
"name": file_name,
|
|
173
|
+
}
|
|
174
|
+
response = self.client.post_file("attachment",
|
|
175
|
+
data=data,
|
|
176
|
+
params=params,
|
|
177
|
+
files=files)
|
|
178
|
+
```
|
|
179
|
+
|
|
149
180
|
## Uploading a batch of files to the file manager
|
|
150
181
|
|
|
151
182
|
### Prerequisites
|
|
@@ -162,5 +193,5 @@ In this example, we simply upload the content of a directory to a folder in the
|
|
|
162
193
|
client = Client("mybot.konverso.ai", api_key="17ebXXXXXXXXXXXXXXXXXXXXX")
|
|
163
194
|
|
|
164
195
|
syncer = FolderSync(client)
|
|
165
|
-
syncer.sync("/tmp/my_source_folder/", "
|
|
196
|
+
syncer.sync("/tmp/my_source_folder/", "1831f-XXXXXXXXXXXXXXXXXXXXXXX")
|
|
166
197
|
print("Syncing is done :)")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|