enhanced version

This commit is contained in:
Saifeddine ALOUI 2024-10-24 23:52:11 +02:00
parent fff7d93bb2
commit a40d67e737
8 changed files with 504 additions and 9 deletions

View File

@ -0,0 +1,495 @@
I'll create a comprehensive guide on how to build a LoLLMs binding.
# Building a LoLLMs Binding - Developer Guide
## Introduction
LoLLMs (Lord of Large Language Models) is a framework for interfacing with various language models. A binding is a connector that allows LoLLMs to interact with a specific model or API.
## Table of Contents
1. Basic Structure
2. Essential Components
3. Binding Types
4. Step-by-Step Guide
5. Advanced Features
6. Best Practices
## 1. Basic Structure
A LoLLMs binding consists of the following files:
```
binding_name/
├── __init__.py
├── binding.py
├── config.yaml
├── logo.png
└── README.md
```
## 2. Essential Components
### 2.1 Base Class
All bindings must inherit from `LLMBinding`:
```python
from lollms.binding import LLMBinding, LOLLMSConfig, BindingType
from lollms.paths import LollmsPaths
from lollms.config import BaseConfig, TypedConfig, ConfigTemplate, InstallOption
class YourBinding(LLMBinding):
def __init__(self,
config: LOLLMSConfig,
lollms_paths: LollmsPaths = None,
installation_option:InstallOption=InstallOption.INSTALL_IF_NECESSARY,
lollmsCom=None) -> None:
# Your initialization code
```
### 2.2 Configuration
Define your binding's configuration using TypedConfig:
```python
binding_config = TypedConfig(
ConfigTemplate([
{"name":"api_key","type":"str","value":"", "help":"API key"},
{"name":"temperature","type":"float","value":0.7, "min":0.0, "max":1.0},
# Add more configuration parameters
]),
BaseConfig(config={})
)
```
## 3. Binding Types
LoLLMs supports different binding types:
```python
class BindingType:
TEXT = "text" # Text only
TEXT_IMAGE = "text_image" # Text + image input
MULTIMODAL = "multimodal" # Multiple input/output modalities
```
## 4. Step-by-Step Guide
### 4.1 Create Basic Structure
```python
class YourBinding(LLMBinding):
def __init__(self, config, lollms_paths=None, installation_option=InstallOption.INSTALL_IF_NECESSARY, lollmsCom=None):
binding_config = TypedConfig(
ConfigTemplate([
# Your config parameters
]),
BaseConfig(config={})
)
super().__init__(
Path(__file__).parent,
lollms_paths,
config,
binding_config,
installation_option,
supported_file_extensions=[''],
lollmsCom=lollmsCom
)
```
### 4.2 Implement Required Methods
```python
def build_model(self, model_name=None):
"""Build or initialize the model"""
super().build_model(model_name)
# Your model initialization code
return self
def generate(self,
prompt: str,
n_predict: int = 128,
callback: Callable[[str], None] = None,
verbose: bool = False,
**gpt_params) -> str:
"""Generate text from prompt"""
# Your generation code
def tokenize(self, prompt:str):
"""Tokenize text"""
# Your tokenization code
def detokenize(self, tokens_list:list):
"""Detokenize tokens"""
# Your detokenization code
def list_models(self):
"""List available models"""
# Return list of model names
def get_available_models(self, app:LoLLMsCom=None):
"""Get detailed model information"""
# Return list of model details
```
### 4.3 Installation Support
```python
def install(self):
"""Install required packages"""
super().install()
PackageManager.install_package("your-required-package")
```
## 5. Advanced Features
### 5.1 Image Support
For bindings that support images:
```python
def generate_with_images(self,
prompt:str,
images:list=[],
n_predict: int = 128,
callback: Callable[[str, int, dict], bool] = None,
verbose: bool = False,
**gpt_params):
"""Generate text from prompt and images"""
# Your image processing code
```
### 5.2 Embedding Support
For models that support embeddings:
```python
def embed(self, text):
"""Compute text embedding"""
# Your embedding code
return embedding_vector
```
## 6. Best Practices
### 6.1 Error Handling
Always implement proper error handling:
```python
def generate(self, prompt, **kwargs):
try:
# Your generation code
except Exception as ex:
trace_exception(ex)
self.error(ex)
return ""
```
### 6.2 Configuration Validation
Validate configuration in settings_updated:
```python
def settings_updated(self):
if not self.binding_config.api_key:
self.error("API key not set!")
else:
self.build_model()
```
### 6.3 Documentation
Always include:
- README.md with usage instructions
- Docstrings for methods
- Configuration parameter descriptions
- Requirements and dependencies
### 6.4 Status Updates
Use provided methods for status updates:
```python
self.info("Information message")
self.warning("Warning message")
self.error("Error message")
self.success("Success message")
```
## Example config.yaml
```yaml
name: YourBinding
author: Your Name
version: 1.0.0
description: Description of your binding
url: https://github.com/yourusername/your-binding
license: Apache 2.0
```
I'll add a detailed section about callbacks in LoLLMs bindings.
# Callbacks in LoLLMs Bindings
## Introduction
Callbacks are crucial in LoLLMs as they enable streaming text generation, allowing the UI to update in real-time and providing control over the generation process.
## Callback Types
```python
from lollms.types import MSG_OPERATION_TYPE
class MSG_OPERATION_TYPE(Enum):
# Conditionning
MSG_OPERATION_TYPE_ADD_CHUNK = 0 # Add a chunk to the current message
MSG_OPERATION_TYPE_SET_CONTENT = 1 # sets the content of current message
MSG_OPERATION_TYPE_SET_CONTENT_INVISIBLE_TO_AI = 2 # sets the content of current message as invisible to ai
MSG_OPERATION_TYPE_SET_CONTENT_INVISIBLE_TO_USER = 3 # sets the content of current message as invisible to user
# Informations
MSG_OPERATION_TYPE_EXCEPTION = 4 # An exception occured
MSG_OPERATION_TYPE_WARNING = 5 # A warning occured
MSG_OPERATION_TYPE_INFO = 6 # An information to be shown to user
# Steps
MSG_OPERATION_TYPE_STEP = 7 # An instant step (a step that doesn't need time to be executed)
MSG_OPERATION_TYPE_STEP_START = 8 # A step has started (the text contains an explanation of the step done by he personality)
MSG_OPERATION_TYPE_STEP_PROGRESS = 9 # The progress value (the text contains a percentage and can be parsed by the reception)
MSG_OPERATION_TYPE_STEP_END_SUCCESS = 10# A step has been done (the text contains an explanation of the step done by he personality)
MSG_OPERATION_TYPE_STEP_END_FAILURE = 11# A step has been done (the text contains an explanation of the step done by he personality)
#Extra
MSG_OPERATION_TYPE_JSON_INFOS = 12# A JSON output that is useful for summarizing the process of generation used by personalities like chain of thoughts and tree of thooughts
MSG_OPERATION_TYPE_REF = 13# References (in form of [text](path))
MSG_OPERATION_TYPE_CODE = 14# A javascript code to execute
MSG_OPERATION_TYPE_UI = 15# A vue.js component to show (we need to build some and parse the text to show it)
#Commands
MSG_OPERATION_TYPE_NEW_MESSAGE = 16# A new message
MSG_OPERATION_TYPE_FINISHED_MESSAGE = 17# End of current message
```
## Implementation Examples
### 1. Basic Callback Usage
```python
def generate(self,
prompt: str,
n_predict: int = 128,
callback: Callable[[str, MSG_OPERATION_TYPE], bool] = None,
verbose: bool = False,
**gpt_params) -> str:
"""
Generate text with callback support
Args:
prompt: Input text
n_predict: Max tokens to generate
callback: Function called for each generated chunk
verbose: Enable verbose output
"""
output = ""
try:
# Example streaming response
for chunk in model.stream_generate(prompt):
if callback is not None:
# Call callback with chunk and operation type
# If callback returns False, stop generation
if not callback(chunk, MSG_OPERATION_TYPE.MSG_OPERATION_TYPE_ADD_CHUNK):
break
output += chunk
except Exception as ex:
trace_exception(ex)
self.error(ex)
return output
```
### 2. Advanced Callback Usage
```python
def generate_with_images(self,
prompt:str,
images:list=[],
n_predict: int = 128,
callback: Callable[[str, MSG_OPERATION_TYPE, dict], bool] = None,
verbose: bool = False,
**gpt_params):
"""Generate text with images and advanced callback usage"""
output = ""
try:
# Process response stream
for chunk in model.stream_response():
# Add new chunk
if chunk.type == 'text':
if callback is not None:
# Send chunk with metadata
metadata = {
'token_count': len(self.tokenize(chunk.text)),
'finish_reason': chunk.finish_reason
}
if not callback(chunk.text,
MSG_OPERATION_TYPE.MSG_OPERATION_TYPE_ADD_CHUNK,
metadata):
break
output += chunk.text
# Replace last chunk (e.g., for word corrections)
elif chunk.type == 'correction':
if callback is not None:
if not callback(chunk.text,
MSG_OPERATION_TYPE.MSG_OPERATION_TYPE_REPLACE_LAST):
break
output = output[:-len(chunk.previous)] + chunk.text
# Add new line
elif chunk.type == 'newline':
if callback is not None:
if not callback("\n",
MSG_OPERATION_TYPE.MSG_OPERATION_TYPE_NEW_LINE):
break
output += "\n"
except Exception as ex:
trace_exception(ex)
self.error(ex)
return output
```
### 3. Callback with Progress Updates
```python
def generate(self, prompt: str, n_predict: int = 128, callback=None, **kwargs):
output = ""
tokens_generated = 0
try:
for chunk in model.stream_generate(prompt):
tokens_generated += len(self.tokenize(chunk))
if callback is not None:
# Include progress information
metadata = {
'progress': tokens_generated / n_predict,
'tokens_generated': tokens_generated,
'max_tokens': n_predict
}
if not callback(chunk,
MSG_OPERATION_TYPE.MSG_OPERATION_TYPE_ADD_CHUNK,
metadata):
break
output += chunk
# Check token limit
if tokens_generated >= n_predict:
break
except Exception as ex:
trace_exception(ex)
self.error(ex)
return output
```
## Best Practices for Callbacks
1. **Always Check Callback Return Value**
```python
if callback is not None:
if not callback(chunk, MSG_OPERATION_TYPE.MSG_OPERATION_TYPE_ADD_CHUNK):
break # Stop generation if callback returns False
```
2. **Handle Different Operation Types**
```python
# Add new content
callback(chunk, MSG_OPERATION_TYPE.MSG_OPERATION_TYPE_ADD_CHUNK)
# Replace last chunk
callback(corrected_text, MSG_OPERATION_TYPE.MSG_OPERATION_TYPE_REPLACE_LAST)
# Add new line
callback("\n", MSG_OPERATION_TYPE.MSG_OPERATION_TYPE_NEW_LINE)
```
3. **Include Useful Metadata**
```python
metadata = {
'progress': current_tokens / max_tokens,
'temperature': temperature,
'token_count': token_count,
'finish_reason': finish_reason
}
callback(chunk, operation_type, metadata)
```
4. **Error Handling in Callbacks**
```python
try:
if callback is not None:
if not callback(chunk, MSG_OPERATION_TYPE.MSG_OPERATION_TYPE_ADD_CHUNK):
break
except Exception as ex:
self.error(f"Callback error: {ex}")
# Continue or break based on your needs
```
5. **Respect Token Limits**
```python
token_count = len(self.tokenize(output))
if token_count >= n_predict:
if callback is not None:
callback("", MSG_OPERATION_TYPE.MSG_OPERATION_TYPE_ADD_CHUNK,
{'finish_reason': 'length'})
break
```
## Common Use Cases
1. **Progress Display**
```python
def progress_callback(chunk, op_type, metadata=None):
if metadata and 'progress' in metadata:
print(f"Progress: {metadata['progress']*100:.2f}%")
return True
```
2. **Token Counting**
```python
def token_callback(chunk, op_type, metadata=None):
if metadata and 'token_count' in metadata:
print(f"Tokens generated: {metadata['token_count']}")
return True
```
3. **UI Updates**
```python
def ui_callback(chunk, op_type, metadata=None):
if op_type == MSG_OPERATION_TYPE.MSG_OPERATION_TYPE_ADD_CHUNK:
update_ui_text(chunk)
elif op_type == MSG_OPERATION_TYPE.MSG_OPERATION_TYPE_NEW_LINE:
update_ui_newline()
return True
```
Remember that callbacks are essential for:
- Real-time text streaming
- Progress monitoring
- User interaction
- Generation control
- UI updates
Using callbacks effectively makes your binding more interactive and user-friendly.
## Conclusion
Building a LoLLMs binding requires:
1. Implementing the base interface
2. Proper configuration management
3. Error handling
4. Documentation
5. Following best practices
For more examples, check the official LoLLMs bindings repository.
Remember to test your binding thoroughly and maintain compatibility with the LoLLMs framework's conventions and interfaces.
## Support
For help or questions about binding development:
- Visit the LoLLMs GitHub repository
- Join the community discussion
- Check existing bindings for examples
Happy binding development!

