cycls 0.0.2.22__tar.gz → 0.0.2.23__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.
- {cycls-0.0.2.22 → cycls-0.0.2.23}/PKG-INFO +7 -5
- {cycls-0.0.2.22 → cycls-0.0.2.23}/README.md +6 -4
- {cycls-0.0.2.22 → cycls-0.0.2.23}/cycls/cycls.py +27 -38
- {cycls-0.0.2.22 → cycls-0.0.2.23}/pyproject.toml +1 -1
- {cycls-0.0.2.22 → cycls-0.0.2.23}/cycls/__init__.py +0 -0
- {cycls-0.0.2.22 → cycls-0.0.2.23}/cycls/tuns +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: cycls
|
|
3
|
-
Version: 0.0.2.
|
|
3
|
+
Version: 0.0.2.23
|
|
4
4
|
Summary: Cycls SDK
|
|
5
5
|
Author: Mohammed Jamal
|
|
6
6
|
Author-email: mj@cycls.com
|
|
@@ -49,13 +49,13 @@ from cycls import Cycls
|
|
|
49
49
|
|
|
50
50
|
cycls = Cycls()
|
|
51
51
|
|
|
52
|
-
@cycls("@spark")
|
|
52
|
+
@cycls("@spark") # pick a unique handle name
|
|
53
53
|
def app(x):
|
|
54
54
|
return x.content + "from spark"
|
|
55
55
|
|
|
56
56
|
cycls.push()
|
|
57
57
|
```
|
|
58
|
-
`cycls.push()` will then publish the app `@spark` on [cycls.com/@spark](https://cycls.com/@spark)
|
|
58
|
+
`cycls.push()` will then publish the app `@spark-dev` on [cycls.com/@spark-dev](https://cycls.com/@spark-dev) in development mode. Make sure to pick a unique app name; Cycls maintains a global namespace for handles.
|
|
59
59
|
## Async Apps
|
|
60
60
|
For performance, make the function asynchronous. The following is an async app with message `history` and session `id`
|
|
61
61
|
```py
|
|
@@ -87,6 +87,8 @@ cycls.push()
|
|
|
87
87
|
```
|
|
88
88
|
|
|
89
89
|
### Try it live
|
|
90
|
-
- [cycls.com/@groq](https://cycls.com/@groq)
|
|
91
|
-
- [cycls.com/@openai](https://cycls.com/@openai)
|
|
90
|
+
- [cycls.com/@groq](https://cycls.com/@groq) | [groq.py](https://github.com/Cycls/examples/blob/main/groq.py)
|
|
91
|
+
- [cycls.com/@openai](https://cycls.com/@openai) | [openai.py](https://github.com/Cycls/examples/blob/main/openai.py)
|
|
92
|
+
- [cycls.com/@anthropic](https://cycls.com/@anthropic) | [anthropic.py](https://github.com/Cycls/examples/blob/main/anthropic.py)
|
|
93
|
+
- [cycls.com/@gemini](https://cycls.com/@gemini) | [gemini.py](https://github.com/Cycls/examples/blob/main/gemini.py)
|
|
92
94
|
|
|
@@ -31,13 +31,13 @@ from cycls import Cycls
|
|
|
31
31
|
|
|
32
32
|
cycls = Cycls()
|
|
33
33
|
|
|
34
|
-
@cycls("@spark")
|
|
34
|
+
@cycls("@spark") # pick a unique handle name
|
|
35
35
|
def app(x):
|
|
36
36
|
return x.content + "from spark"
|
|
37
37
|
|
|
38
38
|
cycls.push()
|
|
39
39
|
```
|
|
40
|
-
`cycls.push()` will then publish the app `@spark` on [cycls.com/@spark](https://cycls.com/@spark)
|
|
40
|
+
`cycls.push()` will then publish the app `@spark-dev` on [cycls.com/@spark-dev](https://cycls.com/@spark-dev) in development mode. Make sure to pick a unique app name; Cycls maintains a global namespace for handles.
|
|
41
41
|
## Async Apps
|
|
42
42
|
For performance, make the function asynchronous. The following is an async app with message `history` and session `id`
|
|
43
43
|
```py
|
|
@@ -69,5 +69,7 @@ cycls.push()
|
|
|
69
69
|
```
|
|
70
70
|
|
|
71
71
|
### Try it live
|
|
72
|
-
- [cycls.com/@groq](https://cycls.com/@groq)
|
|
73
|
-
- [cycls.com/@openai](https://cycls.com/@openai)
|
|
72
|
+
- [cycls.com/@groq](https://cycls.com/@groq) | [groq.py](https://github.com/Cycls/examples/blob/main/groq.py)
|
|
73
|
+
- [cycls.com/@openai](https://cycls.com/@openai) | [openai.py](https://github.com/Cycls/examples/blob/main/openai.py)
|
|
74
|
+
- [cycls.com/@anthropic](https://cycls.com/@anthropic) | [anthropic.py](https://github.com/Cycls/examples/blob/main/anthropic.py)
|
|
75
|
+
- [cycls.com/@gemini](https://cycls.com/@gemini) | [gemini.py](https://github.com/Cycls/examples/blob/main/gemini.py)
|
|
@@ -10,7 +10,7 @@ import inspect
|
|
|
10
10
|
import logging
|
|
11
11
|
logging.basicConfig(level=logging.ERROR)
|
|
12
12
|
|
|
13
|
-
O = lambda x,y: print(f"✦/✧ {str(x).ljust(
|
|
13
|
+
O = lambda x,y: print(f"✦/✧ {str(x).ljust(12)} | {y}")
|
|
14
14
|
|
|
15
15
|
import os
|
|
16
16
|
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
@@ -42,30 +42,32 @@ async def create_ssh_tunnel(x,y,z='tuns.sh'):
|
|
|
42
42
|
except (OSError, asyncssh.Error) as e:
|
|
43
43
|
O("tunnel",f"disconnected ({e})")
|
|
44
44
|
|
|
45
|
-
def register(handles, net,
|
|
45
|
+
def register(handles, net, api_key):
|
|
46
46
|
try:
|
|
47
47
|
with httpx.Client() as client:
|
|
48
|
-
response = client.post(f"{net}/register", json={"handles":handles, "
|
|
48
|
+
response = client.post(f"{net}/register", json={"handles":handles, "net":net, "api_key":api_key})
|
|
49
|
+
data = response.json()
|
|
49
50
|
if response.status_code==200:
|
|
50
|
-
data = (response.json()).get("content")
|
|
51
51
|
for i in data:
|
|
52
|
-
O(i[
|
|
52
|
+
O(f"{i['status']}/{i['mode']}", f"{net}/{i['handle']}" if i["status"] != "taken" else "")
|
|
53
|
+
return True
|
|
53
54
|
else:
|
|
54
|
-
|
|
55
|
+
O("failed", data.get("error"))
|
|
56
|
+
return False
|
|
55
57
|
except Exception as e:
|
|
56
|
-
|
|
58
|
+
O("error",e)
|
|
59
|
+
return False
|
|
57
60
|
|
|
58
61
|
class Cycls:
|
|
59
|
-
def __init__(self, url="", net="https://cycls.com", port=find_available_port(8001),
|
|
62
|
+
def __init__(self, url="", net="https://cycls.com", port=find_available_port(8001), api_key=None):
|
|
60
63
|
import uuid
|
|
61
|
-
self.subdomain = str(uuid.uuid4())[:8]
|
|
64
|
+
self.subdomain = str(uuid.uuid4())[:8] #!
|
|
62
65
|
self.server = FastAPI()
|
|
63
66
|
self.net = net
|
|
64
67
|
self.port = port
|
|
65
68
|
self.url = url
|
|
66
69
|
self.apps = {}
|
|
67
|
-
self.
|
|
68
|
-
self.email = email
|
|
70
|
+
self.api_key = api_key
|
|
69
71
|
|
|
70
72
|
def __call__(self, handle):
|
|
71
73
|
def decorator(func):
|
|
@@ -76,13 +78,7 @@ class Cycls:
|
|
|
76
78
|
def sync_wrapper(*args, **kwargs):
|
|
77
79
|
return StreamingResponse(func(*args, **kwargs))
|
|
78
80
|
wrapper = async_wrapper if inspect.iscoroutinefunction(func) else sync_wrapper
|
|
79
|
-
|
|
80
|
-
if self.url != "": self.prod=True #!
|
|
81
|
-
if not self.prod:
|
|
82
|
-
self.apps[handle + "-dev"] = wrapper
|
|
83
|
-
else:
|
|
84
|
-
self.apps[handle] = wrapper
|
|
85
|
-
|
|
81
|
+
self.apps[handle] = wrapper
|
|
86
82
|
return wrapper
|
|
87
83
|
return decorator
|
|
88
84
|
|
|
@@ -96,29 +92,22 @@ class Cycls:
|
|
|
96
92
|
return {"error": "Handle not found"}
|
|
97
93
|
|
|
98
94
|
def push(self):
|
|
99
|
-
if self.email:
|
|
100
|
-
O("email",self.email)
|
|
101
95
|
O("port",self.port)
|
|
102
|
-
if self.
|
|
103
|
-
|
|
104
|
-
|
|
96
|
+
if self.url=="":
|
|
97
|
+
self.url = f"https://{self.subdomain}-cycls.tuns.sh"
|
|
98
|
+
mode = "dev"
|
|
105
99
|
else:
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
@self.server.on_event("startup")
|
|
113
|
-
def startup_event():
|
|
114
|
-
if self.prod:
|
|
115
|
-
pass
|
|
116
|
-
else:
|
|
100
|
+
mode = "prod"
|
|
101
|
+
config = [{"handle": handle, "url": self.url+"/gateway", "mode":mode} for handle in list(self.apps.keys())]
|
|
102
|
+
if on := register(config, self.net, self.api_key):
|
|
103
|
+
self.server.post("/gateway")(self.gateway)
|
|
104
|
+
@self.server.on_event("startup")
|
|
105
|
+
def startup_event():
|
|
117
106
|
asyncio.create_task(create_ssh_tunnel(f"{self.subdomain}-cycls", self.port))
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
107
|
+
try:
|
|
108
|
+
uvicorn.run(self.server, host="127.0.0.1", port=self.port, log_level="error")
|
|
109
|
+
except KeyboardInterrupt:
|
|
110
|
+
print(" ");O("exit","done")
|
|
122
111
|
|
|
123
112
|
async def call(self, handle, content):
|
|
124
113
|
data = {"handle":handle, "content":content, "session":{}, "agent":"yes"}
|
|
File without changes
|
|
File without changes
|