Spaces:
Sleeping
Sleeping
File size: 10,855 Bytes
ab2cf61 a68f13c ab2cf61 2895204 ab2cf61 2895204 ab2cf61 01e2dc9 ab2cf61 a68f13c ab2cf61 bd14caf 60032e2 9ec25fc 5bf406d 9ec25fc bd14caf 9ec25fc bd14caf 60032e2 bd14caf 9ec25fc bd14caf 9ec25fc bd14caf 9ec25fc bd14caf 60032e2 bd14caf 60032e2 bd14caf | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 | import gradio as gr
import os
import json
from typing import TypedDict, List, Dict, Any, Optional
from langgraph.graph import StateGraph, START, END
# from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, AIMessage
# from llama_index.llms.huggingface_api import HuggingFaceInferenceAPI
from huggingface_hub import InferenceClient
class EmailState(TypedDict):
# 正在处理的电子邮件
email: Dict[str, Any] # 包含主题、发件人、正文等。
# 分析与决策
is_spam: Optional[bool]
spam_reason: Optional[str]
email_category: Optional[str]
# 响应生成
draft_response: Optional[str]
# 处理元数据
messages: List[Dict[str, Any]] # 跟踪与 LLM 的对话以进行分析
# Initialize our LLM
# model = ChatOpenAI(temperature=0)
# model = HuggingFaceInferenceAPI(model_name="Qwen/Qwen2.5-Coder-32B-Instruct")
hf_token=os.getenv("hf_token")
model = InferenceClient(
model="Qwen/Qwen2.5-Coder-32B-Instruct",
token=hf_token,
timeout=30
)
def query_llm(prompt: str):
response = model.chat.completions.create(messages=[
{
"role": "user",
"content": prompt
}],temperature=0)
return response.choices[0].message
def read_email(state: EmailState):
"""Alfred reads and logs the incoming email"""
email = state["email"]
# 在这里我们可能会做一些初步的预处理
print(f"Alfred is processing an email from {email['sender']} with subject: {email['subject']}")
# 这里不需要更改状态
return {}
def classify_email(state: EmailState):
"""Alfred uses an LLM to determine if the email is spam or legitimate"""
email = state["email"]
# 为 LLM 准备提示
prompt = f"""
As Alfred the butler, analyze this email and determine if it is spam or legitimate.
Email:
From: {email['sender']}
Subject: {email['subject']}
Body: {email['body']}
First, determine if this email is spam. If it is spam, explain why.
If it is legitimate, categorize it (inquiry, complaint, thank you, etc.).
Please answer strictly in the following format:
Email category: inquiry, complaint, thank you, spam, etc.
Is spam:
Reason for spam:
"""
# Call the LLM
# messages = [HumanMessage(content=prompt)]
response = query_llm(prompt)
# 解析响应的简单逻辑(在实际应用中,您需要更强大的解析)
response_text = response.content.lower()
# print(f"test response_text:{response_text}")
is_spam = "is spam: yes" in response_text
# print(f"test is_spam:{is_spam and "reasoning:" in response_text}")
# print(f"test reasoning:{response_text.split("reasoning:")[1].strip()}")
# 如果是垃圾邮件,请提取原因,输出的格式可能不同,需要根据提示词固定格式。
spam_reason = None
spam_reason_keyword="reason for spam:"
if is_spam and spam_reason_keyword in response_text:
spam_reason = response_text.split(spam_reason_keyword)[1].strip()
# print(f"test spam_reason:{spam_reason}")
# 确定类别是否合法
email_category = None
if not is_spam:
categories = ["inquiry", "complaint", "thank you", "request", "information"]
for category in categories:
if category in response_text:
email_category = category
break
# 更新消息以进行追踪
new_messages = state.get("messages", []) + [
{"role": "user", "content": prompt},
{"role": "assistant", "content": response.content}
]
# 返回状态更新
return {
"is_spam": is_spam,
"spam_reason": spam_reason,
"email_category": email_category,
"messages": new_messages
}
def route_email(state: EmailState) -> str:
"""Determine the next step based on spam classification"""
# print(f"route_email,state={state}")
if state["is_spam"]:
return "spam"
else:
return "legitimate"
def handle_spam(state: EmailState):
"""Alfred discards spam email with a note"""
# print(f"handle_spam,state={state}")
# print(f"is_spam:{state.get("is_spam","none")}")
print(f"Alfred has marked the email as spam. Reason: {state.get("spam_reason","none")}")
print("The email has been moved to the spam folder.")
# 我们已处理完这封电子邮件
return {}
def draft_response(state: EmailState):
"""Alfred drafts a preliminary response for legitimate emails"""
email = state["email"]
category = state["email_category"] or "general"
# 为 LLM 准备提示词
prompt = f"""
As Alfred the butler, draft a polite preliminary response to this email.
Email:
From: {email['sender']}
Subject: {email['subject']}
Body: {email['body']}
This email has been categorized as: {category}
Draft a brief, professional response that Mr. Hugg can review and personalize before sending.
"""
# Call the LLM
# messages = [HumanMessage(content=prompt)]
response = query_llm(prompt)
# 更新消息以进行追踪
new_messages = state.get("messages", []) + [
{"role": "user", "content": prompt},
{"role": "assistant", "content": response.content}
]
# 返回状态更新
return {
"draft_response": response.content,
"messages": new_messages
}
def notify_mr_hugg(state: EmailState):
"""Alfred notifies Mr. Hugg about the email and presents the draft response"""
email = state["email"]
print("\n" + "="*50)
print(f"Sir, you've received an email from {email['sender']}.")
print(f"Subject: {email['subject']}")
print(f"Category: {state['email_category']}")
print("\nI've prepared a draft response for your review:")
print("-"*50)
print(state["draft_response"])
print("="*50 + "\n")
# 我们已处理完这封电子邮件
return {}
# 创建 graph
email_graph = StateGraph(EmailState)
# 添加 nodes
email_graph.add_node("read_email", read_email)
email_graph.add_node("classify_email", classify_email)
email_graph.add_node("handle_spam", handle_spam)
email_graph.add_node("draft_response", draft_response)
email_graph.add_node("notify_mr_hugg", notify_mr_hugg)
# 添加 edges - 定义流程
email_graph.add_edge(START, "read_email")
email_graph.add_edge("read_email", "classify_email")
# 从 classify_email 添加条件分支
email_graph.add_conditional_edges(
"classify_email",
route_email,
{
"spam": "handle_spam",
"legitimate": "draft_response"
}
)
# 添加最后的 edges
email_graph.add_edge("handle_spam", END)
email_graph.add_edge("draft_response", "notify_mr_hugg")
email_graph.add_edge("notify_mr_hugg", END)
# 编译 graph
compiled_graph = email_graph.compile()
# 合法电子邮件示例
legitimate_email = {
"sender": "john.smith@example.com",
"subject": "Question about your services",
"body": "Dear Mr. Hugg, I was referred to you by a colleague and I'm interested in learning more about your consulting services. Could we schedule a call next week? Best regards, John Smith"
}
# 垃圾邮件示例
spam_email = {
"sender": "winner@lottery-intl.com",
"subject": "YOU HAVE WON $5,000,000!!!",
"body": "CONGRATULATIONS! You have been selected as the winner of our international lottery! To claim your $5,000,000 prize, please send us your bank details and a processing fee of $100."
}
def classify_email(json_input):
email = json.loads(json_input)
result = compiled_graph.invoke({
"email": email,
"is_spam": None,
"spam_reason": None,
"email_category": None,
"draft_response": None,
"messages": []
})
return f"is_spam:{result.get("is_spam")}\nspam_reason:{result.get("spam_reason")}"
# ===================== 核心处理函数(模拟邮件分析) =====================
def classify_email(sender: str, subject: str, body: str) -> tuple[str, str]:
if sender.strip() == "" or subject.strip() == "" or body.strip() == "" :
return "true", "sender、subject、subject为空"
email = {
"sender": sender,
"subject": subject,
"body": body
}
result = compiled_graph.invoke({
"email": email,
"is_spam": None,
"spam_reason": None,
"email_category": None,
"draft_response": None,
"messages": []
})
return result.get("is_spam"), result.get("spam_reason")
# ===================== Gradio 表单界面构建 =====================
with gr.Blocks(title="邮件分析表单", theme=gr.themes.Soft()) as demo:
# 标题说明
gr.Markdown("### 📧 邮件垃圾信息分析表单")
gr.Markdown("请输入以下3项信息,提交后自动分析邮件是否为垃圾邮件")
# 表单区域:3个文本输入框
with gr.Row(): # 行布局,可选:改为 gr.Column() 垂直布局
with gr.Column(scale=1):
sender_input = gr.Textbox(
label="1. 发件人邮箱地址",
placeholder="john.smith@gmail.com",
lines=1,
max_lines=1
)
with gr.Column(scale=2):
subject_input = gr.Textbox(
label="2. 邮件主题",
placeholder="预约会议",
lines=1,
max_lines=1
)
# 第三个文本框:多行输入(邮件内容)
content_input = gr.Textbox(
label="3. 邮件内容",
placeholder="我想预约下周二的咨询会议",
lines=5,
max_lines=10
)
# 提交按钮
submit_btn = gr.Button("📤 提交分析", variant="primary", size="lg")
# 分割线
# gr.Divider()
# 结果展示区域(结构化输出)
gr.Markdown("### 📝 分析结果")
with gr.Row():
is_spam_output = gr.Textbox(label="是否垃圾邮件", interactive=False)
reason_output = gr.Textbox(label="判定原因", lines=3, interactive=False)
# 绑定按钮与处理函数
submit_btn.click(
fn=classify_email,
inputs=[sender_input, subject_input, content_input], # 3个输入框
outputs=[is_spam_output, reason_output] # 2个输出框
)
# 重置按钮(可选)
reset_btn = gr.Button("🔄 清空输入")
reset_btn.click(
fn=lambda: ("", "", "", "", "", ""), # 重置所有输入输出
inputs=[],
outputs=[sender_input, subject_input, content_input, is_spam_output, reason_output]
)
# ===================== 启动界面 =====================
if __name__ == "__main__":
# server_name="0.0.0.0" 允许局域网访问,server_port 自定义端口
demo.launch()
# demo = gr.Interface(fn=classify_email, inputs="text", outputs="text")
# demo.launch() |