Download app.py from fdbw/wtmx: direct link, hf CLI and curl.
- Browser
- Download file 5.71 kB
-
https://huggingface.co/spaces/fdbw/wtmx/resolve/main/app.py
- Command line
-
hf download hf://spaces/fdbw/wtmx/app.py
-
curl -L -o app.py https://huggingface.co/spaces/fdbw/wtmx/resolve/main/app.py
5.71 kB
| # app.py —— 永久一键切换:微调 / 测试 / 机器人 | |
| import os | |
| import gradio as gr | |
| from transformers import GPT2LMHeadModel, GPT2Tokenizer, TextDataset, DataCollatorForLanguageModeling | |
| from transformers import Trainer, TrainingArguments | |
| import re | |
| import torch | |
| MODEL_DIR = "./fine_tuned_model" | |
| BASE_MODEL = "uer/gpt2-chinese-cluecorpussmall" | |
| # ==================== 微调函数 ==================== | |
| def finetune_model(progress=gr.Progress()): | |
| if os.path.exists(MODEL_DIR): | |
| return "已存在微调好的模型,无需重复微调!直接切换到「测试」或「机器人」模式即可。" | |
| progress(0, desc="正在读取家谱文件...") | |
| with open("genealogy.txt", encoding="utf-8") as f: | |
| text = f.read() | |
| # 简单但有效的信息抽取 | |
| blocks = re.split(r"\n\d+——|\n故祖考|\n故祖妣|\n孝男|\n孝媳|\n孝孙|\n曾孙|\n外曾孙|\n外玄孙", text) | |
| examples = [] | |
| for block in blocks[1:]: | |
| if len(block) < 10: | |
| continue | |
| # 提取姓名 | |
| name_match = re.search(r"[\u4e00-\u9fa5]{2,4}", block[:15]) | |
| name = name_match.group() if name_match else "某人" | |
| born = re.search(r"生[於于]\s*([^\n地名]+)", block) | |
| died = re.search(r"(死[於于]|卒于|去世于)\s*([^\n地名]+)", block) | |
| place = re.search(r"地名\s*([^\n]+)", block) | |
| born = born.group(1).strip() if born else "未知" | |
| place = place.group(1).strip() if place else "未知" | |
| died = died.group(2).strip() if died else None | |
| examples.append(f"查询: {name}出生时间和地点?\n回答: {name}出生于{born},地点{place}。") | |
| if died: | |
| examples.append(f"查询: {name}去世时间?\n回答: {name}去世于{died}。") | |
| data_text = "\n\n".join(examples) | |
| with open("train.txt", "w", encoding="utf-8") as f: | |
| f.write(data_text) | |
| progress(0.3, desc="加载 tokenizer 和数据集...") | |
| tokenizer = GPT2Tokenizer.from_pretrained(BASE_MODEL) | |
| dataset = TextDataset(tokenizer=tokenizer, file_path="train.txt", block_size=128) | |
| data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False) | |
| progress(0.6, desc="开始微调(预计40–90分钟,请耐心等待勿关闭页面)...") | |
| model = GPT2LMHeadModel.from_pretrained(BASE_MODEL) | |
| training_args = TrainingArguments( | |
| output_dir="./results", | |
| overwrite_output_dir=True, | |
| num_train_epochs=3, | |
| per_device_train_batch_size=2, | |
| save_steps=500, | |
| logging_steps=20, | |
| save_total_limit=1, | |
| ) | |
| trainer = Trainer( | |
| model=model, | |
| args=training_args, | |
| data_collator=data_collator, | |
| train_dataset=dataset, | |
| ) | |
| trainer.train() | |
| progress(1.0, desc="保存模型...") | |
| model.save_pretrained(MODEL_DIR) | |
| tokenizer.save_pretrained(MODEL_DIR) | |
| return "微调成功!模型已保存。现在可以切换到「测试」或「机器人」模式使用啦!" | |
| # ==================== 推理函数 ==================== | |
| def load_model(): | |
| if not os.path.exists(MODEL_DIR): | |
| return None, None | |
| tokenizer = GPT2Tokenizer.from_pretrained(MODEL_DIR) | |
| model = GPT2LMHeadModel.from_pretrained(MODEL_DIR) | |
| return model, tokenizer | |
| model, tokenizer = load_model() | |
| def chat(message, history): | |
| if model is None: | |
| return "模型尚未微调完成!请先在上面选择「微调模型」运行一次。" | |
| prompt = "\n".join([f"查询: {h[0]}\n回答: {h[1]}" for h in history if h[1]] + [f"查询: {message}\n回答:"]) | |
| inputs = tokenizer.encode(prompt, return_tensors="pt") | |
| outputs = model.generate( | |
| inputs, | |
| max_length=inputs.shape[1] + 120, | |
| do_sample=True, | |
| temperature=0.7, | |
| top_p=0.9, | |
| no_repeat_ngram_size=3, | |
| pad_token_id=tokenizer.eos_token_id | |
| ) | |
| reply = tokenizer.decode(outputs[0], skip_special_tokens=True) | |
| return reply.split("回答:")[-1].strip() | |
| # ==================== 主界面 ==================== | |
| with gr.Blocks(theme=gr.themes.Soft(), title="冯氏家谱智能查询") as demo: | |
| gr.Markdown("# 冯氏家谱智能查询机器人\n一次上传,永久使用,三个模式一键切换") | |
| mode = gr.Radio( | |
| ["微调模型", "测试模型", "正式机器人"], | |
| label="请选择当前模式", | |
| value="正式机器人" if os.path.exists(MODEL_DIR) else "微调模型" | |
| ) | |
| with gr.Column(visible=False) as finetune_box: | |
| gr.Markdown("### 第一步:点击下方按钮开始微调(只需执行一次,耐心等待40–90分钟)") | |
| btn = gr.Button("开始微调模型(免费CPU可完成)", variant="primary", size="lg") | |
| output = gr.Textbox(label="微调日志", lines=20) | |
| btn.click(finetune_model, None, output) | |
| with gr.Column(visible=True) as chat_box: | |
| gr.ChatInterface( | |
| fn=chat, | |
| title=None, | |
| description="直接问:冯达尊出生地、冯乔福几个儿子、冯宗德姐妹是谁……", | |
| examples=[ | |
| "冯达尊出生时间和地点?", | |
| "冯乔源的孩子有哪些?", | |
| "冯宗福的兄弟姐妹是谁?", | |
| "冯永明是哪一支的?", | |
| "冯仁杰的父亲是谁?" | |
| ] | |
| ) | |
| def update_interface(choice): | |
| if choice == "微调模型": | |
| return gr.update(visible=True), gr.update(visible=False) | |
| else: | |
| return gr.update(visible=False), gr.update(visible=True) | |
| mode.change(update_interface, mode, [finetune_box, chat_box]) | |
| # 启动时自动显示正确界面 | |
| demo.launch() |