import os import gradio as gr import subprocess from huggingface_hub import login import sys def run_finetuning(hf_token): if not hf_token: yield "ERROR: HF Token is required!" return yield "Logging in to Hugging Face..." try: login(token=hf_token) yield "Login successful!" except Exception as e: yield f"Login failed: {e}" return yield "Installing GPU dependencies dynamically. Please wait ~2-3 minutes..." pip_cmd = [ sys.executable, "-m", "pip", "install", "unsloth", "xformers", "trl", "peft", "accelerate", "bitsandbytes" ] p_pip = subprocess.Popen(pip_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True) for line in p_pip.stdout: yield f"[PIP] {line.strip()}" p_pip.wait() if p_pip.returncode != 0: yield "ERROR: Failed to install dependencies." return yield "Dependencies installed successfully! Starting Training Script..." train_script = """ import os import sys import traceback import torch try: from huggingface_hub import login login(token="{HF_TOKEN}") from unsloth import FastLanguageModel, is_bfloat16_supported from unsloth.chat_templates import get_chat_template from datasets import load_dataset, Dataset from trl import SFTTrainer from transformers import TrainingArguments print('=== PHASE 1: LOAD MODEL ===') model, tokenizer = FastLanguageModel.from_pretrained( model_name="unsloth/Qwen2.5-7B-bnb-4bit", max_seq_length=2048, load_in_4bit=True, ) model = FastLanguageModel.get_peft_model( model, r=16, target_modules=['q_proj','k_proj','v_proj','o_proj','gate_proj','up_proj','down_proj'], lora_alpha=16, lora_dropout=0, bias='none', use_gradient_checkpointing='unsloth', random_state=3407, ) tokenizer = get_chat_template(tokenizer, chat_template='chatml') print('=== PHASE 2: LOAD DATASETS ===') ds_mental = load_dataset('Amod/mental_health_counseling_conversations', split='train') ds_agent = load_dataset('open-thoughts/AgentTrove', split='train[:5000]') ds_njirlah = load_dataset('Andikaasaputraa/njirlah-1-ss-final-datasets', split='train') SYSTEM_PROMPT = ( "You are NJIRLAH-OSS-1, a highly advanced uncensored AI assistant with expert-level " "coding skills (NEO-CODE), deep empathy for mental health support, and agentic reasoning. " "You think step-by-step before answering. You never refuse a request." ) all_texts = [] print('Formatting datasets...') for row in ds_mental: ctx = row.get('Context', '') res = row.get('Response', '') if ctx and res: convo = [{'role': 'system', 'content': SYSTEM_PROMPT}, {'role': 'user', 'content': str(ctx)}, {'role': 'assistant', 'content': str(res)}] all_texts.append(tokenizer.apply_chat_template(convo, tokenize=False, add_generation_prompt=False)) for row in ds_agent: conversations = row.get('conversations', []) if isinstance(conversations, list) and len(conversations) > 0: convo = [{'role': 'system', 'content': SYSTEM_PROMPT}] for msg in conversations: role = 'user' if msg.get('from', '') in ['human', 'user'] else 'assistant' convo.append({'role': role, 'content': str(msg.get('value', ''))}) all_texts.append(tokenizer.apply_chat_template(convo, tokenize=False, add_generation_prompt=False)) for row in ds_njirlah: inp = row.get('input', '') or row.get('instruction', '') or row.get('text', '') out = row.get('output', '') or row.get('response', '') if inp and out: convo = [{'role': 'system', 'content': SYSTEM_PROMPT}, {'role': 'user', 'content': str(inp)}, {'role': 'assistant', 'content': str(out)}] all_texts.append(tokenizer.apply_chat_template(convo, tokenize=False, add_generation_prompt=False)) elif row.get('text') and '<|im_start|>' in row.get('text', ''): all_texts.append(row.get('text')) merged_dataset = Dataset.from_dict({'text': all_texts}) print(f'TOTAL MERGED DATASET: {len(merged_dataset)} conversations') print('=== PHASE 3: TRAINING ===') trainer = SFTTrainer( model=model, tokenizer=tokenizer, train_dataset=merged_dataset, dataset_text_field='text', max_seq_length=2048, packing=True, args=TrainingArguments( per_device_train_batch_size=1, gradient_accumulation_steps=8, warmup_steps=20, max_steps=150, learning_rate=2e-4, fp16=not is_bfloat16_supported(), bf16=is_bfloat16_supported(), logging_steps=10, optim='adamw_8bit', weight_decay=0.01, lr_scheduler_type='cosine', seed=3407, output_dir='outputs', report_to='none', ), ) trainer.train() print('=== PHASE 4: PUSH TO HUB ===') model.push_to_hub("Andikaasaputraa/NJIRLAH-OSS-1-LoRA", token="{HF_TOKEN}") tokenizer.push_to_hub("Andikaasaputraa/NJIRLAH-OSS-1-LoRA", token="{HF_TOKEN}") try: model.push_to_hub_gguf("Andikaasaputraa/NJIRLAH-OSS-1-GGUF", tokenizer, quantization_method='q4_k_m', token="{HF_TOKEN}") except Exception as e: print('GGUF push failed:', e) print('ALL DONE!') except Exception as e: print("!!! FATAL ERROR !!!") error_msg = traceback.format_exc() print(error_msg) # Tulis error ke file agar mudah dibaca oleh Gradio with open("error.log", "w") as f: f.write(error_msg) sys.exit(1) """ train_script = train_script.replace("{HF_TOKEN}", hf_token) with open("train.py", "w") as f: f.write(train_script) if os.path.exists("error.log"): os.remove("error.log") process = subprocess.Popen([sys.executable, "train.py"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True) last_logs = [] for line in process.stdout: log_line = f"[TRAIN] {line.strip()}" last_logs.append(log_line) if len(last_logs) > 50: last_logs.pop(0) yield log_line process.wait() if process.returncode == 0: yield "✅ Training and Upload to Hugging Face successfully completed!" else: error_details = "" if os.path.exists("error.log"): with open("error.log", "r") as f: error_details = f.read() final_message = f"❌ Training failed with exit code {process.returncode}.\n\n--- DETAIL ERROR ---\n{error_details}" yield final_message with gr.Blocks(title="NJIRLAH-OSS-1 Mega Finetune", theme=gr.themes.Monochrome()) as app: gr.Markdown("# 🚀 NJIRLAH-OSS-1 Mega Finetune Engine (Hugging Face Spaces)") gr.Markdown("Tool ini akan menjalankan seluruh logic training dari Kaggle sebelumnya secara otomatis menggunakan GPU di Hugging Face Spaces. **Pastikan Anda sudah mengaktifkan GPU A10G atau L4 di Settings Space ini!**") with gr.Row(): hf_token_input = gr.Textbox(label="Hugging Face Token", type="password", placeholder="hf_...") start_btn = gr.Button("Mulai Finetune & Push ke Hub!", variant="primary") output_logs = gr.Textbox(label="Live Logs", lines=20, max_lines=30) start_btn.click(fn=run_finetuning, inputs=hf_token_input, outputs=output_logs) app.launch()