lollms-client 0.27.2__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.

@@ -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.2" # Updated version
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
- "name": model_name, "provider": "litellm", "rank": "1.0", "type": "api",
200
+ "model_name": model_name, "provider": "litellm", "rank": "1.0", "type": "api",
182
201
  "variants": [{
183
- "name": model_name, "size": context_size,
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
- 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
- )
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
- completion = self.client.chat.completions.create(**params)
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
 
@@ -287,6 +287,19 @@ class LollmsClient():
287
287
  else:
288
288
  return None
289
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
+
290
303
  def update_tts_binding(self, binding_name: str, config: Optional[Dict[str, Any]] = None):
291
304
  """Update the TTS binding with a new configuration."""
292
305
  self.tts = self.tts_binding_manager.create_binding(
@@ -521,6 +534,57 @@ class LollmsClient():
521
534
  )
522
535
  raise RuntimeError("LLM binding not initialized.")
523
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.")
524
588
 
525
589
  def chat(self,
526
590
  discussion: LollmsDiscussion,
@@ -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,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lollms_client
3
- Version: 0.27.2
3
+ Version: 0.27.3
4
4
  Summary: A client library for LoLLMs generate endpoint
5
5
  Author-email: ParisNeo <parisneoai@gmail.com>
6
6
  License: Apache Software License
@@ -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=FNukbXeOwWGP1i58B6V4_LtjA1QumGvROeGjoxK2wBs,1147
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=SuU5HpBHXkG9GGpSMRHiRA-qSDBFNEDis3V9ZaV_Tvw,165323
34
+ lollms_client/lollms_core.py,sha256=QliAE6hYiIGqQSDWWmjii1Hj8hsj3IxwBuUFshxJDlM,169099
32
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=eBRbiTLsaB-g-UwB2JQTdzTQ6qFvDZk14viDdcxy-ck,12451
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=xlTaKosxK1tKz1YJ6witK6wAJHIENTV6O7ZbfpUOdB4,11289
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=QufsYqak2VlA2XGbzks8u55yNJFeDH2V35NGeZABkm8,32554
57
- lollms_client/llm_bindings/open_router/__init__.py,sha256=10Dyb73zTdJATOWawJVqPgDmjN6mAw7LwQIYFIN6oJk,13274
58
- lollms_client/llm_bindings/openai/__init__.py,sha256=4Mk8eBdc9VScI0Sdh4g4p_0eU2afJeCEUEJnCQO-QkM,20014
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.2.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
92
- lollms_client-0.27.2.dist-info/METADATA,sha256=PLlEliNSNJfH4IkjgrxdrTaNW2QEoEWuF91u2zCszbI,25778
93
- lollms_client-0.27.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
94
- lollms_client-0.27.2.dist-info/top_level.txt,sha256=NI_W8S4OYZvJjb0QWMZMSIpOrYzpqwPGYaklhyWKH2w,23
95
- lollms_client-0.27.2.dist-info/RECORD,,
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,,