Spaces:
Runtime error
Runtime error
File size: 13,347 Bytes
a0fe41e ccda82a a0fe41e ccda82a a0fe41e 16bcae7 a0fe41e ccda82a a0fe41e 16bcae7 a0fe41e |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
#!/usr/bin/env python
# coding: utf-8
import gradio as gr
from llama_cpp import Llama
from langchain_community.llms import LlamaCpp
from langchain.prompts import PromptTemplate
import llama_cpp
from langchain.callbacks.manager import CallbackManager
from sentence_transformers import SentenceTransformer
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
import numpy as np
import pandas as pd
import re
import os
from sklearn.metrics.pairwise import cosine_similarity
from transformers import AutoTokenizer, AutoModelForCausalLM
model = SentenceTransformer('sentence-transformers/paraphrase-multilingual-mpnet-base-v2',device='cpu')
model1 = AutoModelForCausalLM.from_pretrained("MediaTek-Research/Breeze-7B-Instruct-v0_1")
def invoke_with_temperature(prompt, temperature=0.4):
# 將 prompt 編碼為模型的輸入格式
inputs = tokenizer(prompt, return_tensors="pt")
# 使用生成方法生成文本,設置溫度參數
output = model1.generate(inputs["input_ids"], max_length=200, temperature=temperature, num_return_sequences=1)
# 解碼並返回生成的文本
return tokenizer.decode(output[0], skip_special_tokens=True)
# llm = LlamaCpp(
# model_path=r"MediaTek-Research/Breeze-7B-Instruct-v0_1",
# n_gpu_layers=100,
# n_batch=512,
# n_ctx=3000,
# f16_kv=True,
# callback_manager=CallbackManager([StreamingStdOutCallbackHandler()]),
# verbose=False,
# )
embedd_bk=pd.read_pickle(r".\bk_description1_角色形容詞_677.pkl")
df_bk=pd.read_excel(r".\bk_description1_角色形容詞短文.xlsx")
# def invoke_with_temperature(prompt, temperature=0.4):
# return llm.invoke(prompt, temperature=temperature)
def process_user_input(message):
user_mental_state4= PromptTemplate(
input_variables=["input"],
template="""[INST]<<SYS>>你是一位具有同理心的專業心理諮商師,沒有性別歧視,你可以客觀的根據談話內容的描述,判斷說話的人的心理困擾<</SYS>>
請根據{input}描述三個最有可能心理困擾,輸出只包含三個心理困擾,回答格式只採用CSV格式,分隔符號使用逗號,參考以下範例:名詞1,名詞2,名詞3。[/INST]"""
)
user_character= PromptTemplate(
input_variables=["input"],
template="""[INST]<<SYS>>你是一位具有同理心的專業心理諮商師,沒有性別歧視,你可以客觀的根據談話內容的描述,判斷說話的大學生,在生活中的多重角色身分<</SYS>>
請你根據談話內容{input},客觀的判斷說話的大學生,在談話內容中的角色,以及他生活中其他角色的身分,提供三個最有可能的角色身分名詞,
輸出只包含三個身分名詞,回答格式只採用CSV格式,分隔符號使用逗號,參考以下範例:名詞1,名詞2,名詞3。[/INST]"""
)
df_user=pd.DataFrame(columns=["輸入內容","形容詞1", "形容詞2", "形容詞3", "角色1", "角色2", "角色3"])
#df_user_record=pd.read_excel(r"C:\Users\Cora\推薦系統實作\gradio系統歷史紀錄.xlsx")
prompt_value1=user_mental_state4.invoke({"input":message})
string=invoke_with_temperature(prompt_value1)
#print("\n")
# 將字符串分割為名詞
adjectives = [adj.strip() for adj in re.split('[,、,]', string)]
index=len(df_user)
df_user.loc[index, '輸入內容'] = message
# 確保形容詞數量符合欄位數量
if len(adjectives) == 3:
df_user.loc[index, '形容詞1'] = adjectives[0]
df_user.loc[index, '形容詞2'] = adjectives[1]
df_user.loc[index, '形容詞3'] = adjectives[2]
prompt_value2=user_character.invoke({"input":message})
string=invoke_with_temperature(prompt_value2)
#print("\n")
# 將字符串分割為名詞
character = [adj.strip() for adj in re.split('[,、,]', string)]
for i in range(min(len(character), 3)):
df_user.loc[index, f'角色{i+1}'] = character[i]
# if len(character) == 3:
# df_user.loc[index, '角色1'] = character[0]
# df_user.loc[index, '角色2'] = character[1]
# df_user.loc[index, '角色3'] = character[2]
df_user.to_excel("user_gradio系統.xlsx")
return df_user
#return message
def embedd_df_user(df_user):
columns_to_encode=df_user.loc[:,["形容詞1", "形容詞2", "形容詞3"]]
# 初始化一個空的 DataFrame,用來存儲向量化結果
embedd_user=df_user[["輸入內容"]]
#user_em= user_em.assign(形容詞1=None, 形容詞2=None, 形容詞3=None,角色1=None,角色2=None,角色3=None)
embedd_user= embedd_user.assign(形容詞1=None, 形容詞2=None, 形容詞3=None)
# 遍歷每一個單元格,將結果存入新的 DataFrame 中
i=len(df_user)-1
for col in columns_to_encode:
#print(i,col)
# 將每個單元格的內容進行向量化
embedd_user.at[i, col] = model.encode(df_user.at[i, col])
#embedd_user.to_pickle(r"C:\Users\user\推薦系統實作\user_gradio系統.pkl")
return embedd_user
#word="happy"
#return word
def top_n_books_by_average(df, n=3):
# 根据 `average` 列降序排序
sorted_df = df.sort_values(by='average', ascending=False)
# 选择前 N 行
top_n_df = sorted_df.head(n)
# 提取书名列
top_books = top_n_df['書名'].tolist()
return top_books,sorted_df
def similarity(embedd_user,embedd_bk,df_bk):
df_similarity= pd.DataFrame(df_bk[['書名','短文','URL',"形容詞1", "形容詞2", "形容詞3", '角色1', '角色2', '角色3']])
df_similarity['average'] = np.nan
#for p in range(len(embedd_user)):
index=len(embedd_user)-1
for k in range(len(embedd_bk)):
list=[]
for i in range(1,4):
for j in range(3,6):
vec1=embedd_user.iloc[index,i]#i是第i個形容詞,index是第幾個是使用者輸入
vec2=embedd_bk.iloc[k,j]
similarity = cosine_similarity([vec1], [vec2])
list.append(similarity[0][0])
# 计算总和
total_sum = sum(list)
# 计算数量
count = len(list)
# 计算平均值
average = total_sum / count
df_similarity.loc[k,'average']=average
top_books,sorted_df = top_n_books_by_average(df_similarity)
return sorted_df
def filter(sorted_df,df_user):
filter_prompt4 = PromptTemplate(
input_variables=["mental_issue", "user_identity"," book","book_reader", "book_description"],
template="""[INST]<<SYS>>你是專業的心理諮商師和書籍推薦專家,擅長根據使用者的心理問題、身份特質,以及書名、書籍針對的主題和適合的讀者,判斷書籍是否適合推薦給使用者。
你的目的是幫助讀者找到可以緩解心理問題的書籍。請注意:
1. 若書籍針對的問題與使用者的心理問題有關聯,即使書籍適合的讀者群與使用者身份沒有直接關聯,應偏向推薦。
2. 若使用者身份的需求與書籍針對的問題有潛在關聯,應偏向推薦。
3. 若書籍適合的讀者與使用者身份特質有任何關聯,應傾向推薦。
4. 若書名跟使用者的心理問題或身分特質有任何關聯,應偏向推薦<</SYS>>
使用者提供的資訊如下:
使用者身份是「{user_identity}」,其心理問題是「{mental_issue}」。書名是{book},書籍適合的讀者群為「{book_reader}」,書籍針對的問題是「{book_description}」。
請根據以上資訊判斷這本書是否適合推薦給該使用者。
僅輸出「是」或「否」,輸出後即停止。[/INST]"""
)
df_filter=sorted_df.iloc[:20,:]
df_filter = df_filter.reset_index(drop=True)
df_filter=df_filter.assign(推薦=None)
p=len(df_user)-1
sum_for_bk=0
# 提取角色內容
role1 = df_user["角色1"].iloc[p] if pd.notnull(df_user["角色1"].iloc[p]) else ""
role2 = df_user["角色2"].iloc[p] if pd.notnull(df_user["角色2"].iloc[p]) else ""
role3 = df_user["角色3"].iloc[p] if pd.notnull(df_user["角色3"].iloc[p]) else ""
# 用"、"連接不為空的角色
user_identity = "、".join([role for role in [role1, role2, role3] if role]) # 只加入有內容的角色
#user_identity = df_user["角色1"].iloc[p]+"、"+df_user["角色2"].iloc[p]+"、"+df_user["角色3"].iloc[p]
mental_issue=df_user["形容詞1"].iloc[p]+"、"+df_user["形容詞2"].iloc[p]+"、"+df_user["形容詞3"].iloc[p]
for k in range(len(df_filter)):
#word=df_user["輸入內容"].iloc[p]
#book_reader = df_filter["角色1"].iloc[p] + "or" + df_filter["角色2"].iloc[p] + "or" + df_filter["角色3"].iloc[p]
book=df_filter["書名"].iloc[k]
book_reader = df_filter["角色1"].iloc[k]
# user_identity = df_user["角色1"].iloc[p]+"、"+df_user["角色2"].iloc[p]+"、"+df_user["角色3"].iloc[p]
# mental_issue=df_user["形容詞1"].iloc[p]+"、"+df_user["形容詞2"].iloc[p]+"、"+df_user["形容詞3"].iloc[p]
book_description=df_filter["形容詞1"].iloc[k]+"、"+df_filter["形容詞2"].iloc[k]+"、"+df_filter["形容詞3"].iloc[k]
print(book_reader)
print(user_identity)
#output = filter_prompt1.invoke({"user_identity": user_identity, "book_reader": book_reader})
output = filter_prompt4.invoke({"mental_issue":mental_issue,"user_identity": user_identity, "book":book,"book_description":book_description,"book_reader": book_reader})
string2=invoke_with_temperature(output)
df_filter.loc[k, '推薦'] =string2
if string2.strip()=="是":
sum_for_bk+=1
if(sum_for_bk==3):
break
df_recommend=df_filter[df_filter["推薦"].str.strip() == "是"]
return df_recommend
def output_content(df_recommend):
title = {}
URL = {}
summary = {}
for i in range(3):
title[f'title_{i}'] = df_recommend.iloc[i, 0] # Using iloc instead of loc
URL[f'URL_{i}'] = df_recommend.iloc[i, 2]
summary[f'summary_{i}'] = df_recommend.iloc[i, 1]
output = f"""根據您的狀態,這裡提供三本書供您參考\n
<第一本>
書名:{title['title_0']}\n
本書介紹:{summary['summary_0']}\n
購書網址:{URL['URL_0']}\n
<第二本>
書名:{title['title_1']}\n
本書介紹:{summary['summary_1']}\n
購書網址:{URL['URL_1']}\n
<第三本>
書名:{title['title_2']}\n
本書介紹:{summary['summary_2']}\n
購書網址:{URL['URL_2']}\n
希望對您有所幫助"""
return output
def main_pipeline(message,history):
df_user=process_user_input(message)
embedd_user=embedd_df_user(df_user)
sorted_df=similarity(embedd_user,embedd_bk,df_bk)
df_filter=filter(sorted_df,df_user)
final=output_content(df_filter)
return final
css = """
.chatbox .message-box {
height: 500px !important; # 設定訊息框的高度
width: 100%
overflow-y: auto; # 如果內容超出高度則顯示滾動條
text-rendering: optimizeLegibility; # 啟用抗鋸齒渲染
}
"""
theme=gr.themes.Default(primary_hue=gr.themes.colors.red, secondary_hue=gr.themes.colors.pink,font=[gr.themes.GoogleFont("LXGW WenKai Mono TC")]).set(
body_background_fill='#FFF5EE'
)
with gr.Blocks(theme=theme) as demo:
with gr.Row():
with gr.Column():
gr.Markdown("""
<div style="text-align: center;">
<h1 style="display: inline; vertical-align: middle;">
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR_Rj6Add1OjrIeVXL4z84YzG4QIEuM4ptvvQ&s"
width="100" height="100" style="display: inline; vertical-align: middle; margin-right: 10px;">
心理書籍推薦系統
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR_Rj6Add1OjrIeVXL4z84YzG4QIEuM4ptvvQ&s"
width="100" height="100" style="display: inline; vertical-align: middle; margin-left: 10px;">
</h1>
</div>
""")
gr.ChatInterface(
main_pipeline,
type="messages",
title="", # title 設為空,使用自定義 Markdown 標題
description='<div style="text-align: center;font-size:16px">這是個讓人放鬆的網站,希望透過讓人抒發心情表達現在面臨的狀況與挑戰,從書裡獲得解答。</div><div style="text-align: center;font-size: 16px;">-你可以告訴我們最近的心情和想法,放心我們不會儲存任何紀錄-</div>',
css=css
)
if __name__ == "__main__":
demo.launch(share=True)
# In[ ]:
|