Compare commits

...
12 Commits
Author SHA1 Message Date
Mervin Praison 361fa67108 Merge pull request #377 from MervinPraison/develop
Bump version to 2.0.72 and enhance CLI configuration in train and cli…
2025-02-06 07:26:59 +00:00
MervinPraison c5abcf362a Bump version to 2.0.72 and enhance CLI configuration in train and cli modules
- Updated version to 2.0.72 across multiple files (praisonai.rb, pyproject.toml, uv.lock, Dockerfile, docs)
- Refined CLI configuration handling in cli.py for config.yaml generation
- Simplified train.py main function to always use provided config path
- Improved configuration flexibility for training and model setup
2025-02-06 07:26:41 +00:00
Mervin Praison 7ed2d99a11 Merge pull request #376 from MervinPraison/develop
Enhance train.py CLI configuration handling and bump version to 2.0.71
2025-02-06 07:19:11 +00:00
MervinPraison 81307da7c8 Enhance train.py CLI configuration handling and bump version to 2.0.71
- Updated version to 2.0.71 across multiple files (praisonai.rb, pyproject.toml, uv.lock, Dockerfile, docs)
- Modified train.py to use existing config.yaml when no CLI arguments are provided
- Improved CLI configuration flexibility for training command
2025-02-06 07:18:56 +00:00
Mervin Praison fb75153b5c Merge pull request #373 from MervinPraison/develop
Bump version to 2.0.70 and update configuration handling
2025-02-05 06:28:07 +00:00
MervinPraison cddcfcf170 Bump version to 2.0.70 and update configuration handling
- Updated version to 2.0.70 across multiple files (praisonai.rb, pyproject.toml, uv.lock, Dockerfile, docs)
- Enhanced CLI configuration handling in cli.py to load existing config when not creating a new one
- Minor improvements to configuration management and deployment scripts
2025-02-05 06:27:50 +00:00
Mervin Praison 398b0473e0 Merge pull request #372 from MervinPraison/develop
Update train.mdx with Wandb configuration and requirements
2025-02-05 05:07:23 +00:00
MervinPraison c5d260782a Update train.mdx with Wandb configuration and requirements
- Added detailed requirements for training, including Huggingface token and model details
- Included Wandb login and configuration instructions
- Updated documentation with environment variables for Wandb logging
2025-02-05 05:07:08 +00:00
Mervin Praison 116ac5a64d Merge pull request #370 from MervinPraison/develop
Add Wandb Support for Training and Bump Version to 2.0.69
2025-02-04 11:18:42 +00:00
MervinPraison abf6e2e8d1 Add Wandb Support for Training and Bump Version to 2.0.69
- Updated version to 2.0.69 across multiple files (praisonai.rb, pyproject.toml, uv.lock, Dockerfile, docs)
- Enhanced train.py with optional Wandb logging support
- Added environment variable-based Wandb configuration
- Implemented dynamic Wandb reporting and run naming
2025-02-04 11:18:20 +00:00
Mervin Praison cb2b3617fa Merge pull request #369 from MervinPraison/develop
Bump version to 2.0.68 and enhance Ollama model template generation
2025-02-04 11:10:50 +00:00
MervinPraison 6de67c7d0d Bump version to 2.0.68 and enhance Ollama model template generation
- Updated version across multiple files (praisonai.rb, pyproject.toml, uv.lock, Dockerfile, docs)
- Significantly improved train.py's prepare_modelfile_content() method
- Added comprehensive template and stop token mapping for multiple model architectures
- Implemented dynamic template selection based on model name
- Enhanced Ollama model file generation with more flexible configuration
2025-02-04 11:10:26 +00:00
10 changed files with 246 additions and 48 deletions

No files matched your search

