Update app.py
Browse files
app.py
CHANGED
|
@@ -1,136 +1,128 @@
|
|
| 1 |
import gradio as gr
|
| 2 |
import re
|
|
|
|
|
|
|
| 3 |
from transformers import pipeline
|
| 4 |
|
| 5 |
# ---------------------------
|
| 6 |
-
#
|
| 7 |
# ---------------------------
|
| 8 |
translator = pipeline("translation", model="Helsinki-NLP/opus-mt-zh-en")
|
| 9 |
|
| 10 |
-
|
| 11 |
def translate_text(cn_text):
|
| 12 |
try:
|
| 13 |
-
|
| 14 |
-
return result
|
| 15 |
except:
|
| 16 |
return "Translation model error."
|
| 17 |
|
| 18 |
|
| 19 |
# ---------------------------
|
| 20 |
-
#
|
| 21 |
# ---------------------------
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
|
| 27 |
|
| 28 |
# ---------------------------
|
| 29 |
-
# TIRA
|
| 30 |
-
# 基于中文意图 + 英文特征双通道判定
|
| 31 |
# ---------------------------
|
| 32 |
def classify_tira(cn_text, en_text):
|
| 33 |
cn = cn_text.strip()
|
| 34 |
-
en = en_text.lower()
|
| 35 |
|
| 36 |
-
# ---- 中文触发条件 ----
|
| 37 |
cn_amplify = ["能否", "是否方便", "请您帮忙", "抽空", "劳驾", "麻烦帮我"]
|
| 38 |
cn_attenuate = ["尽快", "必须", "需要您", "立即"]
|
| 39 |
cn_redirect = ["给您添麻烦", "不好意思打扰", "不胜感激"]
|
| 40 |
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
en_passive_nominal = ["inconvenience", "may cause", "it is requested"]
|
| 45 |
-
|
| 46 |
-
# ---- 双通道判断 ----
|
| 47 |
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
return "Redirect(转向)", "中文情感敬辞或英文被动/名词化导致策略位移 → 方向不确定。"
|
| 51 |
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
return "Amplify(放大)", "英文加入显性礼貌 markers,如 could / please / possibly → PDI 上移。"
|
| 55 |
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
return "Attenuate(削弱)", "英文更直接或缺乏缓和手段 → PDI 下移。"
|
| 59 |
|
| 60 |
-
|
| 61 |
-
return "Retain(保留)", "英文基本保持中文的礼貌策略 → PDI 稳定。"
|
| 62 |
|
| 63 |
|
| 64 |
# ---------------------------
|
| 65 |
-
#
|
| 66 |
# ---------------------------
|
| 67 |
-
def
|
| 68 |
-
|
| 69 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
|
| 71 |
-
#
|
| 72 |
-
|
| 73 |
|
| 74 |
-
|
| 75 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
|
| 77 |
-
|
| 78 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
"Retain": "低风险(关系保持稳定)",
|
| 80 |
-
"Amplify": "
|
| 81 |
-
"Attenuate": "
|
| 82 |
-
"Redirect": "
|
| 83 |
}
|
| 84 |
-
|
| 85 |
-
|
| 86 |
|
| 87 |
-
return
|
| 88 |
|
| 89 |
|
| 90 |
# ---------------------------
|
| 91 |
-
#
|
| 92 |
# ---------------------------
|
| 93 |
css = """
|
| 94 |
-
h1 {text-align:
|
| 95 |
-
.gradio-container {background-color
|
| 96 |
-
label {font-weight:
|
| 97 |
"""
|
| 98 |
|
| 99 |
-
with gr.Blocks(css=css, title="TIRA
|
| 100 |
-
|
| 101 |
gr.Markdown("""
|
| 102 |
-
# **📘 TIRA Academic Email Translation
|
| 103 |
-
### *Real Translation + Politeness Feature
|
| 104 |
-
---
|
| 105 |
-
|
| 106 |
-
输入中文学术邮件 → 系统将:
|
| 107 |
-
1. 使用 Transformer 翻译为英文
|
| 108 |
-
2. 自动抽取礼貌标记
|
| 109 |
-
3. 判定 TIRA 类型
|
| 110 |
-
4. 评估 PDI 风险
|
| 111 |
-
5. 给出翻译偏移解释
|
| 112 |
-
|
| 113 |
-
---
|
| 114 |
-
""")
|
| 115 |
-
|
| 116 |
-
cn_input = gr.Textbox(
|
| 117 |
-
label="✉ 输入中文邮件内容",
|
| 118 |
-
lines=5,
|
| 119 |
-
placeholder="例如:能否请您帮我看一下附件?"
|
| 120 |
-
)
|
| 121 |
-
|
| 122 |
-
btn = gr.Button("🔍 翻译与 TIRA 预测", variant="primary")
|
| 123 |
-
|
| 124 |
-
en_output = gr.Textbox(label="🌐 英文翻译")
|
| 125 |
-
marker_output = gr.Textbox(label="🔎 英文中的礼貌标记")
|
| 126 |
-
tira_output = gr.Textbox(label="📌 TIRA 类型")
|
| 127 |
-
analysis_output = gr.Textbox(label="📘 解释说明")
|
| 128 |
-
risk_output = gr.Textbox(label="⚠ PDI 风险")
|
| 129 |
-
|
| 130 |
-
btn.click(
|
| 131 |
-
fn=predict_tira,
|
| 132 |
-
inputs=cn_input,
|
| 133 |
-
outputs=[en_output, marker_output, tira_output, analysis_output, risk_output]
|
| 134 |
-
)
|
| 135 |
-
|
| 136 |
-
demo.launch()
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
import re
|
| 3 |
+
import matplotlib.pyplot as plt
|
| 4 |
+
import numpy as np
|
| 5 |
from transformers import pipeline
|
| 6 |
|
| 7 |
# ---------------------------
|
| 8 |
+
# Translator Model
|
| 9 |
# ---------------------------
|
| 10 |
translator = pipeline("translation", model="Helsinki-NLP/opus-mt-zh-en")
|
| 11 |
|
|
|
|
| 12 |
def translate_text(cn_text):
|
| 13 |
try:
|
| 14 |
+
return translator(cn_text)[0]["translation_text"]
|
|
|
|
| 15 |
except:
|
| 16 |
return "Translation model error."
|
| 17 |
|
| 18 |
|
| 19 |
# ---------------------------
|
| 20 |
+
# Politeness Markers Extraction
|
| 21 |
# ---------------------------
|
| 22 |
+
POLITENESS_FEATURES = {
|
| 23 |
+
"modals": ["could", "would", "may", "might"],
|
| 24 |
+
"softener": ["please", "kindly"],
|
| 25 |
+
"hedging": ["possibly", "perhaps", "a bit", "a little"],
|
| 26 |
+
"formal": ["professor", "sir", "madam"],
|
| 27 |
+
"passive": ["is requested", "may cause", "is appreciated"],
|
| 28 |
+
"appreciation": ["thank", "appreciate", "grateful"]
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
def extract_politeness_scores(en_text):
|
| 32 |
+
text = en_text.lower()
|
| 33 |
+
scores = {}
|
| 34 |
+
|
| 35 |
+
for feat, markers in POLITENESS_FEATURES.items():
|
| 36 |
+
score = sum(text.count(m) for m in markers)
|
| 37 |
+
score = min(score, 5) # cap at 5 for radar chart
|
| 38 |
+
scores[feat] = score
|
| 39 |
+
|
| 40 |
+
return scores
|
| 41 |
|
| 42 |
|
| 43 |
# ---------------------------
|
| 44 |
+
# TIRA Classification
|
|
|
|
| 45 |
# ---------------------------
|
| 46 |
def classify_tira(cn_text, en_text):
|
| 47 |
cn = cn_text.strip()
|
| 48 |
+
en = en_text.lower()
|
| 49 |
|
|
|
|
| 50 |
cn_amplify = ["能否", "是否方便", "请您帮忙", "抽空", "劳驾", "麻烦帮我"]
|
| 51 |
cn_attenuate = ["尽快", "必须", "需要您", "立即"]
|
| 52 |
cn_redirect = ["给您添麻烦", "不好意思打扰", "不胜感激"]
|
| 53 |
|
| 54 |
+
en_amplify = ["please", "could you", "possibly", "would you"]
|
| 55 |
+
en_attenuate = ["directly", "must", "asap"]
|
| 56 |
+
en_redirect = ["inconvenience", "may cause"]
|
|
|
|
|
|
|
|
|
|
| 57 |
|
| 58 |
+
if any(p in cn for p in cn_redirect) or any(p in en for p in en_redirect):
|
| 59 |
+
return "Redirect(转向)", "中文敬辞或英文名词化导致策略转向 → 方向不定。"
|
|
|
|
| 60 |
|
| 61 |
+
if any(p in cn for p in cn_amplify) or any(p in en for p in en_amplify):
|
| 62 |
+
return "Amplify(放大)", "英文显性礼貌增强 → PDI 上移。"
|
|
|
|
| 63 |
|
| 64 |
+
if any(p in cn for p in cn_attenuate) or any(p in en for p in en_attenuate):
|
| 65 |
+
return "Attenuate(削弱)", "英文更直接 → PDI 下移。"
|
|
|
|
| 66 |
|
| 67 |
+
return "Retain(保留)", "礼貌构式基本被稳定保留。"
|
|
|
|
| 68 |
|
| 69 |
|
| 70 |
# ---------------------------
|
| 71 |
+
# Radar Chart Drawing
|
| 72 |
# ---------------------------
|
| 73 |
+
def draw_radar(scores_dict):
|
| 74 |
+
labels = list(scores_dict.keys())
|
| 75 |
+
scores = list(scores_dict.values())
|
| 76 |
+
|
| 77 |
+
angles = np.linspace(0, 2 * np.pi, len(labels), endpoint=False).tolist()
|
| 78 |
+
scores += scores[:1]
|
| 79 |
+
angles += angles[:1]
|
| 80 |
+
|
| 81 |
+
fig, ax = plt.subplots(figsize=(5, 5), subplot_kw=dict(polar=True))
|
| 82 |
|
| 83 |
+
ax.fill(angles, scores, color="#1B3B6F80", alpha=0.4)
|
| 84 |
+
ax.plot(angles, scores, color="#1B3B6F", linewidth=2)
|
| 85 |
|
| 86 |
+
ax.set_xticks(angles[:-1])
|
| 87 |
+
ax.set_xticklabels([label.capitalize() for label in labels], fontsize=10)
|
| 88 |
+
ax.set_yticks(range(1, 6))
|
| 89 |
+
ax.set_yticklabels([str(i) for i in range(1, 6)], fontsize=8)
|
| 90 |
+
ax.set_ylim(0, 5)
|
| 91 |
+
ax.grid(True)
|
| 92 |
|
| 93 |
+
return fig
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
# ---------------------------
|
| 97 |
+
# Main Function
|
| 98 |
+
# ---------------------------
|
| 99 |
+
def full_process(cn_text):
|
| 100 |
+
en = translate_text(cn_text)
|
| 101 |
+
scores = extract_politeness_scores(en)
|
| 102 |
+
tira, analysis = classify_tira(cn_text, en)
|
| 103 |
+
|
| 104 |
+
risk = {
|
| 105 |
"Retain": "低风险(关系保持稳定)",
|
| 106 |
+
"Amplify": "中风险(可能显得更有距离)",
|
| 107 |
+
"Attenuate": "中偏高(可能显得更直接)",
|
| 108 |
+
"Redirect": "不稳定(可能造成理解偏差)"
|
| 109 |
}
|
| 110 |
+
risk_out = risk[tira.split("(")[0]]
|
| 111 |
+
radar = draw_radar(scores)
|
| 112 |
|
| 113 |
+
return en, scores, tira, analysis, risk_out, radar
|
| 114 |
|
| 115 |
|
| 116 |
# ---------------------------
|
| 117 |
+
# UI (Deep Blue Academic Style)
|
| 118 |
# ---------------------------
|
| 119 |
css = """
|
| 120 |
+
h1 {text-align:center; color:#1B3B6F;}
|
| 121 |
+
.gradio-container {background-color:#F6F8FA;}
|
| 122 |
+
label {font-weight:bold;}
|
| 123 |
"""
|
| 124 |
|
| 125 |
+
with gr.Blocks(css=css, title="TIRA Radar System") as demo:
|
|
|
|
| 126 |
gr.Markdown("""
|
| 127 |
+
# **📘 TIRA Academic Email Translation Visualizer**
|
| 128 |
+
### *Real-Time Translation + Politeness Feature Radar + TIRA Classificatio*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|