lollms-client 0.27.1__py3-none-any.whl → 0.27.3__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.
Potentially problematic release.
This version of lollms-client might be problematic. Click here for more details.
- examples/lollms_chat/calculator.py +59 -0
- examples/lollms_chat/derivative.py +48 -0
- examples/lollms_chat/test_openai_compatible_with_lollms_chat.py +12 -0
- lollms_client/__init__.py +1 -1
- lollms_client/llm_bindings/litellm/__init__.py +21 -2
- lollms_client/llm_bindings/lollms_chat/__init__.py +547 -0
- lollms_client/llm_bindings/ollama/__init__.py +70 -0
- lollms_client/llm_bindings/open_router/__init__.py +1 -2
- lollms_client/llm_bindings/openai/__init__.py +109 -10
- lollms_client/lollms_core.py +87 -5
- lollms_client/lollms_discussion.py +57 -1
- lollms_client/lollms_llm_binding.py +44 -5
- {lollms_client-0.27.1.dist-info → lollms_client-0.27.3.dist-info}/METADATA +1 -1
- {lollms_client-0.27.1.dist-info → lollms_client-0.27.3.dist-info}/RECORD +17 -13
- {lollms_client-0.27.1.dist-info → lollms_client-0.27.3.dist-info}/WHEEL +0 -0
- {lollms_client-0.27.1.dist-info → lollms_client-0.27.3.dist-info}/licenses/LICENSE +0 -0
- {lollms_client-0.27.1.dist-info → lollms_client-0.27.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# This is a simple example of a calculator using lollms_chat. don't expect this to be perfect as LLMs are very bad in computing
|
|
2
|
+
# this can be used for very simple calculations. don't expect it to be accurate to compute sqrt(35) or something
|
|
3
|
+
# it is just for the purpose of experimentation as even the best models in the world are not capable of doing accurate calculations yet without a calculator
|
|
4
|
+
|
|
5
|
+
from lollms_client import LollmsClient
|
|
6
|
+
import json
|
|
7
|
+
import math # Import the math module for calculations
|
|
8
|
+
|
|
9
|
+
# Make sure you use your key
|
|
10
|
+
lc = LollmsClient(
|
|
11
|
+
"openai",
|
|
12
|
+
"http://localhost:9642/v1/",
|
|
13
|
+
service_key="lollms_y-uyV-p2_AQGo5Ut6uHDmfIoRk6rKfmf0Rz6xQx-Zkl8cNyVUSFM"# make sure you generate your own key
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
# if you want to see what binding/model does the server support, use this:
|
|
17
|
+
models = lc.listModels()
|
|
18
|
+
print(f"Found models:\n{models}")
|
|
19
|
+
|
|
20
|
+
lc.set_model_name("ollama/gemma3:27b") # Or your preferred binding/model
|
|
21
|
+
|
|
22
|
+
expression = input("Give an expression to evaluate: ")
|
|
23
|
+
|
|
24
|
+
# Construct a detailed prompt
|
|
25
|
+
system_prompt = (
|
|
26
|
+
"You are a highly accurate calculator. You receive a mathematical expression "
|
|
27
|
+
"as input and return the result as a JSON object. "
|
|
28
|
+
"The expression can include numbers, basic arithmetic operators (+, -, *, /), "
|
|
29
|
+
"parentheses, and common mathematical functions like sin, cos, tan, pi, sqrt, and log. "
|
|
30
|
+
"Always evaluate the expression and return the final numeric result. If the expression is invalid, return 'Error'."
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
template = '{"result": the numeric result of the evaluated expression}'
|
|
34
|
+
|
|
35
|
+
# Include the expression in the user prompt. This is important!
|
|
36
|
+
user_prompt = f"Evaluate the following expression: {expression}"
|
|
37
|
+
|
|
38
|
+
# Generate the code
|
|
39
|
+
generation_output = lc.generate_code(
|
|
40
|
+
user_prompt,
|
|
41
|
+
system_prompt=system_prompt,
|
|
42
|
+
template=template
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
# Attempt to parse the JSON response
|
|
47
|
+
generation_output = json.loads(generation_output)
|
|
48
|
+
result = generation_output["result"]
|
|
49
|
+
|
|
50
|
+
# Attempt to convert the result to a float
|
|
51
|
+
try:
|
|
52
|
+
result = float(result)
|
|
53
|
+
print(f"Result: {result}")
|
|
54
|
+
except ValueError:
|
|
55
|
+
print(f"Result: {result} (Could not convert to a number)") #Handles cases where the LLM returns non-numeric output
|
|
56
|
+
except json.JSONDecodeError:
|
|
57
|
+
print(f"Error: Could not decode JSON response: {generation_output}")
|
|
58
|
+
except KeyError:
|
|
59
|
+
print(f"Error: 'result' key not found in JSON response: {generation_output}")
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from lollms_client import LollmsClient
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
# Make sure you use your key
|
|
5
|
+
lc = LollmsClient(
|
|
6
|
+
"openai",
|
|
7
|
+
"http://localhost:9642/v1/",
|
|
8
|
+
service_key="lollms_y-uyV-p2_AQGo5Ut6uHDmfIoRk6rKfmf0Rz6xQx-Zkl8cNyVUSFM" # make sure you generate your own key
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
# if you want to see what binding/model does the server support, use this:
|
|
12
|
+
models = lc.listModels()
|
|
13
|
+
print(f"Found models:\n{models}")
|
|
14
|
+
|
|
15
|
+
lc.set_model_name("ollama/gemma3:27b") # Or your preferred binding/model
|
|
16
|
+
|
|
17
|
+
function = input("Enter the function (e.g., x^2 + 2*x): ")
|
|
18
|
+
parameter = input("Enter the parameter to differentiate with respect to (e.g., x): ")
|
|
19
|
+
|
|
20
|
+
# Construct a detailed prompt
|
|
21
|
+
system_prompt = (
|
|
22
|
+
"You are a symbolic differentiation engine. You receive a mathematical function "
|
|
23
|
+
"and a parameter as input, and you return the derivative of the function with respect to that parameter. "
|
|
24
|
+
"The function can include variables, numbers, and common mathematical operations. "
|
|
25
|
+
"Return the derivative as a string. If the function or parameter is invalid, return 'Error'."
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
template = '"{derivative}": the derivative of the function with respect to the parameter'
|
|
29
|
+
|
|
30
|
+
# Include the function and parameter in the user prompt. This is important!
|
|
31
|
+
user_prompt = f"Find the derivative of the function '{function}' with respect to '{parameter}'."
|
|
32
|
+
|
|
33
|
+
# Generate the code
|
|
34
|
+
generation_output = lc.generate_code(
|
|
35
|
+
user_prompt,
|
|
36
|
+
system_prompt=system_prompt,
|
|
37
|
+
template=template
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
try:
|
|
41
|
+
# Attempt to parse the JSON response
|
|
42
|
+
generation_output = json.loads(generation_output)
|
|
43
|
+
derivative = generation_output["derivative"]
|
|
44
|
+
print(f"Derivative: {derivative}")
|
|
45
|
+
except json.JSONDecodeError:
|
|
46
|
+
print(f"Error: Could not decode JSON response: {generation_output}")
|
|
47
|
+
except KeyError:
|
|
48
|
+
print(f"Error: 'derivative' key not found in JSON response: {generation_output}")
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from lollms_client import LollmsClient
|
|
2
|
+
#make sure you use your key
|
|
3
|
+
lc = LollmsClient("openai","http://localhost:9642/v1/", service_key="lollms_zXQdyvrP_ecMXm3UZ0D004x979aHpyF8iq4ki_b52q0WdFuiEfMo")
|
|
4
|
+
models = lc.listModels()
|
|
5
|
+
print(f"Found models:\n{models}")
|
|
6
|
+
|
|
7
|
+
lc.set_model_name("ollama/gemma3:27b")
|
|
8
|
+
|
|
9
|
+
res = lc.generate_text("Describe this image",images=[
|
|
10
|
+
r"C:\Users\parisneo\Pictures\me.jpg"
|
|
11
|
+
])
|
|
12
|
+
print(res)
|
lollms_client/__init__.py
CHANGED
|
@@ -8,7 +8,7 @@ from lollms_client.lollms_utilities import PromptReshaper # Keep general utiliti
|
|
|
8
8
|
from lollms_client.lollms_mcp_binding import LollmsMCPBinding, LollmsMCPBindingManager
|
|
9
9
|
from lollms_client.lollms_llm_binding import LollmsLLMBindingManager
|
|
10
10
|
|
|
11
|
-
__version__ = "0.27.
|
|
11
|
+
__version__ = "0.27.3" # Updated version
|
|
12
12
|
|
|
13
13
|
# Optionally, you could define __all__ if you want to be explicit about exports
|
|
14
14
|
__all__ = [
|
|
@@ -110,6 +110,25 @@ class LiteLLMBinding(LollmsLLMBinding):
|
|
|
110
110
|
|
|
111
111
|
return self._perform_generation(messages, n_predict, is_streaming, temperature, top_p, repeat_penalty, seed, streaming_callback)
|
|
112
112
|
|
|
113
|
+
def generate_from_messages(self,
|
|
114
|
+
messages: List[Dict],
|
|
115
|
+
n_predict: Optional[int] = None,
|
|
116
|
+
stream: Optional[bool] = None,
|
|
117
|
+
temperature: Optional[float] = None,
|
|
118
|
+
top_k: Optional[int] = None,
|
|
119
|
+
top_p: Optional[float] = None,
|
|
120
|
+
repeat_penalty: Optional[float] = None,
|
|
121
|
+
repeat_last_n: Optional[int] = None,
|
|
122
|
+
seed: Optional[int] = None,
|
|
123
|
+
n_threads: Optional[int] = None,
|
|
124
|
+
ctx_size: int | None = None,
|
|
125
|
+
streaming_callback: Optional[Callable[[str, MSG_TYPE], None]] = None,
|
|
126
|
+
**kwargs
|
|
127
|
+
) -> Union[str, dict]:
|
|
128
|
+
is_streaming = stream if stream is not None else (streaming_callback is not None)
|
|
129
|
+
return self._perform_generation(messages, n_predict, is_streaming, temperature, top_p, repeat_penalty, seed, streaming_callback)
|
|
130
|
+
|
|
131
|
+
|
|
113
132
|
def chat(self, discussion: LollmsDiscussion, branch_tip_id: Optional[str] = None, n_predict: Optional[int] = None, stream: Optional[bool] = None, temperature: float = 0.7, top_p: float = 0.9, repeat_penalty: float = 1.1, seed: Optional[int] = None, streaming_callback: Optional[Callable[[str, MSG_TYPE], None]] = None, **kwargs) -> Union[str, dict]:
|
|
114
133
|
is_streaming = stream if stream is not None else (streaming_callback is not None)
|
|
115
134
|
messages = discussion.export("openai_chat", branch_tip_id)
|
|
@@ -178,9 +197,9 @@ class LiteLLMBinding(LollmsLLMBinding):
|
|
|
178
197
|
entries.append({
|
|
179
198
|
"category": "api", "datasets": "unknown", "icon": get_icon_path(model_name),
|
|
180
199
|
"license": "unknown", "model_creator": model_info.get('owned_by', 'unknown'),
|
|
181
|
-
"
|
|
200
|
+
"model_name": model_name, "provider": "litellm", "rank": "1.0", "type": "api",
|
|
182
201
|
"variants": [{
|
|
183
|
-
"
|
|
202
|
+
"model_name": model_name, "size": context_size,
|
|
184
203
|
"input_cost_per_token": model_info.get('input_cost_per_token', 0),
|
|
185
204
|
"output_cost_per_token": model_info.get('output_cost_per_token', 0),
|
|
186
205
|
"max_output_tokens": model_info.get('max_output_tokens', 0),
|
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
# bindings/Lollms_chat/binding.py
|
|
2
|
+
import requests
|
|
3
|
+
import json
|
|
4
|
+
from lollms_client.lollms_llm_binding import LollmsLLMBinding
|
|
5
|
+
from lollms_client.lollms_types import MSG_TYPE
|
|
6
|
+
from lollms_client.lollms_utilities import encode_image
|
|
7
|
+
from lollms_client.lollms_types import ELF_COMPLETION_FORMAT
|
|
8
|
+
from lollms_client.lollms_discussion import LollmsDiscussion
|
|
9
|
+
from typing import Optional, Callable, List, Union
|
|
10
|
+
from ascii_colors import ASCIIColors, trace_exception
|
|
11
|
+
from typing import List, Dict
|
|
12
|
+
|
|
13
|
+
import pipmaster as pm
|
|
14
|
+
|
|
15
|
+
pm.ensure_packages(["openai","tiktoken"])
|
|
16
|
+
|
|
17
|
+
import openai
|
|
18
|
+
import tiktoken
|
|
19
|
+
import os
|
|
20
|
+
|
|
21
|
+
BindingName = "LollmsChatBinding"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class LollmsChatBinding(LollmsLLMBinding):
|
|
25
|
+
"""LollmsChat-specific binding implementation (open ai compatible with some extra parameters)"""
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def __init__(self,
|
|
29
|
+
host_address: str = None,
|
|
30
|
+
model_name: str = "",
|
|
31
|
+
service_key: str = None,
|
|
32
|
+
verify_ssl_certificate: bool = True,
|
|
33
|
+
default_completion_format: ELF_COMPLETION_FORMAT = ELF_COMPLETION_FORMAT.Chat,
|
|
34
|
+
**kwargs):
|
|
35
|
+
"""
|
|
36
|
+
Initialize the OpenAI binding.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
host_address (str): Host address for the OpenAI service. Defaults to DEFAULT_HOST_ADDRESS.
|
|
40
|
+
model_name (str): Name of the model to use. Defaults to empty string.
|
|
41
|
+
service_key (str): Authentication key for the service. Defaults to None.
|
|
42
|
+
verify_ssl_certificate (bool): Whether to verify SSL certificates. Defaults to True.
|
|
43
|
+
personality (Optional[int]): Ignored parameter for compatibility with LollmsLLMBinding.
|
|
44
|
+
"""
|
|
45
|
+
super().__init__(
|
|
46
|
+
binding_name = "openai",
|
|
47
|
+
)
|
|
48
|
+
self.host_address=host_address
|
|
49
|
+
self.model_name=model_name
|
|
50
|
+
self.service_key=service_key
|
|
51
|
+
self.verify_ssl_certificate=verify_ssl_certificate
|
|
52
|
+
self.default_completion_format=default_completion_format
|
|
53
|
+
|
|
54
|
+
if not self.service_key:
|
|
55
|
+
self.service_key = os.getenv("OPENAI_API_KEY", self.service_key)
|
|
56
|
+
self.client = openai.OpenAI(api_key=self.service_key, base_url=None if host_address is None else host_address if len(host_address)>0 else None)
|
|
57
|
+
self.completion_format = ELF_COMPLETION_FORMAT.Chat
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def generate_text(self,
|
|
61
|
+
prompt: str,
|
|
62
|
+
images: Optional[List[str]] = None,
|
|
63
|
+
system_prompt: str = "",
|
|
64
|
+
n_predict: Optional[int] = None,
|
|
65
|
+
stream: Optional[bool] = None,
|
|
66
|
+
temperature: float = 0.7,
|
|
67
|
+
top_k: int = 40,
|
|
68
|
+
top_p: float = 0.9,
|
|
69
|
+
repeat_penalty: float = 1.1,
|
|
70
|
+
repeat_last_n: int = 64,
|
|
71
|
+
seed: Optional[int] = None,
|
|
72
|
+
n_threads: Optional[int] = None,
|
|
73
|
+
ctx_size: int | None = None,
|
|
74
|
+
streaming_callback: Optional[Callable[[str, MSG_TYPE], None]] = None,
|
|
75
|
+
split:Optional[bool]=False, # put to true if the prompt is a discussion
|
|
76
|
+
user_keyword:Optional[str]="!@>user:",
|
|
77
|
+
ai_keyword:Optional[str]="!@>assistant:",
|
|
78
|
+
) -> Union[str, dict]:
|
|
79
|
+
"""
|
|
80
|
+
Generate text using the active LLM binding, using instance defaults if parameters are not provided.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
prompt (str): The input prompt for text generation.
|
|
84
|
+
images (Optional[List[str]]): List of image file paths for multimodal generation.
|
|
85
|
+
n_predict (Optional[int]): Maximum number of tokens to generate. Uses instance default if None.
|
|
86
|
+
stream (Optional[bool]): Whether to stream the output. Uses instance default if None.
|
|
87
|
+
temperature (Optional[float]): Sampling temperature. Uses instance default if None.
|
|
88
|
+
top_k (Optional[int]): Top-k sampling parameter. Uses instance default if None.
|
|
89
|
+
top_p (Optional[float]): Top-p sampling parameter. Uses instance default if None.
|
|
90
|
+
repeat_penalty (Optional[float]): Penalty for repeated tokens. Uses instance default if None.
|
|
91
|
+
repeat_last_n (Optional[int]): Number of previous tokens to consider for repeat penalty. Uses instance default if None.
|
|
92
|
+
seed (Optional[int]): Random seed for generation. Uses instance default if None.
|
|
93
|
+
n_threads (Optional[int]): Number of threads to use. Uses instance default if None.
|
|
94
|
+
ctx_size (int | None): Context size override for this generation.
|
|
95
|
+
streaming_callback (Optional[Callable[[str, str], None]]): Callback function for streaming output.
|
|
96
|
+
- First parameter (str): The chunk of text received.
|
|
97
|
+
- Second parameter (str): The message type (e.g., MSG_TYPE.MSG_TYPE_CHUNK).
|
|
98
|
+
split:Optional[bool]: put to true if the prompt is a discussion
|
|
99
|
+
user_keyword:Optional[str]: when splitting we use this to extract user prompt
|
|
100
|
+
ai_keyword:Optional[str]": when splitting we use this to extract ai prompt
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
Union[str, dict]: Generated text or error dictionary if failed.
|
|
104
|
+
"""
|
|
105
|
+
count = 0
|
|
106
|
+
output = ""
|
|
107
|
+
messages = [
|
|
108
|
+
{
|
|
109
|
+
"role": "system",
|
|
110
|
+
"content": system_prompt or "You are a helpful assistant.",
|
|
111
|
+
}
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
# Prepare messages based on whether images are provided
|
|
115
|
+
if images:
|
|
116
|
+
if split:
|
|
117
|
+
messages += self.split_discussion(prompt,user_keyword=user_keyword, ai_keyword=ai_keyword)
|
|
118
|
+
if images:
|
|
119
|
+
messages[-1]["content"] = [
|
|
120
|
+
{
|
|
121
|
+
"type": "text",
|
|
122
|
+
"text": messages[-1]["content"]
|
|
123
|
+
}
|
|
124
|
+
]+[
|
|
125
|
+
{
|
|
126
|
+
"type": "image_url",
|
|
127
|
+
"image_url": {
|
|
128
|
+
"url": f"data:image/jpeg;base64,{encode_image(image_path)}"
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
for image_path in images
|
|
132
|
+
]
|
|
133
|
+
else:
|
|
134
|
+
messages.append({
|
|
135
|
+
'role': 'user',
|
|
136
|
+
'content': [
|
|
137
|
+
{
|
|
138
|
+
"type": "text",
|
|
139
|
+
"text": prompt
|
|
140
|
+
}
|
|
141
|
+
] + [
|
|
142
|
+
{
|
|
143
|
+
"type": "image_url",
|
|
144
|
+
"image_url": {
|
|
145
|
+
"url": f"data:image/jpeg;base64,{encode_image(image_path)}"
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
for image_path in images
|
|
149
|
+
]
|
|
150
|
+
}
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
else:
|
|
154
|
+
|
|
155
|
+
if split:
|
|
156
|
+
messages += self.split_discussion(prompt,user_keyword=user_keyword, ai_keyword=ai_keyword)
|
|
157
|
+
if images:
|
|
158
|
+
messages[-1]["content"] = [
|
|
159
|
+
{
|
|
160
|
+
"type": "text",
|
|
161
|
+
"text": messages[-1]["content"]
|
|
162
|
+
}
|
|
163
|
+
]
|
|
164
|
+
else:
|
|
165
|
+
messages.append({
|
|
166
|
+
'role': 'user',
|
|
167
|
+
'content': [
|
|
168
|
+
{
|
|
169
|
+
"type": "text",
|
|
170
|
+
"text": prompt
|
|
171
|
+
}
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
# Generate text using the OpenAI API
|
|
177
|
+
if self.completion_format == ELF_COMPLETION_FORMAT.Chat:
|
|
178
|
+
chat_completion = self.client.chat.completions.create(
|
|
179
|
+
model=self.model_name, # Choose the engine according to your OpenAI plan
|
|
180
|
+
messages=messages,
|
|
181
|
+
max_tokens=n_predict, # Adjust the desired length of the generated response
|
|
182
|
+
n=1, # Specify the number of responses you want
|
|
183
|
+
temperature=temperature, # Adjust the temperature for more or less randomness in the output
|
|
184
|
+
stream=stream
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
if stream:
|
|
188
|
+
for resp in chat_completion:
|
|
189
|
+
if count >= n_predict:
|
|
190
|
+
break
|
|
191
|
+
try:
|
|
192
|
+
word = resp.choices[0].delta.content
|
|
193
|
+
except Exception as ex:
|
|
194
|
+
word = ""
|
|
195
|
+
if streaming_callback is not None:
|
|
196
|
+
if not streaming_callback(word, MSG_TYPE.MSG_TYPE_CHUNK):
|
|
197
|
+
break
|
|
198
|
+
if word:
|
|
199
|
+
output += word
|
|
200
|
+
count += 1
|
|
201
|
+
else:
|
|
202
|
+
output = chat_completion.choices[0].message.content
|
|
203
|
+
else:
|
|
204
|
+
completion = self.client.completions.create(
|
|
205
|
+
model=self.model_name, # Choose the engine according to your OpenAI plan
|
|
206
|
+
prompt=prompt,
|
|
207
|
+
max_tokens=n_predict, # Adjust the desired length of the generated response
|
|
208
|
+
n=1, # Specify the number of responses you want
|
|
209
|
+
temperature=temperature, # Adjust the temperature for more or less randomness in the output
|
|
210
|
+
stream=stream
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
if stream:
|
|
214
|
+
for resp in completion:
|
|
215
|
+
if count >= n_predict:
|
|
216
|
+
break
|
|
217
|
+
try:
|
|
218
|
+
word = resp.choices[0].text
|
|
219
|
+
except Exception as ex:
|
|
220
|
+
word = ""
|
|
221
|
+
if streaming_callback is not None:
|
|
222
|
+
if not streaming_callback(word, "MSG_TYPE_CHUNK"):
|
|
223
|
+
break
|
|
224
|
+
if word:
|
|
225
|
+
output += word
|
|
226
|
+
count += 1
|
|
227
|
+
else:
|
|
228
|
+
output = completion.choices[0].text
|
|
229
|
+
|
|
230
|
+
return output
|
|
231
|
+
|
|
232
|
+
def generate_from_messages(self,
|
|
233
|
+
messages: List[Dict],
|
|
234
|
+
n_predict: Optional[int] = None,
|
|
235
|
+
stream: Optional[bool] = None,
|
|
236
|
+
temperature: Optional[float] = None,
|
|
237
|
+
top_k: Optional[int] = None,
|
|
238
|
+
top_p: Optional[float] = None,
|
|
239
|
+
repeat_penalty: Optional[float] = None,
|
|
240
|
+
repeat_last_n: Optional[int] = None,
|
|
241
|
+
seed: Optional[int] = None,
|
|
242
|
+
n_threads: Optional[int] = None,
|
|
243
|
+
ctx_size: int | None = None,
|
|
244
|
+
streaming_callback: Optional[Callable[[str, MSG_TYPE], None]] = None,
|
|
245
|
+
**kwargs
|
|
246
|
+
) -> Union[str, dict]:
|
|
247
|
+
# Build the request parameters
|
|
248
|
+
params = {
|
|
249
|
+
"model": self.model_name,
|
|
250
|
+
"messages": messages,
|
|
251
|
+
"max_tokens": n_predict,
|
|
252
|
+
"n": 1,
|
|
253
|
+
"temperature": temperature,
|
|
254
|
+
"top_p": top_p,
|
|
255
|
+
"frequency_penalty": repeat_penalty,
|
|
256
|
+
"stream": stream
|
|
257
|
+
}
|
|
258
|
+
# Add seed if available, as it's supported by newer OpenAI models
|
|
259
|
+
if seed is not None:
|
|
260
|
+
params["seed"] = seed
|
|
261
|
+
|
|
262
|
+
# Remove None values, as the API expects them to be absent
|
|
263
|
+
params = {k: v for k, v in params.items() if v is not None}
|
|
264
|
+
|
|
265
|
+
output = ""
|
|
266
|
+
# 2. Call the API
|
|
267
|
+
try:
|
|
268
|
+
completion = self.client.chat.completions.create(**params)
|
|
269
|
+
|
|
270
|
+
if stream:
|
|
271
|
+
for chunk in completion:
|
|
272
|
+
# The streaming response for chat has a different structure
|
|
273
|
+
delta = chunk.choices[0].delta
|
|
274
|
+
if delta.content:
|
|
275
|
+
word = delta.content
|
|
276
|
+
if streaming_callback is not None:
|
|
277
|
+
if not streaming_callback(word, MSG_TYPE.MSG_TYPE_CHUNK):
|
|
278
|
+
break
|
|
279
|
+
output += word
|
|
280
|
+
else:
|
|
281
|
+
output = completion.choices[0].message.content
|
|
282
|
+
|
|
283
|
+
except Exception as e:
|
|
284
|
+
# Handle API errors gracefully
|
|
285
|
+
error_message = f"An error occurred with the OpenAI API: {e}"
|
|
286
|
+
if streaming_callback:
|
|
287
|
+
streaming_callback(error_message, MSG_TYPE.MSG_TYPE_EXCEPTION)
|
|
288
|
+
return {"status": "error", "message": error_message}
|
|
289
|
+
|
|
290
|
+
return output
|
|
291
|
+
|
|
292
|
+
def chat(self,
|
|
293
|
+
discussion: LollmsDiscussion,
|
|
294
|
+
branch_tip_id: Optional[str] = None,
|
|
295
|
+
n_predict: Optional[int] = None,
|
|
296
|
+
stream: Optional[bool] = None,
|
|
297
|
+
temperature: float = 0.7,
|
|
298
|
+
top_k: int = 40,
|
|
299
|
+
top_p: float = 0.9,
|
|
300
|
+
repeat_penalty: float = 1.1,
|
|
301
|
+
repeat_last_n: int = 64,
|
|
302
|
+
seed: Optional[int] = None,
|
|
303
|
+
n_threads: Optional[int] = None,
|
|
304
|
+
ctx_size: Optional[int] = None,
|
|
305
|
+
streaming_callback: Optional[Callable[[str, MSG_TYPE], None]] = None
|
|
306
|
+
) -> Union[str, dict]:
|
|
307
|
+
"""
|
|
308
|
+
Conduct a chat session with the OpenAI model using a LollmsDiscussion object.
|
|
309
|
+
|
|
310
|
+
Args:
|
|
311
|
+
discussion (LollmsDiscussion): The discussion object containing the conversation history.
|
|
312
|
+
branch_tip_id (Optional[str]): The ID of the message to use as the tip of the conversation branch. Defaults to the active branch.
|
|
313
|
+
n_predict (Optional[int]): Maximum number of tokens to generate.
|
|
314
|
+
stream (Optional[bool]): Whether to stream the output.
|
|
315
|
+
temperature (float): Sampling temperature.
|
|
316
|
+
top_k (int): Top-k sampling parameter (Note: not all OpenAI models use this).
|
|
317
|
+
top_p (float): Top-p sampling parameter.
|
|
318
|
+
repeat_penalty (float): Frequency penalty for repeated tokens.
|
|
319
|
+
seed (Optional[int]): Random seed for generation.
|
|
320
|
+
streaming_callback (Optional[Callable[[str, MSG_TYPE], None]]): Callback for streaming output.
|
|
321
|
+
|
|
322
|
+
Returns:
|
|
323
|
+
Union[str, dict]: The generated text or an error dictionary.
|
|
324
|
+
"""
|
|
325
|
+
# 1. Export the discussion to the OpenAI chat format
|
|
326
|
+
# This handles system prompts, user/assistant roles, and multi-modal content automatically.
|
|
327
|
+
messages = discussion.export("openai_chat", branch_tip_id)
|
|
328
|
+
|
|
329
|
+
# Build the request parameters
|
|
330
|
+
params = {
|
|
331
|
+
"model": self.model_name,
|
|
332
|
+
"messages": messages,
|
|
333
|
+
"max_tokens": n_predict,
|
|
334
|
+
"n": 1,
|
|
335
|
+
"temperature": temperature,
|
|
336
|
+
"top_p": top_p,
|
|
337
|
+
"frequency_penalty": repeat_penalty,
|
|
338
|
+
"stream": stream
|
|
339
|
+
}
|
|
340
|
+
# Add seed if available, as it's supported by newer OpenAI models
|
|
341
|
+
if seed is not None:
|
|
342
|
+
params["seed"] = seed
|
|
343
|
+
|
|
344
|
+
# Remove None values, as the API expects them to be absent
|
|
345
|
+
params = {k: v for k, v in params.items() if v is not None}
|
|
346
|
+
|
|
347
|
+
output = ""
|
|
348
|
+
# 2. Call the API
|
|
349
|
+
try:
|
|
350
|
+
# Check if we should use the chat completions or legacy completions endpoint
|
|
351
|
+
if self.completion_format == ELF_COMPLETION_FORMAT.Chat:
|
|
352
|
+
completion = self.client.chat.completions.create(**params)
|
|
353
|
+
|
|
354
|
+
if stream:
|
|
355
|
+
for chunk in completion:
|
|
356
|
+
# The streaming response for chat has a different structure
|
|
357
|
+
delta = chunk.choices[0].delta
|
|
358
|
+
if delta.content:
|
|
359
|
+
word = delta.content
|
|
360
|
+
if streaming_callback is not None:
|
|
361
|
+
if not streaming_callback(word, MSG_TYPE.MSG_TYPE_CHUNK):
|
|
362
|
+
break
|
|
363
|
+
output += word
|
|
364
|
+
else:
|
|
365
|
+
output = completion.choices[0].message.content
|
|
366
|
+
|
|
367
|
+
else: # Fallback to legacy completion format (not recommended for chat)
|
|
368
|
+
# We need to format the messages list into a single string prompt
|
|
369
|
+
legacy_prompt = discussion.export("openai_completion", branch_tip_id)
|
|
370
|
+
legacy_params = {
|
|
371
|
+
"model": self.model_name,
|
|
372
|
+
"prompt": legacy_prompt,
|
|
373
|
+
"max_tokens": n_predict,
|
|
374
|
+
"n": 1,
|
|
375
|
+
"temperature": temperature,
|
|
376
|
+
"top_p": top_p,
|
|
377
|
+
"frequency_penalty": repeat_penalty,
|
|
378
|
+
"stream": stream
|
|
379
|
+
}
|
|
380
|
+
completion = self.client.completions.create(**legacy_params)
|
|
381
|
+
|
|
382
|
+
if stream:
|
|
383
|
+
for chunk in completion:
|
|
384
|
+
word = chunk.choices[0].text
|
|
385
|
+
if streaming_callback is not None:
|
|
386
|
+
if not streaming_callback(word, MSG_TYPE.MSG_TYPE_CHUNK):
|
|
387
|
+
break
|
|
388
|
+
output += word
|
|
389
|
+
else:
|
|
390
|
+
output = completion.choices[0].text
|
|
391
|
+
|
|
392
|
+
except Exception as e:
|
|
393
|
+
# Handle API errors gracefully
|
|
394
|
+
error_message = f"An error occurred with the OpenAI API: {e}"
|
|
395
|
+
if streaming_callback:
|
|
396
|
+
streaming_callback(error_message, MSG_TYPE.MSG_TYPE_EXCEPTION)
|
|
397
|
+
return {"status": "error", "message": error_message}
|
|
398
|
+
|
|
399
|
+
return output
|
|
400
|
+
def tokenize(self, text: str) -> list:
|
|
401
|
+
"""
|
|
402
|
+
Tokenize the input text into a list of characters.
|
|
403
|
+
|
|
404
|
+
Args:
|
|
405
|
+
text (str): The text to tokenize.
|
|
406
|
+
|
|
407
|
+
Returns:
|
|
408
|
+
list: List of individual characters.
|
|
409
|
+
"""
|
|
410
|
+
try:
|
|
411
|
+
return tiktoken.model.encoding_for_model(self.model_name).encode(text)
|
|
412
|
+
except:
|
|
413
|
+
return tiktoken.model.encoding_for_model("gpt-3.5-turbo").encode(text)
|
|
414
|
+
|
|
415
|
+
def detokenize(self, tokens: list) -> str:
|
|
416
|
+
"""
|
|
417
|
+
Convert a list of tokens back to text.
|
|
418
|
+
|
|
419
|
+
Args:
|
|
420
|
+
tokens (list): List of tokens (characters) to detokenize.
|
|
421
|
+
|
|
422
|
+
Returns:
|
|
423
|
+
str: Detokenized text.
|
|
424
|
+
"""
|
|
425
|
+
try:
|
|
426
|
+
return tiktoken.model.encoding_for_model(self.model_name).decode(tokens)
|
|
427
|
+
except:
|
|
428
|
+
return tiktoken.model.encoding_for_model("gpt-3.5-turbo").decode(tokens)
|
|
429
|
+
|
|
430
|
+
def count_tokens(self, text: str) -> int:
|
|
431
|
+
"""
|
|
432
|
+
Count tokens from a text.
|
|
433
|
+
|
|
434
|
+
Args:
|
|
435
|
+
tokens (list): List of tokens to detokenize.
|
|
436
|
+
|
|
437
|
+
Returns:
|
|
438
|
+
int: Number of tokens in text.
|
|
439
|
+
"""
|
|
440
|
+
return len(self.tokenize(text))
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
def embed(self, text: str, **kwargs) -> list:
|
|
444
|
+
"""
|
|
445
|
+
Get embeddings for the input text using OpenAI API
|
|
446
|
+
|
|
447
|
+
Args:
|
|
448
|
+
text (str or List[str]): Input text to embed
|
|
449
|
+
**kwargs: Additional arguments like model, truncate, options, keep_alive
|
|
450
|
+
|
|
451
|
+
Returns:
|
|
452
|
+
dict: Response containing embeddings
|
|
453
|
+
"""
|
|
454
|
+
pass
|
|
455
|
+
def get_model_info(self) -> dict:
|
|
456
|
+
"""
|
|
457
|
+
Return information about the current OpenAI model.
|
|
458
|
+
|
|
459
|
+
Returns:
|
|
460
|
+
dict: Dictionary containing model name, version, and host address.
|
|
461
|
+
"""
|
|
462
|
+
return {
|
|
463
|
+
"name": "OpenAI",
|
|
464
|
+
"version": "2.0",
|
|
465
|
+
"host_address": self.host_address,
|
|
466
|
+
"model_name": self.model_name
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
def listModels(self) -> List[Dict]:
|
|
470
|
+
# Known context lengths
|
|
471
|
+
known_context_lengths = {
|
|
472
|
+
"gpt-4o": 128000,
|
|
473
|
+
"gpt-4": 8192,
|
|
474
|
+
"gpt-4-0613": 8192,
|
|
475
|
+
"gpt-4-1106-preview": 128000,
|
|
476
|
+
"gpt-4-0125-preview": 128000,
|
|
477
|
+
"gpt-4-turbo": 128000,
|
|
478
|
+
"gpt-3.5-turbo": 4096,
|
|
479
|
+
"gpt-3.5-turbo-16k": 16000,
|
|
480
|
+
"gpt-3.5-turbo-1106": 16385,
|
|
481
|
+
"gpt-3.5-turbo-0125": 16385,
|
|
482
|
+
"text-davinci-003": 4097,
|
|
483
|
+
"text-davinci-002": 4097,
|
|
484
|
+
"davinci": 2049,
|
|
485
|
+
"curie": 2049,
|
|
486
|
+
"babbage": 2049,
|
|
487
|
+
"ada": 2049,
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
generation_prefixes = (
|
|
491
|
+
"gpt-",
|
|
492
|
+
"text-davinci",
|
|
493
|
+
"davinci",
|
|
494
|
+
"curie",
|
|
495
|
+
"babbage",
|
|
496
|
+
"ada"
|
|
497
|
+
)
|
|
498
|
+
|
|
499
|
+
models_info = []
|
|
500
|
+
prompt_buffer = 500
|
|
501
|
+
|
|
502
|
+
try:
|
|
503
|
+
models = self.client.models.list()
|
|
504
|
+
for model in models.data:
|
|
505
|
+
model_id = model.id
|
|
506
|
+
if model_id.startswith(generation_prefixes):
|
|
507
|
+
context_length = known_context_lengths.get(model_id, "unknown")
|
|
508
|
+
max_generation = (
|
|
509
|
+
context_length - prompt_buffer
|
|
510
|
+
if isinstance(context_length, int)
|
|
511
|
+
else "unknown"
|
|
512
|
+
)
|
|
513
|
+
models_info.append({
|
|
514
|
+
"model_name": model_id,
|
|
515
|
+
"owned_by": getattr(model, "owned_by", "N/A"),
|
|
516
|
+
"created": getattr(model, "created", "N/A"),
|
|
517
|
+
"context_length": context_length,
|
|
518
|
+
"max_generation": max_generation,
|
|
519
|
+
})
|
|
520
|
+
else:
|
|
521
|
+
models_info.append({
|
|
522
|
+
"model_name": model_id,
|
|
523
|
+
"owned_by": getattr(model, "owned_by", "N/A"),
|
|
524
|
+
"created": getattr(model, "created", "N/A"),
|
|
525
|
+
"context_length": None,
|
|
526
|
+
"max_generation": None,
|
|
527
|
+
})
|
|
528
|
+
|
|
529
|
+
except Exception as e:
|
|
530
|
+
print(f"Failed to list models: {e}")
|
|
531
|
+
|
|
532
|
+
return models_info
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
def load_model(self, model_name: str) -> bool:
|
|
536
|
+
"""
|
|
537
|
+
Load a specific model into the OpenAI binding.
|
|
538
|
+
|
|
539
|
+
Args:
|
|
540
|
+
model_name (str): Name of the model to load.
|
|
541
|
+
|
|
542
|
+
Returns:
|
|
543
|
+
bool: True if model loaded successfully.
|
|
544
|
+
"""
|
|
545
|
+
self.model = model_name
|
|
546
|
+
self.model_name = model_name
|
|
547
|
+
return True
|
|
@@ -258,7 +258,77 @@ class OllamaBinding(LollmsLLMBinding):
|
|
|
258
258
|
error_message = f"An unexpected error occurred: {str(ex)}"
|
|
259
259
|
trace_exception(ex)
|
|
260
260
|
return {"status": False, "error": error_message}
|
|
261
|
+
|
|
262
|
+
def generate_from_messages(self,
|
|
263
|
+
messages: List[Dict],
|
|
264
|
+
n_predict: Optional[int] = None,
|
|
265
|
+
stream: Optional[bool] = None,
|
|
266
|
+
temperature: Optional[float] = None,
|
|
267
|
+
top_k: Optional[int] = None,
|
|
268
|
+
top_p: Optional[float] = None,
|
|
269
|
+
repeat_penalty: Optional[float] = None,
|
|
270
|
+
repeat_last_n: Optional[int] = None,
|
|
271
|
+
seed: Optional[int] = None,
|
|
272
|
+
n_threads: Optional[int] = None,
|
|
273
|
+
ctx_size: int | None = None,
|
|
274
|
+
streaming_callback: Optional[Callable[[str, MSG_TYPE], None]] = None,
|
|
275
|
+
**kwargs
|
|
276
|
+
) -> Union[str, dict]:
|
|
277
|
+
if not self.ollama_client:
|
|
278
|
+
return {"status": False, "error": "Ollama client not initialized."}
|
|
279
|
+
|
|
280
|
+
options = {}
|
|
281
|
+
if n_predict is not None: options['num_predict'] = n_predict
|
|
282
|
+
if temperature is not None: options['temperature'] = float(temperature)
|
|
283
|
+
if top_k is not None: options['top_k'] = top_k
|
|
284
|
+
if top_p is not None: options['top_p'] = top_p
|
|
285
|
+
if repeat_penalty is not None: options['repeat_penalty'] = repeat_penalty
|
|
286
|
+
if repeat_last_n is not None: options['repeat_last_n'] = repeat_last_n
|
|
287
|
+
if seed is not None: options['seed'] = seed
|
|
288
|
+
if n_threads is not None: options['num_thread'] = n_threads
|
|
289
|
+
if ctx_size is not None: options['num_ctx'] = ctx_size
|
|
290
|
+
|
|
291
|
+
full_response_text = ""
|
|
292
|
+
|
|
293
|
+
try:
|
|
294
|
+
if stream:
|
|
295
|
+
response_stream = self.ollama_client.chat(
|
|
296
|
+
model=self.model_name,
|
|
297
|
+
messages=messages,
|
|
298
|
+
stream=True,
|
|
299
|
+
options=options if options else None
|
|
300
|
+
)
|
|
301
|
+
for chunk_dict in response_stream:
|
|
302
|
+
chunk_content = chunk_dict.get('message', {}).get('content', '')
|
|
303
|
+
if chunk_content: # Ensure there is content to process
|
|
304
|
+
full_response_text += chunk_content
|
|
305
|
+
if streaming_callback:
|
|
306
|
+
if not streaming_callback(chunk_content, MSG_TYPE.MSG_TYPE_CHUNK):
|
|
307
|
+
break # Callback requested stop
|
|
308
|
+
return full_response_text
|
|
309
|
+
else: # Not streaming
|
|
310
|
+
response_dict = self.ollama_client.chat(
|
|
311
|
+
model=self.model_name,
|
|
312
|
+
messages=messages,
|
|
313
|
+
stream=False,
|
|
314
|
+
options=options if options else None
|
|
315
|
+
)
|
|
316
|
+
return response_dict.get('message', {}).get('content', '')
|
|
317
|
+
|
|
318
|
+
except ollama.ResponseError as e:
|
|
319
|
+
error_message = f"Ollama API ResponseError: {e.error or 'Unknown error'} (status code: {e.status_code})"
|
|
320
|
+
ASCIIColors.error(error_message)
|
|
321
|
+
return {"status": False, "error": error_message, "status_code": e.status_code}
|
|
322
|
+
except ollama.RequestError as e: # Covers connection errors, timeouts during request
|
|
323
|
+
error_message = f"Ollama API RequestError: {str(e)}"
|
|
324
|
+
ASCIIColors.error(error_message)
|
|
325
|
+
return {"status": False, "error": error_message}
|
|
326
|
+
except Exception as ex:
|
|
327
|
+
error_message = f"An unexpected error occurred: {str(ex)}"
|
|
328
|
+
trace_exception(ex)
|
|
329
|
+
return {"status": False, "error": error_message}
|
|
261
330
|
|
|
331
|
+
|
|
262
332
|
def chat(self,
|
|
263
333
|
discussion: LollmsDiscussion,
|
|
264
334
|
branch_tip_id: Optional[str] = None,
|
|
@@ -276,7 +276,6 @@ if __name__ == '__main__':
|
|
|
276
276
|
binding.load_model("meta-llama/llama-3-8b-instruct:free") # Use the free tier on OpenRouter
|
|
277
277
|
full_streamed_text = ""
|
|
278
278
|
def stream_callback(chunk: str, msg_type: int):
|
|
279
|
-
nonlocal full_streamed_text
|
|
280
279
|
ASCIIColors.green(chunk, end="", flush=True)
|
|
281
280
|
full_streamed_text += chunk
|
|
282
281
|
return True
|
|
@@ -301,4 +300,4 @@ if __name__ == '__main__':
|
|
|
301
300
|
ASCIIColors.error(f"An error occurred during testing: {e}")
|
|
302
301
|
trace_exception(e)
|
|
303
302
|
|
|
304
|
-
ASCIIColors.yellow("\nOpenRouterBinding test finished.")
|
|
303
|
+
ASCIIColors.yellow("\nOpenRouterBinding test finished.")
|
|
@@ -175,14 +175,25 @@ class OpenAIBinding(LollmsLLMBinding):
|
|
|
175
175
|
|
|
176
176
|
# Generate text using the OpenAI API
|
|
177
177
|
if self.completion_format == ELF_COMPLETION_FORMAT.Chat:
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
178
|
+
try:
|
|
179
|
+
chat_completion = self.client.chat.completions.create(
|
|
180
|
+
model=self.model_name, # Choose the engine according to your OpenAI plan
|
|
181
|
+
messages=messages,
|
|
182
|
+
max_tokens=n_predict, # Adjust the desired length of the generated response
|
|
183
|
+
n=1, # Specify the number of responses you want
|
|
184
|
+
temperature=temperature, # Adjust the temperature for more or less randomness in the output
|
|
185
|
+
stream=stream
|
|
186
|
+
)
|
|
187
|
+
except Exception as ex:
|
|
188
|
+
# exception for new openai models
|
|
189
|
+
chat_completion = self.client.chat.completions.create(
|
|
190
|
+
model=self.model_name, # Choose the engine according to your OpenAI plan
|
|
191
|
+
messages=messages,
|
|
192
|
+
max_completion_tokens=n_predict, # Adjust the desired length of the generated response
|
|
193
|
+
n=1, # Specify the number of responses you want
|
|
194
|
+
temperature=1, # Adjust the temperature for more or less randomness in the output
|
|
195
|
+
stream=stream
|
|
196
|
+
)
|
|
186
197
|
|
|
187
198
|
if stream:
|
|
188
199
|
for resp in chat_completion:
|
|
@@ -229,6 +240,75 @@ class OpenAIBinding(LollmsLLMBinding):
|
|
|
229
240
|
|
|
230
241
|
return output
|
|
231
242
|
|
|
243
|
+
def generate_from_messages(self,
|
|
244
|
+
messages: List[Dict],
|
|
245
|
+
n_predict: Optional[int] = None,
|
|
246
|
+
stream: Optional[bool] = None,
|
|
247
|
+
temperature: Optional[float] = None,
|
|
248
|
+
top_k: Optional[int] = None,
|
|
249
|
+
top_p: Optional[float] = None,
|
|
250
|
+
repeat_penalty: Optional[float] = None,
|
|
251
|
+
repeat_last_n: Optional[int] = None,
|
|
252
|
+
seed: Optional[int] = None,
|
|
253
|
+
n_threads: Optional[int] = None,
|
|
254
|
+
ctx_size: int | None = None,
|
|
255
|
+
streaming_callback: Optional[Callable[[str, MSG_TYPE], None]] = None,
|
|
256
|
+
**kwargs
|
|
257
|
+
) -> Union[str, dict]:
|
|
258
|
+
# Build the request parameters
|
|
259
|
+
params = {
|
|
260
|
+
"model": self.model_name,
|
|
261
|
+
"messages": messages,
|
|
262
|
+
"max_tokens": n_predict,
|
|
263
|
+
"n": 1,
|
|
264
|
+
"temperature": temperature,
|
|
265
|
+
"top_p": top_p,
|
|
266
|
+
"frequency_penalty": repeat_penalty,
|
|
267
|
+
"stream": stream
|
|
268
|
+
}
|
|
269
|
+
# Add seed if available, as it's supported by newer OpenAI models
|
|
270
|
+
if seed is not None:
|
|
271
|
+
params["seed"] = seed
|
|
272
|
+
|
|
273
|
+
# Remove None values, as the API expects them to be absent
|
|
274
|
+
params = {k: v for k, v in params.items() if v is not None}
|
|
275
|
+
|
|
276
|
+
output = ""
|
|
277
|
+
# 2. Call the API
|
|
278
|
+
try:
|
|
279
|
+
try:
|
|
280
|
+
completion = self.client.chat.completions.create(**params)
|
|
281
|
+
except Exception as ex:
|
|
282
|
+
# exception for new openai models
|
|
283
|
+
params["max_completion_tokens"]=params["max_tokens"]
|
|
284
|
+
params["temperature"]=1
|
|
285
|
+
del params["max_tokens"]
|
|
286
|
+
del params["top_p"]
|
|
287
|
+
del params["frequency_penalty"]
|
|
288
|
+
|
|
289
|
+
completion = self.client.chat.completions.create(**params)
|
|
290
|
+
if stream:
|
|
291
|
+
for chunk in completion:
|
|
292
|
+
# The streaming response for chat has a different structure
|
|
293
|
+
delta = chunk.choices[0].delta
|
|
294
|
+
if delta.content:
|
|
295
|
+
word = delta.content
|
|
296
|
+
if streaming_callback is not None:
|
|
297
|
+
if not streaming_callback(word, MSG_TYPE.MSG_TYPE_CHUNK):
|
|
298
|
+
break
|
|
299
|
+
output += word
|
|
300
|
+
else:
|
|
301
|
+
output = completion.choices[0].message.content
|
|
302
|
+
|
|
303
|
+
except Exception as e:
|
|
304
|
+
# Handle API errors gracefully
|
|
305
|
+
error_message = f"An error occurred with the OpenAI API: {e}"
|
|
306
|
+
if streaming_callback:
|
|
307
|
+
streaming_callback(error_message, MSG_TYPE.MSG_TYPE_EXCEPTION)
|
|
308
|
+
return {"status": "error", "message": error_message}
|
|
309
|
+
|
|
310
|
+
return output
|
|
311
|
+
|
|
232
312
|
def chat(self,
|
|
233
313
|
discussion: LollmsDiscussion,
|
|
234
314
|
branch_tip_id: Optional[str] = None,
|
|
@@ -289,8 +369,18 @@ class OpenAIBinding(LollmsLLMBinding):
|
|
|
289
369
|
try:
|
|
290
370
|
# Check if we should use the chat completions or legacy completions endpoint
|
|
291
371
|
if self.completion_format == ELF_COMPLETION_FORMAT.Chat:
|
|
292
|
-
|
|
293
|
-
|
|
372
|
+
try:
|
|
373
|
+
completion = self.client.chat.completions.create(**params)
|
|
374
|
+
except Exception as ex:
|
|
375
|
+
# exception for new openai models
|
|
376
|
+
params["max_completion_tokens"]=params["max_tokens"]
|
|
377
|
+
params["temperature"]=1
|
|
378
|
+
del params["max_tokens"]
|
|
379
|
+
del params["top_p"]
|
|
380
|
+
del params["frequency_penalty"]
|
|
381
|
+
|
|
382
|
+
completion = self.client.chat.completions.create(**params)
|
|
383
|
+
|
|
294
384
|
if stream:
|
|
295
385
|
for chunk in completion:
|
|
296
386
|
# The streaming response for chat has a different structure
|
|
@@ -457,6 +547,15 @@ class OpenAIBinding(LollmsLLMBinding):
|
|
|
457
547
|
"context_length": context_length,
|
|
458
548
|
"max_generation": max_generation,
|
|
459
549
|
})
|
|
550
|
+
else:
|
|
551
|
+
models_info.append({
|
|
552
|
+
"model_name": model_id,
|
|
553
|
+
"owned_by": getattr(model, "owned_by", "N/A"),
|
|
554
|
+
"created": getattr(model, "created", "N/A"),
|
|
555
|
+
"context_length": None,
|
|
556
|
+
"max_generation": None,
|
|
557
|
+
})
|
|
558
|
+
|
|
460
559
|
except Exception as e:
|
|
461
560
|
print(f"Failed to list models: {e}")
|
|
462
561
|
|
lollms_client/lollms_core.py
CHANGED
|
@@ -280,6 +280,26 @@ class LollmsClient():
|
|
|
280
280
|
available = self.binding_manager.get_available_bindings()
|
|
281
281
|
raise ValueError(f"Failed to update LLM binding: {binding_name}. Available: {available}")
|
|
282
282
|
|
|
283
|
+
def get_ctx_size(self, model_name=None):
|
|
284
|
+
if self.binding:
|
|
285
|
+
ctx_size = self.binding.get_ctx_size(model_name)
|
|
286
|
+
return ctx_size if ctx_size else self.default_ctx_size
|
|
287
|
+
else:
|
|
288
|
+
return None
|
|
289
|
+
|
|
290
|
+
def get_model_name(self):
|
|
291
|
+
if self.binding:
|
|
292
|
+
return self.binding.model_name
|
|
293
|
+
else:
|
|
294
|
+
return None
|
|
295
|
+
|
|
296
|
+
def set_model_name(self, model_name)->bool:
|
|
297
|
+
if self.binding:
|
|
298
|
+
self.binding.model_name = model_name
|
|
299
|
+
return True
|
|
300
|
+
else:
|
|
301
|
+
return False
|
|
302
|
+
|
|
283
303
|
def update_tts_binding(self, binding_name: str, config: Optional[Dict[str, Any]] = None):
|
|
284
304
|
"""Update the TTS binding with a new configuration."""
|
|
285
305
|
self.tts = self.tts_binding_manager.create_binding(
|
|
@@ -373,10 +393,6 @@ class LollmsClient():
|
|
|
373
393
|
pass
|
|
374
394
|
|
|
375
395
|
# --- Core LLM Binding Methods ---
|
|
376
|
-
def get_ctx_size(self, model_name):
|
|
377
|
-
return self.binding.get_ctx_size(model_name)
|
|
378
|
-
|
|
379
|
-
|
|
380
396
|
def tokenize(self, text: str) -> list:
|
|
381
397
|
"""
|
|
382
398
|
Tokenize text using the active LLM binding.
|
|
@@ -518,6 +534,57 @@ class LollmsClient():
|
|
|
518
534
|
)
|
|
519
535
|
raise RuntimeError("LLM binding not initialized.")
|
|
520
536
|
|
|
537
|
+
def generate_from_messages(self,
|
|
538
|
+
messages: List[Dict],
|
|
539
|
+
n_predict: Optional[int] = None,
|
|
540
|
+
stream: Optional[bool] = None,
|
|
541
|
+
temperature: Optional[float] = None,
|
|
542
|
+
top_k: Optional[int] = None,
|
|
543
|
+
top_p: Optional[float] = None,
|
|
544
|
+
repeat_penalty: Optional[float] = None,
|
|
545
|
+
repeat_last_n: Optional[int] = None,
|
|
546
|
+
seed: Optional[int] = None,
|
|
547
|
+
n_threads: Optional[int] = None,
|
|
548
|
+
ctx_size: int | None = None,
|
|
549
|
+
streaming_callback: Optional[Callable[[str, MSG_TYPE], None]] = None,
|
|
550
|
+
**kwargs
|
|
551
|
+
) -> Union[str, dict]:
|
|
552
|
+
"""
|
|
553
|
+
Generate text using the active LLM binding, using instance defaults if parameters are not provided.
|
|
554
|
+
|
|
555
|
+
Args:
|
|
556
|
+
messages (List[Dict]): A openai compatible list of messages
|
|
557
|
+
n_predict (Optional[int]): Maximum number of tokens to generate. Uses instance default if None.
|
|
558
|
+
stream (Optional[bool]): Whether to stream the output. Uses instance default if None.
|
|
559
|
+
temperature (Optional[float]): Sampling temperature. Uses instance default if None.
|
|
560
|
+
top_k (Optional[int]): Top-k sampling parameter. Uses instance default if None.
|
|
561
|
+
top_p (Optional[float]): Top-p sampling parameter. Uses instance default if None.
|
|
562
|
+
repeat_penalty (Optional[float]): Penalty for repeated tokens. Uses instance default if None.
|
|
563
|
+
repeat_last_n (Optional[int]): Number of previous tokens to consider for repeat penalty. Uses instance default if None.
|
|
564
|
+
seed (Optional[int]): Random seed for generation. Uses instance default if None.
|
|
565
|
+
n_threads (Optional[int]): Number of threads to use. Uses instance default if None.
|
|
566
|
+
ctx_size (int | None): Context size override for this generation.
|
|
567
|
+
streaming_callback (Optional[Callable[[str, MSG_TYPE], None]]): Callback for streaming output.
|
|
568
|
+
|
|
569
|
+
Returns:
|
|
570
|
+
Union[str, dict]: Generated text or error dictionary if failed.
|
|
571
|
+
"""
|
|
572
|
+
if self.binding:
|
|
573
|
+
return self.binding.generate_from_messages(
|
|
574
|
+
messages=messages,
|
|
575
|
+
n_predict=n_predict if n_predict is not None else self.default_n_predict,
|
|
576
|
+
stream=stream if stream is not None else self.default_stream,
|
|
577
|
+
temperature=temperature if temperature is not None else self.default_temperature,
|
|
578
|
+
top_k=top_k if top_k is not None else self.default_top_k,
|
|
579
|
+
top_p=top_p if top_p is not None else self.default_top_p,
|
|
580
|
+
repeat_penalty=repeat_penalty if repeat_penalty is not None else self.default_repeat_penalty,
|
|
581
|
+
repeat_last_n=repeat_last_n if repeat_last_n is not None else self.default_repeat_last_n,
|
|
582
|
+
seed=seed if seed is not None else self.default_seed,
|
|
583
|
+
n_threads=n_threads if n_threads is not None else self.default_n_threads,
|
|
584
|
+
ctx_size = ctx_size if ctx_size is not None else self.default_ctx_size,
|
|
585
|
+
streaming_callback=streaming_callback if streaming_callback is not None else self.default_streaming_callback,
|
|
586
|
+
)
|
|
587
|
+
raise RuntimeError("LLM binding not initialized.")
|
|
521
588
|
|
|
522
589
|
def chat(self,
|
|
523
590
|
discussion: LollmsDiscussion,
|
|
@@ -1588,6 +1655,11 @@ Provide your response as a single JSON object inside a JSON markdown tag. Use th
|
|
|
1588
1655
|
"description": """Generates and stores code into a buffer to be used by another tool. You can put the uuid of the generated code into the fields that require long code among the tools. If no tool requires code as input do not use put_code_in_buffer. put_code_in_buffer do not execute the code nor does it audit it.""",
|
|
1589
1656
|
"input_schema": {"type": "object", "properties": {"prompt": {"type": "string", "description": "A detailed natural language description of the code's purpose and requirements."}, "language": {"type": "string", "description": "The programming language of the generated code. By default it uses python."}}, "required": ["prompt"]}
|
|
1590
1657
|
})
|
|
1658
|
+
available_tools.append({
|
|
1659
|
+
"name": "view_generated_code",
|
|
1660
|
+
"description": """Views the code that was generated and stored to the buffer. You need to have a valid uuid of the generated code.""",
|
|
1661
|
+
"input_schema": {"type": "object", "properties": {"code_id": {"type": "string", "description": "The case sensitive uuid of the generated code."}}, "required": ["uuid"]}
|
|
1662
|
+
})
|
|
1591
1663
|
# Add the new refactor_scratchpad tool definition
|
|
1592
1664
|
available_tools.append({
|
|
1593
1665
|
"name": "refactor_scratchpad",
|
|
@@ -1599,7 +1671,7 @@ Provide your response as a single JSON object inside a JSON markdown tag. Use th
|
|
|
1599
1671
|
formatted_tools_list += "\n**request_clarification**:\nUse if the user's request is ambiguous and you can not infer a clear idea of his intent. this tool has no parameters."
|
|
1600
1672
|
formatted_tools_list += "\n**final_answer**:\nUse when you are ready to respond to the user. this tool has no parameters."
|
|
1601
1673
|
|
|
1602
|
-
if discovery_step_id: log_event("**Discovering tools**",MSG_TYPE.MSG_TYPE_STEP_END, event_id=discovery_step_id)
|
|
1674
|
+
if discovery_step_id: log_event(f"**Discovering tools** found {len(available_tools)} tools",MSG_TYPE.MSG_TYPE_STEP_END, event_id=discovery_step_id)
|
|
1603
1675
|
|
|
1604
1676
|
# --- 2. Dynamic Reasoning Loop ---
|
|
1605
1677
|
for i in range(max_reasoning_steps):
|
|
@@ -1699,6 +1771,16 @@ Provide your response as a single JSON object inside a JSON markdown tag. Use th
|
|
|
1699
1771
|
if code_gen_id: log_event(f"Generating code...", MSG_TYPE.MSG_TYPE_TOOL_CALL, metadata={"id": code_gen_id, "result": tool_result})
|
|
1700
1772
|
if reasoning_step_id: log_event(f"**Reasoning Step {i+1}/{max_reasoning_steps}**", MSG_TYPE.MSG_TYPE_STEP_END, event_id= reasoning_step_id)
|
|
1701
1773
|
continue # Go to the next reasoning step immediately
|
|
1774
|
+
if tool_name == 'view_generated_code':
|
|
1775
|
+
code_id = tool_params.get("code_id")
|
|
1776
|
+
if code_id:
|
|
1777
|
+
tool_result = {"status": "success", "code_id": code_id, "generated_code":generated_code_store[code_uuid]}
|
|
1778
|
+
else:
|
|
1779
|
+
tool_result = {"status": "error", "code_id": code_id, "error":"Unknown uuid"}
|
|
1780
|
+
observation_text = f"```json\n{json.dumps(tool_result, indent=2)}\n```"
|
|
1781
|
+
current_scratchpad += f"\n\n### Step {i+1}: Observation\n- **Action:** Called `{tool_name}`\n- **Result:**\n{observation_text}"
|
|
1782
|
+
log_event(f"Result from `{tool_name}`:\n```\n{generated_code_store[code_uuid]}\n```\n", MSG_TYPE.MSG_TYPE_TOOL_CALL, metadata={"id": code_gen_id, "result": tool_result})
|
|
1783
|
+
continue
|
|
1702
1784
|
if tool_name == 'refactor_scratchpad':
|
|
1703
1785
|
scratchpad_cleaning_prompt = f"""Enhance this scratchpad content to be more organized and comprehensive. Keep relevant experience information and remove any useless redundancies. Try to log learned things from the context so that you won't make the same mistakes again. Do not remove the main objective information or any crucial information that may be useful for the next iterations. Answer directly with the new scratchpad content without any comments.
|
|
1704
1786
|
--- YOUR INTERNAL SCRATCHPAD (Work History & Analysis) ---
|
|
@@ -372,6 +372,7 @@ class LollmsDiscussion:
|
|
|
372
372
|
object.__setattr__(self, 'autosave', autosave)
|
|
373
373
|
object.__setattr__(self, 'max_context_size', max_context_size)
|
|
374
374
|
object.__setattr__(self, 'scratchpad', "")
|
|
375
|
+
object.__setattr__(self, 'images', [])
|
|
375
376
|
|
|
376
377
|
# Internal state
|
|
377
378
|
object.__setattr__(self, '_session', None)
|
|
@@ -1048,6 +1049,61 @@ class LollmsDiscussion:
|
|
|
1048
1049
|
self.touch()
|
|
1049
1050
|
print(f"[INFO] Discussion auto-pruned. {len(messages_to_prune)} messages summarized. History preserved.")
|
|
1050
1051
|
|
|
1052
|
+
def count_discussion_tokens(self, format_type: str, branch_tip_id: Optional[str] = None) -> int:
|
|
1053
|
+
"""Counts the number of tokens in the exported discussion content.
|
|
1054
|
+
|
|
1055
|
+
This method exports the discussion in the specified format and then uses
|
|
1056
|
+
the lollmsClient's tokenizer to count the tokens in the resulting text.
|
|
1057
|
+
|
|
1058
|
+
Args:
|
|
1059
|
+
format_type: The target format (e.g., "lollms_text", "openai_chat").
|
|
1060
|
+
branch_tip_id: The ID of the message to use as the end of the context.
|
|
1061
|
+
Defaults to the active branch ID.
|
|
1062
|
+
|
|
1063
|
+
Returns:
|
|
1064
|
+
The total number of tokens.
|
|
1065
|
+
"""
|
|
1066
|
+
exported_content = self.export(format_type, branch_tip_id)
|
|
1067
|
+
|
|
1068
|
+
text_to_count = ""
|
|
1069
|
+
if isinstance(exported_content, str):
|
|
1070
|
+
text_to_count = exported_content
|
|
1071
|
+
elif isinstance(exported_content, list):
|
|
1072
|
+
# Handle list of dicts (OpenAI/Ollama format)
|
|
1073
|
+
full_content = []
|
|
1074
|
+
for message in exported_content:
|
|
1075
|
+
content = message.get("content")
|
|
1076
|
+
if isinstance(content, str):
|
|
1077
|
+
full_content.append(content)
|
|
1078
|
+
elif isinstance(content, list): # Handle OpenAI content parts
|
|
1079
|
+
for part in content:
|
|
1080
|
+
if part.get("type") == "text":
|
|
1081
|
+
full_content.append(part.get("text", ""))
|
|
1082
|
+
text_to_count = "\n".join(full_content)
|
|
1083
|
+
|
|
1084
|
+
return self.lollmsClient.count_tokens(text_to_count)
|
|
1085
|
+
|
|
1086
|
+
def get_context_status(self, branch_tip_id: Optional[str] = None) -> Dict[str, Optional[int]]:
|
|
1087
|
+
"""Returns the current token count and the maximum context size.
|
|
1088
|
+
|
|
1089
|
+
This provides a snapshot of the context usage, taking into account
|
|
1090
|
+
any non-destructive pruning that has occurred. The token count is
|
|
1091
|
+
based on the "lollms_text" export format, which is the format used
|
|
1092
|
+
for pruning calculations.
|
|
1093
|
+
|
|
1094
|
+
Args:
|
|
1095
|
+
branch_tip_id: The ID of the message branch to measure. Defaults
|
|
1096
|
+
to the active branch.
|
|
1097
|
+
|
|
1098
|
+
Returns:
|
|
1099
|
+
A dictionary with 'current_tokens' and 'max_tokens'.
|
|
1100
|
+
"""
|
|
1101
|
+
current_tokens = self.count_discussion_tokens("lollms_text", branch_tip_id)
|
|
1102
|
+
return {
|
|
1103
|
+
"current_tokens": current_tokens,
|
|
1104
|
+
"max_tokens": self.max_context_size
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1051
1107
|
def switch_to_branch(self, branch_id):
|
|
1052
1108
|
self.active_branch_id = branch_id
|
|
1053
1109
|
|
|
@@ -1078,4 +1134,4 @@ class LollmsDiscussion:
|
|
|
1078
1134
|
new_metadata = (self.metadata or {}).copy()
|
|
1079
1135
|
new_metadata[itemname] = item_value
|
|
1080
1136
|
self.metadata = new_metadata
|
|
1081
|
-
self.commit()
|
|
1137
|
+
self.commit()
|
|
@@ -6,8 +6,8 @@ from typing import Optional, Callable, List, Union
|
|
|
6
6
|
from lollms_client.lollms_types import ELF_COMPLETION_FORMAT
|
|
7
7
|
import importlib
|
|
8
8
|
from pathlib import Path
|
|
9
|
-
from typing import Optional
|
|
10
|
-
from ascii_colors import trace_exception
|
|
9
|
+
from typing import Optional, Dict, List
|
|
10
|
+
from ascii_colors import trace_exception, ASCIIColors
|
|
11
11
|
from lollms_client.lollms_types import MSG_TYPE
|
|
12
12
|
from lollms_client.lollms_discussion import LollmsDiscussion
|
|
13
13
|
import re
|
|
@@ -73,7 +73,45 @@ class LollmsLLMBinding(ABC):
|
|
|
73
73
|
Union[str, dict]: Generated text or error dictionary if failed.
|
|
74
74
|
"""
|
|
75
75
|
pass
|
|
76
|
-
|
|
76
|
+
|
|
77
|
+
def generate_from_messages(self,
|
|
78
|
+
messages: List[Dict],
|
|
79
|
+
n_predict: Optional[int] = None,
|
|
80
|
+
stream: Optional[bool] = None,
|
|
81
|
+
temperature: Optional[float] = None,
|
|
82
|
+
top_k: Optional[int] = None,
|
|
83
|
+
top_p: Optional[float] = None,
|
|
84
|
+
repeat_penalty: Optional[float] = None,
|
|
85
|
+
repeat_last_n: Optional[int] = None,
|
|
86
|
+
seed: Optional[int] = None,
|
|
87
|
+
n_threads: Optional[int] = None,
|
|
88
|
+
ctx_size: int | None = None,
|
|
89
|
+
streaming_callback: Optional[Callable[[str, MSG_TYPE], None]] = None,
|
|
90
|
+
**kwargs
|
|
91
|
+
) -> Union[str, dict]:
|
|
92
|
+
"""
|
|
93
|
+
Generate text using the active LLM binding, using instance defaults if parameters are not provided.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
messages (List[Dict]): A openai compatible list of messages
|
|
97
|
+
n_predict (Optional[int]): Maximum number of tokens to generate. Uses instance default if None.
|
|
98
|
+
stream (Optional[bool]): Whether to stream the output. Uses instance default if None.
|
|
99
|
+
temperature (Optional[float]): Sampling temperature. Uses instance default if None.
|
|
100
|
+
top_k (Optional[int]): Top-k sampling parameter. Uses instance default if None.
|
|
101
|
+
top_p (Optional[float]): Top-p sampling parameter. Uses instance default if None.
|
|
102
|
+
repeat_penalty (Optional[float]): Penalty for repeated tokens. Uses instance default if None.
|
|
103
|
+
repeat_last_n (Optional[int]): Number of previous tokens to consider for repeat penalty. Uses instance default if None.
|
|
104
|
+
seed (Optional[int]): Random seed for generation. Uses instance default if None.
|
|
105
|
+
n_threads (Optional[int]): Number of threads to use. Uses instance default if None.
|
|
106
|
+
ctx_size (int | None): Context size override for this generation.
|
|
107
|
+
streaming_callback (Optional[Callable[[str, MSG_TYPE], None]]): Callback for streaming output.
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
Union[str, dict]: Generated text or error dictionary if failed.
|
|
111
|
+
"""
|
|
112
|
+
ASCIIColors.red("This binding does not support generate_from_messages")
|
|
113
|
+
|
|
114
|
+
|
|
77
115
|
@abstractmethod
|
|
78
116
|
def chat(self,
|
|
79
117
|
discussion: LollmsDiscussion,
|
|
@@ -115,8 +153,9 @@ class LollmsLLMBinding(ABC):
|
|
|
115
153
|
"""
|
|
116
154
|
pass
|
|
117
155
|
|
|
118
|
-
def get_ctx_size(self, model_name):
|
|
119
|
-
|
|
156
|
+
def get_ctx_size(self, model_name=None):
|
|
157
|
+
# if model_name is none use current model name
|
|
158
|
+
return None
|
|
120
159
|
|
|
121
160
|
|
|
122
161
|
@abstractmethod
|
|
@@ -20,18 +20,21 @@ examples/deep_analyze/deep_analyse.py,sha256=fZNmDrfEAuxEAfdbjAgJYIh1k6wbiuZ4Rvw
|
|
|
20
20
|
examples/deep_analyze/deep_analyze_multiple_files.py,sha256=fOryShA33P4IFxcxUDe-nJ2kW0v9w9yW8KsToS3ETl8,1032
|
|
21
21
|
examples/generate_and_speak/generate_and_speak.py,sha256=RAlvRwtEKXCh894l9M3iQbADe8CvF5N442jtRurK02I,13908
|
|
22
22
|
examples/generate_game_sfx/generate_game_fx.py,sha256=MgLNGi4hGBRoyr4bqYuCUdCSqd-ldDVfF0VSDUjgzsg,10467
|
|
23
|
+
examples/lollms_chat/calculator.py,sha256=0mIakM3XehyUaoCsBS0l3eDTrqc81E88itfdHmdMYYc,2484
|
|
24
|
+
examples/lollms_chat/derivative.py,sha256=1a4LKx_mD6Mq9oh-iGON0nfINP3Ul_TUSeDjEX7vSzE,1896
|
|
25
|
+
examples/lollms_chat/test_openai_compatible_with_lollms_chat.py,sha256=JsooHpu7Hk4HSZNXvlL6N76-K6eFyq4gOH1lcsv_BcA,419
|
|
23
26
|
examples/mcp_examples/external_mcp.py,sha256=swx1KCOz6jk8jGTAycq-xu7GXPAhRMDe1x--SKocugE,13371
|
|
24
27
|
examples/mcp_examples/local_mcp.py,sha256=w40dgayvHYe01yvekEE0LjcbkpwKjWwJ-9v4_wGYsUk,9113
|
|
25
28
|
examples/mcp_examples/openai_mcp.py,sha256=7IEnPGPXZgYZyiES_VaUbQ6viQjenpcUxGiHE-pGeFY,11060
|
|
26
29
|
examples/mcp_examples/run_remote_mcp_example_v2.py,sha256=bbNn93NO_lKcFzfIsdvJJijGx2ePFTYfknofqZxMuRM,14626
|
|
27
30
|
examples/mcp_examples/run_standard_mcp_example.py,sha256=GSZpaACPf3mDPsjA8esBQVUsIi7owI39ca5avsmvCxA,9419
|
|
28
31
|
examples/test_local_models/local_chat.py,sha256=slakja2zaHOEAUsn2tn_VmI4kLx6luLBrPqAeaNsix8,456
|
|
29
|
-
lollms_client/__init__.py,sha256=
|
|
32
|
+
lollms_client/__init__.py,sha256=KvZT0D6ahj16AharXFGhRMw2qc4a4HXDLYO75H5medY,1147
|
|
30
33
|
lollms_client/lollms_config.py,sha256=goEseDwDxYJf3WkYJ4IrLXwg3Tfw73CXV2Avg45M_hE,21876
|
|
31
|
-
lollms_client/lollms_core.py,sha256=
|
|
32
|
-
lollms_client/lollms_discussion.py,sha256=
|
|
34
|
+
lollms_client/lollms_core.py,sha256=QliAE6hYiIGqQSDWWmjii1Hj8hsj3IxwBuUFshxJDlM,169099
|
|
35
|
+
lollms_client/lollms_discussion.py,sha256=tvANNvpTkUr4L6GKowosIyfV7l3SA6cXnzElt36e2s8,52133
|
|
33
36
|
lollms_client/lollms_js_analyzer.py,sha256=01zUvuO2F_lnUe_0NLxe1MF5aHE1hO8RZi48mNPv-aw,8361
|
|
34
|
-
lollms_client/lollms_llm_binding.py,sha256=
|
|
37
|
+
lollms_client/lollms_llm_binding.py,sha256=cU0cmxZfIrp-ofutbRLx7W_59dxzPXpU-vO98MqVnQA,14788
|
|
35
38
|
lollms_client/lollms_mcp_binding.py,sha256=0rK9HQCBEGryNc8ApBmtOlhKE1Yfn7X7xIQssXxS2Zc,8933
|
|
36
39
|
lollms_client/lollms_personality.py,sha256=dILUI5DZdzJ3NDDQiIsK2UptVF-jZK3XYXZ2bpXP_ew,8035
|
|
37
40
|
lollms_client/lollms_python_analyzer.py,sha256=7gf1fdYgXCOkPUkBAPNmr6S-66hMH4_KonOMsADASxc,10246
|
|
@@ -49,13 +52,14 @@ lollms_client/llm_bindings/gemini/__init__.py,sha256=ZflZVwAkAa-GfctuehOWIav977o
|
|
|
49
52
|
lollms_client/llm_bindings/grok/__init__.py,sha256=5tIf3348RgAEaSp6FdG-LM9N8R7aR0t7OFspHf3XATs,23141
|
|
50
53
|
lollms_client/llm_bindings/groq/__init__.py,sha256=zyWKM78qHwSt5g0Bb8Njj7Jy8CYuLMyplx2maOKFFpg,12218
|
|
51
54
|
lollms_client/llm_bindings/hugging_face_inference_api/__init__.py,sha256=PxgeRqT8dpa9GZoXwtSncy9AUgAN2cDKrvp_nbaWq0E,14027
|
|
52
|
-
lollms_client/llm_bindings/litellm/__init__.py,sha256=
|
|
55
|
+
lollms_client/llm_bindings/litellm/__init__.py,sha256=pNkwyRPeENvTM4CDh6Pj3kQfxHfhX2pvXhGJDjKjp30,12340
|
|
53
56
|
lollms_client/llm_bindings/llamacpp/__init__.py,sha256=Qj5RvsgPeHGNfb5AEwZSzFwAp4BOWjyxmm9qBNtstrc,63716
|
|
54
57
|
lollms_client/llm_bindings/lollms/__init__.py,sha256=7GNv-YyX4YyaR1EP2banQEHnX47QpUyNZU6toAiX1ak,17854
|
|
58
|
+
lollms_client/llm_bindings/lollms_chat/__init__.py,sha256=UU3Ep1YkB_pAPkZEA9PpuY_f2KUXghVyzAnUD-u2-tg,23035
|
|
55
59
|
lollms_client/llm_bindings/mistral/__init__.py,sha256=624Gr462yBh52ttHFOapKgJOn8zZ1vZcTEcC3i4FYt8,12750
|
|
56
|
-
lollms_client/llm_bindings/ollama/__init__.py,sha256=
|
|
57
|
-
lollms_client/llm_bindings/open_router/__init__.py,sha256=
|
|
58
|
-
lollms_client/llm_bindings/openai/__init__.py,sha256=
|
|
60
|
+
lollms_client/llm_bindings/ollama/__init__.py,sha256=1yxw_JXye_8l1YaEznK5QhOZmLV_opY-FkYnwy530eo,36109
|
|
61
|
+
lollms_client/llm_bindings/open_router/__init__.py,sha256=v91BpNcuQCbbA6r82gbgMP8UYhSrJUMOf4UtOzEo18Q,13235
|
|
62
|
+
lollms_client/llm_bindings/openai/__init__.py,sha256=pXuLDI7Js0LLXVDCHIMMB5rAQb_wC6JqGvK8B5S0Uy0,24596
|
|
59
63
|
lollms_client/llm_bindings/openllm/__init__.py,sha256=xv2XDhJNCYe6NPnWBboDs24AQ1VJBOzsTuMcmuQ6xYY,29864
|
|
60
64
|
lollms_client/llm_bindings/pythonllamacpp/__init__.py,sha256=7dM42TCGKh0eV0njNL1tc9cInhyvBRIXzN3dcy12Gl0,33551
|
|
61
65
|
lollms_client/llm_bindings/tensor_rt/__init__.py,sha256=nPaNhGRd-bsG0UlYwcEqjd_UagCMEf5VEbBUW-GWu6A,32203
|
|
@@ -88,8 +92,8 @@ lollms_client/tts_bindings/piper_tts/__init__.py,sha256=0IEWG4zH3_sOkSb9WbZzkeV5
|
|
|
88
92
|
lollms_client/tts_bindings/xtts/__init__.py,sha256=FgcdUH06X6ZR806WQe5ixaYx0QoxtAcOgYo87a2qxYc,18266
|
|
89
93
|
lollms_client/ttv_bindings/__init__.py,sha256=UZ8o2izQOJLQgtZ1D1cXoNST7rzqW22rL2Vufc7ddRc,3141
|
|
90
94
|
lollms_client/ttv_bindings/lollms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
91
|
-
lollms_client-0.27.
|
|
92
|
-
lollms_client-0.27.
|
|
93
|
-
lollms_client-0.27.
|
|
94
|
-
lollms_client-0.27.
|
|
95
|
-
lollms_client-0.27.
|
|
95
|
+
lollms_client-0.27.3.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
|
|
96
|
+
lollms_client-0.27.3.dist-info/METADATA,sha256=mkv0Y0vIE5s2o5TwsgZmODaY7e4crlfr1G5OWwMCD8Q,25778
|
|
97
|
+
lollms_client-0.27.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
98
|
+
lollms_client-0.27.3.dist-info/top_level.txt,sha256=NI_W8S4OYZvJjb0QWMZMSIpOrYzpqwPGYaklhyWKH2w,23
|
|
99
|
+
lollms_client-0.27.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|