oneiros / app.py
adindamochamad's picture
Deploy via HF API: runtime llama-cpp install [build-trigger]
f30e3f5 verified
Raw
History Blame Contribute Delete
9.06 kB
""" # build: 20260603-1016
Oneiros — Day 2: mimpi → SVG dream map + Markdown panel (Space & lokal).
HF Spaces: objek `demo` harus ada di level modul (bukan hanya di __main__).
"""
from __future__ import annotations
import os
import traceback
import gradio as gr
from map.format_panel import format_panel_entitas
from map.generator import generate_dream_map
from ui.gaya_oneiros import (
CONTOH_MIMPI,
CSS_ONEIROS,
PESAN_STATUS_IDLE,
TEKS_FOOTER,
TEKS_LANGKAH,
buat_teks_header,
buat_teks_latar,
format_status_error,
format_status_hasil,
tema_oneiros,
)
from ui.konstan import PANJANG_MINIMUM_MIMPI
DISCLAIMER = (
"This online demo reads your dream on our servers so you can try it in the browser. "
"Want to keep dreams only on your own computer? See the project README."
)
def _pastikan_llama_cpp() -> bool:
"""Install llama-cpp-python jika tidak ada di Docker image (fallback runtime)."""
try:
import llama_cpp # noqa: F401
return True
except ImportError:
pass
if not os.getenv("SPACE_ID"):
return False # lokal: jangan install otomatis
print("[oneiros] llama_cpp tidak ada — install runtime (1-3 menit)…")
import subprocess
wheel = (
"llama-cpp-python @ https://github.com/abetlen/llama-cpp-python"
"/releases/download/v0.3.19/llama_cpp_python-0.3.19-cp310-cp310-linux_x86_64.whl"
)
result = subprocess.run(
["pip", "install", "--no-cache-dir", "--quiet", wheel],
capture_output=True,
text=True,
timeout=300,
)
if result.returncode == 0:
print("[oneiros] llama_cpp berhasil diinstall.")
return True
print(f"[oneiros] install llama_cpp gagal: {result.stderr[:500]}")
return False
def warmup_model() -> None:
"""Muat model sekali saat startup; aman jika preload belum selesai."""
from model.loader import (
diagnosis_lingkungan_model,
get_model,
get_model_path,
reset_model_path_cache,
)
diag = diagnosis_lingkungan_model()
print(f"[oneiros] diagnosis: {diag}")
if os.getenv("ONEIROS_SKIP_WARMUP") == "1":
print("Warm-up dilewati (ONEIROS_SKIP_WARMUP=1).")
return
if not _pastikan_llama_cpp():
print("Warm-up: llama_cpp tidak tersedia, skip.")
return
try:
reset_model_path_cache()
get_model()
print(f"Model siap: {get_model_path()}")
except FileNotFoundError as e:
print(f"Warm-up: model belum tersedia — {e}")
except Exception as e:
print(f"Warm-up gagal (app tetap jalan): {type(e).__name__}: {e}")
def proses_mimpi(teks_mimpi: str, progress=gr.Progress()):
if not teks_mimpi or len(teks_mimpi.strip()) < PANJANG_MINIMUM_MIMPI:
err_html = format_status_error(
f"Please write a bit more—at least {PANJANG_MINIMUM_MIMPI} characters "
"(a sentence or two about what happened and how it felt)."
)
return "", "", err_html
try:
progress(0.10, desc="Checking dream reader…")
_pastikan_llama_cpp() # no-op jika sudah ada; install jika belum
progress(0.20, desc="Reading your dream…")
from model.extractor import extract_entities_dengan_waktu
from storage.trace_logger import log_trace
entities, raw, parse_ok, err, detik, raw_pertama = extract_entities_dengan_waktu(
teks_mimpi
)
progress(0.60, desc="Drawing the map…")
except ModuleNotFoundError:
err_html = format_status_error(
"The dream reader is still loading. Please try again in a minute."
)
return "", "", err_html
except FileNotFoundError:
err_html = format_status_error(
"We are still waking up the dream reader. Please wait a moment and try again."
)
return "", "", err_html
except Exception as e:
traceback.print_exc()
return "", "", format_status_error(
"Something went wrong while reading your dream. Please try again."
)
svg = generate_dream_map(entities)
panel = format_panel_entitas(entities)
lingkungan = "hf_space" if os.getenv("SPACE_ID") else "local"
try:
log_trace(
dream_text=teks_mimpi,
raw_model_output=raw,
entities=entities,
parse_ok=parse_ok,
parse_error=err,
elapsed_extract=detik,
elapsed_render=0.0,
environment=lingkungan,
raw_percobaan_pertama=raw_pertama,
)
except OSError as e:
print(f"Trace tidak tertulis: {e}")
progress(1.0, desc="Done")
return svg, panel, format_status_hasil(entities, parse_ok, err, detik)
def reset_form():
return "", "", "", PESAN_STATUS_IDLE
demo = gr.Blocks(
title="Oneiros",
theme=tema_oneiros(),
css=CSS_ONEIROS,
)
with demo:
gr.HTML(buat_teks_latar(), elem_classes=["oneiros-latar-host"])
gr.HTML(buat_teks_header())
gr.HTML(TEKS_LANGKAH)
if os.getenv("SPACE_ID"):
gr.Markdown(DISCLAIMER, elem_classes=["oneiros-notice"])
if not os.getenv("ONEIROS_FULL_DEPLOY"):
gr.Markdown(
"The page is open, but dream reading may not work until setup finishes. "
"If the button does nothing useful, try again in a few minutes.",
elem_classes=["oneiros-notice"],
)
with gr.Row(elem_classes=["oneiros-workspace"]):
with gr.Column(scale=5, elem_classes=["oneiros-panel"]):
gr.Markdown("Write your dream", elem_classes=["oneiros-panel-head"])
gr.Markdown(
"Tell the story in your own words—what happened, how it felt, who was there.",
elem_classes=["oneiros-panel-desc"],
)
input_mimpi = gr.Textbox(
label="Dream narrative",
placeholder=(
"I stood in a house I did not recognize, yet knew was mine. "
"The walls shifted between memory and somewhere I had never been. "
"Through a window that appeared and vanished, I saw a garden where "
"someone I loved was planting light instead of seeds…"
),
lines=12,
max_lines=22,
elem_classes=["oneiros-dream-input"],
)
gr.Markdown(
f"A few sentences work best (at least {PANJANG_MINIMUM_MIMPI} characters).",
elem_classes=["oneiros-hint"],
)
with gr.Row(elem_classes=["oneiros-actions"]):
btn_ekstrak = gr.Button(
"Understand my dream",
variant="primary",
elem_classes=["oneiros-btn-primary"],
scale=2,
)
btn_reset = gr.Button(
"Clear",
variant="secondary",
elem_classes=["oneiros-btn-secondary"],
scale=1,
)
with gr.Accordion("Sample dreams", open=False, elem_classes=["oneiros-examples"]):
gr.Examples(examples=CONTOH_MIMPI, inputs=[input_mimpi])
with gr.Column(scale=7, elem_classes=["oneiros-panel"]):
gr.Markdown("Dream map", elem_classes=["oneiros-panel-head"])
gr.Markdown(
"People, places, and images from your story—connected by feeling.",
elem_classes=["oneiros-panel-desc"],
)
output_svg = gr.HTML(
value="",
elem_classes=["oneiros-map-output"],
)
output_panel = gr.Markdown(
value="",
elem_classes=["oneiros-entity-panel"],
)
output_status = gr.HTML(value=PESAN_STATUS_IDLE)
gr.HTML(TEKS_FOOTER)
btn_ekstrak.click(
fn=proses_mimpi,
inputs=[input_mimpi],
outputs=[output_svg, output_panel, output_status],
show_progress=True,
)
btn_reset.click(
fn=reset_form,
outputs=[input_mimpi, output_svg, output_panel, output_status],
)
def _jalankan_warmup_space() -> None:
"""Warm-up di background pada Space agar startup tidak hang."""
if not os.getenv("SPACE_ID"):
return
if os.getenv("ONEIROS_SKIP_WARMUP") == "1":
return
import threading
def _kerja():
try:
warmup_model()
except ModuleNotFoundError:
print("[oneiros] warm-up: llama-cpp belum terpasang (fase boot?)")
except FileNotFoundError as e:
print(f"[oneiros] warm-up: model belum ada — {e}")
except Exception as e:
print(f"[oneiros] warm-up gagal: {type(e).__name__}: {e}")
threading.Thread(target=_kerja, daemon=True, name="oneiros-warmup").start()
_jalankan_warmup_space()
if __name__ == "__main__":
warmup_model()
demo.launch()