nobox-chat-sdk 1.0.0__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.
- nobox_chat_sdk-1.0.0/PKG-INFO +186 -0
- nobox_chat_sdk-1.0.0/README.md +163 -0
- nobox_chat_sdk-1.0.0/nobox_chat.py +202 -0
- nobox_chat_sdk-1.0.0/nobox_chat_sdk.egg-info/PKG-INFO +186 -0
- nobox_chat_sdk-1.0.0/nobox_chat_sdk.egg-info/SOURCES.txt +8 -0
- nobox_chat_sdk-1.0.0/nobox_chat_sdk.egg-info/dependency_links.txt +1 -0
- nobox_chat_sdk-1.0.0/nobox_chat_sdk.egg-info/requires.txt +1 -0
- nobox_chat_sdk-1.0.0/nobox_chat_sdk.egg-info/top_level.txt +1 -0
- nobox_chat_sdk-1.0.0/setup.cfg +4 -0
- nobox_chat_sdk-1.0.0/setup.py +27 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nobox-chat-sdk
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Official Python SDK and SignalR/Webhook Integration for NoBox.Ai platform
|
|
5
|
+
Home-page: https://gitlab.ubig.co.id/erik/nobox-chat-python
|
|
6
|
+
Author: NoBox.Ai Team
|
|
7
|
+
Author-email: support@nobox.ai
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.7
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
Requires-Dist: requests>=2.25.0
|
|
14
|
+
Dynamic: author
|
|
15
|
+
Dynamic: author-email
|
|
16
|
+
Dynamic: classifier
|
|
17
|
+
Dynamic: description
|
|
18
|
+
Dynamic: description-content-type
|
|
19
|
+
Dynamic: home-page
|
|
20
|
+
Dynamic: requires-dist
|
|
21
|
+
Dynamic: requires-python
|
|
22
|
+
Dynamic: summary
|
|
23
|
+
|
|
24
|
+
# NoBox.Ai Chat Python SDK (`nobox-chat-sdk`)
|
|
25
|
+
|
|
26
|
+
Official Python Client SDK and Real-time Webhook Receiver Application for **NoBox.Ai** Omnichannel Platform Integration.
|
|
27
|
+
|
|
28
|
+
🔗 **GitLab Repository**: [https://gitlab.ubig.co.id/erik/nobox-chat-python](https://gitlab.ubig.co.id/erik/nobox-chat-python)
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 🐍 Preview Aplikasi Demo & Interactive Console Inspector
|
|
33
|
+
|
|
34
|
+
Package ini menyediakan solusi **Python SDK lengkap** (dukungan Python 3.7+) yang dilengkapi dengan Service REST API, Webhook HMAC-SHA256 Verifier & Parser, serta **Flask Web Application & Interactive Traffic Inspector** bawaan untuk mempermudah debugging dan integrasi platform NoBox.Ai.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 📦 Instalasi & Dependensi
|
|
39
|
+
|
|
40
|
+
### Opsi A: Instalasi via PyPI / Pip
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install nobox-chat-sdk
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Atau instalasi langsung dari Git Repository:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pip install git+https://gitlab.ubig.co.id/erik/nobox-chat-python.git
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Opsi B: Import Library di Kode Python
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from nobox_chat import NoboxChat
|
|
56
|
+
|
|
57
|
+
# Inisialisasi SDK
|
|
58
|
+
nb = NoboxChat(base_url="https://id.nobox.ai/", app_name="NoBoxChatPython", app_version="1.0.0")
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## ✨ Fitur Utama
|
|
64
|
+
|
|
65
|
+
- 🔑 **Autentikasi Native Python**: Login ke NoBox.Ai REST API untuk memperoleh Bearer Token secara otomatis.
|
|
66
|
+
- 📋 **Chatrooms & Messages Manager**: Service intuitif untuk mengambil daftar percakapan, channel, akun WhatsApp terhubung, serta riwayat pesan.
|
|
67
|
+
- 📤 **Fast Message Dispatcher & Media Upload**: Mengirim pesan teks dan konversi attachment base64 ke URL media secara langsung.
|
|
68
|
+
- 🔐 **Webhook HMAC-SHA256 Verifier & Event Parser**: Verifikasi keamanan signature `X-Nobox-Signature-256` dan parsing event payload otomatis (`TerimaPesan`, `TerimaAck`, `TerimaRead`).
|
|
69
|
+
- 📊 **AppInfo & Metadata Tracking**: Melacak header metadata `X-App-Name: NoBoxChatPython` dan `X-App-Version: 1.0.0` pada setiap request API.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 📂 Struktur Repositori
|
|
74
|
+
|
|
75
|
+
```text
|
|
76
|
+
nobox-chat-python/
|
|
77
|
+
├── setup.py # Konfigurasi PyPI Package Installer
|
|
78
|
+
├── requirements.txt # Dependensi Python (requests, flask)
|
|
79
|
+
├── README.md # Dokumentasi Resmi Python SDK
|
|
80
|
+
├── nobox_chat.py # Core Python SDK Library (`NoboxChat`)
|
|
81
|
+
├── app.py # Flask Web Application & Webhook Receiver
|
|
82
|
+
├── templates/
|
|
83
|
+
│ └── index.html # Frontend Web UI Demo
|
|
84
|
+
└── static/ # Custom CSS/JS Static Assets
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 📖 Panduan Penggunaan Python SDK (`NoboxChat`)
|
|
90
|
+
|
|
91
|
+
### 1. Autentikasi & Generate Token
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from nobox_chat import NoboxChat
|
|
95
|
+
|
|
96
|
+
nb = NoboxChat()
|
|
97
|
+
|
|
98
|
+
# Login untuk mendapatkan Bearer token
|
|
99
|
+
result = nb.generate_token("user@example.com", "password")
|
|
100
|
+
|
|
101
|
+
if not result["IsError"]:
|
|
102
|
+
token = result["Data"]
|
|
103
|
+
print("Token Berhasil Didapatkan:", token)
|
|
104
|
+
else:
|
|
105
|
+
print("Gagal Login:", result["Error"])
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
### 2. Mengambil Daftar Percakapan & Riwayat Chat
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
# 1. Ambil 20 Percakapan Teratas
|
|
114
|
+
chatrooms = nb.fetch_chatrooms(take=20)
|
|
115
|
+
print("Daftar Chatroom:", chatrooms["Data"])
|
|
116
|
+
|
|
117
|
+
# 2. Ambil Riwayat Pesan berdasarkan Room ID
|
|
118
|
+
messages = nb.fetch_messages(room_id="ROOM_ID_123", take=50)
|
|
119
|
+
print("Riwayat Pesan:", messages["Data"])
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
### 3. Mengirim Pesan Teks & Media via REST API
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
# 1. Mengirim Pesan Teks
|
|
128
|
+
send_res = nb.send_message(
|
|
129
|
+
ext_id="628123456789",
|
|
130
|
+
channel_id=1,
|
|
131
|
+
account_id="744927678136325",
|
|
132
|
+
text="Halo dari Python SDK NoBox.Ai!"
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
# 2. Upload Attachment Base64
|
|
136
|
+
with open("photo.jpg", "rb") as f:
|
|
137
|
+
import base64
|
|
138
|
+
b64_data = base64.b64encode(f.read()).decode("utf-8")
|
|
139
|
+
|
|
140
|
+
upload_res = nb.upload_base64_to_file({
|
|
141
|
+
"media": {
|
|
142
|
+
"filename": "photo.jpg",
|
|
143
|
+
"mimetype": "image/jpeg",
|
|
144
|
+
"data": b64_data
|
|
145
|
+
}
|
|
146
|
+
})
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
### 4. Webhook Verification & Event Handler
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
from nobox_chat import NoboxChat
|
|
155
|
+
|
|
156
|
+
# Verifikasi & Parse Payload Webhook HMAC-SHA256
|
|
157
|
+
try:
|
|
158
|
+
event_data = NoboxChat.handle_webhook(
|
|
159
|
+
payload_body=raw_json_body,
|
|
160
|
+
signature_header=request_headers.get("X-Nobox-Signature-256"),
|
|
161
|
+
webhook_secret="YOUR_WEBHOOK_SECRET",
|
|
162
|
+
throw_error=True
|
|
163
|
+
)
|
|
164
|
+
print("Webhook Valid! Event:", event_data)
|
|
165
|
+
except ValueError as e:
|
|
166
|
+
print("Webhook Invalid:", str(e))
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## 🌐 Menjalankan Flask Application Demo secara Lokal
|
|
172
|
+
|
|
173
|
+
Untuk menjalankan aplikasi demo Web UI & Webhook receiver lokal:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
pip install -r requirements.txt
|
|
177
|
+
python app.py
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Buka browser Anda di: `http://localhost:5001` atau `http://127.0.0.1:5001`.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## 📄 Lisensi
|
|
185
|
+
|
|
186
|
+
Proyek ini dirilis di bawah lisensi **MIT License**.
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# NoBox.Ai Chat Python SDK (`nobox-chat-sdk`)
|
|
2
|
+
|
|
3
|
+
Official Python Client SDK and Real-time Webhook Receiver Application for **NoBox.Ai** Omnichannel Platform Integration.
|
|
4
|
+
|
|
5
|
+
🔗 **GitLab Repository**: [https://gitlab.ubig.co.id/erik/nobox-chat-python](https://gitlab.ubig.co.id/erik/nobox-chat-python)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 🐍 Preview Aplikasi Demo & Interactive Console Inspector
|
|
10
|
+
|
|
11
|
+
Package ini menyediakan solusi **Python SDK lengkap** (dukungan Python 3.7+) yang dilengkapi dengan Service REST API, Webhook HMAC-SHA256 Verifier & Parser, serta **Flask Web Application & Interactive Traffic Inspector** bawaan untuk mempermudah debugging dan integrasi platform NoBox.Ai.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 📦 Instalasi & Dependensi
|
|
16
|
+
|
|
17
|
+
### Opsi A: Instalasi via PyPI / Pip
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install nobox-chat-sdk
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Atau instalasi langsung dari Git Repository:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install git+https://gitlab.ubig.co.id/erik/nobox-chat-python.git
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Opsi B: Import Library di Kode Python
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
from nobox_chat import NoboxChat
|
|
33
|
+
|
|
34
|
+
# Inisialisasi SDK
|
|
35
|
+
nb = NoboxChat(base_url="https://id.nobox.ai/", app_name="NoBoxChatPython", app_version="1.0.0")
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## ✨ Fitur Utama
|
|
41
|
+
|
|
42
|
+
- 🔑 **Autentikasi Native Python**: Login ke NoBox.Ai REST API untuk memperoleh Bearer Token secara otomatis.
|
|
43
|
+
- 📋 **Chatrooms & Messages Manager**: Service intuitif untuk mengambil daftar percakapan, channel, akun WhatsApp terhubung, serta riwayat pesan.
|
|
44
|
+
- 📤 **Fast Message Dispatcher & Media Upload**: Mengirim pesan teks dan konversi attachment base64 ke URL media secara langsung.
|
|
45
|
+
- 🔐 **Webhook HMAC-SHA256 Verifier & Event Parser**: Verifikasi keamanan signature `X-Nobox-Signature-256` dan parsing event payload otomatis (`TerimaPesan`, `TerimaAck`, `TerimaRead`).
|
|
46
|
+
- 📊 **AppInfo & Metadata Tracking**: Melacak header metadata `X-App-Name: NoBoxChatPython` dan `X-App-Version: 1.0.0` pada setiap request API.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 📂 Struktur Repositori
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
nobox-chat-python/
|
|
54
|
+
├── setup.py # Konfigurasi PyPI Package Installer
|
|
55
|
+
├── requirements.txt # Dependensi Python (requests, flask)
|
|
56
|
+
├── README.md # Dokumentasi Resmi Python SDK
|
|
57
|
+
├── nobox_chat.py # Core Python SDK Library (`NoboxChat`)
|
|
58
|
+
├── app.py # Flask Web Application & Webhook Receiver
|
|
59
|
+
├── templates/
|
|
60
|
+
│ └── index.html # Frontend Web UI Demo
|
|
61
|
+
└── static/ # Custom CSS/JS Static Assets
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 📖 Panduan Penggunaan Python SDK (`NoboxChat`)
|
|
67
|
+
|
|
68
|
+
### 1. Autentikasi & Generate Token
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from nobox_chat import NoboxChat
|
|
72
|
+
|
|
73
|
+
nb = NoboxChat()
|
|
74
|
+
|
|
75
|
+
# Login untuk mendapatkan Bearer token
|
|
76
|
+
result = nb.generate_token("user@example.com", "password")
|
|
77
|
+
|
|
78
|
+
if not result["IsError"]:
|
|
79
|
+
token = result["Data"]
|
|
80
|
+
print("Token Berhasil Didapatkan:", token)
|
|
81
|
+
else:
|
|
82
|
+
print("Gagal Login:", result["Error"])
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
### 2. Mengambil Daftar Percakapan & Riwayat Chat
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
# 1. Ambil 20 Percakapan Teratas
|
|
91
|
+
chatrooms = nb.fetch_chatrooms(take=20)
|
|
92
|
+
print("Daftar Chatroom:", chatrooms["Data"])
|
|
93
|
+
|
|
94
|
+
# 2. Ambil Riwayat Pesan berdasarkan Room ID
|
|
95
|
+
messages = nb.fetch_messages(room_id="ROOM_ID_123", take=50)
|
|
96
|
+
print("Riwayat Pesan:", messages["Data"])
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
### 3. Mengirim Pesan Teks & Media via REST API
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
# 1. Mengirim Pesan Teks
|
|
105
|
+
send_res = nb.send_message(
|
|
106
|
+
ext_id="628123456789",
|
|
107
|
+
channel_id=1,
|
|
108
|
+
account_id="744927678136325",
|
|
109
|
+
text="Halo dari Python SDK NoBox.Ai!"
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# 2. Upload Attachment Base64
|
|
113
|
+
with open("photo.jpg", "rb") as f:
|
|
114
|
+
import base64
|
|
115
|
+
b64_data = base64.b64encode(f.read()).decode("utf-8")
|
|
116
|
+
|
|
117
|
+
upload_res = nb.upload_base64_to_file({
|
|
118
|
+
"media": {
|
|
119
|
+
"filename": "photo.jpg",
|
|
120
|
+
"mimetype": "image/jpeg",
|
|
121
|
+
"data": b64_data
|
|
122
|
+
}
|
|
123
|
+
})
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
### 4. Webhook Verification & Event Handler
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
from nobox_chat import NoboxChat
|
|
132
|
+
|
|
133
|
+
# Verifikasi & Parse Payload Webhook HMAC-SHA256
|
|
134
|
+
try:
|
|
135
|
+
event_data = NoboxChat.handle_webhook(
|
|
136
|
+
payload_body=raw_json_body,
|
|
137
|
+
signature_header=request_headers.get("X-Nobox-Signature-256"),
|
|
138
|
+
webhook_secret="YOUR_WEBHOOK_SECRET",
|
|
139
|
+
throw_error=True
|
|
140
|
+
)
|
|
141
|
+
print("Webhook Valid! Event:", event_data)
|
|
142
|
+
except ValueError as e:
|
|
143
|
+
print("Webhook Invalid:", str(e))
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## 🌐 Menjalankan Flask Application Demo secara Lokal
|
|
149
|
+
|
|
150
|
+
Untuk menjalankan aplikasi demo Web UI & Webhook receiver lokal:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
pip install -r requirements.txt
|
|
154
|
+
python app.py
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Buka browser Anda di: `http://localhost:5001` atau `http://127.0.0.1:5001`.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 📄 Lisensi
|
|
162
|
+
|
|
163
|
+
Proyek ini dirilis di bawah lisensi **MIT License**.
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"""
|
|
2
|
+
NoBox Chat Python SDK
|
|
3
|
+
NoBox.Ai Chat integration via REST API & Webhook.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
from nobox_chat import NoboxChat
|
|
7
|
+
|
|
8
|
+
nb = NoboxChat()
|
|
9
|
+
nb.generate_token("email@domain.com", "password")
|
|
10
|
+
chatrooms = nb.fetch_chatrooms()
|
|
11
|
+
nb.send_message(ext_id, channel_id, account_id, "Hello from Python!")
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import json
|
|
15
|
+
import hashlib
|
|
16
|
+
import hmac
|
|
17
|
+
import re
|
|
18
|
+
import requests
|
|
19
|
+
import urllib3
|
|
20
|
+
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class NoboxChat:
|
|
24
|
+
"""Main NoBox.Ai Chat SDK class."""
|
|
25
|
+
|
|
26
|
+
BODY_TYPE_MAP = {
|
|
27
|
+
1: "Text", 2: "Audio", 3: "Image", 4: "Video", 5: "File",
|
|
28
|
+
7: "Sticker", 9: "Location", 10: "Order", 11: "Product",
|
|
29
|
+
12: "VCARD", 13: "VCARD_MULTI",
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
def __init__(self, token: str = "", base_url: str = "https://id.nobox.ai/", app_name: str = "NoBoxChatPython", app_version: str = "1.0.0"):
|
|
33
|
+
self.base_url = base_url.rstrip("/") + "/"
|
|
34
|
+
self.token = token
|
|
35
|
+
self.app_name = app_name
|
|
36
|
+
self.app_version = app_version
|
|
37
|
+
|
|
38
|
+
def set_token(self, token: str):
|
|
39
|
+
self.token = token
|
|
40
|
+
|
|
41
|
+
def get_token(self):
|
|
42
|
+
return self.token
|
|
43
|
+
|
|
44
|
+
def set_base_url(self, base_url: str):
|
|
45
|
+
self.base_url = base_url.rstrip("/") + "/"
|
|
46
|
+
|
|
47
|
+
def set_app_info(self, app_name: str, app_version: str = "1.0.0"):
|
|
48
|
+
if app_name:
|
|
49
|
+
self.app_name = app_name
|
|
50
|
+
if app_version:
|
|
51
|
+
self.app_version = app_version
|
|
52
|
+
|
|
53
|
+
# ── Internal helpers ────────────────────────────────────────────────
|
|
54
|
+
|
|
55
|
+
@staticmethod
|
|
56
|
+
def _parse_error_message(data: dict, raw_response: str = "") -> str:
|
|
57
|
+
if not data:
|
|
58
|
+
return re.sub(r"<[^>]+>", "", raw_response) if raw_response else "Server error"
|
|
59
|
+
if "Error" in data:
|
|
60
|
+
err = data["Error"]
|
|
61
|
+
if isinstance(err, dict):
|
|
62
|
+
return err.get("InitialText", err.get("Message", json.dumps(err)))
|
|
63
|
+
if isinstance(err, str):
|
|
64
|
+
return err
|
|
65
|
+
for key in ("message", "Message", "error"):
|
|
66
|
+
if key in data and isinstance(data[key], str):
|
|
67
|
+
return data[key]
|
|
68
|
+
return "Server error"
|
|
69
|
+
|
|
70
|
+
def _request(self, endpoint: str, payload: dict = None, requires_auth: bool = True) -> dict:
|
|
71
|
+
"""Internal requester"""
|
|
72
|
+
url = self.base_url + endpoint.lstrip("/")
|
|
73
|
+
headers = {
|
|
74
|
+
"Content-Type": "application/json",
|
|
75
|
+
"X-App-Name": self.app_name,
|
|
76
|
+
"X-App-Version": self.app_version,
|
|
77
|
+
"User-Agent": f"{self.app_name}/{self.app_version}"
|
|
78
|
+
}
|
|
79
|
+
if requires_auth and self.token:
|
|
80
|
+
headers["Authorization"] = f"Bearer {self.token}"
|
|
81
|
+
try:
|
|
82
|
+
resp = requests.post(url, json=payload or {}, headers=headers, timeout=30, verify=False)
|
|
83
|
+
http_code = resp.status_code
|
|
84
|
+
data = resp.json()
|
|
85
|
+
except requests.RequestException as e:
|
|
86
|
+
return {"IsError": True, "Code": 500, "Data": None, "Error": str(e)}
|
|
87
|
+
except (json.JSONDecodeError, ValueError):
|
|
88
|
+
return {"IsError": True, "Code": http_code, "Data": None, "Error": f"Invalid JSON: {resp.text[:200]}"}
|
|
89
|
+
|
|
90
|
+
if "Error" in data and data["Error"] is not None:
|
|
91
|
+
return {
|
|
92
|
+
"IsError": True,
|
|
93
|
+
"Code": http_code,
|
|
94
|
+
"Data": data.get("Entities", data.get("Data")),
|
|
95
|
+
"Error": self._parse_error_message(data, resp.text),
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
"IsError": False,
|
|
99
|
+
"Code": http_code,
|
|
100
|
+
"Data": data.get("Entities", data.get("Data", data)),
|
|
101
|
+
"Error": None,
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
# ── Public API ──────────────────────────────────────────────────────
|
|
105
|
+
|
|
106
|
+
def generate_token(self, username: str, password: str) -> dict:
|
|
107
|
+
"""Authenticate user, store token."""
|
|
108
|
+
url = self.base_url + "AccountAPI/GenerateToken"
|
|
109
|
+
headers = {
|
|
110
|
+
"Content-Type": "application/json",
|
|
111
|
+
"X-App-Name": self.app_name,
|
|
112
|
+
"X-App-Version": self.app_version,
|
|
113
|
+
"User-Agent": f"{self.app_name}/{self.app_version}"
|
|
114
|
+
}
|
|
115
|
+
try:
|
|
116
|
+
resp = requests.post(
|
|
117
|
+
url,
|
|
118
|
+
json={"username": username, "password": password},
|
|
119
|
+
headers=headers,
|
|
120
|
+
timeout=30,
|
|
121
|
+
verify=False,
|
|
122
|
+
)
|
|
123
|
+
http_code = resp.status_code
|
|
124
|
+
data = resp.json()
|
|
125
|
+
except requests.RequestException as e:
|
|
126
|
+
return {"IsError": True, "Code": 500, "Data": None, "Error": str(e)}
|
|
127
|
+
except (json.JSONDecodeError, ValueError):
|
|
128
|
+
return {"IsError": True, "Code": http_code, "Data": None, "Error": f"Invalid JSON: {resp.text[:200]}"}
|
|
129
|
+
|
|
130
|
+
if "token" in data and data["token"]:
|
|
131
|
+
self.token = data["token"]
|
|
132
|
+
return {"IsError": False, "Code": http_code, "Data": data["token"], "Error": None}
|
|
133
|
+
|
|
134
|
+
error_msg = self._parse_error_message(data, resp.text)
|
|
135
|
+
return {"IsError": True, "Code": http_code, "Data": None, "Error": error_msg, "RawResponse": resp.text}
|
|
136
|
+
|
|
137
|
+
def fetch_chatrooms(self, take: int = 20, sort: list = None) -> dict:
|
|
138
|
+
"""Fetch conversation list."""
|
|
139
|
+
payload = {"Sort": sort or ["Up DESC"], "Take": take}
|
|
140
|
+
return self._request("Services/Chat/Chatrooms/List", payload)
|
|
141
|
+
|
|
142
|
+
def fetch_messages(self, room_id=None, ext_id=None, take: int = 20, sort: list = None) -> dict:
|
|
143
|
+
"""Fetch message history per room."""
|
|
144
|
+
payload = {"Sort": sort or ["In DESC"], "Take": take, "EqualityFilter": {}}
|
|
145
|
+
if room_id:
|
|
146
|
+
payload["EqualityFilter"]["RoomId"] = room_id
|
|
147
|
+
return self._request("Services/Chat/Chatmessages/List", payload)
|
|
148
|
+
|
|
149
|
+
def fetch_account_list(self) -> dict:
|
|
150
|
+
"""Fetch WhatsApp accounts."""
|
|
151
|
+
payload = {"IncludeColumns": ["Id", "Name", "Channel"], "ColumnSelection": 1}
|
|
152
|
+
return self._request("Services/Nobox/Account/List", payload)
|
|
153
|
+
|
|
154
|
+
def fetch_channels(self) -> dict:
|
|
155
|
+
"""Fetch channels."""
|
|
156
|
+
payload = {"IncludeColumns": ["Id", "Nm"], "ColumnSelection": 1}
|
|
157
|
+
return self._request("Services/Master/Channel/List", payload)
|
|
158
|
+
|
|
159
|
+
def send_message(self, ext_id, channel_id, account_id, text: str = "", body_type: int = 1, attachment=None) -> dict:
|
|
160
|
+
"""Send message via REST API."""
|
|
161
|
+
payload = {
|
|
162
|
+
"ExtId": str(ext_id),
|
|
163
|
+
"ChannelId": int(channel_id),
|
|
164
|
+
"AccountIds": str(account_id),
|
|
165
|
+
"BodyType": int(body_type),
|
|
166
|
+
"Body": str(text),
|
|
167
|
+
"Attachment": attachment,
|
|
168
|
+
}
|
|
169
|
+
return self._request("Inbox/Send", payload)
|
|
170
|
+
|
|
171
|
+
def upload_base64_to_file(self, payload: dict) -> dict:
|
|
172
|
+
"""Upload base64 media."""
|
|
173
|
+
return self._request("Inbox/UploadFile/ConvertBase64ToFile", payload)
|
|
174
|
+
|
|
175
|
+
# ── Webhook ─────────────────────────────────────────────────────────
|
|
176
|
+
|
|
177
|
+
@staticmethod
|
|
178
|
+
def handle_webhook(payload_body: str, signature_header: str, webhook_secret: str, throw_error: bool = True):
|
|
179
|
+
"""Validate & parse HMAC-SHA256 webhook payload."""
|
|
180
|
+
if not signature_header:
|
|
181
|
+
if throw_error:
|
|
182
|
+
raise ValueError("Unauthorized: Missing Webhook Signature header.")
|
|
183
|
+
return None
|
|
184
|
+
|
|
185
|
+
provided = re.sub(r"sha256=", "", signature_header.lower())
|
|
186
|
+
expected = hmac.new(webhook_secret.encode(), payload_body.encode(), hashlib.sha256).hexdigest()
|
|
187
|
+
|
|
188
|
+
if not hmac.compare_digest(expected, provided):
|
|
189
|
+
if throw_error:
|
|
190
|
+
raise ValueError("Unauthorized: Invalid webhook signature.")
|
|
191
|
+
return None
|
|
192
|
+
|
|
193
|
+
data = json.loads(payload_body)
|
|
194
|
+
if not data:
|
|
195
|
+
if throw_error:
|
|
196
|
+
raise ValueError("Bad Request: Invalid JSON payload.")
|
|
197
|
+
return None
|
|
198
|
+
return data
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
# Backward compatibility alias
|
|
202
|
+
NoboxInbox = NoboxChat
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nobox-chat-sdk
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Official Python SDK and SignalR/Webhook Integration for NoBox.Ai platform
|
|
5
|
+
Home-page: https://gitlab.ubig.co.id/erik/nobox-chat-python
|
|
6
|
+
Author: NoBox.Ai Team
|
|
7
|
+
Author-email: support@nobox.ai
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.7
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
Requires-Dist: requests>=2.25.0
|
|
14
|
+
Dynamic: author
|
|
15
|
+
Dynamic: author-email
|
|
16
|
+
Dynamic: classifier
|
|
17
|
+
Dynamic: description
|
|
18
|
+
Dynamic: description-content-type
|
|
19
|
+
Dynamic: home-page
|
|
20
|
+
Dynamic: requires-dist
|
|
21
|
+
Dynamic: requires-python
|
|
22
|
+
Dynamic: summary
|
|
23
|
+
|
|
24
|
+
# NoBox.Ai Chat Python SDK (`nobox-chat-sdk`)
|
|
25
|
+
|
|
26
|
+
Official Python Client SDK and Real-time Webhook Receiver Application for **NoBox.Ai** Omnichannel Platform Integration.
|
|
27
|
+
|
|
28
|
+
🔗 **GitLab Repository**: [https://gitlab.ubig.co.id/erik/nobox-chat-python](https://gitlab.ubig.co.id/erik/nobox-chat-python)
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 🐍 Preview Aplikasi Demo & Interactive Console Inspector
|
|
33
|
+
|
|
34
|
+
Package ini menyediakan solusi **Python SDK lengkap** (dukungan Python 3.7+) yang dilengkapi dengan Service REST API, Webhook HMAC-SHA256 Verifier & Parser, serta **Flask Web Application & Interactive Traffic Inspector** bawaan untuk mempermudah debugging dan integrasi platform NoBox.Ai.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 📦 Instalasi & Dependensi
|
|
39
|
+
|
|
40
|
+
### Opsi A: Instalasi via PyPI / Pip
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install nobox-chat-sdk
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Atau instalasi langsung dari Git Repository:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pip install git+https://gitlab.ubig.co.id/erik/nobox-chat-python.git
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Opsi B: Import Library di Kode Python
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from nobox_chat import NoboxChat
|
|
56
|
+
|
|
57
|
+
# Inisialisasi SDK
|
|
58
|
+
nb = NoboxChat(base_url="https://id.nobox.ai/", app_name="NoBoxChatPython", app_version="1.0.0")
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## ✨ Fitur Utama
|
|
64
|
+
|
|
65
|
+
- 🔑 **Autentikasi Native Python**: Login ke NoBox.Ai REST API untuk memperoleh Bearer Token secara otomatis.
|
|
66
|
+
- 📋 **Chatrooms & Messages Manager**: Service intuitif untuk mengambil daftar percakapan, channel, akun WhatsApp terhubung, serta riwayat pesan.
|
|
67
|
+
- 📤 **Fast Message Dispatcher & Media Upload**: Mengirim pesan teks dan konversi attachment base64 ke URL media secara langsung.
|
|
68
|
+
- 🔐 **Webhook HMAC-SHA256 Verifier & Event Parser**: Verifikasi keamanan signature `X-Nobox-Signature-256` dan parsing event payload otomatis (`TerimaPesan`, `TerimaAck`, `TerimaRead`).
|
|
69
|
+
- 📊 **AppInfo & Metadata Tracking**: Melacak header metadata `X-App-Name: NoBoxChatPython` dan `X-App-Version: 1.0.0` pada setiap request API.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 📂 Struktur Repositori
|
|
74
|
+
|
|
75
|
+
```text
|
|
76
|
+
nobox-chat-python/
|
|
77
|
+
├── setup.py # Konfigurasi PyPI Package Installer
|
|
78
|
+
├── requirements.txt # Dependensi Python (requests, flask)
|
|
79
|
+
├── README.md # Dokumentasi Resmi Python SDK
|
|
80
|
+
├── nobox_chat.py # Core Python SDK Library (`NoboxChat`)
|
|
81
|
+
├── app.py # Flask Web Application & Webhook Receiver
|
|
82
|
+
├── templates/
|
|
83
|
+
│ └── index.html # Frontend Web UI Demo
|
|
84
|
+
└── static/ # Custom CSS/JS Static Assets
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 📖 Panduan Penggunaan Python SDK (`NoboxChat`)
|
|
90
|
+
|
|
91
|
+
### 1. Autentikasi & Generate Token
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from nobox_chat import NoboxChat
|
|
95
|
+
|
|
96
|
+
nb = NoboxChat()
|
|
97
|
+
|
|
98
|
+
# Login untuk mendapatkan Bearer token
|
|
99
|
+
result = nb.generate_token("user@example.com", "password")
|
|
100
|
+
|
|
101
|
+
if not result["IsError"]:
|
|
102
|
+
token = result["Data"]
|
|
103
|
+
print("Token Berhasil Didapatkan:", token)
|
|
104
|
+
else:
|
|
105
|
+
print("Gagal Login:", result["Error"])
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
### 2. Mengambil Daftar Percakapan & Riwayat Chat
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
# 1. Ambil 20 Percakapan Teratas
|
|
114
|
+
chatrooms = nb.fetch_chatrooms(take=20)
|
|
115
|
+
print("Daftar Chatroom:", chatrooms["Data"])
|
|
116
|
+
|
|
117
|
+
# 2. Ambil Riwayat Pesan berdasarkan Room ID
|
|
118
|
+
messages = nb.fetch_messages(room_id="ROOM_ID_123", take=50)
|
|
119
|
+
print("Riwayat Pesan:", messages["Data"])
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
### 3. Mengirim Pesan Teks & Media via REST API
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
# 1. Mengirim Pesan Teks
|
|
128
|
+
send_res = nb.send_message(
|
|
129
|
+
ext_id="628123456789",
|
|
130
|
+
channel_id=1,
|
|
131
|
+
account_id="744927678136325",
|
|
132
|
+
text="Halo dari Python SDK NoBox.Ai!"
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
# 2. Upload Attachment Base64
|
|
136
|
+
with open("photo.jpg", "rb") as f:
|
|
137
|
+
import base64
|
|
138
|
+
b64_data = base64.b64encode(f.read()).decode("utf-8")
|
|
139
|
+
|
|
140
|
+
upload_res = nb.upload_base64_to_file({
|
|
141
|
+
"media": {
|
|
142
|
+
"filename": "photo.jpg",
|
|
143
|
+
"mimetype": "image/jpeg",
|
|
144
|
+
"data": b64_data
|
|
145
|
+
}
|
|
146
|
+
})
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
### 4. Webhook Verification & Event Handler
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
from nobox_chat import NoboxChat
|
|
155
|
+
|
|
156
|
+
# Verifikasi & Parse Payload Webhook HMAC-SHA256
|
|
157
|
+
try:
|
|
158
|
+
event_data = NoboxChat.handle_webhook(
|
|
159
|
+
payload_body=raw_json_body,
|
|
160
|
+
signature_header=request_headers.get("X-Nobox-Signature-256"),
|
|
161
|
+
webhook_secret="YOUR_WEBHOOK_SECRET",
|
|
162
|
+
throw_error=True
|
|
163
|
+
)
|
|
164
|
+
print("Webhook Valid! Event:", event_data)
|
|
165
|
+
except ValueError as e:
|
|
166
|
+
print("Webhook Invalid:", str(e))
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## 🌐 Menjalankan Flask Application Demo secara Lokal
|
|
172
|
+
|
|
173
|
+
Untuk menjalankan aplikasi demo Web UI & Webhook receiver lokal:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
pip install -r requirements.txt
|
|
177
|
+
python app.py
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Buka browser Anda di: `http://localhost:5001` atau `http://127.0.0.1:5001`.
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
## 📄 Lisensi
|
|
185
|
+
|
|
186
|
+
Proyek ini dirilis di bawah lisensi **MIT License**.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
requests>=2.25.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
nobox_chat
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from setuptools import setup, find_packages
|
|
3
|
+
|
|
4
|
+
with open("README.md", "r", encoding="utf-8") as fh:
|
|
5
|
+
long_description = fh.read()
|
|
6
|
+
|
|
7
|
+
setup(
|
|
8
|
+
name="nobox-chat-sdk",
|
|
9
|
+
version="1.0.0",
|
|
10
|
+
author="NoBox.Ai Team",
|
|
11
|
+
author_email="support@nobox.ai",
|
|
12
|
+
description="Official Python SDK and SignalR/Webhook Integration for NoBox.Ai platform",
|
|
13
|
+
long_description=long_description,
|
|
14
|
+
long_description_content_type="text/markdown",
|
|
15
|
+
url="https://gitlab.ubig.co.id/erik/nobox-chat-python",
|
|
16
|
+
py_modules=["nobox_chat"],
|
|
17
|
+
packages=find_packages(),
|
|
18
|
+
classifiers=[
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Operating System :: OS Independent",
|
|
22
|
+
],
|
|
23
|
+
python_requires=">=3.7",
|
|
24
|
+
install_requires=[
|
|
25
|
+
"requests>=2.25.0",
|
|
26
|
+
],
|
|
27
|
+
)
|