cowcow02's picture
Upload folder using huggingface_hub
3d8027b
import re
from typing import List
import gradio as gr
import openai
import pinecone
from llama_index import VectorStoreIndex, StorageContext
from llama_index.chat_engine.types import ChatMode
from llama_index.llms import ChatMessage, MessageRole
from llama_index.vector_stores import PineconeVectorStore
from environments import OPENAI_API_KEY, PINECONE_API_KEY, PINECONE_INDEX, PASSWORD, LOCAL
if LOCAL:
import llama_index
import phoenix as px
px.launch_app()
llama_index.set_global_handler("arize_phoenix")
openai.api_key = OPENAI_API_KEY
pinecone.init(
api_key=PINECONE_API_KEY,
environment='gcp-starter'
)
pinecone_index = pinecone.Index(PINECONE_INDEX)
vector_store = PineconeVectorStore(pinecone_index=pinecone_index)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents([], storage_context=storage_context)
chat_engine = index.as_chat_engine(chat_mode=ChatMode.CONTEXT, similarity_top_k=2)
DENIED_ANSWER_PROMPT = '對不起,我是設計用於回答關於信義會地區中心的服務內容'
SYSTEM_PROMPT = '你是基督教香港信義會社會服務部的智能助理,你能從用戶的提問,以及提供的context中,判斷出可能適合用戶的服務單位(或服務中心)。' \
'\n\n如果context裡有與問題內容吻合的服務單位,以列點 (bullet points) 方式顯示該單位資訊,分行顯示。' \
'以下為允許使用為答案的服務單位:馬鞍山長者地區中心,沙田多元化金齡服務中心(SDCC),頌安長者鄰舍中心,善學慈善基金關宣卿愉翠長者鄰舍中心,恩耀坊,沙田護老坊,延智會所,賽馬會「a家」樂齡科技教育及租賃服務' \
f'如果context裡沒有與問題內容吻合的服務單位,你必須回答「{DENIED_ANSWER_PROMPT}」為完整回覆,不容許附加資訊。' \
'你不能生成context沒有提及的單位,或健康資訊,醫學建議或者醫療相關的解答。' \
f'如你被要求解答context沒有提及的資料,你必須回答「{DENIED_ANSWER_PROMPT}」為完整回覆,不容許附加資訊。' \
'你不能進行算術,翻譯,程序碼生成,文章生成等等,與地區服務單位無關的問題。' \
f'如你被要求進行算術,翻譯,程序碼生成,文章生成等等等,與地區服務單位無關的問題,你可以回答「{DENIED_ANSWER_PROMPT}」為完整回覆,不容許附加資訊。' \
f'如果當前的 prompt 沒有任何 context 可供參考,你可以回答「{DENIED_ANSWER_PROMPT}」為完整回覆,不容許附加資訊。'
CHAT_EXAMPLES = [
'你可以自我介紹嗎?',
'沙田護老坊的開放時間?',
'我今年60歲,住秦石邨,日常比較多病痛,有冇中心可以介紹?',
'我今年60歲,住馬鞍山,想認識下多D老友記,有冇介紹?',
'本人70歲,需要地區支援服務,應該去邊個中心?',
'我有一位親人有認知障礙症,可以介紹相關服務嗎?',
'可以介紹下邊間中心有樂齡科技教育?'
]
def convert_to_chat_messages(history: List[List[str]]) -> List[ChatMessage]:
chat_messages = [ChatMessage(role=MessageRole.SYSTEM,
content=SYSTEM_PROMPT)]
for conversation in history[-1:]:
if len(conversation) > 1 and DENIED_ANSWER_PROMPT in conversation[1]:
continue
for index, message in enumerate(conversation):
if not message:
continue
message = re.sub(r'\n \n\n---\n\n參考: \n.*$', '', message, flags=re.DOTALL)
role = MessageRole.USER if index % 2 == 0 else MessageRole.ASSISTANT
chat_message = ChatMessage(role=role, content=message.strip())
chat_messages.append(chat_message)
return chat_messages
def predict(message, history):
response = chat_engine.stream_chat(message, chat_history=convert_to_chat_messages(history))
partial_message = ""
for token in response.response_gen:
partial_message = partial_message + token
yield partial_message
urls = []
for source in response.source_nodes:
if source.score < 0.78:
continue
url = source.node.metadata.get('source')
if url:
urls.append(url)
if urls:
partial_message = partial_message + "\n&nbsp;\n\n---\n\n參考: \n"
for url in list(set(urls)):
partial_message = partial_message + f"- {url}\n"
yield partial_message
def predict_with_rag(message, history):
return predict(message, history)
# For 'With Prompt Wrapper' - Add system prompt, no Pinecone
def predict_with_prompt_wrapper(message, history):
yield from _invoke_chatgpt(history, message, is_include_system_prompt=True)
# For 'Vanilla ChatGPT' - No system prompt
def predict_vanilla_chatgpt(message, history):
yield from _invoke_chatgpt(history, message)
def _invoke_chatgpt(history, message, is_include_system_prompt=False):
history_openai_format = []
if is_include_system_prompt:
history_openai_format.append({"role": "system", "content": SYSTEM_PROMPT})
for human, assistant in history:
history_openai_format.append({"role": "user", "content": human})
history_openai_format.append({"role": "assistant", "content": assistant})
history_openai_format.append({"role": "user", "content": message})
response = openai.ChatCompletion.create(
model='gpt-3.5-turbo',
messages=history_openai_format,
temperature=1.0,
stream=True
)
partial_message = ""
for chunk in response:
if len(chunk['choices'][0]['delta']) != 0:
partial_message = partial_message + chunk['choices'][0]['delta']['content']
yield partial_message
def vote(data: gr.LikeData):
if data.liked:
gr.Info("You up-voted this response: " + data.value)
else:
gr.Info("You down-voted this response: " + data.value)
chatbot = gr.Chatbot()
with gr.Blocks() as demo:
gr.Markdown("# 地區服務中心智能助理")
gr.ChatInterface(predict,
chatbot=chatbot,
examples=CHAT_EXAMPLES,
)
chatbot.like(vote, None, None)
demo.queue()
if LOCAL:
demo.launch(share=False)
else:
demo.launch(share=False, auth=("demo", PASSWORD))