import torch, os import torch.nn as nn import gradio as gr import pandas as pd from transformers import AutoTokenizer, AutoModel from typing import Literal, Union, Dict, List, Tuple, Optional MODEL_ID = "TAIDE-EDU/TBCL-Scorer-RoBERTa-2-12_DEMO" HF_TOKEN = os.getenv("HF_TOKEN", None) headers = ['id', '課文類型', 'TBCL等級', "課文標題", '課文內容'] device = "cuda" if torch.cuda.is_available() else "cpu" model = AutoModel.from_pretrained(MODEL_ID, token=HF_TOKEN, trust_remote_code=True) tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, token=HF_TOKEN) device = torch.device("cuda" if torch.cuda.is_available() else "cpu") model.to(device).eval() example_datas = [ { "id": "L1T001\n(shi)", "教材名稱": "華師審查", "課文標題": "你好嗎?", "課文內容": "林春和:力冬,你今天怎麼樣?\n王力冬:很不錯,你呢?\n林春和:我也不錯。你要去哪裡?\n王力冬:我現在要去買東西。我們明天中文課見!\n林春和:明天見!", "list_level": "level_1", "類型": "對話" }, { "id": "L1T004", "教材名稱": "華師審查", "課文標題": "今天下午做什麼?", "課文內容": "銘鈺:曉萱,今天下午你有什麼計畫嗎?\n曉萱:我還不知道,你呢?\n銘鈺:天氣這麼好,我們出去走走吧!\n曉萱:好啊!我們去象山怎麼樣?\n銘鈺:好,聽說那裡的風景很漂亮!可是要怎麼去?\n曉萱:我們可以坐捷運也可以坐公車。我覺得坐捷運比較快!\n銘鈺:那我們2點在中山站見面吧!\n曉萱:一會兒見!", "list_level": "level_1", "類型": "對話" }, { "id": "L2T021", "教材名稱": "華師審查", "課文標題": "教育與學習", "課文內容": "小明:小美,妳最近學習的情況怎麼樣?\n小美:還不錯啦。不過有些部分還需要更努力。\n小明:妳最喜歡上哪一種課?\n小美:我比較喜歡上科學課,覺得科學課很有意思。\n小明:還有其他喜歡的課嗎?\n小美:數學課我也喜歡,因為數學課很有趣。\n小明:妳週末會看書嗎?\n小美:會啊,我有時候會複習科學和數學。\n小明:妳平常會怎麼準備呢?\n小美:我會做筆記和複習重點,讓我更了解學習的內容。", "list_level": "level_2", "類型": "對話" }, { "id": "L2T027", "教材名稱": "華師審查", "課文標題": "寒假旅行計畫", "課文內容": "今天和朋友聊天,聊了寒假的計劃。我們都是第一次來台灣,想看看這裡的冬天和我們國家的有什麼不一樣。老師說台灣很少下雪,可是還是有很多漂亮的風景,我們都很想去看看。\n\n我的朋友很喜歡大海,我們打算在一月中到基隆玩。我的台灣朋友叫我們注意,雖然台灣不會下雪,可是天氣還是會非常冷,得多準備一些衣服。\n\n聽到我們的計畫,老師說我們也應該去基隆的夜市,因為有很多特別的小吃。這次旅行一定會很有意思,也希望我能拍到漂亮的照片給我的家人看。", "list_level": "level_2", "類型": "短文" }, { "id": "L3T003", "教材名稱": "華師審查", "課文標題": "選擇一份適合的工作", "課文內容": "選擇一份適合自己的工作是生活中的重要決定。因為每個人的興趣和能力不同,所以選擇的工作也不同。有些人喜歡幫助別人,可能會選擇當醫生或老師。有些人對研究有興趣,這樣的人可能會選擇當研究員。選擇工作時,除了要考慮自己的興趣以外,也要考慮工作的環境,因為這些事情都會影響我們的心情。雖然每個工作都有困難的部分,可是只要努力,就能解決很多問題,工作也會越來越順利。許多大學生在畢業前就開始想以後的工作,因為找到一份適合的工作不但可以帶來收入,還能讓人過得更快樂。", "list_level": "level_3", "類型": "短文" }, { "id": "L3T007", "教材名稱": "華師審查", "課文標題": "現代社會和傳統社會的差別", "課文內容": "王老師:你們覺得現代社會和傳統社會有什麼不一樣?\n天明:我覺得現代社會的科技進步很快,大家的生活也變了。以前的人寫信聯絡,現在我們用簡訊或者電子郵件。\n美心:對啊!還有,現在的年輕人不像以前那麼傳統,他們更自由了。\n王老師:傳統的價值觀,例如重視家庭,對現代社會有影響嗎?\n天明:影響很大。家人的關心和支持還是很重要。\n美心:是啊,節日時大家還是會一起慶祝,例如春節和中秋節,這些都是傳統對現代社會的影響。\n王老師:最後,請問你們覺得現代社會和傳統社會怎麼結合比較好?\n美心:我想,我們應該學習傳統的好處,同時用現代科技讓生活更方便。\n天明:我同意。", "list_level": "level_3", "類型": "對話" }, { "id": "L4T008\n(shi)", "教材名稱": "華師審查", "課文標題": "讓小興趣變成大夢想", "課文內容": "每個人都有一個夢想,你希望自己長大後變成什麼樣的人呢?是站在舞台上,用歌聲感動觀眾的歌手?在醫院裡幫助病人的醫生?還是到過很多國家的的旅行家?\n選擇夢想時,興趣會帶著我們往前走。當我們對一件事有興趣時,學習就會變得更容易。例如:喜歡看書的人,可能會想當作家;喜歡做研究的人,可能想成為科學家。 \n夢想不會自己實現,它需要我們努力。就像種子要長大,需要陽光和水,為了實現夢想,我們也需要按照計劃,不斷學習和練習,才會有成果。 \n每個人的夢想都是不一樣的,就像世界上沒有兩片相同的葉子。夢想是什麼都沒關係,只要努力,就一定能實現。", "list_level": "level_4", "類型": "對話" }, { "id": "L4T009\n(shi)", "教材名稱": "華師審查", "課文標題": "人與人的互動", "課文內容": "在現代社會,人與人的互動對每個人來說都非常重要。有良好的關係可以帶來許多好處,例如在工作上得到同事的幫助,在生活中得到朋友的支持。為了有好的關係,我們需要學會與別人溝通。與別人相處時,我們應該注意表達自己的想法,接受別人的意見。例如,當我們遇到困難時,可以向朋友請教,並且在他們需要幫助時,我們也應該主動提供幫助。這樣互相支持和幫助能夠加強感情。參加各種活動也是保持關係的好方法。通過這些活動,我們可以認識更多的人,增加自己的朋友。例如,參加朋友的聚餐、工作上的活動,以上這些都是認識新朋友的好機會。同時,保持良好的態度也是保持關係的重要因素。我們應該保持熱情、親切,並且在與人相處時多注意禮貌,這樣可以讓對方感覺到我們的親切。通過有效溝通、積極參加活動和保持良好的態度,我們可以和朋友有良好的關係。", "list_level": "level_4", "類型": "短文" }, { "id": "L5T001\n(shi)", "教材名稱": "華師審查", "課文標題": "休閒活動", "課文內容": "在臺灣,假日是人們放鬆和享受生活的時光。每到假日,人們會選擇各種不同的休閒活動來度過這段時間。以下介紹幾種臺灣人常做的休閒活動。\n\n首先,許多人喜歡到郊外進行健行。例如,在新北市的陽明山國家公園,是許多健行愛好者的熱門去處。陽明山的七星山步道,每到假日總是吸引大批遊客。許多人會早起,踏上登山的步道,一邊呼吸新鮮空氣,一邊享受大自然的寧靜。健行不但可以鍛鍊身體,還能讓人放鬆心情,是一項非常受歡迎的活動。\n\n除了健行,騎自行車也是臺灣人假日的熱門選擇。台中的后豐鐵馬道,是一條將廢棄鐵路整修而成的自行車道。假日時,無論是家庭成員還是朋友團體,都喜歡一起騎著自行車,感受微風吹來的舒適。后豐鐵馬道全長12公里,沿路風景如畫,是台灣自行車愛好者的最愛。\n\n對喜愛美食的人來說,假日則是一個大吃大喝的好時機。士林夜市是臺北市最大的夜市,每到假日,這裡總是人山人海。無論是蚵仔煎、珍珠奶茶還是臭豆腐,都讓人口水直流。士林夜市不只提供了豐富的美食選擇,還是一個體驗當地文化的好地方。\n\n最後,看電影也是臺灣人假日的熱門活動之一。無論是獨自一人還是與親朋好友一起,走進戲院,觀看最新上映的電影,都是一種享受。特別是在炎熱的夏天,電影院內的涼爽空調更是讓人感到舒適。\n\n總之,臺灣人假日的休閒活動多種多樣,無論是親近自然、運動鍛鍊,還是享受美食、文化娛樂,每個人都能找到適合自己的假日休閒活動。這些活動不只豐富了人們的生活,還增進了家庭和朋友之間的感情,使假日變得更加充實和愉快。", "list_level": "level_5", "類型": "短文" }, { "id": "L5T002\n(shi)", "教材名稱": "華師審查", "課文標題": "探索臺北之美", "課文內容": "臺北,作為臺灣的首都,不僅是政治與經濟中心,更是文化與歷史的交匯點。這座城市融合了現代與傳統,讓人每次造訪都有不同的驚喜。現在讓我們一起探索臺北之美吧!\n\n首先,臺北的夜市文化是一大亮點。士林夜市、饒河街夜市和寧夏夜市是其中最著名的幾個。這些夜市提供了豐富的街頭美食,從鹽酥雞、大腸包小腸到芒果冰、蚵仔煎,每一口都是臺灣味道的代表。夜市不僅是品嚐美食的地方,更是體驗臺灣夜生活和文化氛圍的好去處。不僅能滿足味蕾,更能讓人感受到臺北的獨特魅力。\n\n除了夜市,臺北的自然景觀也值得一提。陽明山國家公園以其壯麗的火山地形和溫泉聞名,是市民和遊客放鬆身心的好地方。而大安森林公園則被譽為「臺北的綠肺」,在這裡,你可以遠離城市的喧囂,享受自然的寧靜。這些自然景觀為城市增添了不少綠意和活力。\n\n臺北的歷史建築同樣充滿魅力。國立故宮博物院收藏了豐富的中國古代文物,讓人可以一覽千年歷史的風采。而龍山寺、保安宮等古老寺廟則展示了臺灣傳統宗教文化的深厚底蘊。這些歷史建築不僅是文化的象徵,更是了解臺北歷史的重要窗口。\n\n此外,臺北的交通系統非常便利。臺北捷運覆蓋了臺北市各個主要景點,不僅快捷而且乾淨,使得遊客可以輕鬆遊覽城市的各個角落。大多數捷運站附近有商場和餐廳,方便人們購物和用餐。這樣的交通便利性讓臺北成為一個適合觀光客探索的城市。\n\n總之,臺北是一座充滿活力與魅力的城市,無論是喜歡美食、自然還是歷史文化的人,都能在這裡找到自己的心之所向。來臺北旅行,不僅是一次視覺和味覺的享受,更是一次心靈的滿足。", "list_level": "level_5", "類型": "短文" }] def _to_level_num(s: str): try: return int(str(s).split("_")[-1]) except Exception: return None def tbcl_multitask_judgement(text:str) -> Tuple[Dict[str, float], int]: """Predicts two task distributions for the input text.""" batch_x = tokenizer(text, return_tensors="pt", padding=True, truncation=True, max_length=512).to(device) with torch.no_grad(): out_dict = model(**batch_x, return_dict=True) cls_probs = out_dict["cls_logits"].cpu().tolist()[0] tbcl_level = (out_dict["reg_logits"].squeeze(-1)+1).cpu().tolist()[0] # 任務0(程度等級) classfication_id2label = {0: "捨棄", 1: "保留"} class_prediction = {classfication_id2label[i]: round(cls_probs[i], 3) for i in range(len(cls_probs))} return class_prediction, tbcl_level def on_row_select(evt: gr.SelectData, df): row_idx = evt.index[0] if isinstance(evt.index, (list, tuple)) else evt.index row = df.iloc[int(row_idx)] # 這裡決定選取後要顯示什麼 row_id = row["id"] prompt_str = example_datas_id2data_str[row_id] #questions = [row[f"題目{i}"] for i in range(1, 7)] #md = f"### 範例文章\n{article}\n\n### 題目\n" + "\n".join([f"- {q}" for q in questions]) return prompt_str#, md # 依 headers 的欄位順序組好 DataFrame def _to_level_num(s: str): try: return int(str(s).split("_")[-1]) except Exception: return None example_datas_df = pd.DataFrame( [ { "id": d["id"], "課文類型": d.get("類型", ""), "TBCL等級": _to_level_num(d.get("list_level", "")), "課文標題": d.get("課文標題", ""), "課文內容": d.get("課文內容", ""), } for d in example_datas ], columns=headers, # 確保欄位順序與 headers 一致 ) # 點表格帶入文字時要用到:id -> 要帶入 textbox 的內容 example_datas_id2data_str = {d["id"]: d["課文內容"] for d in example_datas} with gr.Blocks(title="課文內容TBCL評分器") as demo: gr.Markdown("## 課文內容TBCL評分器\n從下方**範例表**點選一列,系統會自動帶入並推論。") with gr.Row(): inp = gr.Textbox(label="輸入文章", lines=6, placeholder="也可手動貼文後按下『送出』") btn = gr.Button("送出") with gr.Row(): out0 = gr.Label(label="任務0:課文是否保留(限定輸入高階模型生成之內容)") out1 = gr.Label(label="任務1:TBCL等級預測") table = gr.Dataframe( value=example_datas_df, headers=headers, row_count=(len(example_datas_df), "fixed"), col_count=len(headers), interactive=False, wrap=True, label="課文範例表" ) table.select( on_row_select, inputs=table, outputs=[inp] ) # 也支援手動輸入後按『送出』 btn.click( tbcl_multitask_judgement, inputs=inp, outputs=[out0, out1] ) demo.queue(max_size=32) if __name__ == "__main__": demo.launch()