aicosmos-client 0.0.5__tar.gz → 0.0.6__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.
- {aicosmos_client-0.0.5 → aicosmos_client-0.0.6}/PKG-INFO +6 -2
- {aicosmos_client-0.0.5 → aicosmos_client-0.0.6}/README.md +5 -1
- aicosmos_client-0.0.6/aicosmos_client/client.py +178 -0
- {aicosmos_client-0.0.5 → aicosmos_client-0.0.6}/pyproject.toml +1 -1
- aicosmos_client-0.0.5/aicosmos_client/client.py +0 -132
- {aicosmos_client-0.0.5 → aicosmos_client-0.0.6}/.gitignore +0 -0
- {aicosmos_client-0.0.5 → aicosmos_client-0.0.6}/LICENSE +0 -0
- {aicosmos_client-0.0.5 → aicosmos_client-0.0.6}/aicosmos_client/__init__.py +0 -0
- {aicosmos_client-0.0.5 → aicosmos_client-0.0.6}/aicosmos_client/cli.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: aicosmos_client
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.6
|
4
4
|
Summary: client for AICosmos platform
|
5
5
|
Project-URL: Homepage, https://github.com/pypa/sampleproject
|
6
6
|
Project-URL: Issues, https://github.com/pypa/sampleproject/issues
|
@@ -28,7 +28,10 @@ from aicosmos_client.client import AICosmosClient
|
|
28
28
|
|
29
29
|
# login
|
30
30
|
client = AICosmosClient(
|
31
|
-
base_url="
|
31
|
+
base_url="https://aicosmos.ai/api",
|
32
|
+
username="xxx",
|
33
|
+
password="xxx",
|
34
|
+
auto_trust=True,
|
32
35
|
)
|
33
36
|
|
34
37
|
# create a new session
|
@@ -62,5 +65,6 @@ To show that the client is enough to build an application, we offer you an comma
|
|
62
65
|
```Python
|
63
66
|
from aicosmos_client.cli import AICosmosCLI
|
64
67
|
|
68
|
+
# url: https://aicosmos.ai/api
|
65
69
|
AICosmosCLI().run()
|
66
70
|
```
|
@@ -12,7 +12,10 @@ from aicosmos_client.client import AICosmosClient
|
|
12
12
|
|
13
13
|
# login
|
14
14
|
client = AICosmosClient(
|
15
|
-
base_url="
|
15
|
+
base_url="https://aicosmos.ai/api",
|
16
|
+
username="xxx",
|
17
|
+
password="xxx",
|
18
|
+
auto_trust=True,
|
16
19
|
)
|
17
20
|
|
18
21
|
# create a new session
|
@@ -46,5 +49,6 @@ To show that the client is enough to build an application, we offer you an comma
|
|
46
49
|
```Python
|
47
50
|
from aicosmos_client.cli import AICosmosCLI
|
48
51
|
|
52
|
+
# url: https://aicosmos.ai/api
|
49
53
|
AICosmosCLI().run()
|
50
54
|
```
|
@@ -0,0 +1,178 @@
|
|
1
|
+
import os
|
2
|
+
import socket
|
3
|
+
import ssl
|
4
|
+
from urllib.parse import urlparse
|
5
|
+
|
6
|
+
import certifi
|
7
|
+
import requests
|
8
|
+
from requests.adapters import HTTPAdapter
|
9
|
+
|
10
|
+
|
11
|
+
class SSLAdapter(HTTPAdapter):
|
12
|
+
"""HTTPS adapter that allows dynamic CA bundle injection."""
|
13
|
+
|
14
|
+
def __init__(self, cafile=None, *args, **kwargs):
|
15
|
+
self.cafile = cafile
|
16
|
+
super().__init__(*args, **kwargs)
|
17
|
+
|
18
|
+
def init_poolmanager(self, *args, **kwargs):
|
19
|
+
context = ssl.create_default_context()
|
20
|
+
context.load_verify_locations(cafile=certifi.where())
|
21
|
+
if self.cafile and os.path.exists(self.cafile):
|
22
|
+
context.load_verify_locations(cafile=self.cafile)
|
23
|
+
kwargs["ssl_context"] = context
|
24
|
+
return super().init_poolmanager(*args, **kwargs)
|
25
|
+
|
26
|
+
|
27
|
+
class AICosmosClient:
|
28
|
+
def __init__(
|
29
|
+
self,
|
30
|
+
base_url: str,
|
31
|
+
username: str,
|
32
|
+
password: str,
|
33
|
+
certs_dir: str = None,
|
34
|
+
auto_trust: bool = False,
|
35
|
+
):
|
36
|
+
"""
|
37
|
+
:param base_url: API base URL, e.g. 'https://aicosmos.ai/api'
|
38
|
+
:param username: Username for login
|
39
|
+
:param password: Password for login
|
40
|
+
:param certs_dir: Directory for storing trusted self-signed certs
|
41
|
+
:param auto_trust: If True, will automatically trust self-signed certs
|
42
|
+
"""
|
43
|
+
self.base_url = base_url.rstrip("/")
|
44
|
+
self.username = username
|
45
|
+
self.password = password
|
46
|
+
self.access_token: str = None
|
47
|
+
self.auto_trust = auto_trust
|
48
|
+
|
49
|
+
host = urlparse(self.base_url).hostname
|
50
|
+
self.certs_dir = certs_dir or os.path.join(
|
51
|
+
os.path.expanduser("~"), ".aicosmos", "certs"
|
52
|
+
)
|
53
|
+
os.makedirs(self.certs_dir, exist_ok=True)
|
54
|
+
self.cert_file = os.path.join(self.certs_dir, f"{host}.pem")
|
55
|
+
|
56
|
+
self.session = requests.Session()
|
57
|
+
self.session.mount("https://", SSLAdapter(cafile=self.cert_file))
|
58
|
+
|
59
|
+
self._login()
|
60
|
+
|
61
|
+
def _fetch_server_cert(self, hostname, port=443):
|
62
|
+
"""Download server's SSL certificate and save locally."""
|
63
|
+
pem_path = self.cert_file
|
64
|
+
conn = socket.create_connection((hostname, port))
|
65
|
+
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
66
|
+
context.check_hostname = False
|
67
|
+
context.verify_mode = ssl.CERT_NONE
|
68
|
+
with context.wrap_socket(conn, server_hostname=hostname) as sock:
|
69
|
+
der_cert = sock.getpeercert(True)
|
70
|
+
pem_cert = ssl.DER_cert_to_PEM_cert(der_cert)
|
71
|
+
with open(pem_path, "w") as f:
|
72
|
+
f.write(pem_cert)
|
73
|
+
return pem_path
|
74
|
+
|
75
|
+
def _robust_request(self, method, url, **kwargs):
|
76
|
+
try:
|
77
|
+
return self.session.request(method, url, **kwargs)
|
78
|
+
except requests.exceptions.SSLError as e:
|
79
|
+
if not self.auto_trust:
|
80
|
+
raise RuntimeError(
|
81
|
+
f"SSL verification failed for {url}. "
|
82
|
+
f"Set auto_trust=True to accept and store the server's certificate."
|
83
|
+
) from e
|
84
|
+
host = urlparse(self.base_url).hostname
|
85
|
+
self._fetch_server_cert(host)
|
86
|
+
self.session.mount("https://", SSLAdapter(cafile=self.cert_file))
|
87
|
+
return self.session.request(method, url, **kwargs)
|
88
|
+
|
89
|
+
def _login(self):
|
90
|
+
login_data = {
|
91
|
+
"username": self.username,
|
92
|
+
"password": self.password,
|
93
|
+
"grant_type": "password",
|
94
|
+
}
|
95
|
+
headers = {"Content-Type": "application/x-www-form-urlencoded"}
|
96
|
+
response = self._robust_request(
|
97
|
+
"POST", f"{self.base_url}/user/login", data=login_data, headers=headers
|
98
|
+
)
|
99
|
+
if response.status_code == 200:
|
100
|
+
token_data = response.json()
|
101
|
+
self.access_token = token_data["access_token"]
|
102
|
+
else:
|
103
|
+
raise ValueError(f"Login failed: {response.status_code} {response.text}")
|
104
|
+
|
105
|
+
def _get_auth_headers(self):
|
106
|
+
if not self.access_token:
|
107
|
+
raise ValueError("Not logged in")
|
108
|
+
return {
|
109
|
+
"Authorization": f"Bearer {self.access_token}",
|
110
|
+
"Content-Type": "application/json",
|
111
|
+
}
|
112
|
+
|
113
|
+
def _get_session_status(self, session_id):
|
114
|
+
response = self._robust_request(
|
115
|
+
"GET",
|
116
|
+
f"{self.base_url}/sessions/{session_id}/status",
|
117
|
+
headers=self._get_auth_headers(),
|
118
|
+
)
|
119
|
+
if response.status_code == 200:
|
120
|
+
return response.json()
|
121
|
+
else:
|
122
|
+
raise ValueError(f"Status code: {response.status_code}")
|
123
|
+
|
124
|
+
def create_session(self):
|
125
|
+
response = self._robust_request(
|
126
|
+
"POST",
|
127
|
+
f"{self.base_url}/sessions/create",
|
128
|
+
headers=self._get_auth_headers(),
|
129
|
+
)
|
130
|
+
if response.status_code == 200:
|
131
|
+
return response.json()["session_id"]
|
132
|
+
else:
|
133
|
+
raise ValueError(f"Status code: {response.status_code}")
|
134
|
+
|
135
|
+
def delete_session(self, session_id: str):
|
136
|
+
response = self._robust_request(
|
137
|
+
"DELETE",
|
138
|
+
f"{self.base_url}/sessions/{session_id}",
|
139
|
+
headers=self._get_auth_headers(),
|
140
|
+
)
|
141
|
+
if response.status_code != 200:
|
142
|
+
raise ValueError(f"Status code: {response.status_code}")
|
143
|
+
|
144
|
+
def get_my_sessions(self):
|
145
|
+
response = self._robust_request(
|
146
|
+
"GET",
|
147
|
+
f"{self.base_url}/sessions/my_sessions",
|
148
|
+
headers=self._get_auth_headers(),
|
149
|
+
)
|
150
|
+
if response.status_code == 200:
|
151
|
+
sessions = response.json()
|
152
|
+
self.active_sessions = sessions
|
153
|
+
return [
|
154
|
+
{
|
155
|
+
"session_id": s["session_id"],
|
156
|
+
"title": s["environment_info"].get("title"),
|
157
|
+
}
|
158
|
+
for s in sessions
|
159
|
+
]
|
160
|
+
else:
|
161
|
+
raise ValueError(f"Status code: {response.status_code}")
|
162
|
+
|
163
|
+
def get_session_history(self, session_id: str):
|
164
|
+
session = self._get_session_status(session_id)
|
165
|
+
return session.get("conversation", [])
|
166
|
+
|
167
|
+
def chat(self, session_id: str, prompt: str):
|
168
|
+
data = {"user_input": prompt, "session_id": session_id}
|
169
|
+
response = self._robust_request(
|
170
|
+
"POST",
|
171
|
+
f"{self.base_url}/chat",
|
172
|
+
json=data,
|
173
|
+
headers=self._get_auth_headers(),
|
174
|
+
)
|
175
|
+
if response.status_code == 200:
|
176
|
+
return response.json()["conversation_history"]
|
177
|
+
else:
|
178
|
+
raise ValueError(f"Status code: {response.status_code}")
|
@@ -1,132 +0,0 @@
|
|
1
|
-
import requests
|
2
|
-
|
3
|
-
|
4
|
-
class AICosmosClient:
|
5
|
-
def __init__(self, base_url: str, username: str, password: str):
|
6
|
-
self.session = requests.Session()
|
7
|
-
self.base_url = base_url
|
8
|
-
self.username: str = username
|
9
|
-
self.password: str = password
|
10
|
-
self.access_token: str = None
|
11
|
-
|
12
|
-
self._login()
|
13
|
-
|
14
|
-
def _login(self):
|
15
|
-
login_data = {
|
16
|
-
"username": self.username,
|
17
|
-
"password": self.password,
|
18
|
-
"grant_type": "password",
|
19
|
-
}
|
20
|
-
headers = {"Content-Type": "application/x-www-form-urlencoded"}
|
21
|
-
try:
|
22
|
-
response = self.session.post(
|
23
|
-
f"{self.base_url}/user/login", data=login_data, headers=headers
|
24
|
-
)
|
25
|
-
if response.status_code == 200:
|
26
|
-
token_data = response.json()
|
27
|
-
self.access_token = token_data["access_token"]
|
28
|
-
return
|
29
|
-
else:
|
30
|
-
raise ValueError(f"Status code: {response.status_code}")
|
31
|
-
except Exception as e:
|
32
|
-
raise ValueError(f"Error: {e}")
|
33
|
-
|
34
|
-
def _get_auth_headers(self):
|
35
|
-
if not self.access_token:
|
36
|
-
raise ValueError("Not logged in")
|
37
|
-
return {
|
38
|
-
"Authorization": f"Bearer {self.access_token}",
|
39
|
-
"Content-Type": "application/json",
|
40
|
-
}
|
41
|
-
|
42
|
-
def _get_session_status(self, session_id):
|
43
|
-
try:
|
44
|
-
response = self.session.get(
|
45
|
-
f"{self.base_url}/sessions/{session_id}/status",
|
46
|
-
headers=self._get_auth_headers(),
|
47
|
-
)
|
48
|
-
success = response.status_code == 200
|
49
|
-
if success:
|
50
|
-
return response.json()
|
51
|
-
else:
|
52
|
-
raise ValueError(f"Status code: {response.status_code}")
|
53
|
-
except Exception as e:
|
54
|
-
raise ValueError(f"Error: {e}")
|
55
|
-
|
56
|
-
def create_session(self):
|
57
|
-
if not self.access_token:
|
58
|
-
raise ValueError("Not logged in")
|
59
|
-
try:
|
60
|
-
response = self.session.post(
|
61
|
-
f"{self.base_url}/sessions/create", headers=self._get_auth_headers()
|
62
|
-
)
|
63
|
-
if response.status_code == 200:
|
64
|
-
response_json = response.json()
|
65
|
-
return response_json["session_id"]
|
66
|
-
else:
|
67
|
-
raise ValueError(f"Status code: {response.status_code}")
|
68
|
-
except Exception as e:
|
69
|
-
raise ValueError(f"Error: {e}")
|
70
|
-
|
71
|
-
def delete_session(self, session_id: str):
|
72
|
-
if not self.access_token:
|
73
|
-
raise ValueError("Not logged in")
|
74
|
-
try:
|
75
|
-
response = self.session.delete(
|
76
|
-
f"{self.base_url}/sessions/{session_id}",
|
77
|
-
headers=self._get_auth_headers(),
|
78
|
-
)
|
79
|
-
if response.status_code == 200:
|
80
|
-
return
|
81
|
-
else:
|
82
|
-
raise ValueError(f"Status code: {response.status_code}")
|
83
|
-
except Exception as e:
|
84
|
-
raise ValueError(f"Error: {e}")
|
85
|
-
|
86
|
-
def get_my_sessions(self):
|
87
|
-
if not self.access_token:
|
88
|
-
raise ValueError("Not logged in")
|
89
|
-
try:
|
90
|
-
response = self.session.get(
|
91
|
-
f"{self.base_url}/sessions/my_sessions",
|
92
|
-
headers=self._get_auth_headers(),
|
93
|
-
)
|
94
|
-
if response.status_code == 200:
|
95
|
-
sessions = response.json()
|
96
|
-
self.active_sessions = sessions
|
97
|
-
return [
|
98
|
-
{
|
99
|
-
"session_id": session["session_id"],
|
100
|
-
"title": session["environment_info"].get("title", None),
|
101
|
-
}
|
102
|
-
for session in sessions
|
103
|
-
]
|
104
|
-
else:
|
105
|
-
raise ValueError(f"Status code: {response.status_code}")
|
106
|
-
except Exception as e:
|
107
|
-
raise ValueError(f"Error: {e}")
|
108
|
-
|
109
|
-
def get_session_history(self, session_id: str):
|
110
|
-
session = self._get_session_status(session_id)
|
111
|
-
return session.get("conversation", [])
|
112
|
-
|
113
|
-
def chat(self, session_id: str, prompt: str):
|
114
|
-
if not self.access_token:
|
115
|
-
raise ValueError("Not logged in")
|
116
|
-
data = {
|
117
|
-
"user_input": prompt,
|
118
|
-
"session_id": session_id,
|
119
|
-
}
|
120
|
-
try:
|
121
|
-
response = self.session.post(
|
122
|
-
f"{self.base_url}/chat",
|
123
|
-
json=data,
|
124
|
-
headers=self._get_auth_headers(),
|
125
|
-
)
|
126
|
-
success = response.status_code == 200
|
127
|
-
if success:
|
128
|
-
return response.json()["conversation_history"]
|
129
|
-
else:
|
130
|
-
raise ValueError(f"Status code: {response.status_code}")
|
131
|
-
except Exception as e:
|
132
|
-
raise ValueError(f"Error: {e}")
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|