monicaa1212 commited on
Commit
9fbb44e
·
verified ·
1 Parent(s): 1cb0751

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +49 -34
app.py CHANGED
@@ -1,23 +1,32 @@
1
  import gradio as gr
2
  import torch
3
- from transformers import AutoModelForCausalLM, AutoTokenizer
4
  import json
5
  import html
 
6
 
7
- # ---------- 使用 Phi-3-mini (3.8B极快且稳定) ----------
8
- MODEL_NAME = "microsoft/Phi-3-mini-4k-instruct"
9
 
10
- print("🔄 加载轻量模型 Phi-3-mini...")
 
 
 
 
 
 
 
11
  tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_code=True)
12
  model = AutoModelForCausalLM.from_pretrained(
13
  MODEL_NAME,
14
- torch_dtype=torch.float16,
15
  device_map="auto",
16
- trust_remote_code=True
 
17
  )
18
  print("✅ 模型加载完成")
19
 
20
- SYSTEM_PROMPT = """你是一个英语精读辅助工具。从用户供的英文文本中提取 8~20 个值得学习的表达(短语、搭配、句式,不是单)。
 
21
 
22
  对每个表达,输出一个 JSON 对象,包含:
23
  - "expression": 原文中的表达
@@ -42,50 +51,52 @@ def parse_output(raw):
42
  data = json.loads(json_str)
43
  required = {"expression","meaning","explanation","original_context","extra_example"}
44
  return [item for item in data if isinstance(item,dict) and required.issubset(item.keys())]
45
- except:
 
46
  return []
47
 
48
  def generate_cards(exprs):
49
  if not exprs:
50
- return '<div style="padding:2rem;text-align:center">⚠️ 未提取到表达,请尝试不同文本</div>'
51
  cards = ""
52
  for e in exprs:
53
  cards += f"""
54
- <div style="background:white;border-radius:20px;border:1px solid #e0e0e0;padding:1.2rem;margin-bottom:1rem;">
55
- <div style="font-weight:600;font-size:1.2rem;margin-bottom:0.8rem;">{html.escape(e['expression'])}</div>
56
- <div><strong>Meaning</strong><br>{html.escape(e['meaning'])}</div>
57
- <div style="margin-top:0.5rem;"><strong>Explanation</strong><br>{html.escape(e['explanation'])}</div>
58
- <div style="margin-top:0.5rem;"><strong>Original Context</strong><br>{html.escape(e['original_context'])}</div>
59
- <div style="margin-top:0.5rem;"><strong>Extra Example</strong><br>{html.escape(e['extra_example'])}</div>
60
  </div>
