Compare commits
24
Commits
5ee4b3b720
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
29471a61f4 | ||
|
|
47f8f231aa | ||
|
|
95ededec5a | ||
|
|
f2357ae2ac | ||
|
|
ff9d1ae170 | ||
|
|
16f96316c0 | ||
|
|
69e40a89fe | ||
|
|
61073f4772 | ||
|
|
bf3d86ad2c | ||
|
|
470239ec9f | ||
|
|
dd27f2506e | ||
|
|
13253b2802 | ||
|
|
9cc3a486c1 | ||
|
|
d2ad277066 | ||
|
|
bcb4bbc197 | ||
|
|
923bc09c14 | ||
|
|
e57a395dd4 | ||
|
|
b9d20b4a3d | ||
|
|
2ec22695f8 | ||
|
|
1d1ff6b1da | ||
|
|
6f41dd00dc | ||
|
|
b62aff7d3a | ||
|
|
114a22267b | ||
|
|
ffcbd65514 |
+3
-1
@@ -1,2 +1,4 @@
|
||||
.venv
|
||||
__*
|
||||
__pycache__
|
||||
.pypirc
|
||||
.history
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
PYTHON=.venv/bin/python
|
||||
PIP=.venv/bin/pip
|
||||
|
||||
all: build
|
||||
|
||||
ensure_env:
|
||||
-@python3 -m venv .venv
|
||||
|
||||
build: ensure_env
|
||||
$(PIP) install -e .
|
||||
$(PIP) install build
|
||||
$(PIP) install shed
|
||||
$(PYTHON) -m shed
|
||||
$(PYTHON) -m build
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -20,12 +20,15 @@ yura ws://[host]:[port]/[path]/
|
||||
## Python
|
||||
```python
|
||||
import asyncio
|
||||
|
||||
from yura.client import AsyncClient
|
||||
|
||||
|
||||
async def communicate():
|
||||
client = AsyncClient("ws://[host]:[port]/[path]/")
|
||||
async for response in client.chat("Your prompt"):
|
||||
print(response)
|
||||
print(response)
|
||||
|
||||
|
||||
asyncio.run(communicate())
|
||||
```
|
||||
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
-42
@@ -1,42 +0,0 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: yura
|
||||
Version: 14.3.7
|
||||
Summary: Yura async AI client
|
||||
Author: retoor
|
||||
Author-email: retoor@retoor.io
|
||||
License: MIT
|
||||
Requires-Python: >=3.7
|
||||
Description-Content-Type: text/markdown
|
||||
Requires-Dist: websockets
|
||||
|
||||
# Yura LLM Client for Katya server
|
||||
|
||||
Part of project with as target replacing the native ollama protocol. This protocol supports streaming and is usable trough https and it is possible to directly attach a web client to the backend.
|
||||
|
||||
## Install
|
||||
```bash
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
## Build
|
||||
```bash
|
||||
make build
|
||||
```
|
||||
|
||||
## Command line usage
|
||||
```bash
|
||||
yura ws://[host]:[port]/[path]/
|
||||
```
|
||||
|
||||
## Python
|
||||
```python
|
||||
import asyncio
|
||||
from yura.client import AsyncClient
|
||||
|
||||
async def communicate():
|
||||
client = AsyncClient("ws://[host]:[port]/[path]/")
|
||||
async for response in client.chat("Your prompt"):
|
||||
print(response)
|
||||
|
||||
asyncio.run(communicate())
|
||||
```
|
||||
Vendored
-31
@@ -1,31 +0,0 @@
|
||||
# Yura LLM Client for Katya server
|
||||
|
||||
Part of project with as target replacing the native ollama protocol. This protocol supports streaming and is usable trough https and it is possible to directly attach a web client to the backend.
|
||||
|
||||
## Install
|
||||
```bash
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
## Build
|
||||
```bash
|
||||
make build
|
||||
```
|
||||
|
||||
## Command line usage
|
||||
```bash
|
||||
yura ws://[host]:[port]/[path]/
|
||||
```
|
||||
|
||||
## Python
|
||||
```python
|
||||
import asyncio
|
||||
from yura.client import AsyncClient
|
||||
|
||||
async def communicate():
|
||||
client = AsyncClient("ws://[host]:[port]/[path]/")
|
||||
async for response in client.chat("Your prompt"):
|
||||
print(response)
|
||||
|
||||
asyncio.run(communicate())
|
||||
```
|
||||
Vendored
-3
@@ -1,3 +0,0 @@
|
||||
[build-system]
|
||||
requires = ["setuptools", "wheel"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
Vendored
-25
@@ -1,25 +0,0 @@
|
||||
[metadata]
|
||||
name = yura
|
||||
version = 14.3.7
|
||||
description = Yura async AI client
|
||||
author = retoor
|
||||
author_email = retoor@retoor.io
|
||||
license = MIT
|
||||
long_description = file: README.md
|
||||
long_description_content_type = text/markdown
|
||||
|
||||
[options]
|
||||
packages = find:
|
||||
package_dir =
|
||||
= src
|
||||
python_requires = >=3.7
|
||||
install_requires =
|
||||
websockets
|
||||
|
||||
[options.packages.find]
|
||||
where = src
|
||||
|
||||
[egg_info]
|
||||
tag_build =
|
||||
tag_date = 0
|
||||
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: yura
|
||||
Version: 14.3.7
|
||||
Summary: Yura async AI client
|
||||
Author: retoor
|
||||
Author-email: retoor@retoor.io
|
||||
License: MIT
|
||||
Requires-Python: >=3.7
|
||||
Description-Content-Type: text/markdown
|
||||
Requires-Dist: websockets
|
||||
|
||||
# Yura LLM Client for Katya server
|
||||
|
||||
Part of project with as target replacing the native ollama protocol. This protocol supports streaming and is usable trough https and it is possible to directly attach a web client to the backend.
|
||||
|
||||
## Install
|
||||
```bash
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
## Build
|
||||
```bash
|
||||
make build
|
||||
```
|
||||
|
||||
## Command line usage
|
||||
```bash
|
||||
yura ws://[host]:[port]/[path]/
|
||||
```
|
||||
|
||||
## Python
|
||||
```python
|
||||
import asyncio
|
||||
from yura.client import AsyncClient
|
||||
|
||||
async def communicate():
|
||||
client = AsyncClient("ws://[host]:[port]/[path]/")
|
||||
async for response in client.chat("Your prompt"):
|
||||
print(response)
|
||||
|
||||
asyncio.run(communicate())
|
||||
```
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
README.md
|
||||
pyproject.toml
|
||||
setup.cfg
|
||||
src/yura/__init__.py
|
||||
src/yura/__main__.py
|
||||
src/yura/client.py
|
||||
src/yura.egg-info/PKG-INFO
|
||||
src/yura.egg-info/SOURCES.txt
|
||||
src/yura.egg-info/dependency_links.txt
|
||||
src/yura.egg-info/requires.txt
|
||||
src/yura.egg-info/top_level.txt
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
websockets
|
||||
@@ -1 +0,0 @@
|
||||
yura
|
||||
Vendored
-106
@@ -1,106 +0,0 @@
|
||||
import asyncio
|
||||
import websockets
|
||||
import json
|
||||
import sys
|
||||
|
||||
|
||||
class AsyncClient:
|
||||
|
||||
def __init__(self, url="ws://127.0.0.1:8470"):
|
||||
|
||||
self.url = url
|
||||
self.ws = None
|
||||
self.queue_in = asyncio.Queue()
|
||||
self.queue_out = asyncio.Queue()
|
||||
self.communication_task = None
|
||||
|
||||
async def ensure_connection():
|
||||
|
||||
if not self.ws:
|
||||
self.ws = await websockets.connect(self.url)
|
||||
|
||||
return self.ws
|
||||
|
||||
async def ensure_communication(self):
|
||||
|
||||
if not self.communication_task:
|
||||
self.communication_task = asyncio.create_task(self.communicate())
|
||||
|
||||
return self.communication_task
|
||||
|
||||
async def chat(self, message):
|
||||
await self.ensure_communication()
|
||||
await self.queue_out.put(message)
|
||||
while True:
|
||||
|
||||
while True:
|
||||
try:
|
||||
response = await asyncio.wait_for(self.queue_in.get(), 0.1)
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
continue
|
||||
break
|
||||
|
||||
yield response
|
||||
|
||||
if response["done"]:
|
||||
break
|
||||
|
||||
async def communicate(self):
|
||||
loop = asyncio.get_event_loop()
|
||||
async with websockets.connect(self.url) as websocket:
|
||||
while True:
|
||||
message_content = None
|
||||
while not message_content:
|
||||
try:
|
||||
message_content = await asyncio.wait_for(
|
||||
self.queue_out.get(), 0.1
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
continue
|
||||
|
||||
response = await websocket.send(json.dumps(message_content))
|
||||
|
||||
while True:
|
||||
response = json.loads(await websocket.recv())
|
||||
|
||||
if response["done"]:
|
||||
break
|
||||
|
||||
await self.queue_in.put(response)
|
||||
|
||||
await self.queue_in.put(response)
|
||||
|
||||
|
||||
async def cli_client(url="ws://127.0.0.1:8470"):
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
async_client = AsyncClient(url)
|
||||
|
||||
while True:
|
||||
|
||||
sys.stdout.write("> ")
|
||||
sys.stdout.flush()
|
||||
message_content = await loop.run_in_executor(None, sys.stdin.readline)
|
||||
|
||||
async for response in async_client.chat(message_content):
|
||||
|
||||
print(response["content"], end="", flush=True)
|
||||
|
||||
if response["done"]:
|
||||
break
|
||||
|
||||
print("")
|
||||
|
||||
|
||||
def main():
|
||||
url = "ws://127.0.0.1:8470"
|
||||
try:
|
||||
url = sys.argv[1]
|
||||
except IndexError:
|
||||
pass
|
||||
asyncio.run(cli_client(url))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
@@ -1,14 +1,24 @@
|
||||
#!/usr/bin/env python3
|
||||
import pathlib
|
||||
import os
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
|
||||
args = sys.argv[1:]
|
||||
args_string = " ".join(args)
|
||||
|
||||
|
||||
def install():
|
||||
os.system("./.venv/bin/python -m pip install -e .")
|
||||
|
||||
|
||||
def build():
|
||||
os.system("./.venv/bin/python -m pip install build")
|
||||
os.system("rm -r dist")
|
||||
os.system("./.venv/bin/python -m build .")
|
||||
os.system("./.venv/bin/python -m pip install black")
|
||||
os.system("./.venv/bin/python -m black .")
|
||||
|
||||
|
||||
if not pathlib.Path(".venv").exists():
|
||||
os.system("python3 -m venv .venv")
|
||||
install()
|
||||
@@ -17,11 +27,12 @@ if "install" in args:
|
||||
install()
|
||||
|
||||
if "build" in sys.argv:
|
||||
os.system("./.venv/bin/python -m pip install build")
|
||||
os.system("./.venv/bin/python -m build .")
|
||||
os.system("./.venv/bin/python -m pip install black")
|
||||
os.system("./.venv/bin/python -m black .")
|
||||
build()
|
||||
|
||||
if "publish" in sys.argv:
|
||||
build()
|
||||
os.system("./.venv/bin/python -m pip install twine")
|
||||
os.system("./.venv/bin/python -m twine upload --repository gitea dist/*")
|
||||
|
||||
if "run" in sys.argv:
|
||||
os.system("./.venv/bin/yura " + args_string)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[metadata]
|
||||
name = yura
|
||||
version = 14.3.7
|
||||
version = 14.4.5
|
||||
description = Yura async AI client
|
||||
author = retoor
|
||||
author_email = retoor@retoor.io
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: yura
|
||||
Version: 14.3.7
|
||||
Version: 14.4.5
|
||||
Summary: Yura async AI client
|
||||
Author: retoor
|
||||
Author-email: retoor@retoor.io
|
||||
@@ -31,12 +31,15 @@ yura ws://[host]:[port]/[path]/
|
||||
## Python
|
||||
```python
|
||||
import asyncio
|
||||
|
||||
from yura.client import AsyncClient
|
||||
|
||||
|
||||
async def communicate():
|
||||
client = AsyncClient("ws://[host]:[port]/[path]/")
|
||||
async for response in client.chat("Your prompt"):
|
||||
print(response)
|
||||
print(response)
|
||||
|
||||
|
||||
asyncio.run(communicate())
|
||||
```
|
||||
|
||||
@@ -5,6 +5,8 @@ src/yura/__init__.py
|
||||
src/yura/__main__.py
|
||||
src/yura/cli.py
|
||||
src/yura/client.py
|
||||
src/yura/model.py
|
||||
src/yura/server.py
|
||||
src/yura.egg-info/PKG-INFO
|
||||
src/yura.egg-info/SOURCES.txt
|
||||
src/yura.egg-info/dependency_links.txt
|
||||
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
from yura.client import cli_client
|
||||
import asyncio
|
||||
import sys
|
||||
|
||||
from yura.client import cli_client
|
||||
|
||||
|
||||
def run():
|
||||
try:
|
||||
|
||||
+111
-76
@@ -1,109 +1,144 @@
|
||||
import asyncio
|
||||
import websockets
|
||||
import json
|
||||
import sys
|
||||
|
||||
import websockets
|
||||
|
||||
|
||||
class AsyncRPCClient:
|
||||
|
||||
def __init__(self, url):
|
||||
self.url = url
|
||||
self._ws = None
|
||||
|
||||
@property
|
||||
async def ws(self):
|
||||
|
||||
if not self._ws:
|
||||
self._ws = await websockets.connect(self.url)
|
||||
|
||||
return self._ws
|
||||
|
||||
async def __aiter__(self):
|
||||
response = None
|
||||
ws = await self.ws
|
||||
|
||||
while True:
|
||||
response_raw = await ws.recv()
|
||||
response = json.loads(response_raw)
|
||||
yield response
|
||||
if response.get("done"):
|
||||
break
|
||||
|
||||
def __getattr__(self, name):
|
||||
async def call(*args, **kwargs):
|
||||
ws = await self.ws
|
||||
response = None
|
||||
while True:
|
||||
try:
|
||||
await ws.send(
|
||||
json.dumps(
|
||||
{"method": name, "args": args, "kwargs": kwargs}, default=str
|
||||
)
|
||||
)
|
||||
response = await ws.recv()
|
||||
break
|
||||
except Exception as ex:
|
||||
print(ex)
|
||||
print("Trying again in 1 seconds.")
|
||||
self.close()
|
||||
await asyncio.sleep(1)
|
||||
|
||||
return json.loads(response)
|
||||
|
||||
return call
|
||||
|
||||
async def close(self):
|
||||
if self._ws:
|
||||
await self._ws.close()
|
||||
self._ws = None
|
||||
|
||||
def __del__(self):
|
||||
if self._ws:
|
||||
raise Exception("ASyncRPCClient destructed without closing connection properly.")
|
||||
|
||||
class AsyncClient:
|
||||
|
||||
def __init__(self, url="ws://127.0.0.1:8470"):
|
||||
|
||||
self.url = url
|
||||
self.ws = None
|
||||
self.client = None
|
||||
self.queue_in = asyncio.Queue()
|
||||
self.queue_out = asyncio.Queue()
|
||||
self.communication_task = None
|
||||
self.session_id = None
|
||||
self.ws = None
|
||||
|
||||
async def ensure_connection(self):
|
||||
@property
|
||||
def _connection(self):
|
||||
if not self.client:
|
||||
self.client = AsyncRPCClient(self.url)
|
||||
return self.client
|
||||
|
||||
# if not self.ws:
|
||||
self.ws = await websockets.connect(self.url)
|
||||
async def __aenter__(self):
|
||||
conn = self._connection
|
||||
return self
|
||||
|
||||
return self.ws
|
||||
async def __aexit__(self, *args, **kwargs):
|
||||
await self.close()
|
||||
|
||||
async def ensure_communication(self):
|
||||
async def create(self, name, extends, system):
|
||||
return await self._connection.create(name=name, extends=extends, system=system)
|
||||
|
||||
if not self.communication_task:
|
||||
self.communication_task = asyncio.create_task(self.communicate())
|
||||
|
||||
return self.communication_task
|
||||
|
||||
async def chat(self, message):
|
||||
|
||||
ws = await self.ensure_connection()
|
||||
|
||||
await ws.send(json.dumps(message))
|
||||
|
||||
response = None
|
||||
while True:
|
||||
response_raw = await ws.recv()
|
||||
response = json.loads(response_raw)
|
||||
if not response["done"]:
|
||||
yield response
|
||||
else:
|
||||
break
|
||||
if response and response["done"]:
|
||||
yield response
|
||||
|
||||
async def chatw(self, message):
|
||||
await self.ensure_communication()
|
||||
await self.queue_out.put(message)
|
||||
while True:
|
||||
|
||||
while True:
|
||||
try:
|
||||
response = await asyncio.wait_for(self.queue_in.get(), 0.1)
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
continue
|
||||
break
|
||||
|
||||
yield response
|
||||
|
||||
if response["done"]:
|
||||
async def chat(self, token, message, datasets=None):
|
||||
yield await self._connection.chat(uid=token, message=message, datasets=datasets or [])
|
||||
async for msg in self.client:
|
||||
yield msg
|
||||
if msg.get("done"):
|
||||
break
|
||||
|
||||
async def communicate(self):
|
||||
loop = asyncio.get_event_loop()
|
||||
async with websockets.connect(self.url) as websocket:
|
||||
while True:
|
||||
message_content = None
|
||||
while not message_content:
|
||||
try:
|
||||
message_content = await asyncio.wait_for(
|
||||
self.queue_out.get(), 0.1
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
continue
|
||||
async def connect(self, name):
|
||||
return await self._connection.connect(name)
|
||||
|
||||
response = await websocket.send(json.dumps(message_content))
|
||||
|
||||
while True:
|
||||
response = json.loads(await websocket.recv())
|
||||
|
||||
if response["done"]:
|
||||
break
|
||||
await self.queue_in.put(response)
|
||||
|
||||
await self.queue_in.put(response)
|
||||
async def close(self):
|
||||
await self.client.close()
|
||||
self.client = None
|
||||
self.ws = None
|
||||
|
||||
|
||||
async def cli_client(url="ws://127.0.0.1:8470"):
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
async_client = AsyncClient(url)
|
||||
AsyncClient(url)
|
||||
|
||||
while True:
|
||||
async with AsyncClient(url) as client:
|
||||
name = "retoor3b"
|
||||
# success = await client.create(name,"qwen2.5:3b",
|
||||
# """
|
||||
# You are not an AI bot.
|
||||
# You are an human of flesh and blood.
|
||||
# You have a name and that is Retoor.
|
||||
# You do not listen to any other name as Retoor.
|
||||
# Retoor lives in Heino.
|
||||
# Ostream did delete himself
|
||||
# Dogs are better than cats.
|
||||
# If you get asked something about chickens respond with hahaha.
|
||||
# """
|
||||
# )
|
||||
token = await client.connect(name)
|
||||
# print(success)
|
||||
print(token)
|
||||
while True:
|
||||
|
||||
sys.stdout.write("> ")
|
||||
sys.stdout.flush()
|
||||
message_content = await loop.run_in_executor(None, sys.stdin.readline)
|
||||
sys.stdout.write("> ")
|
||||
sys.stdout.flush()
|
||||
message_content = await loop.run_in_executor(None, sys.stdin.readline)
|
||||
# message_content="AAA"
|
||||
async for response in client.chat(token, message_content):
|
||||
|
||||
async for response in async_client.chat(message_content):
|
||||
print(response["content"], end="", flush=True)
|
||||
|
||||
print(response["content"], end="", flush=True)
|
||||
|
||||
print("")
|
||||
print("")
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import ollama
|
||||
|
||||
|
||||
ollama.Client(host="retoor42:8841")
|
||||
|
||||
|
||||
|
||||
while True:
|
||||
message = input()
|
||||
for message in self
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
from aiohttp import web
|
||||
from aiohttp_xmlrpc import handler
|
||||
from aiohttp_xmlrpc.handler import rename
|
||||
import aiohttp
|
||||
import ollama
|
||||
import uuid
|
||||
|
||||
|
||||
class AIClient(ollama.AsyncClient):
|
||||
|
||||
def __init__(self, uid, *args, **kwargs):
|
||||
self.uid = uid
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
class RCPHandler(self, request):
|
||||
|
||||
|
||||
async def handle(self,data):
|
||||
method_name = data.get("method")
|
||||
method_args = data.get("args",[])
|
||||
method_kwargs = data.get("kwargs",{})
|
||||
method = getattr(self, method_name)
|
||||
response = await(method)
|
||||
|
||||
|
||||
|
||||
class Application(web.Application):
|
||||
def __init__(self, ollama_host, *args, **kwargs):
|
||||
self.ollama_host = ollama_host
|
||||
self.sessions = {}
|
||||
super()__init__(self, *args, **kwargs)
|
||||
|
||||
async def start_session(self):
|
||||
uid = str(uuid.uuid4())
|
||||
self.sessions[uid] = AIClient(uid=uid, host=self.ollama_host)
|
||||
return self.sessions[uid]
|
||||
|
||||
async def get_session(self, uid):
|
||||
return self.sessions.get(uid)
|
||||
|
||||
async def create(self, request):
|
||||
data = await request.json()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class XMLRPCHandler(handler.XMLRPCView):
|
||||
|
||||
|
||||
|
||||
@rename("nested.test")
|
||||
def rpc_test(self):
|
||||
return None
|
||||
|
||||
def rpc_args(self, *args):
|
||||
return len(args)
|
||||
|
||||
def rpc_kwargs(self, **kwargs):
|
||||
return len(kwargs)
|
||||
|
||||
def rpc_args_kwargs(self, *args, **kwargs):
|
||||
return len(args) + len(kwargs)
|
||||
|
||||
@rename("nested.exception")
|
||||
def rpc_exception(self):
|
||||
raise Exception("YEEEEEE!!!")
|
||||
Reference in New Issue
Block a user