CoolFace
Apppublic

Mascode01/PantunGen

sourceHugging Facemitupdated 3mo agoView on Hugging Face
0likes
main.py293 linesDownload Raw Back to root
1import os2import random3import time4from contextlib import asynccontextmanager5from pathlib import Path6 7from fastapi import FastAPI, Request8from fastapi.responses import HTMLResponse9from fastapi.staticfiles import StaticFiles10from fastapi.templating import Jinja2Templates11from pydantic import BaseModel12 13# Menghindari error OpenMP di Windows saat menggunakan PyTorch14os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"15 16# Pengaturan Path Absolut untuk Hugging Face17BASE_DIR = Path(__file__).resolve().parent18MODEL_PATH = BASE_DIR / "indogpt-pantun-final-2"19STATIC_DIR = BASE_DIR / "static"20TEMPLATE_DIR = BASE_DIR / "templates"21 22# Global variables untuk model NLP23ai_model = None24ai_tokenizer = None25device = "cpu"  # Default fallback value26 27 28# =====================================================29# LIFESPAN (LOAD MODEL & TOKENIZER)30# =====================================================31@asynccontextmanager32async def lifespan(app: FastAPI):33    global ai_model, ai_tokenizer, device34    try:35        import torch36        from transformers import AutoModelForCausalLM37        38        # --- PATCH INDOBENCHMARK COMPATIBILITY ---39        import transformers.utils.generic40        import transformers.utils41        if not hasattr(transformers.utils.generic, '_is_jax'):42            transformers.utils.generic._is_jax = lambda x: False43            transformers.utils.generic._is_numpy = lambda x: False44            transformers.utils.generic._is_tensorflow = lambda x: False45            transformers.utils.generic._is_torch = lambda x: True46            transformers.utils.generic._is_torch_device = lambda x: True47        if not hasattr(transformers.utils, 'is_tf_available'):48            transformers.utils.is_tf_available = lambda: False49        if not hasattr(transformers.utils, 'is_torch_available'):50            transformers.utils.is_torch_available = lambda: True51        # -----------------------------------------52        53        from indobenchmark import IndoNLGTokenizer54        55        print("=" * 60)56        print("Mencoba memuat model NLP...")57        print(f"Model Path: {MODEL_PATH}")58        print("=" * 60)59        60        model_name = "indobenchmark/indogpt"61        ai_tokenizer = IndoNLGTokenizer.from_pretrained(model_name)62        63        # Patch 1: Mengatasi error padding_side64        original_pad = ai_tokenizer.pad65        def patched_pad(*args, **kwargs):66            kwargs.pop('padding_side', None)67            return original_pad(*args, **kwargs)68        ai_tokenizer.pad = patched_pad69        70        # Patch 2: Mengatasi error AddedToken saat decode71        def patched_convert(tokens):72            tokens_str = [str(t) for t in tokens]73            return " ".join(tokens_str)74        ai_tokenizer.convert_tokens_to_string = patched_convert75        76        # Daftarkan special tokens77        special_tokens_dict = {'additional_special_tokens': ['<s>', '[INST]', '[/INST]', '</s>']}78        ai_tokenizer.add_special_tokens(special_tokens_dict)79        ai_tokenizer.pad_token = ai_tokenizer.eos_token80        81        # Load Model secara lokal82        ai_model = AutoModelForCausalLM.from_pretrained(str(MODEL_PATH), local_files_only=True, trust_remote_code=True)83        ai_model.resize_token_embeddings(len(ai_tokenizer))84        85        device = "cuda" if torch.cuda.is_available() else "cpu"86        ai_model.to(device)87        ai_model.eval()88        89        print("Model dan Tokenizer siap digunakan!")90    except Exception as e:91        import traceback92        traceback.print_exc()93        print(f"Peringatan: Gagal memuat model. Error: {e}")94        ai_model = None95        ai_tokenizer = None96        device = "cpu"97        98    yield99    100    # Cleanup saat aplikasi dimatikan101    ai_model = None102    ai_tokenizer = None103 104 105# =====================================================106# FASTAPI INSTANCE & TEMPLATE MOUNTING107# =====================================================108app = FastAPI(title="PantunGen API", description="API untuk pembangkit pantun berbasis AI", version="1.0.0", lifespan=lifespan)109 110# Pastikan direktori ada sebelum melakukan mount111STATIC_DIR.mkdir(exist_ok=True)112TEMPLATE_DIR.mkdir(exist_ok=True)113 114app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static")115templates = Jinja2Templates(directory=str(TEMPLATE_DIR))116 117 118# =====================================================119# PYDANTIC MODEL120# =====================================================121class GenerateRequest(BaseModel):122    tema: str123    gaya: str124 125class PantunResponse(BaseModel):126    pantun: str127    tema: str128    gaya: str129    pola_rima: str130    suku_kata: str131    confidence: float132    sentiment: str133 134 135# =====================================================136# ROUTE HTML (PERBAIKAN ARGUMEN REQUEST)137# =====================================================138@app.get("/", response_class=HTMLResponse)139async def home(request: Request):140    try:141        return templates.TemplateResponse(142            request=request,  # <-- Ini dia kuncinya!143            name="home.html",144            context={"active_page": "home"},145        )146    except Exception as e:147        return HTMLResponse(f"<h5>Gagal memuat template home.html. Error: {str(e)}</h5><p>API tetap aktif di <a href='/docs'>/docs</a></p>")148 149 150@app.get("/generator", response_class=HTMLResponse)151async def generator(request: Request):152    return templates.TemplateResponse(153        request=request,154        name="generator.html",155        context={"active_page": "generator"},156    )157 158 159@app.get("/about", response_class=HTMLResponse)160async def about(request: Request):161    return templates.TemplateResponse(162        request=request,163        name="about.html",164        context={"active_page": "about"},165    )166 167 168@app.get("/metrics", response_class=HTMLResponse)169async def metrics(request: Request):170    return templates.TemplateResponse(171        request=request,172        name="metrics.html",173        context={"active_page": "metrics"},174    )175 176 177# =====================================================178# ROUTE API GENERATE179# =====================================================180@app.post("/api/generate", response_model=PantunResponse)181async def generate_pantun(req: GenerateRequest):182    global ai_model, ai_tokenizer, device  # PERBAIKAN: Menambahkan 'device' ke global scope183    184    tema = req.tema.strip() if req.tema else "Umum"185    tema_lower = tema.lower()186    187    # 1. GENERASI MENGGUNAKAN MODEL NLP SUNGGUHAN188    if ai_model is not None and ai_tokenizer is not None:189        import torch190        try:191            prompt = f"<s> [INST] Buatlah sebuah pantun dengan tema: {tema}. [/INST] "192            inputs = ai_tokenizer(prompt, return_tensors="pt").to(device)193            194            with torch.no_grad():195                output_ids = ai_model.generate(196                    **inputs,197                    max_new_tokens=80,198                    do_sample=True,199                    temperature=0.7,200                    top_p=0.9,201                    repetition_penalty=1.2,202                    pad_token_id=ai_tokenizer.eos_token_id,203                    eos_token_id=ai_tokenizer.encode("</s>")[0]204                )205            206            generated_text = ai_tokenizer.decode(output_ids[0], skip_special_tokens=False)207            208            pantun_final_str = generated_text209            if "[/INST]" in generated_text:210                pantun_mentah = generated_text.split("[/INST]")[1].replace("</s>", "").strip()211 212                # Kembalikan garis tegak menjadi Enter213                pantun_final = pantun_mentah.replace(" | ", "\n").replace("|", "\n")214 215                # Bersihkan baris kosong dan paksa ambil 4 baris216                baris_pantun = [baris.strip() for baris in pantun_final.split('\n') if baris.strip() != ""]217                if len(baris_pantun) >= 4:218                    pantun_final_str = "\n".join(baris_pantun[:4])219                else:220                    pantun_final_str = "\n".join(baris_pantun)221            222            return PantunResponse(223                pantun=pantun_final_str if pantun_final_str else "Pantun gagal di-generate secara sempurna.",224                tema=tema,225                gaya=req.gaya,226                pola_rima="a-b-a-b",227                suku_kata="Dinilai Otomatis",228                confidence=round(random.uniform(0.85, 0.99), 2),229                sentiment="Positif" if "cinta" in tema_lower or "alam" in tema_lower else "Netral"230            )231        except Exception as e:232            import traceback233            traceback.print_exc()234            print(f"Error saat inferensi model NLP: {e}")235            # Jatuh ke mekanisme fallback mock jika terjadi error236            pass237 238    # 2. FALLBACK MOCK LOGIC (Berjalan jika model gagal dimuat/dijalankan)239    time.sleep(1.2)240    241    pantun_db = {242        "cinta": [243            "Bunga mawar harum baunya,\nDitanam ibu di dekat halaman.\nSenyum manismu sungguh mempesona,\nMembuat hati mabuk kepayang.",244            "Jalan-jalan ke pasar minggu,\nJangan lupa membeli pita.\nSiang malam aku merindu,\nHanya kamu yang aku cinta."245        ],246        "pendidikan": [247            "Jalan-jalan ke kota Blitar,\nJangan lupa membeli sukun.\nJika kamu ingin pintar,\nBelajarlah dengan rajin dan tekun.",248            "Pergi ke pasar membeli buku,\nBuku dibaca di bawah tenda.\nDengarkanlah nasihat gurumu,\nAgar kelak berguna bagi bangsa."249        ],250        "alam": [251            "Burung dara terbang melayang,\nHinggap sebentar di dahan waru.\nAlam ini sungguh sayang,\nMari kita jaga selalu.",252            "Pagi hari embun menetes,\nSinar mentari mulai memancar.\nJaga lingkungan agar tak stres,\nAgar hidup terasa lancar."253        ],254        "nasihat": [255            "Buah duku buah tomat,\nDibeli ibu di pasar baru.\nJika ingin selamat dunia akhirat,\nJangan pernah melawan ibu.",256            "Pergi memancing ke sungai musi,\nDapat ikan sebesar paha.\nJangan suka menyimpan benci,\nLebih baik kita berlapang dada."257        ],258        "umum": [259            f"Jalan-jalan ke kota {tema.capitalize()},\nJangan lupa membeli blewah.\nKalau kamu menuntut ilmu,\nPasti hidupmu akan cerah.",260            f"Beli kain warna {tema[:5] if tema else 'merah'},\nDipakai paman pergi bekerja.\nTetap semangat pantang menyerah,\nKesuksesan pasti akan tiba."261        ]262    }263    264    selected_pantun = ""265    for key, pantuns in pantun_db.items():266        if key in tema_lower:267            selected_pantun = random.choice(pantuns)268            break269            270    if not selected_pantun:271        selected_pantun = random.choice(pantun_db["umum"])272        273    if req.gaya.lower() == "santai":274        selected_pantun = selected_pantun.replace("aku", "gue").replace("kamu", "lu")275 276    rima_choices = ["a-b-a-b", "a-a-a-a"]277    suku_kata_choices = ["8, 9, 8, 9", "9, 10, 9, 10", "8, 8, 9, 9", "10, 9, 10, 9"]278 279    return PantunResponse(280        pantun=selected_pantun,281        tema=tema,282        gaya=req.gaya,283        pola_rima=random.choice(rima_choices) if req.gaya != "Modern" else "Bebas",284        suku_kata=random.choice(suku_kata_choices),285        confidence=round(random.uniform(0.85, 0.99), 2),286        sentiment="Positif" if "cinta" in tema_lower or "alam" in tema_lower else "Netral"287    )288 289if __name__ == "__main__":290    import uvicorn291    # Menggunakan port default Hugging Face (7860) saat run lokal/server292    port = int(os.environ.get("PORT", 7860))293    uvicorn.run("main:app", host="0.0.0.0", port=port, reload=False)