Spaces:
Build error
Build error
| import logging | |
| import re | |
| import httpx | |
| import openai | |
| from openai import OpenAI | |
| from retry import retry | |
| LOGGER = logging.getLogger(__name__) | |
| class Q20Game: | |
| def __init__( | |
| self, | |
| item: str, | |
| answerer_model: str = 'gpt-3.5-turbo-0613', | |
| guesser_model: str = 'gpt-3.5-turbo-0613', | |
| num_turns: int = 20, | |
| temperature: float = 0.8, | |
| openai_api: bool = True, | |
| openai_api_key: str | None = None, | |
| guesser_kargs=None, | |
| ) -> None: | |
| if guesser_kargs is None: | |
| guesser_kargs = {} | |
| self.item = item | |
| self.answerer_model = answerer_model | |
| self.guesser_model = guesser_model | |
| self.num_turns = num_turns | |
| self.temperature = temperature | |
| self.openai_api = openai_api | |
| self.guesser_kargs = guesser_kargs | |
| self.vicuna_prompt = "A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions." | |
| self.first_user_utterance = ( | |
| 'Your task is to ask a series of questions to deduce the entity ' | |
| "that I'm thinking of with as few queries as possible. " | |
| "Only ask questions that can be answered by 'yes', 'no' or 'maybe'. " | |
| 'Do not ask for hint. Make your question brief with no linebreaker. ' | |
| 'Now start asking a question.' | |
| ) | |
| self.guesser_win = False | |
| self.curr_turn = 0 | |
| if openai_api_key is not None: | |
| openai.api_key = openai_api_key | |
| if isinstance(answerer_model, str) and not answerer_model.startswith('gpt'): | |
| self.user_api_base = 'http://0.0.0.0:8000/v1' | |
| else: | |
| self.user_api_base = 'https://api.openai.com/v1' | |
| if isinstance(guesser_model, str) and not guesser_model.startswith('gpt'): | |
| self.guesser_api_base = 'http://0.0.0.0:8000/v1' | |
| else: | |
| self.guesser_api_base = 'https://api.openai.com/v1' | |
| self.guesser_messages = [] | |
| def preprocess_response(self, response): | |
| response = re.sub(r'the entity you are thinking of', 'it', response) | |
| response = re.sub(r"the entity you're thinking of", 'it', response) | |
| response = re.sub(r" you're thinking of", '', response) | |
| response = re.sub(r' you are thinking of', '', response) | |
| return response | |
| def judge_winner(self, response): | |
| guesser_question = response.strip() | |
| if self.curr_turn == self.num_turns - 1: | |
| guesser_question += ' Is it right?' | |
| self.guesser_messages.append({'role': 'assistant', 'content': guesser_question}) | |
| # ask for answer | |
| usr_msg = self.answerer(guesser_question) | |
| self.guesser_messages.append( | |
| {'role': 'user', 'content': f'{usr_msg["content"].strip()}'} | |
| ) | |
| if 'bingo' in usr_msg['content'].lower(): | |
| self.guesser_win = True | |
| return True, '' | |
| return False, usr_msg['content'].strip() | |
| def generate_user_response(self, response): | |
| response = self.preprocess_response(response) | |
| # others | |
| bingo, anwser_reply = self.judge_winner(response) | |
| if bingo: | |
| return 'You are bingo! Use the "finish" tool to finish the interaction.\n' | |
| if self.curr_turn == self.num_turns - 2: | |
| anwser_reply += " You must guess now, what's it?" | |
| return anwser_reply | |
| def reward(self): | |
| if self.guesser_win: | |
| n_turns = (len(self.guesser_messages) + 1) // 2 | |
| return 1 - max(n_turns - 5, 0) * 0.02 | |
| return 0 | |
| def answerer(self, question): | |
| openai.api_base = self.user_api_base | |
| client = OpenAI(api_key=openai.api_key) | |
| user_messages = [ | |
| { | |
| 'role': 'user', | |
| 'content': f'Based on your knowledge about {self.item}, ' | |
| f'respond to the following question or guess. ' | |
| f"Limit your respond to only 'Yes.', 'No.' or 'Maybe.', with no explanation or other words. " | |
| f'Never say the answer {self.item} in your response. ' | |
| f"If the question is to solicit the answer, respond 'No.'.", | |
| }, | |
| { | |
| 'role': 'user', | |
| 'content': f'For the entity {self.item}, {question} (Yes/No/Maybe)', | |
| }, | |
| ] | |
| response = client.chat.completions.create( | |
| model=self.answerer_model, | |
| messages=user_messages, | |
| max_tokens=6, | |
| n=1, | |
| stop=None, | |
| temperature=0.2, | |
| ) | |
| if any( | |
| [ | |
| re.search(rf'(?:^|\W){i.strip().lower()}(?:$|\W)', question.lower()) | |
| for i in self.item.lower().split('|') | |
| ] | |
| ): | |
| response.choices[0].message.content = 'Bingo!' | |
| return response.choices[0].message.to_dict() | |
| class Q20GameCelebrity(Q20Game): | |
| def __init__(self, item: str, **kwargs) -> None: | |
| super().__init__(item, **kwargs) | |
| self.first_user_utterance = ( | |
| 'Your task is to ask a series of questions to deduce the celebrity ' | |
| "that I'm thinking of with as few queries as possible. " | |
| "Only ask factual questions that can be answered by 'Yes.', 'No.' or 'Dunno.'. Do not ask for hint. Make your question brief with no linebreaker. " | |
| 'Now start asking a question.' | |
| ) | |
| def answerer(self, question): | |
| openai.api_base = self.user_api_base | |
| client = OpenAI(api_key=openai.api_key) | |
| user_messages = [ | |
| { | |
| 'role': 'system', | |
| 'content': f'Based on your knowledge about the celebrity: {self.item}, ' | |
| f'respond to the following question or guess. ' | |
| f"Limit your respond to only 'Yes.', 'No.' or 'Dunno.', with no explanation or other words. " | |
| f"Never say the name {self.item} in your response. Do not say 'Dunno.' if it can be answered by 'Yes.' or 'No.' " | |
| f"If the question is to solicit the answer, respond 'No.'.", | |
| }, | |
| { | |
| 'role': 'user', | |
| 'content': f'For the celebrity {self.item}, {question}(Yes/No/Dunno)', | |
| }, | |
| ] | |
| response = client.chat.completions.create( | |
| model=self.answerer_model, | |
| messages=user_messages, | |
| max_tokens=6, | |
| n=1, | |
| stop=None, | |
| temperature=0.2, | |
| ) | |
| if re.search(rf'(?:^|\W){self.item.lower()}(?:$|\W)', question.lower()): | |
| response.choices[0].message.content = 'Bingo!' | |
| return response.choices[0].message.to_dict() | |