Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,46 +1,130 @@
|
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
|
| 4 |
-
#
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
SYSTEM_PROMPT = (
|
| 10 |
-
"You are Ivy (Jiexin Chen). Answer
|
| 11 |
-
"
|
| 12 |
-
"
|
| 13 |
-
"Wisers (data science intern, Weibo NLP sentiment). Skills: Python, Java, C, R, MATLAB, PyTorch, SQL, Tableau, Excel, HTML/CSS/JS; "
|
| 14 |
-
"Core: ML, DL, NLP, Data Analysis. If question is unrelated to Ivy, gently steer back."
|
| 15 |
)
|
| 16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
def chat_fn(message, history):
|
| 18 |
-
#
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
**inputs,
|
| 27 |
-
max_new_tokens=
|
| 28 |
-
do_sample=True,
|
| 29 |
-
top_p=0.9,
|
| 30 |
temperature=0.7,
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
pad_token_id=tokenizer.eos_token_id,
|
| 32 |
)
|
| 33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
|
| 35 |
-
|
| 36 |
-
if "Ivy:" in reply:
|
| 37 |
-
reply = reply.split("Ivy:")[-1].strip()
|
| 38 |
-
return reply
|
| 39 |
|
|
|
|
|
|
|
|
|
|
| 40 |
demo = gr.ChatInterface(
|
| 41 |
fn=chat_fn,
|
| 42 |
-
title="Ivy Chatbot (Free Demo)",
|
| 43 |
-
description=
|
|
|
|
|
|
|
|
|
|
| 44 |
chatbot=gr.Chatbot(height=420, label="Chat"),
|
| 45 |
textbox=gr.Textbox(placeholder="Ask me anything about Ivy...", autofocus=True),
|
| 46 |
theme="soft",
|
|
|
|
| 1 |
+
# app.py — Ivy Chatbot (Free RAG Demo on CPU)
|
| 2 |
import gradio as gr
|
| 3 |
+
import numpy as np
|
| 4 |
+
from transformers import (
|
| 5 |
+
BlenderbotSmallTokenizer,
|
| 6 |
+
BlenderbotSmallForConditionalGeneration
|
| 7 |
+
)
|
| 8 |
+
from sentence_transformers import SentenceTransformer
|
| 9 |
+
|
| 10 |
+
# ---------------------------
|
| 11 |
+
# 1) 模型与向量器(免费CPU可跑)
|
| 12 |
+
# ---------------------------
|
| 13 |
+
GEN_MODEL_NAME = "facebook/blenderbot_small-90M"
|
| 14 |
+
EMB_MODEL_NAME = "sentence-transformers/all-MiniLM-L6-v2" # 小、快、准
|
| 15 |
+
|
| 16 |
+
tokenizer = BlenderbotSmallTokenizer.from_pretrained(GEN_MODEL_NAME)
|
| 17 |
+
gen_model = BlenderbotSmallForConditionalGeneration.from_pretrained(GEN_MODEL_NAME)
|
| 18 |
+
embedder = SentenceTransformer(EMB_MODEL_NAME)
|
| 19 |
|
| 20 |
+
# ---------------------------
|
| 21 |
+
# 2) 你的“简历知识库” —— 可继续补充
|
| 22 |
+
# 规则:每一条是一个“可检索文档片段”
|
| 23 |
+
# ---------------------------
|
| 24 |
+
DOCS = [
|
| 25 |
+
# 教育
|
| 26 |
+
"Education: Columbia University, Master's in Statistics (Advanced Machine Learning Track), 2025–2027.",
|
| 27 |
+
"Education: Hong Kong Baptist University, B.Sc. Computer Science and Technology, First Class Honours, 2021–2025.",
|
| 28 |
+
"Exchange: University of Oxford, AI & Machine Learning programme, 2023.",
|
| 29 |
+
# 奖项
|
| 30 |
+
"Awards: First-class Scholarship (2021–2023), Second-class Scholarship (2024), MCM Honorable Mention (2024), Chinese Mathematical Competition Provincial 2nd Prize (2023).",
|
| 31 |
+
# 经验
|
| 32 |
+
"Experience: Social Media Analyst at StudyCo (part-time), Jan 2023–Present, Melbourne (Hybrid). Did audience/product data analysis with Python/Excel, wrote copy, edited short videos, increased Xiaohongshu followers from 3,000+ to 10,000+.",
|
| 33 |
+
"Experience: Data Science Intern at Wisers (May–Jul 2023), Shanghai (Hybrid). Weibo sentiment analysis; Chinese NLP preprocessing (jieba, custom dict, post classification); visualized with matplotlib, wordcloud; Tableau + MySQL real-time dashboards; SQL for data extraction.",
|
| 34 |
+
# 项目(挑重点)
|
| 35 |
+
"Project: Intelligent Retirement — Monte Carlo simulation; economic scenario generator; decision support for investment/consumption under uncertainty (2024).",
|
| 36 |
+
"Project: Predicting Intern Recruitment with Bayesian Networks — VE & Clique Tree inference; DAG with ~12 key nodes; interactive UI to explore outcomes (2024).",
|
| 37 |
+
"Project: LLM Check System — Flask + MySQL + SQLAlchemy; OOA/OOD; unit & integration testing; frontend HTML/CSS/JS (2024).",
|
| 38 |
+
"Project: Twitter Sentiment Analysis — NLP preprocessing; RNN/LSTM/BERT, best accuracy 89% (2024).",
|
| 39 |
+
"Project: Long-text abstraction & character relationship (T5 + PageRank + PySpark) — build character networks, accelerate top-20 character identification (2023).",
|
| 40 |
+
"Project: Online Restaurant Ordering System — ER with 10 entities/15 relationships; VIP, live order status, personalized recommendations; >60k users/products (2022).",
|
| 41 |
+
"Project: Path Planning for Mobile Robots — Q-learning vs DQN; DQN reached 94% in complex mazes (PyTorch) (2022).",
|
| 42 |
+
# 技能
|
| 43 |
+
"Skills: Python, Java, C, R, MATLAB; Web: HTML, CSS, JavaScript; Frameworks/Tools: PyTorch, Tableau, SQL, SPSS, Excel; Core: Machine Learning, Deep Learning, NLP, Data Analysis.",
|
| 44 |
+
]
|
| 45 |
|
| 46 |
+
# 预生成向量
|
| 47 |
+
DOC_EMBS = embedder.encode(DOCS, normalize_embeddings=True)
|
| 48 |
+
|
| 49 |
+
# ---------------------------
|
| 50 |
+
# 3) Prompt 组件
|
| 51 |
+
# ---------------------------
|
| 52 |
SYSTEM_PROMPT = (
|
| 53 |
+
"You are Ivy (Jiexin Chen). Answer in FIRST PERSON, concise, friendly, professional. "
|
| 54 |
+
"Only talk about Ivy's background, education, projects, skills, and experience. "
|
| 55 |
+
"If asked something unrelated, briefly steer back to career topics.\n"
|
|
|
|
|
|
|
| 56 |
)
|
| 57 |
|
| 58 |
+
STYLE_HINT = (
|
| 59 |
+
"Style: 2–5 short sentences. Use concrete facts from the provided context if relevant. "
|
| 60 |
+
"If the information is missing, say it briefly and suggest related areas I can talk about."
|
| 61 |
+
)
|
| 62 |
+
|
| 63 |
+
def build_prompt(question: str, retrieved_snippets: list[str]) -> str:
|
| 64 |
+
context_block = "\n".join(f"- {s}" for s in retrieved_snippets)
|
| 65 |
+
prompt = (
|
| 66 |
+
f"{SYSTEM_PROMPT}\n"
|
| 67 |
+
f"{STYLE_HINT}\n\n"
|
| 68 |
+
f"Context:\n{context_block}\n\n"
|
| 69 |
+
f"User: {question}\n"
|
| 70 |
+
f"Ivy:"
|
| 71 |
+
)
|
| 72 |
+
return prompt
|
| 73 |
+
|
| 74 |
+
# ---------------------------
|
| 75 |
+
# 4) 简���检索器(余弦相似度)
|
| 76 |
+
# ---------------------------
|
| 77 |
+
def retrieve(query: str, top_k: int = 4) -> list[str]:
|
| 78 |
+
q_emb = embedder.encode([query], normalize_embeddings=True)[0]
|
| 79 |
+
sims = (DOC_EMBS @ q_emb) # 余弦相似度(已归一化)
|
| 80 |
+
idx = np.argsort(-sims)[:top_k]
|
| 81 |
+
return [DOCS[i] for i in idx]
|
| 82 |
+
|
| 83 |
+
# ---------------------------
|
| 84 |
+
# 5) 对话函数:检索 → 组 Prompt → 生成
|
| 85 |
+
# ---------------------------
|
| 86 |
def chat_fn(message, history):
|
| 87 |
+
# 最近几轮加入问题提示(帮助检索)
|
| 88 |
+
history_tail = " ".join([u for u, _ in history[-3:]]) if history else ""
|
| 89 |
+
query = (message or "").strip()
|
| 90 |
+
full_query = (query + " " + history_tail).strip() or "Ivy summary"
|
| 91 |
+
|
| 92 |
+
# 检索
|
| 93 |
+
retrieved = retrieve(full_query, top_k=4)
|
| 94 |
+
|
| 95 |
+
# 构造提示词
|
| 96 |
+
prompt = build_prompt(query, retrieved)
|
| 97 |
+
|
| 98 |
+
# 生成
|
| 99 |
+
inputs = tokenizer([prompt], return_tensors="pt")
|
| 100 |
+
output_ids = gen_model.generate(
|
| 101 |
**inputs,
|
| 102 |
+
max_new_tokens=140,
|
|
|
|
|
|
|
| 103 |
temperature=0.7,
|
| 104 |
+
top_p=0.9,
|
| 105 |
+
do_sample=True,
|
| 106 |
+
no_repeat_ngram_size=3,
|
| 107 |
+
repetition_penalty=1.15,
|
| 108 |
pad_token_id=tokenizer.eos_token_id,
|
| 109 |
)
|
| 110 |
+
text = tokenizer.decode(output_ids[0], skip_special_tokens=True)
|
| 111 |
+
|
| 112 |
+
# 抽取 "Ivy:" 之后的回答
|
| 113 |
+
if "Ivy:" in text:
|
| 114 |
+
text = text.split("Ivy:", 1)[-1].strip()
|
| 115 |
|
| 116 |
+
return text
|
|
|
|
|
|
|
|
|
|
| 117 |
|
| 118 |
+
# ---------------------------
|
| 119 |
+
# 6) UI
|
| 120 |
+
# ---------------------------
|
| 121 |
demo = gr.ChatInterface(
|
| 122 |
fn=chat_fn,
|
| 123 |
+
title="Ivy Chatbot (Free RAG Demo)",
|
| 124 |
+
description=(
|
| 125 |
+
"Ask me about my education, projects, skills, and experience. "
|
| 126 |
+
"Runs on free CPU with a small model + retrieval for better accuracy."
|
| 127 |
+
),
|
| 128 |
chatbot=gr.Chatbot(height=420, label="Chat"),
|
| 129 |
textbox=gr.Textbox(placeholder="Ask me anything about Ivy...", autofocus=True),
|
| 130 |
theme="soft",
|