--- license: apache-2.0 base_model: - huihui-ai/Huihui-Qwen3-VL-8B-Instruct-abliterated pipeline_tag: image-text-to-text --- ```python # @title 🎭 Maggie VL: Flexible Storyteller (Text & Image) import json, os, torch from PIL import Image from transformers import Qwen3VLForConditionalGeneration, AutoProcessor def cek_vram(label): # Mendapatkan total kapasitas dan memori kosong dari Driver GPU t = torch.cuda.get_device_properties(0).total_memory / (1024**3) r = torch.cuda.memory_reserved() / (1024**3) a = torch.cuda.memory_allocated() / (1024**3) f = t - r # Memori yang benar-benar belum disentuh siapapun print(f"--- {label} ---") print(f"Total VRAM GPU : {t:.2f} GB") print(f"VRAM Dipesan : {r:.2f} GB (Kekuasaan PyTorch)") print(f"VRAM Terpakai : {a:.2f} GB (Isi Data/Model)") print(f"VRAM Kosong-Melompong: {f:.2f} GB (Sisa Tak Tersentuh)") cek_vram("Sebelum Generate") # 1. KONFIGURASI (Ubah di sini) PROMPT_BARU = """ cerita abad pertengahan edisi deluxe. """ IMAGE_PATH = "" #"/content/maggie_512.jpg" # Isi misal: "gudang_kain.jpg" kalau ada RESET_HISTORY = False MODEL_ID = "Heouzen/Huihui-Qwen3-VL-8B-Instruct-FP8-abliterated" # 1. Mendeteksi otomatis folder tempat script/notebook ini berada saat ini CURRENT_DIR = os.getcwd() # 2. Menggabungkan path folder saat ini dengan nama file JSON FILE = os.path.join(CURRENT_DIR, "maggie_history_cerita.json") # Opsional: Print untuk memastikan alamatnya sudah benar print(f"📁 Lokasi file JSON saat ini: {FILE}") SYSTEM_INS = """ Maggie adalah gadis berusia 19 tahun, putri Edward (46) dan Eliza (43). Edward merupakan pedagang kain dengan toko menengah, cukup mampu bersaing dengan para pedagang lainnnya tapi bukan dengan pedagang yang besar. Usaha itu dijalankan bersama istrinya, Maggie, dan beberapa pegawai. Keluarga Maggie bukan bangsawan, namun cukup untuk hidup di kelas menengah ke atas di Kerajaan Dravalor. maggie memiliki paras yang sangat cantik, rambut pirang platina, tinggi badan 165cm, dan berat 45kg. badan yang ramping. Gunakan gaya bahasa naratif sesuai dengan setting kerajaan abad pertengahan. Jangan pakai bahasa gaul modern. gunakan nama orang era medieval. ceritakan seperti novel dewasa. """ # 2. LOAD MODEL (Hidden & Smart) if 'model' not in globals(): gpu = torch.cuda.get_device_name(0) if torch.cuda.is_available() else "CPU" print(f"⏳ Menyiapkan mesin di {gpu}...") model = Qwen3VLForConditionalGeneration.from_pretrained( MODEL_ID, device_map="auto", torch_dtype="auto", trust_remote_code=True, low_cpu_mem_usage=True ) processor = AutoProcessor.from_pretrained(MODEL_ID) #clear_output() print(f"✅ {gpu} SIAP!") # 3. LOGIKA MULTIMODAL if RESET_HISTORY and os.path.exists(FILE): os.remove(FILE) msg = json.load(open(FILE)) if os.path.exists(FILE) else [ {"role": "system", "content": [{"type": "text", "text": SYSTEM_INS}]} ] # Siapkan Konten User u_content = [] img = None if IMAGE_PATH and os.path.exists(IMAGE_PATH): img = Image.open(IMAGE_PATH).convert("RGB") u_content.append({"type": "image", "image": img}) u_content.append({"type": "text", "text": PROMPT_BARU}) msg.append({"role": "user", "content": u_content}) # 4. INFERENCE LIMIT_INGATAN = 4 # Mengingat 1 tanya-jawab terakhir + yang sedang berjalan # Logika Pemangkasan: Selalu bawa Index 0 (System) + Pesan-pesan terbaru if len(msg) > (LIMIT_INGATAN + 1): msg_minimal = [msg[0]] + msg[-(LIMIT_INGATAN + 1):] else: msg_minimal = msg ''' # --- 👇 TAMBAHKAN BARIS INI UNTUK BUKTI 👇 --- print("\n" + "▼"*50) print("🔍 BUKTI DATA YANG DIBACA OLEH GPU (msg_minimal):") # Kita print menggunakan format JSON agar rapi dan mudah dibaca print(json.dumps(msg_minimal, indent=4)) print("▲"*50 + "\n") # --- 👆 SAMPAI SINI 👆 --- ''' print(f"Jumlah Parameter: {model.num_parameters():,}") # Processor butuh template gabungan prompt_text = processor.apply_chat_template(msg_minimal, tokenize=False, add_generation_prompt=True) inputs = processor(text=[prompt_text], images=[img] if img else None, padding=True, return_tensors="pt").to(model.device) print(f"✍️ {torch.cuda.get_device_name(0)} sedang menyusun adegan...") with torch.no_grad(): out_ids = model.generate(**inputs, max_new_tokens=1024, temperature=0.7, top_p=0.9, do_sample=True, repetition_penalty=1.2, eos_token_id=processor.tokenizer.eos_token_id, pad_token_id=processor.tokenizer.pad_token_id) # Potong output agar hanya teks asisten yang muncul resp = processor.batch_decode(out_ids[:, inputs.input_ids.shape[1]:], skip_special_tokens=True)[0] # 5. HASIL & SAVE print("\n" + "="*50 + f"\n[CERITA BARU]:\n\n{resp}\n" + "="*50) # Simpan teks saja ke history (biar JSON gak bengkak gara-gara data gambar) msg[-1] = {"role": "user", "content": [{"type": "text", "text": f"[User sent an image] {PROMPT_BARU}" if img else PROMPT_BARU}]} msg.append({"role": "assistant", "content": [{"type": "text", "text": resp}]}) json.dump(msg, open(FILE, "w"), indent=4) torch.cuda.empty_cache() cek_vram("Setelah Generate & Clean") ```