61
  """
62
- return f'<div style="max-width:900px;margin:0 auto">{cards}</div>'
63
 
64
  def analyze(text, progress=gr.Progress()):
65
  if len(text.strip()) < 20:
66
- return "<div style='color:red'>请至少输入20个字符</div>", 0
67
  messages = [
68
  {"role": "system", "content": SYSTEM_PROMPT},
69
  {"role": "user", "content": USER_PROMPT_TEMPLATE.format(text=text)}
70
  ]
71
- inputs = tokenizer.apply_chat_template(messages, add_generation_prompt=True, return_tensors="pt").to(model.device)
72
- progress(0.4, desc="模型推理中...")
 
73
  with torch.no_grad():
74
  outputs = model.generate(
75
- inputs,
76
- max_new_tokens=1024,
77
- do_sample=False, # 贪心解码,最快
78
  temperature=1.0,
79
  pad_token_id=tokenizer.eos_token_id
80
  )
81
- response = tokenizer.decode(outputs[0][inputs.shape[1]:], skip_special_tokens=True)
82
- exprs = parse_output(response)
83
  if not exprs:
84
- return "<div style='color:red'>解析失败,请重试</div>", 0
85
  return generate_cards(exprs), len(exprs)
86
 
87
- # ---------- 极简浅色主题(不用任何复杂 CSS,确保生效)----------
88
- LIGHT_THEME = gr.themes.Soft(
89
  primary_hue="neutral",
90
  secondary_hue="neutral",
91
  font=gr.themes.GoogleFont("Inter"),
@@ -96,22 +107,26 @@ LIGHT_THEME = gr.themes.Soft(
96
  block_background_fill="white",
97
  block_border_width="1px",
98
  block_border_color="#e2e2e0",
 
 
 
 
99
  )
100
 
101
- with gr.Blocks(theme=LIGHT_THEME, title="InContext") as demo:
102
- gr.Markdown("# InContext\nLearn English Expressions Through Real Content")
103
  with gr.Row():
104
- textbox = gr.Textbox(lines=10, placeholder="Paste English content here...", label="")
105
  btn = gr.Button("Analyze", variant="primary")
106
- header = gr.HTML('<div style="display:flex;justify-content:space-between;margin:1rem 0"><h3>Expressions Found</h3><span id="count">—</span></div>')
107
  output = gr.HTML()
108
  count_state = gr.Number(visible=False)
109
-
110
  def run(text):
111
  html, cnt = analyze(text)
112
- new_header = f'<div style="display:flex;justify-content:space-between;margin:1rem 0"><h3>Expressions Found</h3><span>{cnt}</span></div>'
113
  return new_header, html, cnt
114
-
115
  btn.click(run, [textbox], [header, output, count_state])
116
 
117
  demo.queue().launch()
 
1
  import gradio as gr
2
  import torch
 
3
  import json
4
  import html
5
+ from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
6
 
7
+ # ---------- 模型:Qwen2.5-3B-Instruct (4bit 量化,稳定且快) ----------
8
+ MODEL_NAME = "Qwen/Qwen2.5-3B-Instruct"
9
 
10
+ quantization_config = BitsAndBytesConfig(
11
+ load_in_4bit=True,
12
+ bnb_4bit_compute_dtype=torch.float16,
13
+ bnb_4bit_use_double_quant=True,
14
+ bnb_4bit_quant_type="nf4"
15
+ )
16
+
17
+ print("🔄 加载 Qwen2.5-3B 模型 (4bit)...")
18
  tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_code=True)
19
  model = AutoModelForCausalLM.from_pretrained(
20
  MODEL_NAME,
21
+ quantization_config=quantization_config,
22
  device_map="auto",
23
+ trust_remote_code=True,
24
+ torch_dtype=torch.float16
25
  )
26
  print("✅ 模型加载完成")
27
 
28
+ # ---------- ----------
29
+ SYSTEM_PROMPT = """你是一个英语精读辅助工具。从用户提供的英文文本中提取 8~20 个值得学习的表达(短语、搭配、句式,不是单个单词)。
30
 
31
  对每个表达,输出一个 JSON 对象,包含:
32
  - "expression": 原文中的表达
 
51
  data = json.loads(json_str)
52
  required = {"expression","meaning","explanation","original_context","extra_example"}
53
  return [item for item in data if isinstance(item,dict) and required.issubset(item.keys())]
54
+ except Exception as e:
55
+ print("解析错误:", e)
56
  return []
57
 
58
  def generate_cards(exprs):
59
  if not exprs:
60
+ return '<div style="padding:2rem;text-align:center;color:#666;">⚠️ 未提取到表达,请尝试不同文本</div>'
61
  cards = ""
62
  for e in exprs:
63
  cards += f"""
64
+ <div style="background:white;border-radius:20px;border:1px solid #e2e2e0;padding:1.2rem;margin-bottom:1rem;box-shadow:0 1px 2px rgba(0,0,0,0.02);">
65
+ <div style="font-weight:600;font-size:1.2rem;margin-bottom:0.8rem;color:#1a1a1a;">{html.escape(e['expression'])}</div>
66
+ <div><strong style="color:#555;">Meaning</strong><br><span style="color:#333;">{html.escape(e['meaning'])}</span></div>
67
+ <div style="margin-top:0.6rem;"><strong style="color:#555;">Explanation</strong><br><span style="color:#333;">{html.escape(e['explanation'])}</span></div>
68
+ <div style="margin-top:0.6rem;"><strong style="color:#555;">Original Context</strong><br><span style="color:#333;">{html.escape(e['original_context'])}</span></div>
69
+ <div style="margin-top:0.6rem;"><strong style="color:#555;">Additional Example</strong><br><span style="color:#333;">{html.escape(e['extra_example'])}</span></div>
70
  </div>
71
  """
