Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import fitz # PyMuPDF | |
| import openai | |
| import re | |
| import os | |
| # ✅ 使用 Hugging Face Secrets 管理 API 金鑰 | |
| openai.api_key = os.environ.get("OPENAI_API_KEY") | |
| # --- 清理文字 --- | |
| def clean_text(text): | |
| text = re.sub(r'^\s*\d+\s*$', '', text, flags=re.MULTILINE) | |
| text = re.sub(r'\n\s*\n+', '\n\n', text) | |
| text = re.sub(r'[ \t]+', ' ', text) | |
| return text.strip() | |
| # --- 改進版:區塊式擷取 PDF 文字 + 座標排序 --- | |
| def extract_text_from_pdf(file): | |
| doc = fitz.open(file.name) | |
| text_blocks = [] | |
| for page in doc: | |
| blocks = page.get_text("blocks") # 回傳每段區塊含座標 | |
| blocks = sorted(blocks, key=lambda b: (b[1], b[0])) # 先依 y,再依 x 排序 | |
| for b in blocks: | |
| text_blocks.append(b[4]) | |
| doc.close() | |
| return clean_text("\n".join(text_blocks)) | |
| # --- GPT 履歷分析(STAR 法則)--- | |
| def analyze_resume(resume_text): | |
| prompt = f""" | |
| 你是一位專業的履歷健檢與職涯輔導顧問,請協助我以下幾件事: | |
| 注意:這份履歷是由 PDF 擷取而來,可能因版面問題導致部分文字順序略有錯亂。請你盡量根據語意邏輯判斷內容。 | |
| 1. 根據下方履歷內容,幫我整理出: | |
| - 學歷背景 | |
| - 技能與工具 | |
| - 工作經歷與專案經歷 | |
| 2. 對於每一段經歷,請用 STAR 法則整理: | |
| - S(情境) | |
| - T(任務) | |
| - A(行動) | |
| - R(成果) | |
| 3. 指出這份履歷的優勢,以及可以優化的建議 | |
| 4. 推薦幾個可能適合的職缺方向(例如:前端工程師、資料分析師、產品實習生等) | |
| 這是履歷內容: | |
| ------------------------ | |
| {resume_text} | |
| ------------------------ | |
| 請以條列式輸出,分段清楚。 | |
| """ | |
| response = openai.ChatCompletion.create( | |
| model="gpt-4", | |
| messages=[ | |
| {"role": "system", "content": "你是一位履歷健檢顧問"}, | |
| {"role": "user", "content": prompt} | |
| ], | |
| temperature=0.7, | |
| max_tokens=1500 | |
| ) | |
| content = response['choices'][0]['message']['content'] | |
| return content.replace("**", "").replace("* ", "• ").replace("*", "").strip() | |
| # --- GPT 自傳撰寫 --- | |
| def generate_autobiography(resume_text): | |
| prompt = f""" | |
| 這是從 PDF 擷取的履歷文字,順序可能略有錯亂。請盡量根據語意整理,幫我撰寫一段約 300 字的個人自傳。口吻自然、自信,強調個人特質、學習歷程與職涯目標,可作為履歷中的「自我介紹」使用: | |
| 履歷內容: | |
| ------------------------ | |
| {resume_text} | |
| ------------------------ | |
| """ | |
| response = openai.ChatCompletion.create( | |
| model="gpt-4", | |
| messages=[ | |
| {"role": "system", "content": "你是一位履歷與自傳輔導顧問"}, | |
| {"role": "user", "content": prompt} | |
| ], | |
| temperature=0.7, | |
| max_tokens=800 | |
| ) | |
| return response['choices'][0]['message']['content'].strip() | |
| # --- Gradio UI --- | |
| with gr.Blocks(title="求職小幫手 AI") as demo: | |
| gr.Markdown("## 🧑💼 求職小幫手 AI\n上傳履歷 PDF,我們幫你分析亮點並撰寫個人自傳!") | |
| with gr.Row(): | |
| pdf_input = gr.File(label="📄 上傳履歷 PDF", file_types=[".pdf"]) | |
| extract_btn = gr.Button("⬇️ 擷取與清理內容") | |
| resume_textbox = gr.Textbox(label="📄 擷取後的履歷純文字", lines=20, interactive=False) | |
| with gr.Row(): | |
| analyze_btn = gr.Button("🧠 分析履歷(STAR 法則)") | |
| bio_btn = gr.Button("📝 撰寫個人自傳") | |
| analysis_output = gr.Textbox(label="✨ GPT 履歷分析結果", lines=25) | |
| bio_output = gr.Textbox(label="✍️ GPT 產生的個人自傳", lines=15) | |
| extract_btn.click(fn=extract_text_from_pdf, inputs=pdf_input, outputs=resume_textbox) | |
| analyze_btn.click(fn=analyze_resume, inputs=resume_textbox, outputs=analysis_output) | |
| bio_btn.click(fn=generate_autobiography, inputs=resume_textbox, outputs=bio_output) | |
| demo.launch() | |