naas-abi-core 1.0.7__py3-none-any.whl → 1.1.0__py3-none-any.whl

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.
@@ -7,7 +7,7 @@ from .init import init
7
7
  from .module import module
8
8
  from .new import new
9
9
  from .secret import secrets
10
-
10
+ from .deploy import deploy
11
11
  # from dotenv import load_dotenv
12
12
 
13
13
  # load_dotenv()
@@ -48,6 +48,7 @@ main.add_command(agent)
48
48
  main.add_command(chat)
49
49
  main.add_command(new)
50
50
  main.add_command(init)
51
+ main.add_command(deploy)
51
52
 
52
53
  # if __name__ == "__main__":
53
54
  main()
@@ -0,0 +1,199 @@
1
+ import json
2
+ import subprocess
3
+ from uuid import uuid4
4
+
5
+ import click
6
+ import requests
7
+ from pydantic import BaseModel
8
+ from rich.console import Console
9
+ from rich.markdown import Markdown
10
+
11
+ from naas_abi_core import logger
12
+ from naas_abi_core.engine.engine_configuration.EngineConfiguration import (
13
+ EngineConfiguration,
14
+ )
15
+
16
+
17
+ @click.group("deploy")
18
+ def deploy():
19
+ pass
20
+
21
+
22
+ class Container(BaseModel):
23
+ name: str
24
+ image: str
25
+ port: int
26
+ cpu: str
27
+ memory: str
28
+ env: dict
29
+
30
+
31
+ class Space(BaseModel):
32
+ name: str
33
+ containers: list[Container]
34
+
35
+
36
+ class NaasAPIClient:
37
+ naas_api_key: str
38
+ base_url: str
39
+
40
+ def __init__(self, naas_api_key: str):
41
+ self.naas_api_key = naas_api_key
42
+ self.base_url = "https://api.naas.ai"
43
+
44
+ def create_registry(self, name: str):
45
+ response = requests.post(
46
+ f"{self.base_url}/registry/",
47
+ headers={"Authorization": f"Bearer {self.naas_api_key}"},
48
+ json={"name": name},
49
+ )
50
+ if response.status_code == 409:
51
+ return self.get_registry(name)
52
+ response.raise_for_status()
53
+ return response.json()
54
+
55
+ def get_registry(self, name: str):
56
+ response = requests.get(
57
+ f"{self.base_url}/registry/{name}",
58
+ headers={"Authorization": f"Bearer {self.naas_api_key}"},
59
+ )
60
+ response.raise_for_status()
61
+ return response.json()
62
+
63
+ def get_registry_credentials(self, name: str):
64
+ response = requests.get(
65
+ f"{self.base_url}/registry/{name}/credentials",
66
+ headers={"Authorization": f"Bearer {self.naas_api_key}"},
67
+ )
68
+ response.raise_for_status()
69
+ return response.json()
70
+
71
+ def update_space(self, space: Space) -> dict:
72
+ response = requests.put(
73
+ f"{self.base_url}/space/{space.name}",
74
+ headers={"Authorization": f"Bearer {self.naas_api_key}"},
75
+ json=space.model_dump(),
76
+ )
77
+ response.raise_for_status()
78
+ return response.json()
79
+
80
+ def create_space(self, space: Space) -> dict:
81
+ response = requests.post(
82
+ f"{self.base_url}/space/",
83
+ headers={"Authorization": f"Bearer {self.naas_api_key}"},
84
+ json=space.model_dump(),
85
+ )
86
+
87
+ if response.status_code == 409:
88
+ return self.update_space(space)
89
+
90
+ response.raise_for_status()
91
+ return response.json()
92
+
93
+ def get_space(self, name: str) -> dict:
94
+ response = requests.get(
95
+ f"{self.base_url}/space/{name}",
96
+ headers={"Authorization": f"Bearer {self.naas_api_key}"},
97
+ )
98
+ response.raise_for_status()
99
+ return response.json()
100
+
101
+
102
+ class NaasDeployer:
103
+ image_name: str
104
+
105
+ naas_api_client: NaasAPIClient
106
+
107
+ def __init__(self, configuration: EngineConfiguration):
108
+ self.configuration = configuration
109
+ self.image_name = str(uuid4())
110
+ assert configuration.deploy is not None
111
+ self.naas_api_client = NaasAPIClient(configuration.deploy.naas_api_key)
112
+
113
+ def docker_build(self, image_name: str):
114
+ subprocess.run(
115
+ f"docker build -t {image_name} . --platform linux/amd64", shell=True
116
+ )
117
+
118
+ def env_list_to_dict(self, env: list[str]) -> dict:
119
+ return {env_var.split("=", 1)[0]: env_var.split("=", 1)[1] for env_var in env}
120
+
121
+ def deploy(self, env: list[str]):
122
+ registry = self.naas_api_client.create_registry(
123
+ self.configuration.deploy.space_name
124
+ )
125
+
126
+ uid = str(uuid4())
127
+
128
+ image_name = f"{registry['registry']['uri']}:{uid}"
129
+ self.docker_build(image_name)
130
+ credentials = self.naas_api_client.get_registry_credentials(
131
+ self.configuration.deploy.space_name
132
+ )
133
+ docker_login_command = f"docker login -u {credentials['credentials']['username']} -p {credentials['credentials']['password']} {registry['registry']['uri']}"
134
+ subprocess.run(docker_login_command, shell=True)
135
+ subprocess.run(f"docker push {image_name}", shell=True)
136
+
137
+ image_sha = (
138
+ subprocess.run(
139
+ "docker inspect --format='{{index .RepoDigests 0}}' "
140
+ + image_name
141
+ + " | cut -d'@' -f2",
142
+ shell=True,
143
+ capture_output=True,
144
+ )
145
+ .stdout.strip()
146
+ .decode("utf-8")
147
+ )
148
+
149
+ image_name_with_sha = f"{image_name.replace(':' + uid, '')}@{image_sha}"
150
+
151
+
152
+ self.naas_api_client.create_space(
153
+ Space(
154
+ name=self.configuration.deploy.space_name,
155
+ containers=[
156
+ Container(
157
+ name="api",
158
+ image=image_name_with_sha,
159
+ port=9879,
160
+ cpu="1",
161
+ memory="1Gi",
162
+ env=self.env_list_to_dict(env) | {
163
+ "NAAS_API_KEY": self.configuration.deploy.naas_api_key,
164
+ "ENV": "prod",
165
+ },
166
+ )
167
+ ],
168
+ )
169
+ )
170
+
171
+ space = self.naas_api_client.get_space(self.configuration.deploy.space_name)
172
+
173
+ Console().print(
174
+ Markdown(f"""
175
+ # Deployment successful
176
+
177
+ - Space: {self.configuration.deploy.space_name}
178
+ - Image: {image_name_with_sha}
179
+ - URL: https://{self.configuration.deploy.space_name}.default.space.naas.ai
180
+
181
+ ```json
182
+ {json.dumps(space, indent=4)}
183
+ ```
184
+ """)
185
+ )
186
+
187
+
188
+ @deploy.command("naas")
189
+ @click.option("-e", "--env", multiple=True, help="Environment variables to set (e.g. -e FOO=BAR -e BAZ=QUX)")
190
+ def naas(env: list[str]):
191
+ configuration: EngineConfiguration = EngineConfiguration.load_configuration()
192
+
193
+ if configuration.deploy is None:
194
+ logger.error(
195
+ "Deploy configuration not found in the yaml configuration file. Please add a deploy section to the configuration file."
196
+ )
197
+
198
+ deployer = NaasDeployer(configuration)
199
+ deployer.deploy(env)
@@ -20,7 +20,7 @@ from naas_abi_core.engine.engine_configuration.EngineConfiguration_VectorStoreSe
20
20
  from naas_abi_core.services.secret.Secret import Secret
