Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,284 +1,6 @@
|
|
| 1 |
-
#
|
| 2 |
-
"""app.ipynb
|
| 3 |
-
|
| 4 |
-
Automatically generated by Colab.
|
| 5 |
-
|
| 6 |
-
Original file is located at
|
| 7 |
-
https://colab.research.google.com/drive/1y3yISz14Lpsr131OIJCKA77lwbFmEJzB
|
| 8 |
-
"""
|
| 9 |
-
|
| 10 |
import streamlit as st
|
| 11 |
-
import os
|
| 12 |
-
import joblib
|
| 13 |
-
import torch
|
| 14 |
-
import numpy as np
|
| 15 |
-
import html
|
| 16 |
-
from transformers import AutoTokenizer, AutoModel, logging as hf_logging
|
| 17 |
-
|
| 18 |
-
# Hugging Face Transformers λ‘κΉ
λ 벨 μ€μ (μ€λ₯λ§ νμ)
|
| 19 |
-
hf_logging.set_verbosity_error()
|
| 20 |
-
|
| 21 |
-
# ββββββββββ μ€μ (Hugging Face Spaces νκ²½μ λ§κ² μ‘°μ ) ββββββββββ
|
| 22 |
-
MODEL_NAME = "bert-base-uncased"
|
| 23 |
-
DEVICE = "cpu" # Hugging Face Spaces λ¬΄λ£ ν°μ΄λ CPU μ¬μ©
|
| 24 |
-
SAVE_DIR = "μ μ₯μ μ₯1" # μ
λ‘λν ν΄λλͺ
κ³Ό μΌμΉν΄μΌ ν¨
|
| 25 |
-
LAYER_ID = 4 # μλ³Έ μ½λμ SeparationScore μ΅κ³ λ μ΄μ΄
|
| 26 |
-
SEED = 0 # μλ³Έ μ½λμ SEED κ°
|
| 27 |
-
CLF_NAME = "linear" # μλ³Έ μ½λμ CLF_NAME
|
| 28 |
-
|
| 29 |
-
# ββββββββββ λͺ¨λΈ λ‘λ (Streamlit μΊμ μ¬μ©μΌλ‘ μ± μ 체μμ ν λ²λ§ μ€ν) ββββββββββ
|
| 30 |
-
@st.cache_resource
|
| 31 |
-
def load_all_models_and_data():
|
| 32 |
-
"""
|
| 33 |
-
LDA, λΆλ₯κΈ°, ν ν¬λμ΄μ , BERT λͺ¨λΈ λ° κ΄λ ¨ νλ ¬λ€μ λ‘λν©λλ€.
|
| 34 |
-
Hugging Face Spacesμ λ°°ν¬ μ νμΌ κ²½λ‘κ° μ νν΄μΌ ν©λλ€.
|
| 35 |
-
"""
|
| 36 |
-
lda_file_path = os.path.join(SAVE_DIR, f"lda_layer{LAYER_ID}_seed{SEED}.pkl")
|
| 37 |
-
clf_file_path = os.path.join(SAVE_DIR, f"{CLF_NAME}_layer{LAYER_ID}_projlda_seed{SEED}.pkl")
|
| 38 |
-
|
| 39 |
-
# νμΌ μ‘΄μ¬ μ¬λΆ νμΈ (λ°°ν¬ νκ²½ λλ²κΉ
μ©)
|
| 40 |
-
if not os.path.isdir(SAVE_DIR):
|
| 41 |
-
st.error(f"μ€λ₯: λͺ¨λΈ μ μ₯ λλ ν 리 '{SAVE_DIR}'λ₯Ό μ°Ύμ μ μμ΅λλ€. Spacesμ ν΄λκ° μ¬λ°λ₯΄κ² μ
λ‘λλμλμ§, μ΄λ¦μ΄ μΌμΉνλμ§ νμΈνμΈμ.")
|
| 42 |
-
return None
|
| 43 |
-
if not os.path.exists(lda_file_path):
|
| 44 |
-
st.error(f"μ€λ₯: LDA λͺ¨λΈ νμΌ '{lda_file_path}'λ₯Ό μ°Ύμ μ μμ΅λλ€. νμΌ μ΄λ¦κ³Ό κ²½λ‘λ₯Ό νμΈνμΈμ.")
|
| 45 |
-
return None
|
| 46 |
-
if not os.path.exists(clf_file_path):
|
| 47 |
-
st.error(f"μ€λ₯: λΆλ₯κΈ° λͺ¨λΈ νμΌ '{clf_file_path}'λ₯Ό μ°Ύμ μ μμ΅λλ€. νμΌ μ΄λ¦κ³Ό κ²½λ‘λ₯Ό νμΈνμΈμ.")
|
| 48 |
-
return None
|
| 49 |
-
|
| 50 |
-
try:
|
| 51 |
-
lda = joblib.load(lda_file_path)
|
| 52 |
-
clf = joblib.load(clf_file_path)
|
| 53 |
-
except Exception as e:
|
| 54 |
-
st.error(f"λͺ¨λΈ νμΌ λ‘λ μ€ μ€λ₯ λ°μ: {e}")
|
| 55 |
-
st.error("νμΌμ΄ μμλμκ±°λ, joblib λ²μ νΈνμ± λ¬Έμ κ° μμ μ μμ΅λλ€.")
|
| 56 |
-
return None
|
| 57 |
-
|
| 58 |
-
if hasattr(clf, "base_estimator"): # Calibrated Ridge κ²½μ°
|
| 59 |
-
clf = clf.base_estimator
|
| 60 |
-
|
| 61 |
-
# LDA νλ ¬Β·νκ· , λΆλ₯κΈ° κ°μ€μΉλ₯Ό PyTorch Tensorλ‘ λ³ν
|
| 62 |
-
W_tensor = torch.tensor(lda.scalings_, dtype=torch.float32, device=DEVICE)
|
| 63 |
-
mu_vector = torch.tensor(lda.xbar_, dtype=torch.float32, device=DEVICE)
|
| 64 |
-
w_p_tensor = torch.tensor(clf.coef_, dtype=torch.float32, device=DEVICE)
|
| 65 |
-
b_p_vector = torch.tensor(clf.intercept_, dtype=torch.float32, device=DEVICE)
|
| 66 |
-
|
| 67 |
-
# Hugging Face ν ν¬λμ΄μ λ° BERT λͺ¨λΈ λ‘λ
|
| 68 |
-
try:
|
| 69 |
-
tokenizer_obj = AutoTokenizer.from_pretrained(MODEL_NAME, use_fast=True)
|
| 70 |
-
model_obj = AutoModel.from_pretrained(
|
| 71 |
-
MODEL_NAME, output_hidden_states=True
|
| 72 |
-
).to(DEVICE).eval()
|
| 73 |
-
except Exception as e:
|
| 74 |
-
st.error(f"Hugging Face λͺ¨λΈ ({MODEL_NAME}) λ‘λ μ€ μ€λ₯: {e}")
|
| 75 |
-
st.error("μΈν°λ· μ°κ²° λλ λͺ¨λΈ μ΄λ¦μ΄ μ¬λ°λ₯Έμ§ νμΈνμΈμ.")
|
| 76 |
-
return None
|
| 77 |
-
|
| 78 |
-
# ν΄λμ€ μ΄λ¦ κ°μ Έμ€κΈ° μλ
|
| 79 |
-
class_names = None
|
| 80 |
-
if hasattr(lda, 'classes_'): # scikit-learn LDAμ κ²½μ°
|
| 81 |
-
class_names = lda.classes_
|
| 82 |
-
elif hasattr(clf, 'classes_'): # scikit-learn λΆλ₯κΈ°μ κ²½μ°
|
| 83 |
-
class_names = clf.classes_
|
| 84 |
-
|
| 85 |
-
return tokenizer_obj, model_obj, W_tensor, mu_vector, w_p_tensor, b_p_vector, class_names
|
| 86 |
-
|
| 87 |
-
# ββββββββββ ν΅μ¬ λΆμ ν¨μ (μλ³Έ μ½λ κΈ°λ°) ββββββββββ
|
| 88 |
-
def explain_sentence_streamlit(
|
| 89 |
-
text: str,
|
| 90 |
-
tokenizer, model, W, mu, w_p, b_p, # λ‘λλ κ°μ²΄λ€
|
| 91 |
-
layer_id_to_use: int, device_to_use: str, # μ€μ κ°
|
| 92 |
-
top_k_tokens: int = 5
|
| 93 |
-
) -> tuple[str, int, float, list] | None: # κ²°κ³Ό νμ
λͺ
μ (μ€ν¨ μ None)
|
| 94 |
-
"""
|
| 95 |
-
μ
λ ₯ λ¬Έμ₯μ μμΈ‘νκ³ ν ν° μ€μλλ₯Ό κ³μ°νμ¬ κ²°κ³Όλ₯Ό λ°νν©λλ€.
|
| 96 |
-
"""
|
| 97 |
-
try:
|
| 98 |
-
# 1) ν ν°ν (μ΅λ κΈΈμ΄ λ° μλ¦Ό μ²λ¦¬ μΆκ°)
|
| 99 |
-
enc = tokenizer(text, return_tensors="pt", truncation=True, max_length=510, padding=True) # BERT μ΅λ κΈΈμ΄ 512 κ³ λ €, CLS/SEP κ³΅κ° ν보
|
| 100 |
-
input_ids = enc["input_ids"].to(device_to_use)
|
| 101 |
-
attn_mask = enc["attention_mask"].to(device_to_use)
|
| 102 |
-
|
| 103 |
-
if input_ids.shape[1] == 0: # μ
λ ₯μ΄ λ무 μ§§κ±°λ λͺ¨λ νν°λ§ λ κ²½μ°
|
| 104 |
-
# Streamlit μ±μμλ μ¬μ©μμκ² κ²½κ³ λ₯Ό νμν μ μμ΅λλ€.
|
| 105 |
-
# st.warning("ν ν°ν κ²°κ³Ό μ ν¨ν ν ν°μ΄ οΏ½οΏ½μ΅λλ€. λ€λ₯Έ λ¬Έμ₯μ μλν΄λ³΄μΈμ.")
|
| 106 |
-
return None
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
# 2) μλ² λ©μ gradient μΆμ
|
| 110 |
-
input_embeds = model.embeddings.word_embeddings(input_ids).clone().detach()
|
| 111 |
-
input_embeds.requires_grad_(True)
|
| 112 |
-
|
| 113 |
-
# 3) Forward pass β CLS λ²‘ν° μΆμΆ
|
| 114 |
-
outputs = model(inputs_embeds=input_embeds,
|
| 115 |
-
attention_mask=attn_mask, # Attention mask μ λ¬
|
| 116 |
-
output_hidden_states=True)
|
| 117 |
-
cls_vec = outputs.hidden_states[layer_id_to_use][:, 0, :] # (1, 768)
|
| 118 |
-
|
| 119 |
-
# 4) LDA ν¬μ β λΆλ₯ logit κ³μ°
|
| 120 |
-
z_projected = (cls_vec - mu) @ W # (1, d)
|
| 121 |
-
logit_output = z_projected @ w_p.T + b_p # (1, C)
|
| 122 |
-
|
| 123 |
-
probs = torch.softmax(logit_output, dim=1)
|
| 124 |
-
pred_idx = torch.argmax(probs, dim=1).item()
|
| 125 |
-
pred_prob = probs[0, pred_idx].item()
|
| 126 |
-
|
| 127 |
-
# 5) Gradient κ³μ°
|
| 128 |
-
if input_embeds.grad is not None:
|
| 129 |
-
input_embeds.grad.zero_() # μ΄μ κ·ΈλλμΈνΈ μ΄κΈ°ν
|
| 130 |
-
logit_output[0, pred_idx].backward() # μ νλ μμΈ‘ ν΄λμ€μ λν κ·ΈλλμΈνΈ κ³μ°
|
| 131 |
-
|
| 132 |
-
if input_embeds.grad is None: # backward νμλ gradκ° μλ μμΈμ μν© λ°©μ§
|
| 133 |
-
# st.error("κ·ΈλλμΈνΈλ₯Ό κ³μ°ν μ μμ΅λλ€.") # Streamlit μ± λ΄μμ μ€λ₯ νμ
|
| 134 |
-
return None
|
| 135 |
-
|
| 136 |
-
grads = input_embeds.grad.clone().detach()
|
| 137 |
-
|
| 138 |
-
# 6) Grad Γ Input β μ€μλ μ μ κ³μ°
|
| 139 |
-
scores = (grads * input_embeds.detach()).norm(dim=2).squeeze(0)
|
| 140 |
-
scores_np = scores.cpu().numpy()
|
| 141 |
-
|
| 142 |
-
# μ ν¨ν μ μλ§μΌλ‘ μ κ·ν (NaN/Inf λ°©μ§)
|
| 143 |
-
valid_scores = scores_np[np.isfinite(scores_np)]
|
| 144 |
-
if len(valid_scores) > 0 and valid_scores.max() > 0:
|
| 145 |
-
scores_np = scores_np / (valid_scores.max() + 1e-9) # 0~1 μ κ·ν
|
| 146 |
-
else: # λͺ¨λ μ μκ° 0μ΄κ±°λ μ ν¨νμ§ μμ κ²½μ°
|
| 147 |
-
scores_np = np.zeros_like(scores_np)
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
# 7) HTML νμ΄λΌμ΄νΈ μμ±
|
| 151 |
-
tokens = tokenizer.convert_ids_to_tokens(input_ids[0], skip_special_tokens=False) # μ€νμ
ν ν° ν¬ν¨
|
| 152 |
-
html_tokens_list = []
|
| 153 |
-
|
| 154 |
-
# CLS, SEP, PAD ν ν° ID νμΈ
|
| 155 |
-
cls_token_id = tokenizer.cls_token_id
|
| 156 |
-
sep_token_id = tokenizer.sep_token_id
|
| 157 |
-
pad_token_id = tokenizer.pad_token_id
|
| 158 |
-
|
| 159 |
-
for i, tok_str in enumerate(tokens):
|
| 160 |
-
if input_ids[0, i] == pad_token_id: # PAD ν ν°μ 건λλ°κΈ°
|
| 161 |
-
continue
|
| 162 |
-
|
| 163 |
-
clean_tok_str = tok_str.replace("##", "") if "##" not in tok_str else tok_str[2:]
|
| 164 |
-
|
| 165 |
-
# μ€νμ
ν ν°μ λ€λ₯Έ μ€νμΌ μ μ© λλ μ€μλ κ³μ°μμ μ μΈ κ°λ₯
|
| 166 |
-
if input_ids[0, i] == cls_token_id or input_ids[0, i] == sep_token_id:
|
| 167 |
-
html_tokens_list.append(f"<span style='font-weight:bold;'>{html.escape(clean_tok_str)}</span>")
|
| 168 |
-
else:
|
| 169 |
-
score_val = scores_np[i] if i < len(scores_np) else 0 # μ μ λ°°μ΄ λ²μ νμΈ
|
| 170 |
-
color = f"rgba(255, 0, 0, {max(0, min(1, score_val)):.2f})" # μ μ λ²μ 0~1λ‘ ν΄λ¦¬ν
|
| 171 |
-
html_tokens_list.append(
|
| 172 |
-
f"<span style='background-color:{color}; padding: 1px 2px; margin: 1px; border-radius: 3px; display:inline-block;'>{html.escape(clean_tok_str)}</span>"
|
| 173 |
-
)
|
| 174 |
-
|
| 175 |
-
html_output_str = " ".join(html_tokens_list)
|
| 176 |
-
# λΆνμν 곡백 μ 리 (μ: subword μ¬μ΄ 곡백)
|
| 177 |
-
html_output_str = html_output_str.replace(" ##", "")
|
| 178 |
-
|
| 179 |
-
# Top-K μ€μ ν ν° μ 보 (μ€νμ
ν ν° λ° PAD ν ν° μ μΈ)
|
| 180 |
-
top_tokens_info_list = []
|
| 181 |
-
valid_indices_for_top_k = [
|
| 182 |
-
idx for idx, token_id in enumerate(input_ids[0].tolist())
|
| 183 |
-
if token_id not in [cls_token_id, sep_token_id, pad_token_id] and idx < len(scores_np)
|
| 184 |
-
]
|
| 185 |
-
|
| 186 |
-
# μ μκ° λμ μμΌλ‘ μ λ ¬
|
| 187 |
-
sorted_valid_indices = sorted(valid_indices_for_top_k, key=lambda idx: -scores_np[idx])
|
| 188 |
-
|
| 189 |
-
for token_idx in sorted_valid_indices[:top_k_tokens]:
|
| 190 |
-
top_tokens_info_list.append({
|
| 191 |
-
"token": tokens[token_idx],
|
| 192 |
-
"score": f"{scores_np[token_idx]:.3f}"
|
| 193 |
-
})
|
| 194 |
-
|
| 195 |
-
return html_output_str, pred_idx, pred_prob, top_tokens_info_list
|
| 196 |
-
|
| 197 |
-
except Exception as e:
|
| 198 |
-
# Streamlit μ± λ΄μμ μ€λ₯λ₯Ό λ μ νμνλλ‘ μμ
|
| 199 |
-
# st.error(f"λ¬Έμ₯ λΆμ μ€ μκΈ°μΉ μμ μ€λ₯ λ°μ: {e}")
|
| 200 |
-
# import traceback
|
| 201 |
-
# st.text_area("μ€λ₯ μμΈ μ 보 (λλ²κΉ
μ©):", traceback.format_exc(), height=200)
|
| 202 |
-
# print(f"λ¬Έμ₯ λΆμ μ€ μκΈ°μΉ μμ μ€λ₯ λ°μ: {e}") # μ½μ λ‘κΉ
(Spaces λ‘κ·Έμμ νμΈ κ°λ₯)
|
| 203 |
-
# import traceback
|
| 204 |
-
# print(traceback.format_exc()) # μ½μ λ‘κΉ
|
| 205 |
-
raise # μ€λ₯λ₯Ό λ€μ λ°μμμΌ Streamlitμ΄ μ²λ¦¬νλλ‘ νκ±°λ, μλμμ Noneμ λ°ν
|
| 206 |
-
# return None
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
# ββββββββββ Streamlit UI κ΅¬μ± ββββββββββ
|
| 210 |
-
st.set_page_config(page_title="λ¬Έμ₯ ν ν° μ€μλ λΆμκΈ°", layout="wide")
|
| 211 |
-
st.title("π λ¬Έμ₯ ν ν° μ€μλ λΆμκΈ°")
|
| 212 |
-
st.markdown("BERTμ LDAλ₯Ό νμ©νμ¬ λ¬Έμ₯ λ΄ κ° ν ν°μ μ€μλλ₯Ό μκ°νν©λλ€.")
|
| 213 |
-
|
| 214 |
-
# λͺ¨λΈ λ‘λ μλ
|
| 215 |
-
loaded_data_tuple = load_all_models_and_data()
|
| 216 |
-
|
| 217 |
-
if loaded_data_tuple:
|
| 218 |
-
tokenizer, model, W, mu, w_p, b_p, class_names = loaded_data_tuple
|
| 219 |
-
|
| 220 |
-
# μ¬μ΄λλ°μ λͺ¨λΈ μ 보 νμ
|
| 221 |
-
st.sidebar.header("βοΈ λͺ¨λΈ λ° μ€μ μ 보")
|
| 222 |
-
st.sidebar.info(f"**BERT λͺ¨λΈ:** `{MODEL_NAME}`\n\n"
|
| 223 |
-
f"**μ¬μ©λ λ μ΄μ΄ ID:** `{LAYER_ID}`\n\n"
|
| 224 |
-
f"**λΆλ₯κΈ° μ’
λ₯:** `{CLF_NAME}` (LDA ν¬μ κΈ°λ°)\n\n"
|
| 225 |
-
f"**μ€ν μ₯μΉ:** `{DEVICE.upper()}`")
|
| 226 |
-
if class_names is not None:
|
| 227 |
-
st.sidebar.markdown(f"**μμΈ‘ κ°λ₯ ν΄λμ€:** `{', '.join(map(str, class_names))}`")
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
# μ¬μ©μ μ
λ ₯
|
| 231 |
-
st.subheader("π λΆμν μμ΄ λ¬Έμ₯μ μ
λ ₯νμΈμ:")
|
| 232 |
-
user_sentence = st.text_area("λ¬Έμ₯ μ
λ ₯:", "This movie is exceptionally good and I highly recommend it.", height=100)
|
| 233 |
-
|
| 234 |
-
top_k_slider = st.slider("νμν Top-K μ€μ ν ν° μ:", min_value=1, max_value=10, value=5, step=1)
|
| 235 |
-
|
| 236 |
-
if st.button("λΆμ μ€ννκΈ° π", type="primary"):
|
| 237 |
-
if user_sentence:
|
| 238 |
-
with st.spinner("λ¬Έμ₯μ λΆμνκ³ μμ΅λλ€... μ‘°κΈλ§ κΈ°λ€λ €μ£ΌμΈμ...β³"):
|
| 239 |
-
analysis_results = None
|
| 240 |
-
try:
|
| 241 |
-
analysis_results = explain_sentence_streamlit(
|
| 242 |
-
user_sentence, tokenizer, model, W, mu, w_p, b_p,
|
| 243 |
-
LAYER_ID, DEVICE, top_k_tokens=top_k_slider
|
| 244 |
-
)
|
| 245 |
-
except Exception as e: # explain_sentence_streamlit λ΄λΆμμ raiseλ μ€λ₯ μ²λ¦¬
|
| 246 |
-
st.error(f"λΆμ μ²λ¦¬ μ€ μ€λ₯ λ°μ: {e}")
|
| 247 |
-
st.info("μ
λ ₯ λ¬Έμ₯μ΄λ λͺ¨λΈ νΈνμ± λ¬Έμ λ₯Ό νμΈν΄λ³΄μΈμ. λ¬Έμ κ° μ§μλλ©΄ κ΄λ¦¬μμκ² λ¬ΈμνμΈμ.")
|
| 248 |
-
# λ μμΈν μ€λ₯λ Spacesμ λ‘κ·Έμμ νμΈ κ°λ₯ (printλ¬Έ μ¬μ© μ)
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
if analysis_results: # μ±κ³΅μ μΌλ‘ κ²°κ³Ό λ°ν μ
|
| 252 |
-
html_viz, predicted_idx, probability, top_k_list = analysis_results
|
| 253 |
-
|
| 254 |
-
st.markdown("---")
|
| 255 |
-
st.subheader("π λΆμ κ²°κ³Ό")
|
| 256 |
-
|
| 257 |
-
predicted_class_label = str(predicted_idx) # κΈ°λ³Έκ°: μΈλ±μ€
|
| 258 |
-
if class_names is not None and 0 <= predicted_idx < len(class_names):
|
| 259 |
-
predicted_class_label = str(class_names[predicted_idx]) # ν΄λμ€ μ΄λ¦ μ¬μ©
|
| 260 |
-
|
| 261 |
-
st.success(f"**μμΈ‘λ ν΄λμ€:** **`{predicted_class_label}`** (μ λ’°λ: **{probability:.2f}**)")
|
| 262 |
-
|
| 263 |
-
st.subheader("π¨ ν ν°λ³ μ€μλ μκ°ν")
|
| 264 |
-
st.markdown(html_viz, unsafe_allow_html=True)
|
| 265 |
-
|
| 266 |
-
st.subheader(f"β Top-{top_k_slider} μ€μ ν ν°")
|
| 267 |
-
if top_k_list:
|
| 268 |
-
cols = st.columns(len(top_k_list) if len(top_k_list) <=5 else 5 ) # ν μ€μ μ΅λ 5κ°
|
| 269 |
-
for i, item in enumerate(top_k_list):
|
| 270 |
-
with cols[i % len(cols)]:
|
| 271 |
-
st.metric(label=item['token'], value=item['score'])
|
| 272 |
-
else:
|
| 273 |
-
st.info("μ€μλ λμ ν ν°μ μ°Ύμ μ μμ΅λλ€ (μ€νμ
ν ν° λ± μ μΈ).")
|
| 274 |
-
# 'analysis_results is None' μ΄κ³ μμΈμ²λ¦¬λ‘ st.errorκ° μ΄λ―Έ νμλ κ²½μ°λ μΆκ° λ©μμ§ λΆνμ
|
| 275 |
-
elif analysis_results is None and not user_sentence: # λ¬Έμ₯ μ
λ ₯ μμ΄ λ²νΌ λλ₯Έ κ²½μ° (μ¬μ€μ μμμ μ²λ¦¬)
|
| 276 |
-
pass # μ΄λ―Έ st.warningμΌλ‘ μ²λ¦¬λ¨
|
| 277 |
-
|
| 278 |
-
else: # λ¬Έμ₯ μ
λ ₯ μμ΄ λ²νΌ λλ₯Έ κ²½μ°
|
| 279 |
-
st.warning("λΆμν λ¬Έμ₯μ μ
λ ₯ν΄μ£ΌμΈμ.")
|
| 280 |
-
else:
|
| 281 |
-
st.error("λͺ¨λΈ λ‘λ©μ μ€ν¨νμ¬ μ ν리μΌμ΄μ
μ μμν μ μμ΅λλ€. μ
λ‘λλ νμΌκ³Ό κ²½λ‘ μ€μ μ νμΈν΄μ£ΌμΈμ. Hugging Face Spacesμ 'Logs' νμμ μμΈ μ€λ₯λ₯Ό νμΈν μ μμ΅λλ€.")
|
| 282 |
|
| 283 |
-
st.
|
| 284 |
-
st.
|
|
|
|
|
|
| 1 |
+
# app.py (μ΅μ κΈ°λ₯ ν
μ€νΈμ©)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
import streamlit as st
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
|
| 4 |
+
st.title("Hugging Face Spaces ν
μ€νΈ μ±")
|
| 5 |
+
st.write("μ΄ λ©μμ§κ° 보μ΄λ©΄ Streamlitμ΄ μ μμ μΌλ‘ μ€νλ κ²μ
λλ€!")
|
| 6 |
+
st.balloons() # μ±κ³΅ μ νμ ν¨κ³Ό
|