regolo 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.
- regolo-1.0.0/LICENSE +21 -0
- regolo-1.0.0/PKG-INFO +180 -0
- regolo-1.0.0/README.md +141 -0
- regolo-1.0.0/pyproject.toml +52 -0
- regolo-1.0.0/setup.cfg +4 -0
- regolo-1.0.0/src/regolo/__init__.py +7 -0
- regolo-1.0.0/src/regolo/client/__init__.py +0 -0
- regolo-1.0.0/src/regolo/client/regolo_client.py +396 -0
- regolo-1.0.0/src/regolo/instance/__init__.py +0 -0
- regolo-1.0.0/src/regolo/instance/regolo_instance.py +51 -0
- regolo-1.0.0/src/regolo/instance/structures/__init__.py +0 -0
- regolo-1.0.0/src/regolo/instance/structures/conversation_model.py +28 -0
- regolo-1.0.0/src/regolo/keys/__init__.py +0 -0
- regolo-1.0.0/src/regolo/keys/keys.py +12 -0
- regolo-1.0.0/src/regolo/models/__init__.py +0 -0
- regolo-1.0.0/src/regolo/models/models.py +19 -0
- regolo-1.0.0/src/regolo.egg-info/PKG-INFO +180 -0
- regolo-1.0.0/src/regolo.egg-info/SOURCES.txt +19 -0
- regolo-1.0.0/src/regolo.egg-info/dependency_links.txt +1 -0
- regolo-1.0.0/src/regolo.egg-info/requires.txt +3 -0
- regolo-1.0.0/src/regolo.egg-info/top_level.txt +1 -0
regolo-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 regolo.ai
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
regolo-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: regolo
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Simple client to interact with regolo.ai
|
|
5
|
+
Author-email: "regolo.ai" <dev@regolo.ai>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2025 regolo.ai
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/regolo-ai/python-client
|
|
29
|
+
Keywords: regolo,llm,chat
|
|
30
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
31
|
+
Classifier: Programming Language :: Python
|
|
32
|
+
Classifier: Programming Language :: Python :: 3
|
|
33
|
+
Requires-Python: >=3.12
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
License-File: LICENSE
|
|
36
|
+
Requires-Dist: httpx~=0.28.1
|
|
37
|
+
Requires-Dist: pydantic~=2.10.6
|
|
38
|
+
Requires-Dist: json_repair~=0.35.0
|
|
39
|
+
|
|
40
|
+
# **Regolo.ai Python Client**
|
|
41
|
+
|
|
42
|
+
A simple Python client for interacting for **Regolo.ai's** LLM-based API.
|
|
43
|
+
|
|
44
|
+
## **Installation**
|
|
45
|
+
Ensure you have the `regolo` module installed. If not, install it using:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install regolo
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
# **Basic Usage**
|
|
52
|
+
|
|
53
|
+
## **1. Import the regolo module**
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
import regolo
|
|
57
|
+
```
|
|
58
|
+
## **2. Set Up Default API Key and Model**
|
|
59
|
+
|
|
60
|
+
To avoid manually passing the API key and model in every request, you can set them globally:
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
regolo.default_key = "<EXAMPLE_KEY>"
|
|
64
|
+
regolo.default_model = "meta-llama/Llama-3.3-70B-Instruct"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
This ensures that all `RegoloClient` instances and static functions will
|
|
68
|
+
use the specified API key and model.
|
|
69
|
+
|
|
70
|
+
Still, you can create run methods by passing model and key directly.
|
|
71
|
+
|
|
72
|
+
## **3. Perform a basic request**
|
|
73
|
+
|
|
74
|
+
### Completion:
|
|
75
|
+
```python
|
|
76
|
+
print(regolo.static_completions(prompt="Tell me something about Rome."))
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Chat_completion
|
|
80
|
+
```python
|
|
81
|
+
print(regolo.static_chat_completions(messages=[{"role": "user", "content": "Tell me something about rome"}]))
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
# **Other usages**
|
|
87
|
+
|
|
88
|
+
## **Handling streams**
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
**With full output:**
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
import regolo
|
|
95
|
+
regolo.default_key = "<EXAMPLE_KEY>"
|
|
96
|
+
regolo.default_model = "meta-llama/Llama-3.3-70B-Instruct"
|
|
97
|
+
|
|
98
|
+
# Completions
|
|
99
|
+
|
|
100
|
+
client = regolo.RegoloClient()
|
|
101
|
+
response = client.completions("Tell me about Rome in a concise manner", full_output=True, stream=True)
|
|
102
|
+
|
|
103
|
+
while True:
|
|
104
|
+
try:
|
|
105
|
+
print(next(response))
|
|
106
|
+
except StopIteration:
|
|
107
|
+
break
|
|
108
|
+
|
|
109
|
+
# Chat completions
|
|
110
|
+
|
|
111
|
+
client = regolo.RegoloClient()
|
|
112
|
+
response = client.run_chat(user_prompt="Tell me about Rome in a concise manner", full_output=True, stream=True)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
while True:
|
|
116
|
+
try:
|
|
117
|
+
print(next(response))
|
|
118
|
+
except StopIteration:
|
|
119
|
+
break
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Without full output:**
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
import regolo
|
|
126
|
+
regolo.default_key = "<EXAMPLE_KEY>"
|
|
127
|
+
regolo.default_model = "meta-llama/Llama-3.3-70B-Instruct"
|
|
128
|
+
|
|
129
|
+
# Completions
|
|
130
|
+
|
|
131
|
+
client = regolo.RegoloClient()
|
|
132
|
+
response = client.completions("Tell me about Rome in a concise manner", full_output=True, stream=True)
|
|
133
|
+
|
|
134
|
+
while True:
|
|
135
|
+
try:
|
|
136
|
+
print(next(response), end='', flush=True)
|
|
137
|
+
except StopIteration:
|
|
138
|
+
break
|
|
139
|
+
|
|
140
|
+
# Chat completions
|
|
141
|
+
|
|
142
|
+
client = regolo.RegoloClient()
|
|
143
|
+
response = client.run_chat(user_prompt="Tell me about Rome in a concise manner", full_output=True, stream=True)
|
|
144
|
+
|
|
145
|
+
while True:
|
|
146
|
+
try:
|
|
147
|
+
res = next(response)
|
|
148
|
+
if res[0]:
|
|
149
|
+
print(res[0] + ":")
|
|
150
|
+
print(res[1], end="", flush=True)
|
|
151
|
+
except StopIteration:
|
|
152
|
+
break
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## **Handling chat through add_prompt_to_chat()**
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
import regolo
|
|
159
|
+
|
|
160
|
+
client = regolo.RegoloClient()
|
|
161
|
+
|
|
162
|
+
# Make a request
|
|
163
|
+
|
|
164
|
+
client.add_prompt_to_chat(role="user", prompt="Tell me about rome!")
|
|
165
|
+
|
|
166
|
+
print(client.run_chat())
|
|
167
|
+
|
|
168
|
+
# Continue the conversation
|
|
169
|
+
|
|
170
|
+
client.add_prompt_to_chat(role="user", prompt="Tell me something more about it!")
|
|
171
|
+
|
|
172
|
+
print(client.run_chat())
|
|
173
|
+
|
|
174
|
+
# You can print the whole conversation if needed
|
|
175
|
+
|
|
176
|
+
print(print(client.instance.get_conversation()))
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
It is to consider that using the user_prompt parameter in run_chat() is equivalent to adding a prompt with role=user
|
|
180
|
+
through add_prompt_to_chat().
|
regolo-1.0.0/README.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# **Regolo.ai Python Client**
|
|
2
|
+
|
|
3
|
+
A simple Python client for interacting for **Regolo.ai's** LLM-based API.
|
|
4
|
+
|
|
5
|
+
## **Installation**
|
|
6
|
+
Ensure you have the `regolo` module installed. If not, install it using:
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
pip install regolo
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
# **Basic Usage**
|
|
13
|
+
|
|
14
|
+
## **1. Import the regolo module**
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
import regolo
|
|
18
|
+
```
|
|
19
|
+
## **2. Set Up Default API Key and Model**
|
|
20
|
+
|
|
21
|
+
To avoid manually passing the API key and model in every request, you can set them globally:
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
regolo.default_key = "<EXAMPLE_KEY>"
|
|
25
|
+
regolo.default_model = "meta-llama/Llama-3.3-70B-Instruct"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
This ensures that all `RegoloClient` instances and static functions will
|
|
29
|
+
use the specified API key and model.
|
|
30
|
+
|
|
31
|
+
Still, you can create run methods by passing model and key directly.
|
|
32
|
+
|
|
33
|
+
## **3. Perform a basic request**
|
|
34
|
+
|
|
35
|
+
### Completion:
|
|
36
|
+
```python
|
|
37
|
+
print(regolo.static_completions(prompt="Tell me something about Rome."))
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Chat_completion
|
|
41
|
+
```python
|
|
42
|
+
print(regolo.static_chat_completions(messages=[{"role": "user", "content": "Tell me something about rome"}]))
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
# **Other usages**
|
|
48
|
+
|
|
49
|
+
## **Handling streams**
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
**With full output:**
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
import regolo
|
|
56
|
+
regolo.default_key = "<EXAMPLE_KEY>"
|
|
57
|
+
regolo.default_model = "meta-llama/Llama-3.3-70B-Instruct"
|
|
58
|
+
|
|
59
|
+
# Completions
|
|
60
|
+
|
|
61
|
+
client = regolo.RegoloClient()
|
|
62
|
+
response = client.completions("Tell me about Rome in a concise manner", full_output=True, stream=True)
|
|
63
|
+
|
|
64
|
+
while True:
|
|
65
|
+
try:
|
|
66
|
+
print(next(response))
|
|
67
|
+
except StopIteration:
|
|
68
|
+
break
|
|
69
|
+
|
|
70
|
+
# Chat completions
|
|
71
|
+
|
|
72
|
+
client = regolo.RegoloClient()
|
|
73
|
+
response = client.run_chat(user_prompt="Tell me about Rome in a concise manner", full_output=True, stream=True)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
while True:
|
|
77
|
+
try:
|
|
78
|
+
print(next(response))
|
|
79
|
+
except StopIteration:
|
|
80
|
+
break
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Without full output:**
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
import regolo
|
|
87
|
+
regolo.default_key = "<EXAMPLE_KEY>"
|
|
88
|
+
regolo.default_model = "meta-llama/Llama-3.3-70B-Instruct"
|
|
89
|
+
|
|
90
|
+
# Completions
|
|
91
|
+
|
|
92
|
+
client = regolo.RegoloClient()
|
|
93
|
+
response = client.completions("Tell me about Rome in a concise manner", full_output=True, stream=True)
|
|
94
|
+
|
|
95
|
+
while True:
|
|
96
|
+
try:
|
|
97
|
+
print(next(response), end='', flush=True)
|
|
98
|
+
except StopIteration:
|
|
99
|
+
break
|
|
100
|
+
|
|
101
|
+
# Chat completions
|
|
102
|
+
|
|
103
|
+
client = regolo.RegoloClient()
|
|
104
|
+
response = client.run_chat(user_prompt="Tell me about Rome in a concise manner", full_output=True, stream=True)
|
|
105
|
+
|
|
106
|
+
while True:
|
|
107
|
+
try:
|
|
108
|
+
res = next(response)
|
|
109
|
+
if res[0]:
|
|
110
|
+
print(res[0] + ":")
|
|
111
|
+
print(res[1], end="", flush=True)
|
|
112
|
+
except StopIteration:
|
|
113
|
+
break
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## **Handling chat through add_prompt_to_chat()**
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
import regolo
|
|
120
|
+
|
|
121
|
+
client = regolo.RegoloClient()
|
|
122
|
+
|
|
123
|
+
# Make a request
|
|
124
|
+
|
|
125
|
+
client.add_prompt_to_chat(role="user", prompt="Tell me about rome!")
|
|
126
|
+
|
|
127
|
+
print(client.run_chat())
|
|
128
|
+
|
|
129
|
+
# Continue the conversation
|
|
130
|
+
|
|
131
|
+
client.add_prompt_to_chat(role="user", prompt="Tell me something more about it!")
|
|
132
|
+
|
|
133
|
+
print(client.run_chat())
|
|
134
|
+
|
|
135
|
+
# You can print the whole conversation if needed
|
|
136
|
+
|
|
137
|
+
print(print(client.instance.get_conversation()))
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
It is to consider that using the user_prompt parameter in run_chat() is equivalent to adding a prompt with role=user
|
|
141
|
+
through add_prompt_to_chat().
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# pyproject.toml
|
|
2
|
+
|
|
3
|
+
[build-system]
|
|
4
|
+
requires = ["setuptools>=75.8.0", "wheel"]
|
|
5
|
+
build-backend = "setuptools.build_meta"
|
|
6
|
+
|
|
7
|
+
[project]
|
|
8
|
+
name = "regolo"
|
|
9
|
+
version = "1.0.0"
|
|
10
|
+
description = "Simple client to interact with regolo.ai"
|
|
11
|
+
readme = "README.md"
|
|
12
|
+
authors = [{ name = "regolo.ai", email = "dev@regolo.ai" }]
|
|
13
|
+
license = { file = "LICENSE" }
|
|
14
|
+
classifiers = [
|
|
15
|
+
"License :: OSI Approved :: MIT License",
|
|
16
|
+
"Programming Language :: Python",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
]
|
|
19
|
+
keywords = ["regolo", "llm", "chat"]
|
|
20
|
+
dependencies = [
|
|
21
|
+
"httpx ~= 0.28.1",
|
|
22
|
+
"pydantic ~= 2.10.6",
|
|
23
|
+
'json_repair ~= 0.35.0',
|
|
24
|
+
]
|
|
25
|
+
requires-python = ">=3.12"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://github.com/regolo-ai/python-client"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
[tool.bumpver]
|
|
33
|
+
current_version = "1.0.0"
|
|
34
|
+
version_pattern = "MAJOR.MINOR.PATCH"
|
|
35
|
+
commit_message = "bump version {old_version} -> {new_version}"
|
|
36
|
+
tag_message = "{new_version}"
|
|
37
|
+
tag_scope = "default"
|
|
38
|
+
commit = true
|
|
39
|
+
tag = true
|
|
40
|
+
push = true
|
|
41
|
+
|
|
42
|
+
[tool.bumpver.file_patterns]
|
|
43
|
+
"pyproject.toml" = [
|
|
44
|
+
'current_version = "{version}"',
|
|
45
|
+
]
|
|
46
|
+
"README.md" = [
|
|
47
|
+
"{version}",
|
|
48
|
+
"{pep440_version}",
|
|
49
|
+
]
|
|
50
|
+
"src/*" = [
|
|
51
|
+
'current_version = "{version}"',
|
|
52
|
+
]
|
regolo-1.0.0/setup.cfg
ADDED
|
File without changes
|
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from types import GeneratorType
|
|
3
|
+
|
|
4
|
+
import httpx
|
|
5
|
+
from typing import Any, Dict, List, Optional, Callable
|
|
6
|
+
|
|
7
|
+
from json_repair import json_repair
|
|
8
|
+
|
|
9
|
+
from regolo.instance.regolo_instance import RegoloInstance
|
|
10
|
+
from regolo.instance.structures.conversation_model import Conversation, ConversationLine
|
|
11
|
+
from regolo.keys.keys import KeysHandler
|
|
12
|
+
from regolo.models.models import ModelsHandler
|
|
13
|
+
from typing import TypeAlias
|
|
14
|
+
|
|
15
|
+
import regolo
|
|
16
|
+
|
|
17
|
+
REGOLO_URL = "https://api.regolo.ai"
|
|
18
|
+
COMPLETIONS_URL_PATH = "/v1/completions"
|
|
19
|
+
CHAT_COMPLETIONS_URL_PATH = "/v1/chat/completions"
|
|
20
|
+
timeout = 500
|
|
21
|
+
|
|
22
|
+
Role: TypeAlias = str
|
|
23
|
+
Content: TypeAlias = str
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def safe_post(client: httpx.Client,
|
|
27
|
+
url_to_query: str,
|
|
28
|
+
json_to_query: dict = None,
|
|
29
|
+
headers_to_query: dict = None) -> httpx.Response:
|
|
30
|
+
response = client.post(url=url_to_query, json=json_to_query, headers=headers_to_query, timeout=timeout)
|
|
31
|
+
response.raise_for_status()
|
|
32
|
+
return response
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class RegoloClient:
|
|
36
|
+
def __init__(self,
|
|
37
|
+
model: Optional[str] = regolo.default_model,
|
|
38
|
+
api_key: Optional[str] = regolo.default_key,
|
|
39
|
+
alternative_url: Optional[str] = None,
|
|
40
|
+
pre_existent_conversation: Optional[Conversation] = None,
|
|
41
|
+
pre_existent_client: httpx.Client = None) -> None:
|
|
42
|
+
"""
|
|
43
|
+
Initialize the client for regolo.ai HTTP API.
|
|
44
|
+
|
|
45
|
+
:param model: The regolo.ai model to use. (Defaults to regolo.default_model)
|
|
46
|
+
:param api_key: The API key for regolo.ai. (Defaults to regolo.default_key)
|
|
47
|
+
:param alternative_url: Base URL of the regolo HTTP server. (Optional)
|
|
48
|
+
:param pre_existent_conversation: An existing conversation instance to continue chatting with. (Optional)
|
|
49
|
+
:param pre_existent_client: An existing httpx.Client instance to use. (Optional)
|
|
50
|
+
"""
|
|
51
|
+
self.base_url = REGOLO_URL if alternative_url is None else alternative_url
|
|
52
|
+
client = httpx.Client(base_url=self.base_url) if pre_existent_client is None else pre_existent_client
|
|
53
|
+
self.instance = RegoloInstance(model=regolo.default_model if model is None else model,
|
|
54
|
+
api_key=regolo.default_key if api_key is None else api_key,
|
|
55
|
+
previous_conversations=pre_existent_conversation, client=client)
|
|
56
|
+
|
|
57
|
+
@classmethod
|
|
58
|
+
def from_instance(cls, instance: RegoloInstance, alternative_url: Optional[str] = None) -> "RegoloClient":
|
|
59
|
+
"""Creates RegoloClient from instance."""
|
|
60
|
+
return cls(api_key=instance.api_key, model=instance.model, alternative_url=alternative_url,
|
|
61
|
+
pre_existent_client=instance.client, pre_existent_conversation=instance.conversation)
|
|
62
|
+
|
|
63
|
+
def change_model(self, model: str) -> None:
|
|
64
|
+
"""Change model used in this instance of regolo_client"""
|
|
65
|
+
try:
|
|
66
|
+
self.instance.change_model(new_model=model)
|
|
67
|
+
except Exception as e:
|
|
68
|
+
print(e)
|
|
69
|
+
|
|
70
|
+
@staticmethod
|
|
71
|
+
def get_available_models() -> List[str]:
|
|
72
|
+
"""Gets all available models on regolo.ai."""
|
|
73
|
+
return ModelsHandler.get_models()
|
|
74
|
+
|
|
75
|
+
@staticmethod
|
|
76
|
+
def process_vllm_stream(tokens):
|
|
77
|
+
output_text = ""
|
|
78
|
+
for token in tokens:
|
|
79
|
+
if token.startswith("▁"): # SentencePiece-style tokenization
|
|
80
|
+
output_text += " " + token[1:]
|
|
81
|
+
else:
|
|
82
|
+
output_text += token # Continuation of the previous word
|
|
83
|
+
return output_text.strip()
|
|
84
|
+
|
|
85
|
+
@staticmethod
|
|
86
|
+
def create_stream_generator(client: httpx.Client,
|
|
87
|
+
base_url: str,
|
|
88
|
+
payload: dict,
|
|
89
|
+
headers: dict,
|
|
90
|
+
full_output: bool,
|
|
91
|
+
search_url: str,
|
|
92
|
+
output_handler: Callable[[Dict], Any]) -> GeneratorType:
|
|
93
|
+
"""
|
|
94
|
+
Yields generators for streams from regolo.ai.
|
|
95
|
+
|
|
96
|
+
:param client: The httpx.Client instance to use.
|
|
97
|
+
:param base_url: Base URL of the regolo HTTP server.
|
|
98
|
+
:param payload: The request payload to send.
|
|
99
|
+
:param headers: The request headers.
|
|
100
|
+
:param full_output: Whether to return the full response.
|
|
101
|
+
:param search_url: The URL for the search request.
|
|
102
|
+
:param output_handler: A function that processes responses if full_output=False.
|
|
103
|
+
:return: A generator that yields streamed responses from regolo.ai.
|
|
104
|
+
"""
|
|
105
|
+
with client.stream("POST", f"{base_url}{search_url}", json=payload, headers=headers) as response:
|
|
106
|
+
if response.status_code != 200:
|
|
107
|
+
raise Exception(f"Error: Received unexpected status code {response.status_code}")
|
|
108
|
+
|
|
109
|
+
# Iterate over complete lines instead of raw bytes
|
|
110
|
+
for line in response.iter_lines():
|
|
111
|
+
if not line:
|
|
112
|
+
continue
|
|
113
|
+
|
|
114
|
+
# Decode if necessary and remove the "data:" prefix if present
|
|
115
|
+
decoded_line = line.decode("utf-8") if isinstance(line, bytes) else line
|
|
116
|
+
decoded_line = decoded_line.strip()
|
|
117
|
+
if decoded_line == "data: [DONE]":
|
|
118
|
+
break
|
|
119
|
+
if decoded_line.startswith("data:"):
|
|
120
|
+
decoded_line = decoded_line[len("data:"):].strip()
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
# Repair and parse the JSON chunk
|
|
124
|
+
data = json.loads(json_repair.repair_json(decoded_line))
|
|
125
|
+
except (Exception,):
|
|
126
|
+
continue
|
|
127
|
+
|
|
128
|
+
if full_output:
|
|
129
|
+
yield data
|
|
130
|
+
else:
|
|
131
|
+
# Handle both dict and list responses uniformly
|
|
132
|
+
yield output_handler(data)
|
|
133
|
+
|
|
134
|
+
# Completions
|
|
135
|
+
|
|
136
|
+
@staticmethod
|
|
137
|
+
def static_completions(prompt: str,
|
|
138
|
+
model: Optional[str] = None,
|
|
139
|
+
api_key: Optional[str] = None,
|
|
140
|
+
stream: bool = False,
|
|
141
|
+
max_tokens: int = 200,
|
|
142
|
+
temperature: Optional[float] = 0.5,
|
|
143
|
+
top_p: Optional[float] = None,
|
|
144
|
+
top_k: Optional[int] = None,
|
|
145
|
+
client: Optional[httpx.Client] = None,
|
|
146
|
+
base_url: str = REGOLO_URL,
|
|
147
|
+
full_output: bool = False) -> GeneratorType:
|
|
148
|
+
"""Will return generators for stream=True and values for stream=False
|
|
149
|
+
Send a prompt to regolo server and get the generated response.
|
|
150
|
+
|
|
151
|
+
:param prompt: The input prompt to the LLM.
|
|
152
|
+
:param model: The regolo.ai model to use. (Optional)
|
|
153
|
+
:param api_key: The API key for regolo.ai. (Optional)
|
|
154
|
+
:param stream: Whether to stream the prompt from regolo.ai. (Defaults to False)
|
|
155
|
+
:param max_tokens: Maximum number of tokens to generate. (Defaults to 200)
|
|
156
|
+
:param temperature: Sampling temperature for randomness. (Optional)
|
|
157
|
+
:param top_p: Nucleus sampling parameter. (Optional)
|
|
158
|
+
:param top_k: Top-k sampling parameter. (Optional)
|
|
159
|
+
:param client: httpx client to use. (Optional)
|
|
160
|
+
:param base_url: Base URL of the regolo HTTP server. (Defaults to REGOLO_URL)
|
|
161
|
+
:param full_output: Whether to return the full response. (Defaults to False)
|
|
162
|
+
|
|
163
|
+
:return: Response from the vLLM server.
|
|
164
|
+
"""
|
|
165
|
+
|
|
166
|
+
def handle_search_text_completions(data: dict) -> str:
|
|
167
|
+
return data.get("choices", [{}])[0].get("text")
|
|
168
|
+
|
|
169
|
+
if api_key is None:
|
|
170
|
+
api_key = regolo.default_key
|
|
171
|
+
|
|
172
|
+
api_key = KeysHandler.check_key(api_key)
|
|
173
|
+
|
|
174
|
+
if model is None:
|
|
175
|
+
model = regolo.default_model
|
|
176
|
+
|
|
177
|
+
ModelsHandler.check_model(model)
|
|
178
|
+
|
|
179
|
+
if client is None:
|
|
180
|
+
client = httpx.Client()
|
|
181
|
+
payload = {
|
|
182
|
+
"prompt": prompt,
|
|
183
|
+
"stream": stream,
|
|
184
|
+
"model": model,
|
|
185
|
+
"max_tokens": max_tokens,
|
|
186
|
+
"temperature": temperature,
|
|
187
|
+
"top_p": top_p,
|
|
188
|
+
"top_k": top_k
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
# Filter out parameters that are None
|
|
192
|
+
payload = {k: v for k, v in payload.items() if v is not None}
|
|
193
|
+
headers = {"Authorization": api_key}
|
|
194
|
+
if stream:
|
|
195
|
+
return RegoloClient.create_stream_generator(client=client, base_url=base_url, payload=payload,
|
|
196
|
+
headers=headers,
|
|
197
|
+
full_output=full_output, search_url=COMPLETIONS_URL_PATH,
|
|
198
|
+
output_handler=handle_search_text_completions)
|
|
199
|
+
else:
|
|
200
|
+
response = safe_post(client=client, url_to_query=f"{base_url}{COMPLETIONS_URL_PATH}",
|
|
201
|
+
json_to_query=payload, headers_to_query=headers)
|
|
202
|
+
if full_output:
|
|
203
|
+
return response.json()
|
|
204
|
+
else:
|
|
205
|
+
return response.json()["choices"][0]["text"]
|
|
206
|
+
|
|
207
|
+
def completions(self,
|
|
208
|
+
prompt: str,
|
|
209
|
+
stream: Optional[bool] = False,
|
|
210
|
+
max_tokens: int = 200,
|
|
211
|
+
temperature: Optional[float] = None,
|
|
212
|
+
top_p: Optional[float] = None,
|
|
213
|
+
top_k: Optional[int] = None,
|
|
214
|
+
full_output: bool = False) -> Dict[str, Any] | GeneratorType:
|
|
215
|
+
"""Performs requests to completions endpoint from RegoloClient instance."""
|
|
216
|
+
response = self.static_completions(prompt=prompt,
|
|
217
|
+
model=self.instance.get_model(),
|
|
218
|
+
api_key=self.instance.get_api_key(),
|
|
219
|
+
stream=stream,
|
|
220
|
+
max_tokens=max_tokens,
|
|
221
|
+
temperature=temperature,
|
|
222
|
+
top_p=top_p,
|
|
223
|
+
top_k=top_k,
|
|
224
|
+
client=self.instance.client,
|
|
225
|
+
base_url=self.base_url,
|
|
226
|
+
full_output=full_output)
|
|
227
|
+
|
|
228
|
+
return response
|
|
229
|
+
|
|
230
|
+
# Chat completions
|
|
231
|
+
|
|
232
|
+
@staticmethod
|
|
233
|
+
def static_chat_completions(messages: Conversation | List[Dict[str, str]],
|
|
234
|
+
model: Optional[str] = None,
|
|
235
|
+
api_key: Optional[str] = None,
|
|
236
|
+
stream: bool = False,
|
|
237
|
+
max_tokens: int = 200,
|
|
238
|
+
temperature: Optional[float] = None,
|
|
239
|
+
top_p: Optional[float] = None,
|
|
240
|
+
top_k: Optional[int] = None,
|
|
241
|
+
client: Optional[httpx.Client] = None,
|
|
242
|
+
base_url: str = REGOLO_URL,
|
|
243
|
+
full_output: bool = False
|
|
244
|
+
) -> GeneratorType | tuple[Role, Content] | dict:
|
|
245
|
+
"""
|
|
246
|
+
Sends a series of chat messages to the vLLM server and gets the response.
|
|
247
|
+
|
|
248
|
+
:param messages: A list of messages in the format [{"role": "user"|"assistant", "content": "message"}].
|
|
249
|
+
:param model: The regolo.ai model to use. (Optional)
|
|
250
|
+
:param api_key: The API key for regolo.ai. (Optional)
|
|
251
|
+
:param stream: Whether to stream the prompt from regolo.ai. (Defaults to False)
|
|
252
|
+
:param max_tokens: Maximum number of tokens to generate. (Defaults to 200)
|
|
253
|
+
:param temperature: Sampling temperature for randomness. (Optional)
|
|
254
|
+
:param top_p: Nucleus sampling parameter. (Optional)
|
|
255
|
+
:param top_k: Top-k sampling parameter. (Optional)
|
|
256
|
+
:param client: httpx client to use. (Optional)
|
|
257
|
+
:param base_url: Base URL of the regolo HTTP server. (Defaults to REGOLO_URL)
|
|
258
|
+
:param full_output: Whether to return full response. (Defaults to False)
|
|
259
|
+
|
|
260
|
+
:return for stream=true, full_output=False: Generator, which yields dicts with the responses from regolo.ai.
|
|
261
|
+
:return for stream=True, full_output=True: Generator, which yields tuples of role, content of response.
|
|
262
|
+
:return for stream=False, full_output=False: String with response from regolo.ai.
|
|
263
|
+
:return for stream=False, full_output=True: Tuple which consists of role and content of response.
|
|
264
|
+
"""
|
|
265
|
+
|
|
266
|
+
def handle_search_text_chat_completions(data: dict) -> tuple[Role, Content]:
|
|
267
|
+
"""Internal method, describes how RegoloClient.create_stream_generator should handle output from chat_completions."""
|
|
268
|
+
if isinstance(data, dict):
|
|
269
|
+
delta = data.get("choices", [{}])[0].get("delta", {})
|
|
270
|
+
out_role = delta.get("role", "")
|
|
271
|
+
out_content = delta.get("content", "")
|
|
272
|
+
return out_role, out_content
|
|
273
|
+
elif isinstance(data, list):
|
|
274
|
+
for element in data:
|
|
275
|
+
delta = element.get("choices", [{}])[0].get("delta", {})
|
|
276
|
+
out_role = delta.get("role", "")
|
|
277
|
+
out_content = delta.get("content", "")
|
|
278
|
+
return out_role, out_content
|
|
279
|
+
|
|
280
|
+
if api_key is None:
|
|
281
|
+
api_key = regolo.default_key
|
|
282
|
+
|
|
283
|
+
api_key = KeysHandler.check_key(api_key)
|
|
284
|
+
|
|
285
|
+
if model is None:
|
|
286
|
+
model = regolo.default_model
|
|
287
|
+
|
|
288
|
+
ModelsHandler.check_model(model)
|
|
289
|
+
|
|
290
|
+
if type(messages) == Conversation:
|
|
291
|
+
messages = messages.get_lines()
|
|
292
|
+
api_key = KeysHandler.check_key(api_key)
|
|
293
|
+
|
|
294
|
+
if client is None:
|
|
295
|
+
client = httpx.Client()
|
|
296
|
+
|
|
297
|
+
payload = {
|
|
298
|
+
"model": model,
|
|
299
|
+
"stream": stream,
|
|
300
|
+
"messages": messages,
|
|
301
|
+
"max_tokens": max_tokens,
|
|
302
|
+
"temperature": temperature,
|
|
303
|
+
"top_p": top_p,
|
|
304
|
+
"top_k": top_k
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
# Filter out parameters that are None
|
|
308
|
+
payload = {k: v for k, v in payload.items() if v is not None}
|
|
309
|
+
headers = {"Authorization": api_key}
|
|
310
|
+
|
|
311
|
+
if stream:
|
|
312
|
+
return RegoloClient.create_stream_generator(client=client, base_url=base_url, payload=payload,
|
|
313
|
+
headers=headers,
|
|
314
|
+
full_output=full_output, search_url=CHAT_COMPLETIONS_URL_PATH,
|
|
315
|
+
output_handler=handle_search_text_chat_completions)
|
|
316
|
+
else:
|
|
317
|
+
response = safe_post(client=client, url_to_query=f"{base_url}{CHAT_COMPLETIONS_URL_PATH}",
|
|
318
|
+
json_to_query=payload, headers_to_query=headers).json()
|
|
319
|
+
if full_output:
|
|
320
|
+
return response
|
|
321
|
+
else:
|
|
322
|
+
role = response["choices"][0]["message"]["role"]
|
|
323
|
+
content = response["choices"][0]["message"]["content"]
|
|
324
|
+
return role, content
|
|
325
|
+
|
|
326
|
+
def add_prompt_to_chat(self, prompt: str, role: str):
|
|
327
|
+
"""
|
|
328
|
+
Adds a prompt to the chat as the role specified
|
|
329
|
+
|
|
330
|
+
:param prompt: The prompt to add.
|
|
331
|
+
:param role: The role of the prompt to add.
|
|
332
|
+
|
|
333
|
+
:example:
|
|
334
|
+
client = RegoloClient()
|
|
335
|
+
client.add_prompt_to_chat(prompt="how are you?", role="user")
|
|
336
|
+
print(client.run_chat())
|
|
337
|
+
"""
|
|
338
|
+
|
|
339
|
+
self.instance.add_prompt_as_role(prompt=prompt, role=role)
|
|
340
|
+
|
|
341
|
+
def clear_conversations(self) -> None:
|
|
342
|
+
"""clear all prompts to start new conversations."""
|
|
343
|
+
self.instance.clear_conversation()
|
|
344
|
+
|
|
345
|
+
def run_chat(self,
|
|
346
|
+
user_prompt: Optional[str] = None,
|
|
347
|
+
stream: bool = False,
|
|
348
|
+
max_tokens: int = 200,
|
|
349
|
+
temperature: Optional[float] = None,
|
|
350
|
+
top_p: Optional[float] = None,
|
|
351
|
+
top_k: Optional[int] = None,
|
|
352
|
+
full_output: bool = False) -> GeneratorType | tuple[Role, Content]:
|
|
353
|
+
"""
|
|
354
|
+
Runs chat endpoint from RegoloClient instance (self.conversation contains the role-prompts dicts).
|
|
355
|
+
|
|
356
|
+
:param user_prompt: Optional prompt to add to conversation before generating response from regolo.ai.
|
|
357
|
+
:param stream: Whether to stream the prompt from regolo.ai.
|
|
358
|
+
:param max_tokens: Maximum number of tokens to generate. (Defaults to 200)
|
|
359
|
+
:param temperature: Sampling temperature for randomness.
|
|
360
|
+
:param top_p: Nucleus sampling parameter.
|
|
361
|
+
:param top_k: Top-k sampling parameter.
|
|
362
|
+
:param full_output: Whether to return full response. (Defaults to False)
|
|
363
|
+
:return for stream=true, full_output=False: Generator, which yields dicts with the responses from regolo.ai.
|
|
364
|
+
:return for stream=True, full_output=True: Generator, which yields tuples of role, content of response.
|
|
365
|
+
:return for stream=False, full_output=False: String with response from regolo.ai.
|
|
366
|
+
:return for stream=False, full_output=True: Tuple which consists of role and content of response.
|
|
367
|
+
"""
|
|
368
|
+
|
|
369
|
+
if user_prompt is not None:
|
|
370
|
+
self.instance.add_prompt_as_role(prompt=user_prompt, role="user")
|
|
371
|
+
|
|
372
|
+
response = self.static_chat_completions(messages=self.instance.get_conversation(),
|
|
373
|
+
model=self.instance.get_model(),
|
|
374
|
+
stream=stream,
|
|
375
|
+
api_key=self.instance.get_api_key(),
|
|
376
|
+
max_tokens=max_tokens,
|
|
377
|
+
temperature=temperature,
|
|
378
|
+
top_p=top_p,
|
|
379
|
+
top_k=top_k,
|
|
380
|
+
client=self.instance.get_client(),
|
|
381
|
+
base_url=self.base_url,
|
|
382
|
+
full_output=full_output)
|
|
383
|
+
|
|
384
|
+
if stream is True:
|
|
385
|
+
return response
|
|
386
|
+
else:
|
|
387
|
+
if full_output:
|
|
388
|
+
responseRole = response["choices"][0]["message"]["role"]
|
|
389
|
+
responseText = response["choices"][0]["message"]["content"]
|
|
390
|
+
else:
|
|
391
|
+
responseRole = response[0]
|
|
392
|
+
responseText = response[1]
|
|
393
|
+
|
|
394
|
+
self.instance.add_line(ConversationLine(role=responseRole, content=responseText))
|
|
395
|
+
|
|
396
|
+
return response
|
|
File without changes
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from typing import Optional, List, Dict
|
|
2
|
+
|
|
3
|
+
import httpx
|
|
4
|
+
|
|
5
|
+
from regolo.instance.structures.conversation_model import Conversation, ConversationLine
|
|
6
|
+
|
|
7
|
+
from regolo.models.models import ModelsHandler
|
|
8
|
+
from regolo.keys.keys import KeysHandler
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class RegoloInstance:
|
|
12
|
+
def __init__(self, model: str, api_key: str, client: Optional[httpx.Client],
|
|
13
|
+
previous_conversations: Optional[Conversation] = None) -> None:
|
|
14
|
+
self.conversation: Conversation = Conversation(
|
|
15
|
+
lines=[]) if previous_conversations is None else previous_conversations
|
|
16
|
+
self.client: httpx.Client = httpx.Client() if client is None else client
|
|
17
|
+
self.api_key = KeysHandler.check_key(api_key)
|
|
18
|
+
self.model: str = model
|
|
19
|
+
|
|
20
|
+
def get_client(self) -> httpx.Client:
|
|
21
|
+
return self.client
|
|
22
|
+
|
|
23
|
+
def get_api_key(self) -> str:
|
|
24
|
+
return self.api_key
|
|
25
|
+
|
|
26
|
+
def get_model(self) -> str:
|
|
27
|
+
return self.model
|
|
28
|
+
|
|
29
|
+
def change_model(self, new_model: str) -> None:
|
|
30
|
+
self.model = ModelsHandler.check_model(new_model)
|
|
31
|
+
|
|
32
|
+
def get_conversation(self) -> List[Dict[str, str]]:
|
|
33
|
+
"""Get conversation as list of dicts"""
|
|
34
|
+
return self.conversation.get_lines()
|
|
35
|
+
|
|
36
|
+
def add_line(self, conversation: ConversationLine) -> None:
|
|
37
|
+
"""Adds a line to the conversation"""
|
|
38
|
+
self.conversation.lines.append(conversation)
|
|
39
|
+
|
|
40
|
+
def overwrite_conversation(self, conversation: Conversation) -> None:
|
|
41
|
+
"""Overwrites the conversation with the given one"""
|
|
42
|
+
self.conversation = conversation
|
|
43
|
+
|
|
44
|
+
def clear_conversation(self) -> None:
|
|
45
|
+
"""Clears the conversation to start a new chat from scratch"""
|
|
46
|
+
self.conversation = Conversation(lines=[])
|
|
47
|
+
|
|
48
|
+
def add_prompt_as_role(self, prompt: str, role: str) -> None:
|
|
49
|
+
"""Adds a prompt as given role to the conversation.
|
|
50
|
+
Normally roles are "user" and "assistant", but they can vary based on model."""
|
|
51
|
+
self.conversation.lines.append(ConversationLine(role=role, content=prompt))
|
|
File without changes
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel
|
|
4
|
+
from typing import List, Dict
|
|
5
|
+
|
|
6
|
+
from pydantic import StrictStr
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ConversationLine(BaseModel):
|
|
10
|
+
role: StrictStr
|
|
11
|
+
content: StrictStr
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Conversation(BaseModel):
|
|
15
|
+
lines: List[ConversationLine]
|
|
16
|
+
|
|
17
|
+
def __init__(self, lines: List[ConversationLine]):
|
|
18
|
+
super().__init__(lines=lines)
|
|
19
|
+
|
|
20
|
+
def to_json(self):
|
|
21
|
+
return json.dumps(self.model_dump(), sort_keys=True)
|
|
22
|
+
|
|
23
|
+
def get_lines(self) -> List[Dict[str, str]]:
|
|
24
|
+
return json.loads((self.to_json()))["lines"]
|
|
25
|
+
|
|
26
|
+
def print_conversation(self):
|
|
27
|
+
for line in self.get_lines():
|
|
28
|
+
print(f"{line["role"]}: {line["content"]}\n")
|
|
File without changes
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
class KeysHandler:
|
|
2
|
+
@staticmethod
|
|
3
|
+
def fix_key(api_key: str) -> str:
|
|
4
|
+
if not api_key.startswith("Bearer "):
|
|
5
|
+
return "Bearer " + api_key
|
|
6
|
+
return api_key
|
|
7
|
+
|
|
8
|
+
@staticmethod
|
|
9
|
+
def check_key(api_key: str) -> str:
|
|
10
|
+
if api_key is None:
|
|
11
|
+
raise RuntimeError("API key is required")
|
|
12
|
+
return KeysHandler.fix_key(api_key)
|
|
File without changes
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
import httpx
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ModelsHandler:
|
|
7
|
+
@staticmethod
|
|
8
|
+
def get_models() -> list[str]:
|
|
9
|
+
models = json.loads(httpx.get("https://regolo.ai/models.json").text)["models"]
|
|
10
|
+
return [model["id"] for model in models]
|
|
11
|
+
|
|
12
|
+
@staticmethod
|
|
13
|
+
def check_model(model: str) -> str:
|
|
14
|
+
if model is None:
|
|
15
|
+
raise RuntimeError("Model is required")
|
|
16
|
+
elif model not in ModelsHandler.get_models():
|
|
17
|
+
raise RuntimeError("Model not found")
|
|
18
|
+
# TODO: fix model request if requested model is understandable
|
|
19
|
+
return model
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: regolo
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Simple client to interact with regolo.ai
|
|
5
|
+
Author-email: "regolo.ai" <dev@regolo.ai>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2025 regolo.ai
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/regolo-ai/python-client
|
|
29
|
+
Keywords: regolo,llm,chat
|
|
30
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
31
|
+
Classifier: Programming Language :: Python
|
|
32
|
+
Classifier: Programming Language :: Python :: 3
|
|
33
|
+
Requires-Python: >=3.12
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
License-File: LICENSE
|
|
36
|
+
Requires-Dist: httpx~=0.28.1
|
|
37
|
+
Requires-Dist: pydantic~=2.10.6
|
|
38
|
+
Requires-Dist: json_repair~=0.35.0
|
|
39
|
+
|
|
40
|
+
# **Regolo.ai Python Client**
|
|
41
|
+
|
|
42
|
+
A simple Python client for interacting for **Regolo.ai's** LLM-based API.
|
|
43
|
+
|
|
44
|
+
## **Installation**
|
|
45
|
+
Ensure you have the `regolo` module installed. If not, install it using:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install regolo
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
# **Basic Usage**
|
|
52
|
+
|
|
53
|
+
## **1. Import the regolo module**
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
import regolo
|
|
57
|
+
```
|
|
58
|
+
## **2. Set Up Default API Key and Model**
|
|
59
|
+
|
|
60
|
+
To avoid manually passing the API key and model in every request, you can set them globally:
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
regolo.default_key = "<EXAMPLE_KEY>"
|
|
64
|
+
regolo.default_model = "meta-llama/Llama-3.3-70B-Instruct"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
This ensures that all `RegoloClient` instances and static functions will
|
|
68
|
+
use the specified API key and model.
|
|
69
|
+
|
|
70
|
+
Still, you can create run methods by passing model and key directly.
|
|
71
|
+
|
|
72
|
+
## **3. Perform a basic request**
|
|
73
|
+
|
|
74
|
+
### Completion:
|
|
75
|
+
```python
|
|
76
|
+
print(regolo.static_completions(prompt="Tell me something about Rome."))
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Chat_completion
|
|
80
|
+
```python
|
|
81
|
+
print(regolo.static_chat_completions(messages=[{"role": "user", "content": "Tell me something about rome"}]))
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
# **Other usages**
|
|
87
|
+
|
|
88
|
+
## **Handling streams**
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
**With full output:**
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
import regolo
|
|
95
|
+
regolo.default_key = "<EXAMPLE_KEY>"
|
|
96
|
+
regolo.default_model = "meta-llama/Llama-3.3-70B-Instruct"
|
|
97
|
+
|
|
98
|
+
# Completions
|
|
99
|
+
|
|
100
|
+
client = regolo.RegoloClient()
|
|
101
|
+
response = client.completions("Tell me about Rome in a concise manner", full_output=True, stream=True)
|
|
102
|
+
|
|
103
|
+
while True:
|
|
104
|
+
try:
|
|
105
|
+
print(next(response))
|
|
106
|
+
except StopIteration:
|
|
107
|
+
break
|
|
108
|
+
|
|
109
|
+
# Chat completions
|
|
110
|
+
|
|
111
|
+
client = regolo.RegoloClient()
|
|
112
|
+
response = client.run_chat(user_prompt="Tell me about Rome in a concise manner", full_output=True, stream=True)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
while True:
|
|
116
|
+
try:
|
|
117
|
+
print(next(response))
|
|
118
|
+
except StopIteration:
|
|
119
|
+
break
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Without full output:**
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
import regolo
|
|
126
|
+
regolo.default_key = "<EXAMPLE_KEY>"
|
|
127
|
+
regolo.default_model = "meta-llama/Llama-3.3-70B-Instruct"
|
|
128
|
+
|
|
129
|
+
# Completions
|
|
130
|
+
|
|
131
|
+
client = regolo.RegoloClient()
|
|
132
|
+
response = client.completions("Tell me about Rome in a concise manner", full_output=True, stream=True)
|
|
133
|
+
|
|
134
|
+
while True:
|
|
135
|
+
try:
|
|
136
|
+
print(next(response), end='', flush=True)
|
|
137
|
+
except StopIteration:
|
|
138
|
+
break
|
|
139
|
+
|
|
140
|
+
# Chat completions
|
|
141
|
+
|
|
142
|
+
client = regolo.RegoloClient()
|
|
143
|
+
response = client.run_chat(user_prompt="Tell me about Rome in a concise manner", full_output=True, stream=True)
|
|
144
|
+
|
|
145
|
+
while True:
|
|
146
|
+
try:
|
|
147
|
+
res = next(response)
|
|
148
|
+
if res[0]:
|
|
149
|
+
print(res[0] + ":")
|
|
150
|
+
print(res[1], end="", flush=True)
|
|
151
|
+
except StopIteration:
|
|
152
|
+
break
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## **Handling chat through add_prompt_to_chat()**
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
import regolo
|
|
159
|
+
|
|
160
|
+
client = regolo.RegoloClient()
|
|
161
|
+
|
|
162
|
+
# Make a request
|
|
163
|
+
|
|
164
|
+
client.add_prompt_to_chat(role="user", prompt="Tell me about rome!")
|
|
165
|
+
|
|
166
|
+
print(client.run_chat())
|
|
167
|
+
|
|
168
|
+
# Continue the conversation
|
|
169
|
+
|
|
170
|
+
client.add_prompt_to_chat(role="user", prompt="Tell me something more about it!")
|
|
171
|
+
|
|
172
|
+
print(client.run_chat())
|
|
173
|
+
|
|
174
|
+
# You can print the whole conversation if needed
|
|
175
|
+
|
|
176
|
+
print(print(client.instance.get_conversation()))
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
It is to consider that using the user_prompt parameter in run_chat() is equivalent to adding a prompt with role=user
|
|
180
|
+
through add_prompt_to_chat().
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/regolo/__init__.py
|
|
5
|
+
src/regolo.egg-info/PKG-INFO
|
|
6
|
+
src/regolo.egg-info/SOURCES.txt
|
|
7
|
+
src/regolo.egg-info/dependency_links.txt
|
|
8
|
+
src/regolo.egg-info/requires.txt
|
|
9
|
+
src/regolo.egg-info/top_level.txt
|
|
10
|
+
src/regolo/client/__init__.py
|
|
11
|
+
src/regolo/client/regolo_client.py
|
|
12
|
+
src/regolo/instance/__init__.py
|
|
13
|
+
src/regolo/instance/regolo_instance.py
|
|
14
|
+
src/regolo/instance/structures/__init__.py
|
|
15
|
+
src/regolo/instance/structures/conversation_model.py
|
|
16
|
+
src/regolo/keys/__init__.py
|
|
17
|
+
src/regolo/keys/keys.py
|
|
18
|
+
src/regolo/models/__init__.py
|
|
19
|
+
src/regolo/models/models.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
regolo
|