21
21
  from pydantic import BaseModel, model_validator
22
22
  from typing_extensions import Literal
23
-
23
+ from naas_abi_core.engine.engine_configuration.EngineConfiguration_Deploy import DeployConfiguration
24
24
 
25
25
  class ServicesConfiguration(BaseModel):
26
26
  object_storage: ObjectStorageServiceConfiguration
@@ -80,6 +80,8 @@ class GlobalConfig(BaseModel):
80
80
 
81
81
  class EngineConfiguration(BaseModel):
82
82
  api: ApiConfiguration
83
+
84
+ deploy: DeployConfiguration | None = None
83
85
 
84
86
  services: ServicesConfiguration
85
87
 
@@ -0,0 +1,6 @@
1
+ from pydantic import BaseModel
2
+
3
+ class DeployConfiguration(BaseModel):
4
+ workspace_id: str
5
+ space_name: str
6
+ naas_api_key: str
@@ -1,10 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: naas-abi-core
3
- Version: 1.0.7
3
+ Version: 1.1.0
4
4
  Summary: Abi framework allowing you to build your AI system.
5
5
  Author-email: Maxime Jublou <maxime@naas.ai>, Florent Ravenel <florent@naas.ai>, Jeremy Ravenel <jeremy@naas.ai>
6
6
  Requires-Python: <4,>=3.10
