import gradio as gr from PIL import Image import numpy as np import faiss import torch #載入聊天機器人模型 from transformers import AutoTokenizer, AutoModelForCausalLM,TextIteratorStreamer,AutoModel from threading import Thread tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2-0.5B-Instruct") model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2-0.5B-Instruct") # device = "cuda" # model.to(device) def chat(message, history): prompt = [ {"role": "system", "content": "You are a helpful assistant."}, ] for i in history: prompt.append({"role": "user", "content": i[0]}) prompt.append({"role": "assisant", "content": i[1]}) prompt.append({"role": "user", "content": message}) messages = prompt text = tokenizer.apply_chat_template( messages, tokenize=False, add_generation_prompt=True ) # model_inputs = tokenizer([text], return_tensors="pt").to("cuda") model_inputs = tokenizer([text], return_tensors="pt") streamer = TextIteratorStreamer(tokenizer, timeout=10., skip_prompt=True, skip_special_tokens=True) generate_kwargs = dict( model_inputs, streamer=streamer, max_new_tokens=512, do_sample=True, top_p=0.95, top_k=1000, temperature=1.0, ) t = Thread(target=model.generate, kwargs=generate_kwargs) t.start() partial_message = "" for new_token in streamer: partial_message += new_token yield partial_message #AI履歷助手(使用RAG) embd= AutoModel.from_pretrained('jinaai/jina-embeddings-v2-base-zh', trust_remote_code=True, torch_dtype=torch.bfloat16) doc={'技能':'python,深度學習,web開發,數據分析', '經歷':'ICIM2024研討會、碩士期間擔任指導教授所開的類神經網路課程助教、大學專題實務成果展競賽亞軍,技術類業界評選第一名。', '論文概述':'題為「基於情緒支持的對話:融合情緒感知和關鍵字識別的研究」。研究旨在通過聊天機器人為情緒困擾者提供陪伴,緩解其短期心理壓力。本文提出的模型結合情緒標籤和關鍵字識別技術,與其他基礎模型相比,能夠提供更精準的回復,從而更有效地支持用戶的情緒需求。', '證照':'電腦硬體裝修丙級、電腦硬體裝修乙級、Database Administration Fundamentals、Software Development Fundamentals、Networking Fundamentals、CRM Merchandise Analyst、Enterprise Resource Planning', '助教工作內容':'主要協助老師指導學生實作部分。包括使用 WEKA 軟體教導學生快速構建和分析機器學習模型,並解釋模型結果的含義。後期則引導學生安裝 Python 環境,撰寫並執行機器學習模型的程式碼,幫助學生在未來能夠運用 AI 技術更有效地完成工作。', '專題內容':'專題名稱:熱影像結合人臉偵測暨網頁瀏覽系統。為因應新冠疫情,無接觸體溫檢測需求激增,本專題開發了利用紅外線熱影像和後端資料庫蒐集,最終實現異地閱覽和確保體溫監測的安全與效率。/n我的貢獻:硬體設備組裝、人臉偵測和後端資料庫及視覺化', '專案':'學生點名系統、氣管插管預測、貨車車牌辨識、聊天機器人', '學生點名系統簡述':''' 動機與目的: 鑒於每次上課點名都是老師的一大負擔,開發了這個學生點名系統,旨在幫助老師更有效地進行點名。本專案使用 Laravel 開源 PHP Web 框架開發,主要功能包括: 老師功能: - 查看課表及點名記錄 - 查看學生出缺席和請假狀況 - 審核學生請假申請 學生功能: - 查看課表及進行點名 - 查看出缺席和請假記錄 - 申請請假 該完整專案在github上,網址:https://github.com/WISD-2020/final02 ''', '氣管插管預測簡述':'動機與目的:為了協助醫生在執行插管時更精確地將氧氣管置入正確位置,我們利用影像分割技術(如 TransUnet、UNet++ 等)來實現該目標。最後,我們結合邊緣檢測與形態學技術,精確量化預測與實際的誤差,以提高插管的成功率並降低風險。', '貨車車牌辨識簡述':'動機與目的:為了提高貨車進出倉庫的效率,我們建立一個車牌辨識系統,該系統基於深度學習技術,主要透過yolo來偵測車牌位置,再透過OCR技術來識別車牌號碼,最後將車牌號碼與倉庫數據庫進行比對,以確保進出貨物的準確性。 ', '聊天機器人簡述':'過去在研究語言模型時,尚未設計與機器人對話的專屬介面,因此這次實作了一個簡單的聊天機器人介面。該聊天機器人基於 Qwen 大型預訓練語言模型,這是一個多語言支持的模型,供使用者進行互動體驗。', } docs=['主要的技能(技術)包含:python,深度學習,web開發,數據分析', '特別經歷包含:ICIM2024研討會、碩士期間擔任指導教授所開的類神經網路課程助教、大學專題實務成果展競賽亞軍,技術類業界評選第一名。', '論文概述:題為「基於情緒支持的對話:融合情緒感知和關鍵字識別的研究」。研究旨在通過聊天機器人為情緒困擾者提供陪伴,緩解其短期心理壓力。本文提出的模型結合情緒標籤和關鍵字識別技術,與其他基礎模型相比,能夠提供更精準的回復,從而更有效地支持用戶的情緒需求。', '在高中和大學時期所拿到的證照有:電腦硬體裝修丙級、電腦硬體裝修乙級、Database Administration Fundamentals、Software Development Fundamentals、Networking Fundamentals、CRM Merchandise Analyst、Enterprise Resource Planning', '助教工作內容:主要協助老師指導學生實作部分。包括使用 WEKA 軟體教導學生快速構建和分析機器學習模型,並解釋模型結果的含義。後期則引導學生安裝 Python 環境,撰寫並執行機器學習模型的程式碼,幫助學生在未來能夠運用 AI 技術更有效地完成工作。', '大學專題內容:專題名稱:熱影像結合人臉偵測暨網頁瀏覽系統。為因應新冠疫情,無接觸體溫檢測需求激增,本專題開發了利用紅外線熱影像和後端資料庫蒐集,最終實現異地閱覽和確保體溫監測的安全與效率。/n我的貢獻:硬體設備組裝、人臉偵測和後端資料庫及視覺化', '參與過的專案包含:學生點名系統、氣管插管預測、貨車車牌辨識、聊天機器人', '''學生點名系統簡述: 動機與目的: 鑒於每次上課點名都是老師的一大負擔,開發了這個學生點名系統,旨在幫助老師更有效地進行點名。本專案使用 Laravel 開源 PHP Web 框架開發,主要功能包括: 老師功能: - 查看課表及點名記錄 - 查看學生出缺席和請假狀況 - 審核學生請假申請 學生功能: - 查看課表及進行點名 - 查看出缺席和請假記錄 - 申請請假 該完整專案在github上,網址:https://github.com/WISD-2020/final02 ''', '氣管插管預測簡述:動機與目的:為了協助醫生在執行插管時更精確地將氧氣管置入正確位置,我們利用影像分割技術(如 TransUnet、UNet++ 等)來實現該目標。最後,我們結合邊緣檢測與形態學技術,精確量化預測與實際的誤差,以提高插管的成功率並降低風險。', '貨車車牌辨識簡述:動機與目的:為了提高貨車進出倉庫的效率,我們建立一個車牌辨識系統,該系統基於深度學習技術,主要透過yolo來偵測車牌位置,再透過OCR技術來識別車牌號碼,最後將車牌號碼與倉庫數據庫進行比對,以確保進出貨物的準確性。 ', '聊天機器人簡述:過去在研究語言模型時,尚未設計與機器人對話的專屬介面,因此這次實作了一個簡單的聊天機器人介面。該聊天機器人基於 Qwen 大型預訓練語言模型,這是一個多語言支持的模型,供使用者進行互動體驗。', ] def get_embedding(text): embd_ = embd.encode(text) embd_ = embd_ / np.linalg.norm(embd_) # 归一化 return embd_ #建立嵌入向量庫 def add_to_faiss_index(embeddings): vector = np.array(embeddings) # 设置检索维度 index = faiss.IndexFlatIP(vector.shape[1]) faiss.normalize_L2(vector) index.add(vector) return index embedding_array = [get_embedding(text) for text in doc] faiss_index =add_to_faiss_index(embedding_array) embedding_array_1 = [get_embedding(text) for text in docs] faiss_index_1 =add_to_faiss_index(embedding_array_1 ) def vector_search(index,index_1, query_embedding, k=3, threshold=0.5): distances, indices = index.search(np.array([query_embedding]), k) # 如果想要筛选相似度大于某个阈值的结果,可以这样做 results = [] for i in range(k): if distances[0][i] > threshold: # 余弦相似度的距离应该是越大越相似 results.append(docs[indices[0][i]]) if not results: distances, indices = index_1.search(np.array([query_embedding]), k) for i in range(k): if distances[0][i] > 0.4: # 余弦相似度的距离应该是越大越相似 results.append(docs[indices[0][i]]) print('\n'.join(results)) return results if results else None def resume_QA(message, history): query_embedding = get_embedding(message) search_results = vector_search(faiss_index,faiss_index_1, query_embedding) if search_results: search_results='\n'.join(search_results) prompt = [ {"role": "system", "content":f""" 你是一位助手,幫助人家了解巫宇哲這個人。你只能根據下列提供的資訊回答問題,並且所有回答必須完全符合已提供的資訊,不能添加任何新內容或自己推測的訊息。如果問題的答案不在提供的資訊中,請明確回答 "沒有這方面的資料"。所有回答必須基於已提供的資料。 並且**嚴禁提及自己是 AI 或無法回答問題**。所有回答必須基於已提供的資料,禁止出現類似「在這個特定的環境下,我無法提供詳細信息」、「我是AI,無法回答此問題」或任何與 AI 自身相關的回覆。 提供的資訊: Name: 巫宇哲 {search_results} 請根據上面的資訊來回答問題。 """} ] for i in history: prompt.append({"role": "user", "content": i[0]}) prompt.append({"role": "assisant", "content": i[1]}) prompt.append({"role": "user", "content": message}) messages = prompt text = tokenizer.apply_chat_template( messages, tokenize=False, add_generation_prompt=True ) model_inputs = tokenizer([text], return_tensors="pt").to("cuda") streamer = TextIteratorStreamer(tokenizer, timeout=50., skip_prompt=True, skip_special_tokens=True) generate_kwargs = dict( model_inputs, streamer=streamer, max_new_tokens=512, do_sample=True, temperature=0.9, top_k=5, top_p=0.95, min_length=50, ) t = Thread(target=model.generate, kwargs=generate_kwargs) t.start() partial_message = "" for new_token in streamer: partial_message += new_token yield partial_message avatar_images = ["https://cdn-icons-png.flaticon.com/128/3135/3135715.png", "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTIJYnfODgs7q_Q4k6RoUL592NBlSF7wUTEhT92lRyqc4HTunB-"] custom_css = """ .gradio-container {background-color: #f0f0f0;padding-top: 0px !important;} /*.container {max-width: 100px; margin: 0; font-family: 'Arial', sans-serif;}*/ .header {background-color: #2c3e50; color: white; padding: 10px; text-align: center; border-radius: 10px 10px 0 0;margin-bottom: 0; /* Ensure no margin below header */} .content {background-color: white; padding: 10px; border-radius: 0 0 10px 10px; margin: 0;margin-top: 0;} .profile-pic {width: 150px; height: 150px; border-radius: 50%; margin: 20px auto; display: block;} .skills {display: flex; justify-content: space-around; margin-top: 20px;margin-bottom: 20px;} .skill {text-align: center; padding: 10px; background-color: #ecf0f1; border-radius: 5px;} .cert-row {border-bottom: 1px solid #ddd; padding: 10px 0;} .cert-header {background-color: #f2f2f2; font-weight: bold;} /* footer styling */ .gradio-container footer { display: none !important; } .custom-footer { text-align: center; padding: 0; /* 减小上下内边距 */ # line-height: 1.2; /* 减小行高 */ margin-top: 0; /* 减小与上方内容的间距 */ margin-bottom: 0; /* 减小与下方内容的间距 */ } .custom-footer p { margin: 0; /* 移除段落的默认外边距 */ } /* 主要針對chatbot聊天對話框設計版面*/ .custom-chatbot { background-color: #FBFBFF !important; /* 機器人對話框背景顏色 */ } .custom-chatbot .flex-wrap.user { background-color: #ECF5FF !important; /* 使用者訊息框的背景顏色 */ border: solid 1px #E6CAFF } .custom-chatbot .flex-wrap.bot { background-color: #ECF5FF !important; /* 使用者訊息框的背景顏色 */ border: solid 1px #E6CAFF } .custom-chatbot label.svelte-1b6s6s { background-color: #E8FFF5 !important; /* 設定背景顏色 */ } button.lg.primary.svelte-cmf5ev { background-image: linear-gradient(120deg, #a1c4fd 0%, #c2e9fb 100%) !important; /* 按鈕背景顏色 */ color: #4F4F4F !important; /* 文字顏色 */ } """ custom_footer = """
""" def load_image(image_path): img = Image.open(image_path) return np.array(img) #讀取頭貼 image_path = "/content/drive/My Drive/個人資料/頭貼.jpg" # profile_array = load_image(image_path) #讀去證照圖片 import gradio as gr def render_html(prove): if prove is not None: return f'點擊查看證明' else: return '' with gr.Blocks(css=custom_css,title='我的履歷') as resume_app:# title可以修改页面标题 # with gr.Column(): gr.HTML("""軟體工程師 | AI 愛好者 | 數據分析師
{name[i]}
{render_html(prove[i])}