Spaces:
Sleeping
Sleeping
| 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") | |