7
7
  Requires-Dist: click<8.2,>=8.1.1
8
+ Requires-Dist: docker>=7.1.0
8
9
  Requires-Dist: dotenv>=0.9.9
9
10
  Requires-Dist: fastapi<0.116,>=0.115.5
10
11
  Requires-Dist: fastmcp>=2.13.2
@@ -7,10 +7,11 @@ naas_abi_core/apps/mcp/mcp_server.py,sha256=U-wDl8rswMk4nefGg2SUByw4x8CM10M59FfL
7
7
  naas_abi_core/apps/mcp/mcp_server_test.py,sha256=8jixnDyERM_HjjDTRtPDQcJ_rzA0ESAn147sl2Gk8gw,5636
8
8
  naas_abi_core/apps/terminal_agent/main.py,sha256=ucrNCGjjixyiO47Eily1yAmrwznS6KOcB1kk02yt_m8,19631
9
9
  naas_abi_core/apps/terminal_agent/terminal_style.py,sha256=YOpfvBlKU52wNyGEKbZPiRQVKxug-hI92H8ScV5L8Ew,5254
10
- naas_abi_core/cli/__init__.py,sha256=UHfBoHZGZ_cRDENqfAtm0gEX3tWKwUxsMezHZ3SXJqg,1273
10
+ naas_abi_core/cli/__init__.py,sha256=P89Ihofvv_pQf2wsfYL-PjLJMl6KRj3fNNIZDB77Qy0,1324
11
11
  naas_abi_core/cli/agent.py,sha256=fMdbC7HsrOfZSf5zVRHWSmyrejI5mUdRlAT5v5YHXzk,658
12
12
  naas_abi_core/cli/chat.py,sha256=3t_TJ7vqCNs0MIIXOtlSke3nzy4rMSEJtB3P6pKItMo,856
13
13
  naas_abi_core/cli/config.py,sha256=CcdDX6HKCP32NjRhbVsCOwLUC9LmaqTm2sv8W5rOt00,1484
14
+ naas_abi_core/cli/deploy.py,sha256=ZMf0EbwGoL4fwae3he2wCLMm6ghRWJthy1uW_tX6fC0,6018
14
15
  naas_abi_core/cli/init.py,sha256=Pcy2-hy-FvpXf3UOKMP6agWyFrCl9z-KP5ktEWltPy0,220
15
16
  naas_abi_core/cli/module.py,sha256=TBl-SpeGUcy1Rrp40Irbt34yQS00xJcNje-OijNE4Hk,717
