Spaces:
Runtime error
Runtime error
File size: 6,551 Bytes
158d1e2 c6e0771 158d1e2 3d8027b 158d1e2 99fc7d0 158d1e2 c6e0771 99fc7d0 c6e0771 99fc7d0 c6e0771 158d1e2 c6e0771 158d1e2 c6e0771 158d1e2 3d8027b 158d1e2 c6e0771 158d1e2 3d8027b c6e0771 |
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 |
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 \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))
|