import json
import torch
from transformers import AutoProcessor, AutoModelForImageTextToText
from peft import PeftModel
BASE = "Qwen/Qwen3.5-0.8B"
REVISION = "2fc06364715b967f1860aea9cf38778875588b17"
ADAPTER = "Tilakoid/qwen3.5-0.8b-hoasa-lora"
SYSTEM_PROMPT = (
"Anda melakukan analisis sentimen berbasis aspek (ABSA) pada ulasan hotel "
"berbahasa Indonesia.\n\n"
"Untuk setiap ulasan, tentukan sentimen untuk SEMUA 10 aspek berikut:\n"
"- ac: pendingin ruangan (air conditioner)\n"
"- air_panas: ketersediaan dan kualitas air panas\n"
"- bau: bau tidak sedap di kamar atau area hotel\n"
"- general: kesan umum terhadap hotel secara keseluruhan\n"
"- kebersihan: kebersihan kamar dan area hotel\n"
"- linen: seprai, handuk, dan linen lainnya\n"
"- service: pelayanan staf dan resepsionis\n"
"- sunrise_meal: makanan sarapan (sunrise meal)\n"
"- tv: televisi di kamar\n"
"- wifi: koneksi internet nirkabel\n\n"
"Setiap aspek diberi tepat satu label dari:\n"
"- neg: sentimen negatif\n"
"- neut: sentimen netral, tidak disebutkan, atau tidak dapat disimpulkan\n"
"- pos: sentimen positif\n"
"- neg_pos: sentimen campuran, yaitu positif dan negatif pada aspek yang sama\n\n"
"Balas HANYA dengan satu objek JSON biasa yang memuat semua 10 kunci aspek "
"di atas sebagai nilai salah satu label. Urutan kunci bebas. Jangan menulis "
"penjelasan, kalimat pembuka, markdown, atau blok kode. Contoh bentuk "
'balasan: {"ac": "<label>", "air_panas": "<label>", "bau": "<label>", '
'"general": "<label>", "kebersihan": "<label>", "linen": "<label>", '
'"service": "<label>", "sunrise_meal": "<label>", "tv": "<label>", '
'"wifi": "<label>"}'
)
processor = AutoProcessor.from_pretrained(BASE, revision=REVISION)
tokenizer = processor.tokenizer
model = AutoModelForImageTextToText.from_pretrained(
BASE, revision=REVISION, dtype=torch.bfloat16, device_map="cuda"
)
model = PeftModel.from_pretrained(model, ADAPTER)
model.eval()
review = "Kamar bersih dan AC dingin, tetapi wifi lemot sekali dan sarapannya kurang enak."
messages = [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": review},
]
prompt = processor.apply_chat_template(
messages, tokenize=False, add_generation_prompt=True, enable_thinking=False
)
inputs = processor(text=prompt, return_tensors="pt").to(model.device)
with torch.inference_mode():
generated = model.generate(
**inputs,
max_new_tokens=256,
do_sample=False,
pad_token_id=tokenizer.eos_token_id,
)
text = tokenizer.decode(
generated[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True
).strip()
print(json.dumps(json.loads(text), indent=2, ensure_ascii=False))