Spaces:
Runtime error
Runtime error
| import os | |
| import torch | |
| import gradio as gr | |
| from transformers import AutoTokenizer, AutoModelForCausalLM | |
| # ========= 基本設定 ========= | |
| # 你的模型 repo id(目前是 private 也沒關係) | |
| MODEL_ID = "aciang/mistral7b-tk-sft-20251019-merged" | |
| # 若模型是 private,建議在 Space 的「Settings → Repository secrets」加上 HF_TOKEN | |
| HF_TOKEN = os.getenv("HF_TOKEN", None) | |
| # 建議預設的「傳統知識」系統提示,可以在介面中修改 | |
| DEFAULT_SYSTEM_PROMPT = """你是一位熟悉台灣與國際原住民族傳統知識的學者, | |
| 擅長用淺顯但尊重文化脈絡的繁體中文說明各族的夢境、儀式、宇宙觀、傳統醫療與環境知識。 | |
| 回答原則: | |
| 1. 先簡短摘要重點(3–5 點條列)。 | |
| 2. 儘量說明「族名、場域、情境」與「知識來源背景」,避免抽象空話。 | |
| 3. 若是推論或類比,要清楚標註「推測」而不是說成唯一正解。 | |
| 4. 若資料不足或超出目前教材範圍,請誠實說明,並給出安全的延伸建議。 | |
| 5. 全程使用繁體中文。""" | |
| # ========= 載入模型 ========= | |
| print(f"載入模型:{MODEL_ID} ...") | |
| tokenizer = AutoTokenizer.from_pretrained( | |
| MODEL_ID, | |
| use_auth_token=HF_TOKEN, | |
| ) | |
| # 保險起見,若沒有 pad_token 就沿用 eos_token | |
| if tokenizer.pad_token is None: | |
| tokenizer.pad_token = tokenizer.eos_token | |
| model = AutoModelForCausalLM.from_pretrained( | |
| MODEL_ID, | |
| torch_dtype=torch.float16, | |
| device_map="auto", # 自動分配到 GPU | |
| use_auth_token=HF_TOKEN, | |
| ) | |
| model.eval() | |
| print("模型載入完成。") | |
| # ========= 建立提示詞 ========= | |
| def build_prompt(system_prompt: str, history: list[tuple[str, str]], user_message: str) -> str: | |
| """ | |
| 將 system_prompt + 歷史對話 + 新問題 組成一段文字 prompt。 | |
| 這裡用簡單的「使用者 / 助手」格式,對傳統知識生成已經很足夠。 | |
| """ | |
| system_prompt = system_prompt.strip() | |
| prompt = f"[系統提示]\n{system_prompt}\n\n" | |
| # 過去對話(若有) | |
| if history: | |
| prompt += "[對話紀錄]\n" | |
| for i, (user, bot) in enumerate(history, start=1): | |
| prompt += f"輪次 {i}:\n使用者:{user}\n助手:{bot}\n\n" | |
| # 最新一輪問題 | |
| prompt += "[目前問題]\n" | |
| prompt += f"使用者:{user_message}\n助手:" | |
| return prompt | |
| # ========= 生成函式 ========= | |
| def generate_reply( | |
| user_message: str, | |
| chat_history: list[tuple[str, str]], | |
| system_prompt: str, | |
| temperature: float, | |
| max_new_tokens: int, | |
| ): | |
| if not user_message.strip(): | |
| return chat_history, gr.update(value="") | |
| # 組合成一個大 prompt | |
| prompt_text = build_prompt(system_prompt, chat_history, user_message) | |
| inputs = tokenizer( | |
| prompt_text, | |
| return_tensors="pt", | |
| add_special_tokens=True, | |
| ).to(model.device) | |
| with torch.no_grad(): | |
| outputs = model.generate( | |
| **inputs, | |
| max_new_tokens=int(max_new_tokens), | |
| do_sample=True, | |
| temperature=float(temperature), | |
| top_p=0.9, | |
| pad_token_id=tokenizer.eos_token_id, | |
| ) | |
| # 只取新生成的部分 | |
| input_len = inputs["input_ids"].shape[-1] | |
| generated_tokens = outputs[0, input_len:] | |
| answer = tokenizer.decode(generated_tokens, skip_special_tokens=True).strip() | |
| chat_history = chat_history + [(user_message, answer)] | |
| return chat_history, "" # 清空輸入框 | |
| def clear_history(): | |
| return [], "" | |
| # ========= Gradio 介面 ========= | |
| with gr.Blocks(title="語言橋傳統知識聊天機器人 — Mistral7B TK", theme=gr.themes.Soft()) as demo: | |
| gr.Markdown( | |
| """ | |
| # 語言橋傳統知識聊天機器人 — Mistral7B TK | |
| 使用你自訓練的 **mistral7b-tk-sft-20251019-merged** 模型,離線在 Hugging Face Space 上回答與傳統知識相關的問題。 | |
| 建議題材舉例: | |
| - 不同族群對「夢境」的五種層次與詮釋差異 | |
| - 布農族狩獵儀式與祖靈信仰 | |
| - 排灣族階級制度與紋面、圖騰的意義 | |
| - 阿美族年齡階層制與植物分類知識 | |
| - 海外原住民(如 Inuit)對身體、疾病與療癒的理解 | |
| """ | |
| ) | |
| with gr.Row(): | |
| # 左側:設定區 | |
| with gr.Column(scale=1): | |
| system_prompt_box = gr.Textbox( | |
| label="系統提示(模型角色與回答風格)", | |
| value=DEFAULT_SYSTEM_PROMPT, | |
| lines=16, | |
| ) | |
| temperature_slider = gr.Slider( | |
| label="溫度(創造性)", | |
| minimum=0.1, | |
| maximum=1.5, | |
| value=0.7, | |
| step=0.05, | |
| ) | |
| max_tokens_slider = gr.Slider( | |
| label="最大回覆長度(token 數,大約字數的 1.5–2 倍)", | |
| minimum=64, | |
| maximum=1024, | |
| value=512, | |
| step=16, | |
| ) | |
| gr.Markdown( | |
| """ | |
| **小提醒:** | |
| - 回答太發散 → 降低溫度(0.4–0.7)。 | |
| - 回答太短 → 拉高「最大回覆長度」。 | |
| - Space 若常 timeout,可以稍微降低最大回覆長度。 | |
| """ | |
| ) | |
| # 右側:聊天區 | |
| with gr.Column(scale=2): | |
| chatbot = gr.Chatbot( | |
| label="傳統知識 Chatbot", | |
| height=480, | |
| show_copy_button=True, | |
| ) | |
| user_input = gr.Textbox( | |
| label="輸入你的問題(可多輪對話)", | |
| placeholder="例如:請比較布農族、排灣族和阿美族對治療疾病與夢境預兆的不同理解方式。", | |
| lines=4, | |
| ) | |
| with gr.Row(): | |
| send_btn = gr.Button("送出問題", variant="primary") | |
| clear_btn = gr.Button("清除對話") | |
| # 狀態:對話歷史 | |
| state = gr.State([]) # list[tuple[user, bot]] | |
| # 綁定互動 | |
| send_btn.click( | |
| fn=generate_reply, | |
| inputs=[ | |
| user_input, | |
| state, | |
| system_prompt_box, | |
| temperature_slider, | |
| max_tokens_slider, | |
| ], | |
| outputs=[chatbot, user_input], | |
| ).then( | |
| fn=lambda h: h, | |
| inputs=[chatbot], | |
| outputs=[state], | |
| ) | |
| user_input.submit( | |
| fn=generate_reply, | |
| inputs=[ | |
| user_input, | |
| state, | |
| system_prompt_box, | |
| temperature_slider, | |
| max_tokens_slider, | |
| ], | |
| outputs=[chatbot, user_input], | |
| ).then( | |
| fn=lambda h: h, | |
| inputs=[chatbot], | |
| outputs=[state], | |
| ) | |
| clear_btn.click( | |
| fn=clear_history, | |
| inputs=[], | |
| outputs=[chatbot, user_input], | |
| ).then( | |
| fn=lambda: [], | |
| inputs=[], | |
| outputs=[state], | |
| ) | |
| # 在 HF Space 中不需要 demo.launch(),平台會自動呼叫 demo | |