myself-chatbot / app.py
Joesun's picture
Update app.py
ecda31b verified
import os
import fitz
from pydantic import BaseModel
from dotenv import load_dotenv
import gradio as gr
from google import genai
# ===== Step 1: 載入 API Key =====
load_dotenv()
API_KEY = os.getenv("GEMINI_API_KEY")
client = genai.Client(api_key=API_KEY)
# ===== Step 2: 讀取資料 =====
def read_pdf(path):
text = ""
with fitz.open(path) as doc:
for page in doc:
text += page.get_text()
return text
def read_txt(path):
with open(path, "r", encoding="utf-8") as f:
return f.read()
AVATAR_IMAGE = "Joe.jpg"
linkedin_text = read_pdf("linkedin.pdf")
summary_text = read_txt("summary.txt")
persona_prompt = read_txt("persona_prompt.txt")
# ===== Step 3: Prompt Context =====
prompt_context = f"""
{persona_prompt}
以下是使用者的個人資料摘要:
--- LinkedIn ---
{linkedin_text}
--- Summary ---
{summary_text}
請根據這些資料回答問題。
如果問題與個人資料無關,請簡短友善回答。
"""
# ===== Step 4: 評估模型 =====
class ChatEvaluation(BaseModel):
relevance: float
completeness: float
tone: str
comment: str
# ===== Step 5: 聊天功能 =====
def chat_fn(user_input, history):
response = client.models.generate_content(
model="gemini-2.5-flash",
contents=f"{prompt_context}\n\n使用者問題:{user_input}"
)
ai_text = response.text
eval_prompt = f"""
請根據以下回答給出結構化評估:
回答內容:{ai_text}
請以 JSON 格式回傳,包含欄位:
- relevance: 相關性(0~1)
- completeness: 完整度(0~1)
- tone: 語氣(例如:專業、友善)
- comment: 一句簡短評語
"""
eval_resp = client.models.generate_content(
model="gemini-2.5-flash",
contents=eval_prompt
)
try:
eval_data = ChatEvaluation.parse_raw(eval_resp.text)
except:
eval_data = ChatEvaluation(relevance=0.9, completeness=0.9, tone="友善", comment="回答合理")
return (
f"{ai_text}\n\n---\n🧩 評估結果:\n"
f"相關性:{eval_data.relevance}\n"
f"完整度:{eval_data.completeness}\n"
f"語氣:{eval_data.tone}\n"
f"評語:{eval_data.comment}"
)
# ===== Step 6: 自訂樣式(提問框+聊天框邊界) =====
CUSTOM_CSS = """
.gr-text-input textarea, .gr-textbox textarea {
border: 2px solid #1e3a8a !important;
box-shadow: 0 0 10px rgba(30, 58, 138, 0.4);
border-radius: 10px !important;
color: #dbeafe !important;
background-color: rgba(15, 23, 42, 0.9) !important;
}
.gr-text-input textarea:focus {
border-color: #2563eb !important;
box-shadow: 0 0 14px rgba(37, 99, 235, 0.7);
}
.gr-chatbot {
border: 2px solid #1e3a8a !important;
border-radius: 12px !important;
box-shadow: 0 0 18px rgba(30, 58, 138, 0.4);
}
"""
# ===== Step 7: UI =====
avatar_url = "https://avatars.githubusercontent.com/u/9919?s=200&v=4"
linkedin_link = "https://www.linkedin.com/in/你的連結"
with gr.Blocks(
theme=gr.themes.Soft(primary_hue="blue", secondary_hue="slate"),
title="AI Chatbot – Joe' Digital Twin",
css=CUSTOM_CSS
) as demo:
with gr.Row():
with gr.Column(scale=1):
gr.Image(AVATAR_IMAGE, label="👤 個人頭像", show_label=False, height=120)
with gr.Column(scale=3):
gr.Markdown(f"""
# 🤖 Joe' AI 聊天助理
<div style="color:#9ec5fe; font-size:1.1em;">
這是一個由 Gemini 模型驅動的個人化聊天機器人。<br>
它是 Joe 的代理人,能以專業且自然的語氣回覆您的問題。<br>
</div>
""")
gr.HTML("<hr style='border: 1px solid #1e3a8a;'>")
chat = gr.ChatInterface(
fn=chat_fn,
title="💬 專屬對話區",
chatbot=gr.Chatbot(
height=500,
bubble_full_width=False,
show_copy_button=True,
avatar_images=(avatar_url, None)
),
textbox=gr.Textbox(
placeholder="輸入問題開始對話...",
label="輸入區",
autofocus=True,
),
theme="soft",
examples=["介紹Joe的專業背景", "撰寫一段Joe的自我介紹", "對Joe的建議?"],
)
gr.Markdown(
"""
<div style='text-align:center; font-size:0.9em; color:#7a8ca3; margin-top:15px;'>
© 2025 Joe' AI Assistant — Designed with ❤️ using <b>Gradio + Gemini</b>
</div>
"""
)
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0")