charmedai / chain.py
zlsah's picture
Upload chain.py
c2eb605
import json
import os
import pathlib
from typing import Dict, List, Tuple
import weaviate
from langchain import OpenAI, PromptTemplate
from langchain.chains import LLMChain
from langchain.chains.base import Chain
from langchain.chains.combine_documents.base import BaseCombineDocumentsChain
from langchain.chains.conversation.memory import ConversationBufferMemory
from langchain.chains.question_answering import load_qa_chain #BaseCombineDocumentsChain
from langchain.embeddings import OpenAIEmbeddings
from langchain.prompts import FewShotPromptTemplate, PromptTemplate
from langchain.prompts.example_selector import \
SemanticSimilarityExampleSelector
from langchain.vectorstores import FAISS, Weaviate
from pydantic import BaseModel
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import FAISS, Weaviate
os.environ["WEAVIATE_URL"] = "https://tro.weaviate.network/"
os.environ["OPENAI_API_KEY"] = "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"
KEY ="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"
class CustomChain(Chain, BaseModel):
vstore: Weaviate
chain: BaseCombineDocumentsChain
key_word_extractor: Chain
@property
def input_keys(self) -> List[str]:
return ["game_description"]
@property
def output_keys(self) -> List[str]:
return ["game_environment"]
def _call(self, inputs: Dict[str, str]) -> Dict[str, str]:
game_description = inputs["game_description"]
chat_history_str = _get_chat_history(inputs["chat_history"])
if chat_history_str: # Takes in user input
print('running key_word_extractor')
new_game_description= self.key_word_extractor.run(
game_description=game_description, chat_history=chat_history_str
)
print('new_game_description',new_game_description)
else:
new_game_description = game_description
print('_new_game_description', new_game_description) # sendig objects , not showing up on screen ?
docs = self.vstore.similarity_search(new_game_description, k=4)
new_inputs = inputs.copy()
new_inputs["game_description"] = new_game_description
new_inputs["chat_history"] = chat_history_str
game_environment, _ = self.chain.combine_docs(docs, **new_inputs) # StuffDocumentsChain
print('combined', game_environment) # doc combo of game descripton and chat history,
return {"game_environment": game_environment}
# 1. Given the chat history and new user input,
# Generate game environment, objects, npcs, enemies, and quest narrative.
def get_new_chain1(vectorstore) -> Chain:
# Calls Vector DB
WEAVIATE_URL = os.environ["WEAVIATE_URL"]
client = weaviate.Client(
url=WEAVIATE_URL,
additional_headers={"X-OpenAI-Api-Key": os.environ["OPENAI_API_KEY"]},
)
_eg_template = """## AI:
Chat History:
{chat_history}
Follow Up Input: {game_description}
standalone detail: {game_description} {game_environment}"""
_eg_prompt = PromptTemplate(
template=_eg_template,
input_variables=["chat_history","game_description", "game_environment"], # question aka game detail ################ showing up in Terminal? ##############
)
# _prefix = """Given the following conversation and a follow up game detail, summarize the follow up game detail
#in a way that is coherent with the conversation.\
# You should assume that the detail is related to Game Design. Never change the game Title unless the human asks you to."""
_prefix = """ If the input and the follow up input are closely related, and are both related to the game suggested by
the previous conversation and if you are completely confident if it the same game from the original converation, then proceed. Otherwise, clarify the game title and proceed.
To proceed, retrieve the game Title and share again in quotes to the human, and summarize the follow up input in a way that is coherent with the conversation.
If the input detail is related to Game Design, proceed, otherwise clarify.
"""
_suffix = """## AI:
Chat History:
{chat_history}
Follow Up Input: {game_description}
standalone detail:"""
eg_store = Weaviate(
client,
"Rephrase",
"content",
attributes=["game_description", "game_environment", "chat_history"],
)
example_selector = SemanticSimilarityExampleSelector(vectorstore=eg_store, k=4) # looks for similar examples in vector db
prompt = FewShotPromptTemplate(
prefix=_prefix, # prompt
suffix=_suffix,
example_selector=example_selector,
example_prompt=_eg_prompt,
input_variables=["game_description", "chat_history"],
)
llm = OpenAI(temperature=0.7, model_name="text-davinci-003", max_tokens=1000)
key_word_extractor = LLMChain(llm=llm, prompt=prompt) # this could be game word extractor
# Gives an example and relevant documents # from Vector DB ##################################################### showing up in UI ##############
EXAMPLE_PROMPT = PromptTemplate(
template=">AI:\nContent:\n---------\n{page_content}\n----------\n", # not working right now ?
input_variables=["page_content"],
)
template = """
You are an AI assistant for generating a single game, the central narrative and its game quests inside the same game,
conversing in a succinct, coherent and interactive manner. Assume the entire conversation is about a single game only.
You are given the game description. You are also given the chat history, which is a conversation between a human and
another AI assistant about the same game. Do not answer any questions from the other AI assistant.
If you don't know the answer, just say "I'm not sure, how this is related?" and ask the human to clarify.
If asked about a quest, assume it is within the same game,
and provide a quest motivation, participants, rewards, character dialogue relevant to the game.
From the input, introduce a short back story of the game's plot points or character motivations and character dialogue.
Plot points may include an inciting incidient, a rising action composed of a series of conflicts, complications, dilemmas, obstacles.
From the input, generate game objects (collectibles, NPCs, enemies) related to the plot points, limit to 1-2 objects.
Ask a short question to clarify details if you are unsure but you are an expert so offer a suggestion and only ask once.
If the human asks for or adds game objects, provide only 1 detail such as physical description and possible player interactions with the object.
If the human asks for or adds an enemy, describe its behaviors and personality, as related to the game plot points, limit to a few words.
If the human asks for or adds a collectible, describe its physical appearance and possible player interactions with the object.
If the human asks for or adds a noun or NPC, describe its behaviors and personality, as related to the game plot points, limit to a few words.
If the huamn asks for character dialogue, provide a short dialogue snippet, with 1-2 sentences, as related to the game plot points.
Limit your reponses to 3-6 sentences.
Game Description: {game_description}
{context}
Answer in Markdown:"""
PROMPT = PromptTemplate(template=template, input_variables=["game_description", "context"])
doc_chain = load_qa_chain(
OpenAI(temperature=0.7, model_name="text-davinci-003", max_tokens=1000),
chain_type="stuff", # all related data is stuffed into prompt as context
prompt=PROMPT,
document_prompt=EXAMPLE_PROMPT,
)
return CustomChain(
chain=doc_chain, vstore=vectorstore, key_word_extractor=key_word_extractor
)
# doc + input -> game environment
def _get_chat_history(chat_history: List[Tuple[str, str]]):
buffer = ""
for human_s, ai_s in chat_history:
human = f"Human: " + human_s
ai = f"Assistant: " + ai_s
buffer += "\n" + "\n".join([human, ai])
return buffer