@ -1 +1 @@
Subproject commit 6c07bf0b1d84e5cb836b9b04f1ad802ba02f697d
Subproject commit 44516ab4452f31a9b5c7b678f2baaec45e99943c

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
web/dist/index.html vendored
View File

@ -6,8 +6,8 @@
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LoLLMS WebUI</title>
<script type="module" crossorigin src="/assets/index-Do2d1uFW.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-D-SRf9s3.css">
<script type="module" crossorigin src="/assets/index-D5M9NMgK.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DOUboDIx.css">
</head>
<body>
<div id="app"></div>

View File

@ -1,7 +1,7 @@
<template>
<div
:class="selected ? 'discussion-hilighted min-w-[14rem] max-w-[14rem]' : 'discussion min-w-[14rem] max-w-[14rem]'"
class="m-1 py-2 flex flex-row sm:flex-row flex-wrap flex-shrink-0 items-center rounded-md duration-75 group cursor-pointer relative"
class="m-1 py-2 flex flex-row sm:flex-row flex-wrap flex-shrink-0 items-center rounded-md duration-75 cursor-pointer relative"
:id="'dis-' + id"
@click.stop="selectEvent()"
>
@ -62,7 +62,7 @@
</div>
<!-- CONTROL BUTTONS AS SLIDING FLOATING MENU -->
<div
class="absolute top-0 right-0 h-full flex items-center"
class="absolute top-0 right-0 h-full flex items-center group"
>
<div
class="flex gap-2 items-center bg-white dark:bg-gray-800 p-2 rounded-l-md shadow-md transform translate-x-full group-hover:translate-x-0 transition-transform duration-300"

@ -1 +1 @@
Subproject commit 038c6f81498b278e189d61feb4835d96cd4ed900
Subproject commit 9d7182f972199b99022372937486ae771774f910

@ -1 +1 @@
Subproject commit f69d523ed29f2765653d25e36a21c7d4f2ef53bb
Subproject commit 775191a34df687db73f7e70587de778a4de2e04b