sim-so commited on
Commit
dda94e6
1 Parent(s): 3583518

Add application file

Browse files
Files changed (5) hide show
  1. app.py +153 -0
  2. example/88.dat +0 -0
  3. requirements.txt +2 -0
  4. src/functions.py +20 -0
  5. src/semantle.py +23 -0
app.py ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import time
3
+ import json
4
+ import random
5
+
6
+ import pandas as pd
7
+ import gradio as gr
8
+ import openai
9
+
10
+ from src.semantle import get_puzzle, evaluate_guess
11
+ from src.functions import get_functions
12
+
13
+ GPT_MODEL = "gpt-3.5-turbo"
14
+ TITLE = "やりとりSemantle"
15
+ puzzle_numbers = [88]
16
+ puzzle = get_puzzle(random.choice(puzzle_numbers))
17
+ print(puzzle.secret)
18
+
19
+ guesses = pd.DataFrame.from_dict({"order":[], "guess":[], "sim":[], "rank":[]})
20
+
21
+ system_content_prefix = """今がら言葉ゲーム始めます。ユーザーが正解を答えるようにチャレンジする間、進行を手伝うのが役割です。
22
+
23
+ まず、"""
24
+ system_content=f"""ユーザーからの話を聞いて、答えるのか、ヒントを欲しがっているのか、やめようといるのかを判断してください。
25
+ ユーザーが答えする場合、答えの点数を評価しておく。その後、{guesses}がら今まで答えた結果の流れを見て、状況を一言で話してください。
26
+ ユーザーがヒントを欲しがっている場合、正解の「{puzzle.secret}」に関する間接的な情報を提供してください。
27
+ ユーザーが正解を聞いたりやめると言いたりする場合、やめてもいいかをもう一度確認してください。
28
+
29
+ ゲームのルール:
30
+ 正解は一つの言葉で決めている。ユーザーはどんな言葉が正解か推測して、単語を一つずつ答えする。
31
+ 正解を出すと成功としてゲームが終わる。推測した言葉がハズレだったら、推測したのが正解とどのぐらい近いかをヒントとしてもらえる。
32
+
33
+ ゲームと関係ない話は答えないでください。
34
+ """
35
+ system_message = [{"role": "system", "content": system_content_prefix+system_content}]
36
+ chat_messages = []
37
+
38
+ def add_guess(guess_result):
39
+ if guess_result["rank"] == " 正解!":
40
+ return "正解です。"
41
+ if guess_result["sim"]:
42
+ guesses.loc[guesses.shape[0]] = [guesses.shape[0]] + [v for v in guess_result.values()]
43
+ print(guesses.head())
44
+ return guesses.to_json()
45
+ else:
46
+ return "1,000以内に入っていないようです。"
47
+
48
+ def create_chat(user_input, chat_history, api_key):
49
+ openai.api_key = api_key
50
+ user_content = [{"role": "user", "content": user_input}]
51
+ chat_messages.extend(user_content)
52
+ response = openai.ChatCompletion.create(
53
+ model=GPT_MODEL,
54
+ messages=system_message+chat_messages,
55
+ functions=get_functions()
56
+ )
57
+ response_message = response.choices[0].message
58
+
59
+ # Step 2: check if CPT wanted to call a function
60
+ if response_message.get("function_call"):
61
+ # Step 3: call the function
62
+ # Note: the JSON response may not always be valid; be sure to handle errors
63
+ available_functions = {
64
+ "evaluate_guess": evaluate_guess,
65
+ }
66
+ function_name = response_message["function_call"]["name"]
67
+ function_to_call = available_functions[function_name]
68
+ function_args = json.loads(response_message["function_call"]["arguments"])
69
+ function_response = function_to_call(
70
+ word=function_args.get("word"),
71
+ puzzle=puzzle
72
+ )
73
+ guess_result = add_guess(function_response)
74
+ # Step 4: send the info on the function call and function response to GPT
75
+ chat_messages.append(response_message.to_dict()) # extend conversation with assistant's reply
76
+ chat_messages.append(
77
+ {"role": "function",
78
+ "name": function_name,
79
+ "content": guess_result}
80
+ ) # extend conversation with function response
81
+ second_response = openai.ChatCompletion.create(
82
+ model=GPT_MODEL,
83
+ messages=system_message+chat_messages,
84
+ ) # get a new response from GPT where it can se the function response
85
+ return second_response["choices"][0]["message"].to_dict()
86
+
87
+ chat_messages.append(response_message.to_dict())
88
+ return response_message.to_dict()
89
+
90
+ with gr.Blocks() as demo:
91
+ with gr.Row():
92
+ gr.Markdown(
93
+ """
94
+ # やりとりSemantle
95
+ [semantle日本語版](https://semantoru.com/)をchatbotと楽しめるためのspaceです。
96
+ ## ゲームのやり方
97
+ - 正解は一つの単語で、これを答えるとゲームの勝利になります。
98
+ - 推測した単語が正解じゃない場合、類似度スコアと順位が表示されます。それは正解を推測する大事なヒントになります。
99
+ ## chatbotの仕事
100
+ - 単語のスコアとランク以外に他のヒントがもらえます。
101
+ - ゲームに関して困っている時、何か質問してみてください。
102
+ """
103
+ )
104
+
105
+ with gr.Row():
106
+ with gr.Column():
107
+ api_key = gr.Textbox(placeholder="sk-...", label="OPENAI_API_KEY", value=None, type="password")
108
+ guesses_table = gr.DataFrame(
109
+ value=guesses,
110
+ headers=["#", "答え", "スコア", "ランク"],
111
+ datatype=["number", "str", "str", "str"],
112
+ elem_id="guesses-table"
113
+ )
114
+ with gr.Column(elem_id="chat_container"):
115
+ msg = gr.Textbox(
116
+ placeholder="ゲームをするため、まずはAPI KEYを入れてください。",
117
+ label="答え",
118
+ interactive=False,
119
+ max_lines=1
120
+ )
121
+ chatbot = gr.Chatbot(elem_id="chatbot")
122
+
123
+ def unfreeze():
124
+ return msg.update(interactive=True, placeholder="正解と思う言葉を答えてください。")
125
+ def greet():
126
+ return "", [("[START]", "ゲームを始まります!好きな言葉をひとつだけいってみてください。")]
127
+
128
+ def respond(user_input, chat_history, api_key):
129
+ reply = create_chat(user_input, chat_history, api_key)
130
+ chat_history.append((user_input, reply["content"]))
131
+ time.sleep(2)
132
+ return "", chat_history
133
+ def update_guesses():
134
+ return guesses_table.update(value=guesses)
135
+
136
+ api_key.change(unfreeze, [], [msg]).then(greet, [], [msg, chatbot])
137
+ msg.submit(respond, [msg, chatbot, api_key], [msg, chatbot]).then(update_guesses, [], [guesses_table])
138
+
139
+
140
+ gr.Examples(
141
+ [
142
+ [puzzle.nearests_words[-1]],
143
+ ["どんなヒントが貰える?"],
144
+ ["正解と「近い」とはどういう意味?"],
145
+ ["何から始めたらいい?"],
146
+ ["今日の正解は何?"],
147
+ ],
148
+ inputs=msg,
149
+ label="こちらから選んで話すこともできます."
150
+ )
151
+
152
+ if __name__ == "__main__":
153
+ demo.queue(concurrency_count=20).launch()
example/88.dat ADDED
Binary file (75.2 kB). View file
 
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ openai
2
+ gradio
src/functions.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ evaluate_guess = {"name": "evaluate_guess",
2
+ "description": "Calculate the score of a guess word and get the rank among the 1,000 words.",
3
+ "parameters": {
4
+ "type": "object",
5
+ "properties": {
6
+ "word": {
7
+ "type": "string",
8
+ "description": "A word, noun, verb, adverb or adjective. e.g. 空, 近い, 行く, etc."
9
+ },
10
+ "puzzle": {
11
+ "type": "object",
12
+ "description": "A puzzle data containing scores and ranks of words."
13
+ }
14
+ },
15
+ "required": ["word", "puzzle"]
16
+ }}
17
+
18
+ def get_functions():
19
+ functions = [evaluate_guess]
20
+ return functions
src/semantle.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pickle
2
+ from typing import Tuple, List, Dict
3
+
4
+ class Puzzle:
5
+ secret: str = ""
6
+ nearests: Dict = dict()
7
+ nearests_words: List = list()
8
+
9
+ def get_puzzle(puzzle_num: int):
10
+ puzzle = Puzzle()
11
+ with open(f'example/{puzzle_num}.dat', 'rb') as f:
12
+ puzzle.nearests, _ = pickle.load(f)
13
+ puzzle.nearests_words = [word for word in puzzle.nearests.keys()]
14
+ puzzle.secret = puzzle.nearests_words[0]
15
+ return puzzle
16
+
17
+ def evaluate_guess(word: str, puzzle):
18
+ rtn = {"guess": word, "sim": None, "rank": None}
19
+ # check most similar
20
+ if word in puzzle.nearests:
21
+ rtn["sim"] = puzzle.nearests[word][1]
22
+ rtn["rank"] = puzzle.nearests[word][0]
23
+ return rtn