72
+ return f'<div style="max-width:950px;margin:0 auto">{cards}</div>'
73
 
74
  def analyze(text, progress=gr.Progress()):
75
  if len(text.strip()) < 20:
76
+ return "<div style='color:#d14;padding:1rem;'>⚠️ 请至少输入20个字符的英文文本。</div>", 0
77
  messages = [
78
  {"role": "system", "content": SYSTEM_PROMPT},
79
  {"role": "user", "content": USER_PROMPT_TEMPLATE.format(text=text)}
80
  ]
81
+ text_input = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
82
+ inputs = tokenizer(text_input, return_tensors="pt").to(model.device)
83
+ progress(0.4, desc="模型推理中(约20-30秒)...")
84
  with torch.no_grad():
85
  outputs = model.generate(
86
+ **inputs,
87
+ max_new_tokens=1536,
88
+ do_sample=False,
89
  temperature=1.0,
90
  pad_token_id=tokenizer.eos_token_id
91
  )
92
+ generated = tokenizer.decode(outputs[0][inputs.input_ids.shape[1]:], skip_special_tokens=True)
93
+ exprs = parse_output(generated)
94
  if not exprs:
95
+ return "<div style='color:#d14;padding:1rem;'>⚠️ 解析失败,请重试或更换文本。</div>", 0
96
  return generate_cards(exprs), len(exprs)
97
 
98
+ # ---------- 强制浅色主题 ----------
99
+ theme = gr.themes.Soft(
100
  primary_hue="neutral",
101
  secondary_hue="neutral",
102
  font=gr.themes.GoogleFont("Inter"),
 
107
  block_background_fill="white",
108
  block_border_width="1px",
109
  block_border_color="#e2e2e0",
110
+ block_title_background_fill="white",
111
+ block_label_background_fill="white",
112
+ input_background_fill="white",
113
+ input_border_color="#e2e2e0",
114
  )
115
 
116
+ with gr.Blocks(theme=theme, title="InContext — Learn English from Real Content", css="footer {visibility: hidden}") as demo:
117
+ gr.Markdown("# InContext\n### Learn English Expressions Through Real Content")
118
  with gr.Row():
119
+ textbox = gr.Textbox(lines=10, placeholder="Paste any English content here...\n\nExample:\nThese links and codes are for registered Build Small participants only.\nPlease don't forward or post them publicly.\nRedemptions are capped.\nEvery leaked claim takes compute away from a fellow builder.", label="")
120
  btn = gr.Button("Analyze", variant="primary")
121
+ header = gr.HTML('<div style="display:flex;justify-content:space-between;align-items:baseline;margin:1.5rem 0 1rem 0;"><h3 style="margin:0;">Expressions Found</h3><span id="count" style="background:#efefec;padding:0.2rem 0.7rem;border-radius:30px;font-size:0.8rem;">—</span></div>')
122
  output = gr.HTML()
123
  count_state = gr.Number(visible=False)
124
+
125
  def run(text):
126
  html, cnt = analyze(text)
127
+ new_header = f'<div style="display:flex;justify-content:space-between;align-items:baseline;margin:1.5rem 0 1rem 0;"><h3 style="margin:0;">Expressions Found</h3><span style="background:#efefec;padding:0.2rem 0.7rem;border-radius:30px;font-size:0.8rem;">{cnt}</span></div>'
128
  return new_header, html, cnt
129
+
130
  btn.click(run, [textbox], [header, output, count_state])
131
 
132
  demo.queue().launch()