16
17
  naas_abi_core/cli/new.py,sha256=aFhKbTHwqYkPdzrd7r8i_h9dfzXNjI03t8qVeqME8w8,262
@@ -20,7 +21,8 @@ naas_abi_core/engine/EngineProxy.py,sha256=o-D8LlP-PjQ_Yct4JWrDZw7mA7yporxb2XrJF
20
21
  naas_abi_core/engine/Engine_test.py,sha256=8eLZEnkL0IR4VAr6LF8fJ_fxZzi9s1mXCLgTVOIsR3E,161
21
22
  naas_abi_core/engine/IEngine.py,sha256=u-m-Qrvt3SP3gYKWPFPVjV8rs05D6NGnzO3XA0FInnw,2865
22
23
  naas_abi_core/engine/conftest.py,sha256=Al-SRVLrEdbTrX8sxQ3bBK4w1bbzE4GoBkzoBK-aXlg,932
23
- naas_abi_core/engine/engine_configuration/EngineConfiguration.py,sha256=XA8BDyuYWvjwREGHDBB1iGFe5neJKFKsaHFRnPPKJXI,5378
24
+ naas_abi_core/engine/engine_configuration/EngineConfiguration.py,sha256=12rKgF1LaLC_YMhKEABFSdU_Fb04qGpW4tft3eVCnPI,5529
25
+ naas_abi_core/engine/engine_configuration/EngineConfiguration_Deploy.py,sha256=NbPMxiNt9C4zfNF70fs7a8prELpd3QAHbZlvHfwcbxs,134
24
26
  naas_abi_core/engine/engine_configuration/EngineConfiguration_GenericLoader.py,sha256=KK2TQx6cNmoqFcwr9En00NKrX4ckkZl4ecv9QCUwPyc,1995
25
27
  naas_abi_core/engine/engine_configuration/EngineConfiguration_ObjectStorageService.py,sha256=cPZBs5-2dqX-piIZ7KTqiOce6O6GbnDDwjPGcfDN_U4,4736
26
28
  naas_abi_core/engine/engine_configuration/EngineConfiguration_ObjectStorageService_test.py,sha256=h1PdIbMTJWi_lG83YgpI6zg8gRo0WEWvGSE6R4uKQp4,1063
@@ -121,7 +123,7 @@ naas_abi_core/utils/onto2py/tests/ttl2py_test.py,sha256=5OZqSxPffjJYiX9T4rT1mV0P
121
123
  naas_abi_core/workflow/__init__.py,sha256=hZD58mCB1PApxITqftP_xgjxL7NeLvOfI-rJENg1ENs,250
122
124
  naas_abi_core/workflow/workflow.py,sha256=ZufSS073JztVl0OQRTqNyK7FepFvv7gXlc4j5FAEZCI,1216
123
125
  assets/favicon.ico,sha256=nWk8wrHZiJV3DeuWrP2MqilXxCuoNWKGtMZfYmEVQLw,666
124
- naas_abi_core-1.0.7.dist-info/METADATA,sha256=gTjTHO7PttQKEINKCxX0toiOwO14J3Nhxkxh2m224EA,3868
125
- naas_abi_core-1.0.7.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
126
- naas_abi_core-1.0.7.dist-info/entry_points.txt,sha256=q68PvlGw_rozZ0nl6mUg6l1l2IhxaTOKlf5K9goRDu0,99
127
- naas_abi_core-1.0.7.dist-info/RECORD,,
126
+ naas_abi_core-1.1.0.dist-info/METADATA,sha256=W0UO3c5K34ADisfJVFt0_pl2YadivJRqKH1UEAiAGvQ,3897
127
+ naas_abi_core-1.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
128
+ naas_abi_core-1.1.0.dist-info/entry_points.txt,sha256=q68PvlGw_rozZ0nl6mUg6l1l2IhxaTOKlf5K9goRDu0,99
129
+ naas_abi_core-1.1.0.dist-info/RECORD,,