+1 -1
View File
@@ -1,6 +1,6 @@
FROM python:3.11-slim
WORKDIR /app
COPY . .
RUN pip install flask praisonai==2.0.67 gunicorn markdown
RUN pip install flask praisonai==2.0.72 gunicorn markdown
EXPOSE 8080
CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]
+1 -1
View File
@@ -110,7 +110,7 @@ Loads environment variables from .env file or system and sets them.</p>
file.write(&#34;FROM python:3.11-slim\n&#34;)
file.write(&#34;WORKDIR /app\n&#34;)
file.write(&#34;COPY . .\n&#34;)
file.write(&#34;RUN pip install flask praisonai==2.0.67 gunicorn markdown\n&#34;)
file.write(&#34;RUN pip install flask praisonai==2.0.72 gunicorn markdown\n&#34;)
file.write(&#34;EXPOSE 8080\n&#34;)
file.write(&#39;CMD [&#34;gunicorn&#34;, &#34;-b&#34;, &#34;0.0.0.0:8080&#34;, &#34;api:app&#34;]\n&#39;)
+22 -2
View File
@@ -28,8 +28,11 @@ praisonai train init
## Required
1. HF_TOKEN
2. Below config.yaml file in the same directory
1. Huggingface token
2. Base model to train on (e.g. unsloth/Meta-Llama-3.1-8B-Instruct-bnb-4bit)
3. Dataset to train on (e.g. yahma/alpaca-cleaned)
4. Huggingface model name to upload to (e.g. mervinpraison/llama3.1-instruct) (Optional)
5. Ollama model name to upload to (e.g. mervinpraison/llama3.1-instruct) (Optional)
## To upload to ollama.com (Linux)
@@ -119,4 +122,21 @@ quantization_method:
```bash
praisonai train
```
## wandb
```bash
wandb login
```
<Note>
Get the key from [here](https://wandb.ai/site/login)
</Note>
```bash
export PRAISON_WANDB=True
export WANDB_LOG_MODEL=checkpoint
export WANDB_PROJECT=praisonai-test
export PRAISON_WANDB_RUN_NAME=praisonai-train
```
+1 -1
View File
@@ -3,7 +3,7 @@ class Praisonai < Formula
desc "AI tools for various AI applications"
homepage "https://github.com/MervinPraison/PraisonAI"
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/2.0.67.tar.gz"
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/2.0.72.tar.gz"
sha256 "1828fb9227d10f991522c3f24f061943a254b667196b40b1a3e4a54a8d30ce32" # Replace with actual SHA256 checksum
license "MIT"
+15 -2
View File
@@ -189,8 +189,7 @@ class PraisonAI:
package_root = os.path.dirname(os.path.abspath(__file__))
config_yaml_destination = os.path.join(os.getcwd(), 'config.yaml')
# Create config.yaml only if it doesn't exist or --model or --dataset is provided
if not os.path.exists(config_yaml_destination) or args.model or args.dataset:
if not os.path.exists(config_yaml_destination):
config = generate_config(
model_name=args.model,
hf_model_name=args.hf,
@@ -201,6 +200,20 @@ class PraisonAI:
)
with open('config.yaml', 'w') as f:
yaml.dump(config, f, default_flow_style=False, indent=2)
elif args.model or args.hf or args.ollama or (args.dataset and args.dataset != "yahma/alpaca-cleaned"):
config = generate_config(
model_name=args.model,
hf_model_name=args.hf,
ollama_model_name=args.ollama,
dataset=[{
"name": args.dataset
}]
)
with open('config.yaml', 'w') as f:
yaml.dump(config, f, default_flow_style=False, indent=2)
else:
with open(config_yaml_destination, 'r') as f:
config = yaml.safe_load(f)
# Overwrite huggingface_save and ollama_save if --hf or --ollama are provided
if args.hf:
+1 -1
View File
@@ -56,7 +56,7 @@ class CloudDeployer:
file.write("FROM python:3.11-slim\n")
file.write("WORKDIR /app\n")
file.write("COPY . .\n")
file.write("RUN pip install flask praisonai==2.0.67 gunicorn markdown\n")
file.write("RUN pip install flask praisonai==2.0.72 gunicorn markdown\n")
file.write("EXPOSE 8080\n")
file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n')
+1 -1
View File
@@ -100,6 +100,6 @@ $PIP_FULL_PATH install "unsloth[colab-new] @ git+https://github.com/unslothai/un
$PIP_FULL_PATH install --no-deps "trl<0.9.0" peft accelerate bitsandbytes
$PIP_FULL_PATH install unsloth_zoo
$PIP_FULL_PATH install cut_cross_entropy
$PIP_FULL_PATH install sentencepiece protobuf datasets huggingface_hub hf_transfer
$PIP_FULL_PATH install sentencepiece protobuf datasets huggingface_hub hf_transfer wandb
echo "Setup completed successfully!"
+201 -36
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
This script finetunes a model using Unsloth’s fast training framework.
This script finetunes a model using Unsloth's fast training framework.
It supports both ShareGPT and Alpaca‑style datasets by converting raw conversation
data into plain-text prompts using a chat template, then pre‑tokenizing the prompts.
Extra debug logging is added to help trace the root cause of errors.
@@ -27,7 +27,7 @@ from functools import partial
#####################################
def formatting_prompts_func(examples, tokenizer):
"""
Converts each example’s conversation into a single plain-text prompt.
Converts each example's conversation into a single plain-text prompt.
If the example has a "conversations" field, process it as ShareGPT-style.
Otherwise, assume Alpaca-style data with "instruction", "input", and "output" fields.
"""
@@ -230,7 +230,9 @@ class TrainModel:
lr_scheduler_type="linear",
seed=3407,
output_dir="outputs",
report_to="none",
report_to="none" if not os.getenv("PRAISON_WANDB") else "wandb",
save_steps=100 if os.getenv("PRAISON_WANDB") else None,
run_name=os.getenv("PRAISON_WANDB_RUN_NAME", "praisonai-train") if os.getenv("PRAISON_WANDB") else None,
remove_unused_columns=False,
)
# Since the dataset is pre-tokenized, we supply a dummy dataset_text_field.
@@ -312,42 +314,205 @@ class TrainModel:
def prepare_modelfile_content(self):
output_model = self.config["hf_model_name"]
# Determine stop tokens from config or infer based on model name
model_name = self.config["model_name"].lower()
if "phi" in model_name:
inferred_stop_tokens = ["<|end|>", "<|user|>", "<|assistant|>"]
elif "llava" in model_name:
inferred_stop_tokens = ["</s>", "USER:", "ASSSISTANT:"]
elif "mistral" in model_name:
inferred_stop_tokens = ["[INST]", "[/INST]"]
elif "qwen" in model_name:
inferred_stop_tokens = ["<|endoftext|>"]
elif "deepseek" in model_name:
inferred_stop_tokens = ["<|begin▁of▁sentence|>", "<|end▁of▁sentence|>", "<|User|>", "<|Assistant|>"]
else:
inferred_stop_tokens = ["<|start_header_id|>", "<|end_header_id|>", "<|eot_id|>"]
# Use stop_tokens from config if provided, otherwise use inferred
model_stop_tokens = self.config.get("stop_tokens", inferred_stop_tokens)
gguf_path = f"{output_model}/unsloth.Q4_K_M.gguf"
if not os.path.exists(gguf_path):
self.model, self.hf_tokenizer = self.load_model()
self.save_model_gguf()
stop_parameters = "\n".join([f'PARAMETER stop "{token}"' for token in model_stop_tokens])
return f"""FROM {output_model}/unsloth.Q4_K_M.gguf
TEMPLATE \"\"\"Below are some instructions that describe some tasks. Write responses that appropriately complete each request.{{{{ if .Prompt }}}}
### Instruction:
{{{{ .Prompt }}}}
{{{{ end }}}}### Response:
{{{{ .Response }}}}\"\"\"
{stop_parameters}
# Mapping from model name keywords to their default TEMPLATE and stop tokens (and optional SYSTEM/num_ctx)
mapping = {
"llama": {
"template": """<|start_header_id|>system<|end_header_id|>
Cutting Knowledge Date: December 2023
{{ if .System }}{{ .System }}
{{- end }}
{{- if .Tools }}When you receive a tool call response, use the output to format an answer to the orginal user question.
You are a helpful assistant with tool calling capabilities.
{{- end }}<|eot_id|>
{{- range $i, $_ := .Messages }}
{{- $last := eq (len (slice $.Messages $i)) 1 }}
{{- if eq .Role "user" }}<|start_header_id|>user<|end_header_id|>
{{- if and $.Tools $last }}
Given the following functions, please respond with a JSON for a function call with its proper arguments that best answers the given prompt.
Respond in the format {"name": function name, "parameters": dictionary of argument name and its value}. Do not use variables.
{{ range $.Tools }}
{{- . }}
{{ end }}
{{ .Content }}<|eot_id|>
{{- else }}
{{ .Content }}<|eot_id|>
{{- end }}{{ if $last }}<|start_header_id|>assistant<|end_header_id|>
{{ end }}
{{- else if eq .Role "assistant" }}<|start_header_id|>assistant<|end_header_id|>
{{- if .ToolCalls }}
{{ range .ToolCalls }}
{"name": "{{ .Function.Name }}", "parameters": {{ .Function.Arguments }}}{{ end }}
{{- else }}
{{ .Content }}
{{- end }}{{ if not $last }}<|eot_id|>{{ end }}
{{- else if eq .Role "tool" }}<|start_header_id|>ipython<|end_header_id|>
{{ .Content }}<|eot_id|>{{ if $last }}<|start_header_id|>assistant<|end_header_id|>
{{ end }}
{{- end }}
{{- end }}""",
"stop_tokens": ["<|start_header_id|>", "<|end_header_id|>", "<|eot_id|>"]
},
"qwen": {
"template": """{{- if .Suffix }}<|fim_prefix|>{{ .Prompt }}<|fim_suffix|>{{ .Suffix }}<|fim_middle|>
{{- else if .Messages }}
{{- if or .System .Tools }}<|im_start|>system
{{- if .System }}
{{ .System }}
{{- end }}
{{- if .Tools }}
# Tools
You may call one or more functions to assist with the user query.
You are provided with function signatures within <tools></tools> XML tags:
<tools>
{{- range .Tools }}
{"type": "function", "function": {{ .Function }}}
{{- end }}
</tools>
For each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:
<tool_call>
{"name": <function-name>, "arguments": <args-json-object>}
</tool_call>
{{- end }}<|im_end|>
{{ end }}
{{- range $i, $_ := .Messages }}
{{- $last := eq (len (slice $.Messages $i)) 1 -}}
{{- if eq .Role "user" }}<|im_start|>user
{{ .Content }}<|im_end|>
{{ else if eq .Role "assistant" }}<|im_start|>assistant
{{ if .Content }}{{ .Content }}
{{- else if .ToolCalls }}<tool_call>
{{ range .ToolCalls }}{"name": "{{ .Function.Name }}", "arguments": {{ .Function.Arguments }}}
{{ end }}</tool_call>
{{- end }}{{ if not $last }}<|im_end|>
{{ end }}
{{- else if eq .Role "tool" }}<|im_start|>user
<tool_response>
{{ .Content }}
</tool_response><|im_end|>
{{ end }}
{{- if and (ne .Role "assistant") $last }}<|im_start|>assistant
{{ end }}
{{- end }}
{{- else }}
{{- if .System }}<|im_start|>system
{{ .System }}<|im_end|>
{{ end }}{{ if .Prompt }}<|im_start|>user
{{ .Prompt }}<|im_end|>
{{ end }}<|im_start|>assistant
{{ end }}{{ .Response }}{{ if .Response }}<|im_end|>{{ end }}""",
"system": "You are Qwen, created by Alibaba Cloud. You are a helpful assistant.",
"num_ctx": 32768,
"stop_tokens": ["<|endoftext|>"]
},
"mistral": {
"template": "[INST] {{ if .System }}{{ .System }} {{ end }}{{ .Prompt }} [/INST]",
"stop_tokens": ["[INST]", "[/INST]"]
},
"phi": {
"template": """{{- range $i, $_ := .Messages }}
{{- $last := eq (len (slice $.Messages $i)) 1 -}}
<|im_start|>{{ .Role }}<|im_sep|>
{{ .Content }}{{ if not $last }}<|im_end|>
{{ end }}
{{- if and (ne .Role "assistant") $last }}<|im_end|>
<|im_start|>assistant<|im_sep|>
{{ end }}
{{- end }}""",
"stop_tokens": ["<|im_start|>", "<|im_end|>", "<|im_sep|>"]
},
"deepseek": {
"template": """{{- if .System }}{{ .System }}{{ end }}
{{- range $i, $_ := .Messages }}
{{- $last := eq (len (slice $.Messages $i)) 1}}
{{- if eq .Role "user" }}<|User|>{{ .Content }}
{{- else if eq .Role "assistant" }}<|Assistant|>{{ .Content }}{{- if not $last }}<|end▁of▁sentence|>{{- end }}
{{- end }}
{{- if and $last (ne .Role "assistant") }}<|Assistant|>{{- end }}
{{- end }}""",
"stop_tokens": ["<|begin▁of▁sentence|>", "<|end▁of▁sentence|>", "<|User|>", "<|Assistant|>"]
},
"llava": {
"template": """{{- if .Suffix }}<|fim_prefix|>{{ .Prompt }}<|fim_suffix|>{{ .Suffix }}<|fim_middle|>
{{- else if .Messages }}
{{- if or .System .Tools }}<|im_start|>system
{{- if .System }}
{{ .System }}
{{- end }}
{{- if .Tools }}
# Tools
You may call one or more functions to assist with the user query.
You are provided with function signatures within <tools></tools> XML tags:
<tools>
{{- range .Tools }}
{"type": "function", "function": {{ .Function }}}
{{- end }}
</tools>
For each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:
<tool_call>
{"name": <function-name>, "arguments": <args-json-object>}
</tool_call>
{{- end }}<|im_end|>
{{ end }}
{{- range $i, $_ := .Messages }}
{{- $last := eq (len (slice $.Messages $i)) 1 -}}
{{- if eq .Role "user" }}<|im_start|>user
{{ .Content }}<|im_end|>
{{ else if eq .Role "assistant" }}<|im_start|>assistant
{{ if .Content }}{{ .Content }}
{{- else if .ToolCalls }}<tool_call>
{{ range .ToolCalls }}{"name": "{{ .Function.Name }}", "arguments": {{ .Function.Arguments }}}
{{ end }}</tool_call>
{{- end }}{{ if not $last }}<|im_end|>
{{ end }}
{{- else if eq .Role "tool" }}<|im_start|>user
<tool_response>
{{ .Content }}
</tool_response><|im_end|>
{{ end }}
{{- if and (ne .Role "assistant") $last }}<|im_start|>assistant
{{ end }}
{{- end }}
{{- else }}
{{- if .System }}<|im_start|>system
{{ .System }}<|im_end|>
{{ end }}{{ if .Prompt }}<|im_start|>user
{{ .Prompt }}<|im_end|>
{{ end }}<|im_start|>assistant
{{ end }}{{ .Response }}{{ if .Response }}<|im_end|>{{ end }}""",
"stop_tokens": ["</s>", "USER:", "ASSSISTANT:"]
}
}
# Select mapping by checking if any key is in the model_name.
chosen = None
for key, settings in mapping.items():
if key in model_name:
chosen = settings
break
if chosen is None:
# Fallback default
chosen = {
"template": """{{ if .System }}<|start_header_id|>system<|end_header_id|>
{{ .System }}<|eot_id|>{{ end }}{{ if .Prompt }}<|start_header_id|>user<|end_header_id|>
{{ .Prompt }}<|eot_id|>{{ end }}<|start_header_id|>assistant<|end_header_id|>
{{ .Response }}<|eot_id|>""",
"stop_tokens": ["<|start_header_id|>", "<|end_header_id|>", "<|eot_id|>"]
}
# Build the stop parameter lines.
stop_params = "\n".join([f"PARAMETER stop {token}" for token in chosen["stop_tokens"]])
# Optionally include a SYSTEM line and num_ctx if defined in the mapping.
system_line = ""
if "system" in chosen:
system_line = f"SYSTEM {chosen['system']}\n"
num_ctx_line = ""
if "num_ctx" in chosen:
num_ctx_line = f"PARAMETER num_ctx {chosen['num_ctx']}\n"
# Assemble and return the modelfile content.
return f"""FROM {output_model}
TEMPLATE \"\"\"{chosen['template']}\"\"\"
{system_line}{num_ctx_line}{stop_params}
"""
def create_and_push_ollama_model(self):
modelfile_content = self.prepare_modelfile_content()
with open("Modelfile", "w") as file:
+2 -2
View File
@@ -1,6 +1,6 @@
[project]
name = "PraisonAI"
version = "2.0.67"
version = "2.0.72"
description = "PraisonAI is an AI Agents Framework with Self Reflection. PraisonAI application combines PraisonAI Agents, AutoGen, and CrewAI into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customisation, and efficient human-agent collaboration."
readme = "README.md"
license = ""
@@ -84,7 +84,7 @@ autogen = ["pyautogen>=0.2.19", "praisonai-tools>=0.0.7", "crewai"]
[tool.poetry]
name = "PraisonAI"
version = "2.0.67"
version = "2.0.72"
description = "PraisonAI is an AI Agents Framework with Self Reflection. PraisonAI application combines PraisonAI Agents, AutoGen, and CrewAI into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customisation, and efficient human–agent collaboration."
authors = ["Mervin Praison"]
license = ""
Generated
+1 -1
View File
@@ -3060,7 +3060,7 @@ wheels = [
[[package]]
name = "praisonai"
version = "2.0.67"
version = "2.0.72"
source = { editable = "." }
dependencies = [
{ name = "instructor" },