Spaces:
Runtime error
Runtime error
| import gradio as gr | |
| import torch | |
| from model_utils import load_model | |
| from dataset_utils import prepare_dataset, create_synthetic_dataset | |
| from training_utils import finetune_model | |
| from inference_utils import test_model | |
| from gguf_utils import convert_to_gguf | |
| from unsloth import FastLanguageModel | |
| from unsloth.chat_templates import get_chat_template | |
| from upload_utils import upload_to_huggingface, upload_gguf_to_huggingface | |
| def create_gradio_interface(): | |
| models = [ | |
| "unsloth/Meta-Llama-3.1-8B-bnb-4bit", | |
| "unsloth/Mistral-Small-Instruct-2409", | |
| "unsloth/mistral-7b-instruct-v0.3-bnb-4bit", | |
| "unsloth/Phi-3.5-mini-instruct", | |
| "unsloth/Phi-3-medium-4k-instruct", | |
| "unsloth/gemma-2-9b-bnb-4bit", | |
| "unsloth/gemma-2-27b-bnb-4bit", | |
| "unsloth/Llama-3.2-3B-Instruct", | |
| ] | |
| with gr.Blocks() as demo: | |
| gr.Markdown("# LLM Finetuner") | |
| model = gr.State(None) | |
| tokenizer = gr.State(None) | |
| dataset = gr.State(None) | |
| with gr.Tab("Settings"): | |
| hf_token = gr.Textbox(label="Hugging Face Token", type="password") | |
| model_path = gr.Dropdown(label="Model", choices=models, value="unsloth/Llama-3.2-3B-Instruct") | |
| load_model_btn = gr.Button("Load Model") | |
| load_model_output = gr.Textbox(label="Load Model Output") | |
| with gr.Tab("Dataset"): | |
| with gr.Group(): | |
| gr.Markdown("## Use Existing Dataset") | |
| dataset_source = gr.Radio(["Hugging Face", "Local File"], label="Dataset Source", value="Hugging Face") | |
| hf_dataset_path = gr.Textbox(label="Hugging Face Dataset Path", value="mlabonne/FineTome-100k") | |
| local_dataset_path = gr.File(label="Upload Local Dataset (JSON or CSV)", visible=False) | |
| prepare_dataset_btn = gr.Button("Prepare Dataset") | |
| prepare_dataset_output = gr.Textbox(label="Prepare Dataset Output") | |
| with gr.Group(): | |
| gr.Markdown("## Create Synthetic Dataset") | |
| examples = gr.Textbox(label="Example Conversations", lines=10, placeholder="Enter example conversations here...") | |
| expected_structure = gr.Textbox(label="Expected Dataset Structure", lines=5, placeholder="Enter the expected structure for the dataset...") | |
| num_samples = gr.Number(label="Number of Samples to Generate", value=100) | |
| ai_provider = gr.Radio(["OpenAI", "Anthropic", "Ollama"], label="AI Provider") | |
| api_key = gr.Textbox(label="API Key", type="password") | |
| ollama_model = gr.Textbox(label="Ollama Model Name", visible=False) | |
| create_dataset_btn = gr.Button("Create Synthetic Dataset") | |
| create_dataset_output = gr.Textbox(label="Create Dataset Output") | |
| with gr.Tab("Training"): | |
| learning_rate = gr.Number(label="Learning Rate", value=2e-4) | |
| batch_size = gr.Number(label="Batch Size", value=2) | |
| num_epochs = gr.Number(label="Number of Epochs", value=1) | |
| train_btn = gr.Button("Start Training") | |
| train_output = gr.Textbox(label="Training Output") | |
| with gr.Tab("Test"): | |
| test_input = gr.Textbox(label="Test Input") | |
| test_btn = gr.Button("Test Model") | |
| test_output = gr.Textbox(label="Model Output") | |
| with gr.Tab("GGUF Conversion"): | |
| gguf_output_path = gr.Textbox(label="GGUF Output Path") | |
| gguf_quant_method = gr.Dropdown( | |
| label="Quantization Method", | |
| choices=["q8_0", "q4_k_m", "q5_k_m", "f16"], | |
| value="q8_0" | |
| ) | |
| gguf_convert_btn = gr.Button("Convert to GGUF") | |
| gguf_output = gr.Textbox(label="GGUF Conversion Output") | |
| with gr.Tab("Upload to Hugging Face"): | |
| repo_name = gr.Textbox(label="Hugging Face Repository Name") | |
| model_type = gr.Radio(["Fine-tuned Model", "GGUF Converted Model"], label="Model Type to Upload", value="Fine-tuned Model") | |
| gguf_file_path = gr.Textbox(label="GGUF File Path (if uploading GGUF model)", visible=False) | |
| upload_btn = gr.Button("Upload to Hugging Face") | |
| upload_output = gr.Textbox(label="Upload Output") | |
| def load_model_and_tokenizer(model_path, hf_token): | |
| model_val, tokenizer_val = load_model(model_path, hf_token) | |
| tokenizer_val = get_chat_template(tokenizer_val, chat_template="llama-3.1") | |
| return model_val, tokenizer_val, "Model and tokenizer loaded successfully!" | |
| def update_ollama_visibility(choice): | |
| return gr.update(visible=(choice == "Ollama")) | |
| def update_dataset_input_visibility(choice): | |
| return gr.update(visible=(choice == "Hugging Face")), gr.update(visible=(choice == "Local File")) | |
| def update_gguf_path_visibility(choice): | |
| return gr.update(visible=(choice == "GGUF Converted Model")) | |
| load_model_btn.click( | |
| load_model_and_tokenizer, | |
| inputs=[model_path, hf_token], | |
| outputs=[model, tokenizer, load_model_output] | |
| ) | |
| dataset_source.change( | |
| update_dataset_input_visibility, | |
| inputs=[dataset_source], | |
| outputs=[hf_dataset_path, local_dataset_path] | |
| ) | |
| model_type.change( | |
| update_gguf_path_visibility, | |
| inputs=[model_type], | |
| outputs=[gguf_file_path] | |
| ) | |
| def prepare_dataset_wrapper(source, hf_path, local_file, hf_token, tokenizer_val): | |
| if tokenizer_val is None: | |
| return "Error: Model and tokenizer not loaded. Please load the model first." | |
| if source == "Hugging Face": | |
| dataset_val = prepare_dataset("huggingface", hf_path, tokenizer_val, hf_token) | |
| elif source == "Local File": | |
| if local_file is not None: | |
| dataset_val = prepare_dataset("local", local_file.name, tokenizer_val) | |
| else: | |
| return "No file uploaded. Please upload a local dataset file." | |
| else: | |
| return "Invalid dataset source selected." | |
| return dataset_val, "Dataset prepared successfully!" | |
| prepare_dataset_btn.click( | |
| prepare_dataset_wrapper, | |
| inputs=[dataset_source, hf_dataset_path, local_dataset_path, hf_token, tokenizer], | |
| outputs=[dataset, prepare_dataset_output] | |
| ) | |
| def create_synthetic_dataset_wrapper(examples, expected_structure, num_samples, ai_provider, api_key, ollama_model, tokenizer_val): | |
| if tokenizer_val is None: | |
| return "Error: Model and tokenizer not loaded. Please load the model first." | |
| dataset_val = create_synthetic_dataset(examples, expected_structure, num_samples, ai_provider, api_key, ollama_model) | |
| return dataset_val, "Synthetic dataset created successfully!" | |
| create_dataset_btn.click( | |
| create_synthetic_dataset_wrapper, | |
| inputs=[examples, expected_structure, num_samples, ai_provider, api_key, ollama_model, tokenizer], | |
| outputs=[dataset, create_dataset_output] | |
| ) | |
| ai_provider.change(update_ollama_visibility, inputs=[ai_provider], outputs=[ollama_model]) | |
| def train_model_wrapper(model_val, tokenizer_val, dataset_val, learning_rate, batch_size, num_epochs): | |
| if model_val is None or tokenizer_val is None: | |
| return "Error: Model and tokenizer not loaded. Please load the model first." | |
| if dataset_val is None: | |
| return "Error: Dataset not prepared. Please prepare or create a dataset first." | |
| try: | |
| trainer = finetune_model(model_val, tokenizer_val, dataset_val, learning_rate, batch_size, num_epochs) | |
| return "Training completed successfully!" | |
| except Exception as e: | |
| return f"Error during training: {str(e)}" | |
| train_btn.click( | |
| train_model_wrapper, | |
| inputs=[model, tokenizer, dataset, learning_rate, batch_size, num_epochs], | |
| outputs=[train_output] | |
| ) | |
| def test_model_wrapper(model_val, tokenizer_val, test_input): | |
| if model_val is None or tokenizer_val is None: | |
| return "Error: Model and tokenizer not loaded. Please load the model first." | |
| FastLanguageModel.for_inference(model_val) # Enable native 2x faster inference | |
| messages = [{"role": "user", "content": test_input}] | |
| inputs = tokenizer_val.apply_chat_template( | |
| messages, | |
| tokenize=True, | |
| add_generation_prompt=True, | |
| return_tensors="pt" | |
| ).to("cuda" if torch.cuda.is_available() else "cpu") | |
| outputs = model_val.generate(input_ids=inputs, max_new_tokens=128, temperature=1.5, min_p=0.1) | |
| return tokenizer_val.batch_decode(outputs)[0] | |
| test_btn.click( | |
| test_model_wrapper, | |
| inputs=[model, tokenizer, test_input], | |
| outputs=[test_output] | |
| ) | |
| def convert_to_gguf_wrapper(model_val, tokenizer_val, gguf_output_path, gguf_quant_method): | |
| if model_val is None or tokenizer_val is None: | |
| return "Error: Model and tokenizer not loaded. Please load the model first." | |
| output = convert_to_gguf(model_val, tokenizer_val, gguf_output_path, gguf_quant_method) | |
| return output | |
| gguf_convert_btn.click( | |
| convert_to_gguf_wrapper, | |
| inputs=[model, tokenizer, gguf_output_path, gguf_quant_method], | |
| outputs=[gguf_output] | |
| ) | |
| def upload_to_hf_wrapper(model_val, tokenizer_val, repo_name, hf_token, model_type, gguf_file_path): | |
| if model_type == "Fine-tuned Model": | |
| if model_val is None or tokenizer_val is None: | |
| return "Error: Model and tokenizer not loaded. Please load the model first." | |
| result = upload_to_huggingface(model_val, tokenizer_val, repo_name, hf_token) | |
| elif model_type == "GGUF Converted Model": | |
| if not gguf_file_path: | |
| return "Error: GGUF file path not provided. Please enter the path to the GGUF file." | |
| result = upload_gguf_to_huggingface(gguf_file_path, repo_name, hf_token) | |
| else: | |
| return "Error: Invalid model type selected." | |
| return result | |
| upload_btn.click( | |
| upload_to_hf_wrapper, | |
| inputs=[model, tokenizer, repo_name, hf_token, model_type, gguf_file_path], | |
| outputs=[upload_output] | |
| ) | |
| return demo | |
| if __name__ == "__main__": | |
| demo = create_gradio_interface() | |
| demo.launch() |