Javierss
commited on
Commit
·
7c2eafe
1
Parent(s):
e70a337
Add comments to code,Update README.md, Sintezise game.py modules
Browse files- README.md +102 -1
- __pycache__/app.cpython-311.pyc +0 -0
- __pycache__/game.cpython-311.pyc +0 -0
- __pycache__/game_transformer.cpython-311.pyc +0 -0
- __pycache__/hints.cpython-311.pyc +0 -0
- app.py +144 -17
- data/ranking.txt +9 -4
- game_word2vec.py → game.py +138 -30
- game_transformer.py +0 -228
- hints.py +78 -31
- ranking.txt +0 -1
- requirements.txt +2 -2
README.md
CHANGED
@@ -10,4 +10,105 @@ pinned: false
|
|
10 |
license: other
|
11 |
---
|
12 |
|
13 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
license: other
|
11 |
---
|
12 |
|
13 |
+
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
14 |
+
# Semantrix Game
|
15 |
+
|
16 |
+
This repository contains the implementation of the Semantrix game, a word guessing game using word embeddings. The game supports multiple languages (Spanish and English) and can be configured to use either a Word2Vec model or a SentenceTransformer model for word embeddings.
|
17 |
+
|
18 |
+
## Modules
|
19 |
+
|
20 |
+
|
21 |
+
|
22 |
+
### app.py
|
23 |
+
|
24 |
+
This module defines a Gradio-based web application for the Semantrix game. The application allows users to play the game in either Spanish or English, using different embedding models for word similarity.
|
25 |
+
|
26 |
+
#### Functions
|
27 |
+
|
28 |
+
- `convert_to_markdown_centered(text)`: Converts text to a centered markdown format for displaying game history and last attempt.
|
29 |
+
- **Parameters**:
|
30 |
+
- `text (str)`: The text to be converted.
|
31 |
+
- **Returns**: `str`: The centered markdown formatted text.
|
32 |
+
|
33 |
+
- `reset(difficulty, lang, model)`: Resets the game state based on the selected difficulty, language, and model.
|
34 |
+
- **Parameters**:
|
35 |
+
- `difficulty`: The selected difficulty level.
|
36 |
+
- `lang`: The selected language.
|
37 |
+
- `model`: The selected embedding model.
|
38 |
+
- **Returns**: `list`: A list of initial output components for the UI.
|
39 |
+
|
40 |
+
- `change(state, inp)`: Changes the game state by incrementing the state variable.
|
41 |
+
- **Parameters**:
|
42 |
+
- `state`: The current game state.
|
43 |
+
- `inp`: The user input.
|
44 |
+
- **Returns**: `list`: A list containing the updated state and input component.
|
45 |
+
|
46 |
+
- `update(state, radio, inp, hint)`: Updates the game state and UI components based on the current state and user inputs.
|
47 |
+
- **Parameters**:
|
48 |
+
- `state`: The current game state.
|
49 |
+
- `radio`: The radio input component.
|
50 |
+
- `inp`: The user input.
|
51 |
+
- `hint`: The hint state.
|
52 |
+
- **Returns**: `list`: A list of updated output components for the UI.
|
53 |
+
|
54 |
+
### game.py
|
55 |
+
|
56 |
+
This module defines the Semantrix class, which implements a word guessing game using word embeddings. The game can be configured to use either a Word2Vec model or a SentenceTransformer model for word embeddings. The game supports multiple languages and difficulty levels.
|
57 |
+
|
58 |
+
#### Classes
|
59 |
+
|
60 |
+
- `Semantrix`: A class that implements the Semantrix word guessing game.
|
61 |
+
- **Methods**:
|
62 |
+
- `__init__(self, lang=0, model_type="SentenceTransformer")`: Initializes the Semantrix game with the specified language and model type.
|
63 |
+
- `prepare_game(self, difficulty)`: Prepares the game with the selected difficulty level.
|
64 |
+
- `gen_rank(self, repeated)`: Generates the ranking file based on the scores.
|
65 |
+
- `play_game(self, word)`: Plays the game with the selected word and returns feedback.
|
66 |
+
- `curiosity(self)`: Generates a curiosity hint about the secret word once the game is over.
|
67 |
+
|
68 |
+
### hints.py
|
69 |
+
|
70 |
+
This module provides functions to generate dynamic hints and curiosities about a secret word using language models (LLMs).
|
71 |
+
|
72 |
+
#### Functions
|
73 |
+
|
74 |
+
- `hint(secret, n, model, last_hint, lang, Config)`: Generates a dynamic hint based on the secret word and the number of hints given.
|
75 |
+
- **Parameters**:
|
76 |
+
- `secret (str)`: The secret word.
|
77 |
+
- `n (int)`: The number of hints already given.
|
78 |
+
- `model`: The sentence transformer model used for encoding.
|
79 |
+
- `last_hint (int)`: The index of the last hint given.
|
80 |
+
- `lang (int)`: The language code (0 for Spanish, 1 for English).
|
81 |
+
- `Config`: Configuration object containing hint templates.
|
82 |
+
- **Returns**: `tuple`: A tuple containing the generated hint (str), the updated number of hints (int), and the index of the last hint given (int).
|
83 |
+
|
84 |
+
- `curiosity(secret, Config)`: Generates a curiosity about the secret word.
|
85 |
+
- **Parameters**:
|
86 |
+
- `secret (str)`: The secret word.
|
87 |
+
- `Config`: Configuration object containing the curiosity template.
|
88 |
+
- **Returns**: `str`: The generated curiosity.
|
89 |
+
|
90 |
+
- `ireplace(old, new, text)`: Replaces all occurrences of a substring in a string, case-insensitively.
|
91 |
+
- **Parameters**:
|
92 |
+
- `old (str)`: The substring to be replaced.
|
93 |
+
- `new (str)`: The substring to replace with.
|
94 |
+
- `text (str)`: The original string.
|
95 |
+
- **Returns**: `str`: The modified string with all occurrences of the old substring replaced by the new substring.
|
96 |
+
|
97 |
+
|
98 |
+
## How to Run
|
99 |
+
|
100 |
+
1. Clone the repository.
|
101 |
+
2. Install the required dependencies.
|
102 |
+
3. Run the `app.py` script to launch the Gradio web application.
|
103 |
+
|
104 |
+
## Dependencies
|
105 |
+
|
106 |
+
- Gradio
|
107 |
+
- OpenAI
|
108 |
+
- SentenceTransformers
|
109 |
+
- Gensim
|
110 |
+
- NumPy
|
111 |
+
|
112 |
+
## License
|
113 |
+
|
114 |
+
This project is licensed under the MIT License.
|
__pycache__/app.cpython-311.pyc
CHANGED
Binary files a/__pycache__/app.cpython-311.pyc and b/__pycache__/app.cpython-311.pyc differ
|
|
__pycache__/game.cpython-311.pyc
CHANGED
Binary files a/__pycache__/game.cpython-311.pyc and b/__pycache__/game.cpython-311.pyc differ
|
|
__pycache__/game_transformer.cpython-311.pyc
CHANGED
Binary files a/__pycache__/game_transformer.cpython-311.pyc and b/__pycache__/game_transformer.cpython-311.pyc differ
|
|
__pycache__/hints.cpython-311.pyc
CHANGED
Binary files a/__pycache__/hints.cpython-311.pyc and b/__pycache__/hints.cpython-311.pyc differ
|
|
app.py
CHANGED
@@ -1,19 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
import gradio as gr
|
2 |
import json
|
3 |
-
from
|
4 |
-
from game_transformer import Semantrix as semantrix_sentence_transformers
|
5 |
-
|
6 |
|
|
|
7 |
config_file_path = "config/lang.json"
|
8 |
logo_path = "config/images/logo.png"
|
9 |
logo_win_path = "config/images/logo_win.gif"
|
10 |
|
|
|
11 |
with open(config_file_path, "r") as file:
|
12 |
Config_full = json.load(file)
|
13 |
|
14 |
-
lang_conf = 0
|
15 |
-
|
16 |
|
|
|
17 |
if lang_conf == 1:
|
18 |
Config = Config_full["ENG"]["Game"]
|
19 |
Menu = Config_full["ENG"]["Menu"]
|
@@ -22,6 +81,7 @@ else:
|
|
22 |
Menu = Config_full["SPA"]["Menu"]
|
23 |
|
24 |
|
|
|
25 |
def convert_to_markdown_centered(text):
|
26 |
lines = text.strip().split("\n")
|
27 |
|
@@ -64,13 +124,17 @@ def convert_to_markdown_centered(text):
|
|
64 |
return markdown
|
65 |
|
66 |
|
|
|
67 |
with gr.Blocks() as demo:
|
68 |
-
state
|
69 |
-
|
70 |
-
|
|
|
71 |
|
72 |
-
game
|
|
|
73 |
|
|
|
74 |
header = gr.Markdown(
|
75 |
"""
|
76 |
<p style="text-align:center"> """
|
@@ -79,15 +143,22 @@ with gr.Blocks() as demo:
|
|
79 |
"""
|
80 |
)
|
81 |
|
|
|
82 |
def reset(difficulty, lang, model):
|
83 |
-
global Config, game, Menu
|
|
|
|
|
84 |
language = 1 if lang == "English" else 0
|
85 |
|
|
|
86 |
if model == "Word2Vec":
|
87 |
-
game =
|
88 |
else:
|
89 |
-
game =
|
|
|
|
|
90 |
|
|
|
91 |
if language == 1:
|
92 |
Config = Config_full["ENG"]["Game"]
|
93 |
Menu = Config_full["ENG"]["Menu"]
|
@@ -95,7 +166,10 @@ with gr.Blocks() as demo:
|
|
95 |
Config = Config_full["SPA"]["Game"]
|
96 |
Menu = Config_full["SPA"]["Menu"]
|
97 |
|
|
|
98 |
game.prepare_game(difficulty)
|
|
|
|
|
99 |
output = [
|
100 |
-1,
|
101 |
gr.Textbox(visible=False),
|
@@ -114,20 +188,30 @@ with gr.Blocks() as demo:
|
|
114 |
),
|
115 |
]
|
116 |
|
|
|
117 |
return output
|
118 |
|
|
|
119 |
def change(state, inp):
|
120 |
-
|
121 |
state = state + 1
|
|
|
|
|
122 |
return [state, inp]
|
123 |
|
|
|
124 |
def update(state, radio, inp, hint):
|
125 |
global difficulty
|
|
|
|
|
126 |
dif_state = 4
|
|
|
|
|
127 |
output = [state]
|
128 |
|
129 |
state_int = state
|
130 |
|
|
|
131 |
if state_int == -1:
|
132 |
output.extend(
|
133 |
[
|
@@ -145,6 +229,7 @@ with gr.Blocks() as demo:
|
|
145 |
]
|
146 |
)
|
147 |
|
|
|
148 |
elif state_int == 1:
|
149 |
output.extend(
|
150 |
[
|
@@ -161,6 +246,8 @@ with gr.Blocks() as demo:
|
|
161 |
gr.Markdown(visible=False),
|
162 |
]
|
163 |
)
|
|
|
|
|
164 |
elif state_int == 2:
|
165 |
if radio == Menu["No"]:
|
166 |
output = [
|
@@ -196,6 +283,8 @@ with gr.Blocks() as demo:
|
|
196 |
gr.Markdown(visible=False),
|
197 |
]
|
198 |
)
|
|
|
|
|
199 |
elif state_int == dif_state:
|
200 |
output.extend(
|
201 |
[
|
@@ -215,6 +304,8 @@ with gr.Blocks() as demo:
|
|
215 |
gr.Markdown(visible=False),
|
216 |
]
|
217 |
)
|
|
|
|
|
218 |
elif state_int == dif_state + 1:
|
219 |
if radio == Menu["Easy"]:
|
220 |
difficulty = 1
|
@@ -241,6 +332,7 @@ with gr.Blocks() as demo:
|
|
241 |
]
|
242 |
)
|
243 |
|
|
|
244 |
elif state_int == dif_state + 2:
|
245 |
|
246 |
game.prepare_game(difficulty)
|
@@ -263,8 +355,14 @@ with gr.Blocks() as demo:
|
|
263 |
gr.Markdown(visible=False),
|
264 |
]
|
265 |
)
|
|
|
|
|
266 |
elif state_int > dif_state + 2:
|
|
|
|
|
267 |
feed = game.play_game(inp)
|
|
|
|
|
268 |
feedback_trim = feed.split("[rank]")
|
269 |
if len(feedback_trim) > 1:
|
270 |
ranking_vis = True
|
@@ -274,17 +372,30 @@ with gr.Blocks() as demo:
|
|
274 |
ranking_vis = False
|
275 |
ranking_md = ""
|
276 |
|
|
|
277 |
feedback = feedback_trim[0].split("[hint]")
|
278 |
win = feedback_trim[0].split("[win]")
|
279 |
lose = feedback_trim[0].split("[lose]")
|
|
|
|
|
280 |
if len(feedback) > 1:
|
281 |
hint = True
|
|
|
|
|
282 |
else:
|
283 |
hint = False
|
|
|
284 |
|
|
|
285 |
if len(win) > 1 or len(lose) > 1:
|
|
|
|
|
286 |
won = True if len(win) > 1 else False
|
|
|
|
|
287 |
curiosity = game.curiosity()
|
|
|
|
|
288 |
output.extend(
|
289 |
[
|
290 |
gr.Button(Menu["Send"], visible=False, variant="primary"),
|
@@ -304,24 +415,25 @@ with gr.Blocks() as demo:
|
|
304 |
gr.Markdown(visible=False),
|
305 |
]
|
306 |
)
|
|
|
307 |
return output
|
308 |
|
|
|
309 |
output.extend(
|
310 |
[
|
311 |
gr.Button(Menu["Send"], visible=True, variant="primary"),
|
312 |
gr.Radio(label="", visible=False),
|
313 |
-
gr.Textbox(feedback
|
314 |
gr.Button(visible=True, variant="stop"),
|
315 |
gr.Textbox(value="", visible=True, placeholder=Menu["New_word"]),
|
316 |
gr.Image(logo_path, interactive=False, visible=False),
|
317 |
-
gr.Textbox(
|
318 |
-
feedback[1] if hint else "", visible=hint, label="Pista"
|
319 |
-
),
|
320 |
gr.Button(visible=False),
|
321 |
gr.Markdown(ranking_md, visible=ranking_vis),
|
322 |
]
|
323 |
)
|
324 |
|
|
|
325 |
else:
|
326 |
output.extend(
|
327 |
[
|
@@ -338,23 +450,31 @@ with gr.Blocks() as demo:
|
|
338 |
gr.Markdown(visible=False),
|
339 |
]
|
340 |
)
|
|
|
|
|
341 |
return output
|
342 |
|
|
|
343 |
img = gr.Image(logo_path, height=430, interactive=False, visible=True)
|
344 |
ranking = gr.Markdown(visible=False)
|
345 |
|
346 |
with gr.Row():
|
347 |
out = gr.Textbox(visible=False, placeholder=Config[list(Config.keys())[0]])
|
348 |
hint_out = gr.Textbox(visible=False)
|
|
|
349 |
radio = gr.Radio(visible=False)
|
|
|
350 |
with gr.Row():
|
351 |
inp = gr.Textbox(visible=False, interactive=True, label="")
|
352 |
but = gr.Button(Menu["Start"])
|
353 |
give_up = gr.Button("Pista", visible=False)
|
354 |
reload = gr.Button(Menu["Play_again"], visible=False)
|
355 |
|
|
|
356 |
with gr.Accordion("Configuración/Settings", open=False):
|
357 |
with gr.Row():
|
|
|
|
|
358 |
model = (
|
359 |
gr.Dropdown(
|
360 |
["Sentence Transformers", "Word2Vec"],
|
@@ -362,12 +482,17 @@ with gr.Blocks() as demo:
|
|
362 |
label="Embedding Model",
|
363 |
),
|
364 |
)
|
|
|
|
|
365 |
lang = (
|
366 |
gr.Dropdown(
|
367 |
["Español", "English"], value="Español", label="Idioma/Language"
|
368 |
),
|
369 |
)
|
370 |
|
|
|
|
|
|
|
371 |
inp.submit(change, inputs=[state, inp], outputs=[state, inp])
|
372 |
but.click(change, inputs=[state, inp], outputs=[state, inp])
|
373 |
give_up.click(
|
@@ -380,6 +505,7 @@ with gr.Blocks() as demo:
|
|
380 |
)
|
381 |
radio.input(change, inputs=[state, inp], outputs=[state, inp])
|
382 |
|
|
|
383 |
reload.click(
|
384 |
reset,
|
385 |
inputs=[difficulty, lang[0], model[0]],
|
@@ -401,6 +527,7 @@ with gr.Blocks() as demo:
|
|
401 |
outputs=[state, out, inp, img, but, radio, hint_out, reload, header],
|
402 |
)
|
403 |
|
|
|
404 |
state.change(
|
405 |
update,
|
406 |
inputs=[state, radio, inp, hint],
|
|
|
1 |
+
"""
|
2 |
+
This module defines a Gradio-based web application for the Semantrix game. The application allows users to play the game in either Spanish or English, using different embedding models for word similarity.
|
3 |
+
|
4 |
+
Modules:
|
5 |
+
gradio: Used for creating the web interface.
|
6 |
+
json: Used for loading configuration files.
|
7 |
+
game: Contains the Semantrix class for game logic.
|
8 |
+
|
9 |
+
File Paths:
|
10 |
+
config_file_path: Path to the configuration file.
|
11 |
+
logo_path: Path to the logo image.
|
12 |
+
logo_win_path: Path to the winning logo image.
|
13 |
+
|
14 |
+
Functions:
|
15 |
+
convert_to_markdown_centered(text):
|
16 |
+
Converts text to a centered markdown format for displaying game history and last attempt.
|
17 |
+
|
18 |
+
reset(difficulty, lang, model):
|
19 |
+
Resets the game state based on the selected difficulty, language, and model.
|
20 |
+
|
21 |
+
change(state, inp):
|
22 |
+
Changes the game state by incrementing the state variable.
|
23 |
+
|
24 |
+
update(state, radio, inp, hint):
|
25 |
+
Updates the game state and UI components based on the current state and user inputs.
|
26 |
+
|
27 |
+
Gradio Components:
|
28 |
+
demo: The main Gradio Blocks component that contains the entire UI layout.
|
29 |
+
header: A Markdown component for displaying the game header.
|
30 |
+
state: A State component for tracking the current game state.
|
31 |
+
difficulty: A State component for tracking the difficulty level.
|
32 |
+
hint: A State component for tracking if a hint is provided.
|
33 |
+
img: An Image component for displaying the game logo.
|
34 |
+
ranking: A Markdown component for displaying the ranking.
|
35 |
+
out: A Textbox component for displaying game messages.
|
36 |
+
hint_out: A Textbox component for displaying hints.
|
37 |
+
radio: A Radio component for user selections.
|
38 |
+
inp: A Textbox component for user input.
|
39 |
+
but: A Button component for several actions.
|
40 |
+
give_up: A Button component for giving up.
|
41 |
+
reload: A Button component for reloading the game.
|
42 |
+
model: A Dropdown component for selecting the embedding model.
|
43 |
+
lang: A Dropdown component for selecting the language.
|
44 |
+
|
45 |
+
Events:
|
46 |
+
inp.submit: Triggers the change function on input submission.
|
47 |
+
but.click: Triggers the change function on button click.
|
48 |
+
give_up.click: Triggers the change function on give up button click.
|
49 |
+
radio.input: Triggers the change function on radio input.
|
50 |
+
reload.click: Triggers the reset function on reload button click.
|
51 |
+
demo.load: Triggers the reset function on demo load.
|
52 |
+
lang[0].select: Triggers the reset function on language selection.
|
53 |
+
model[0].select: Triggers the reset function on model selection.
|
54 |
+
state.change: Triggers the update function on state change.
|
55 |
+
|
56 |
+
Main:
|
57 |
+
Launches the Gradio application if the script is run as the main module.
|
58 |
+
"""
|
59 |
+
|
60 |
import gradio as gr
|
61 |
import json
|
62 |
+
from game import Semantrix
|
|
|
|
|
63 |
|
64 |
+
# File paths for configuration and images
|
65 |
config_file_path = "config/lang.json"
|
66 |
logo_path = "config/images/logo.png"
|
67 |
logo_win_path = "config/images/logo_win.gif"
|
68 |
|
69 |
+
# Loading the configuration file
|
70 |
with open(config_file_path, "r") as file:
|
71 |
Config_full = json.load(file)
|
72 |
|
73 |
+
lang_conf = 0 # Language configuration flag (0 for Spanish, 1 for English)
|
|
|
74 |
|
75 |
+
# Setting the configuration based on the language flag
|
76 |
if lang_conf == 1:
|
77 |
Config = Config_full["ENG"]["Game"]
|
78 |
Menu = Config_full["ENG"]["Menu"]
|
|
|
81 |
Menu = Config_full["SPA"]["Menu"]
|
82 |
|
83 |
|
84 |
+
# Function to convert text to centered markdown format
|
85 |
def convert_to_markdown_centered(text):
|
86 |
lines = text.strip().split("\n")
|
87 |
|
|
|
124 |
return markdown
|
125 |
|
126 |
|
127 |
+
#
|
128 |
with gr.Blocks() as demo:
|
129 |
+
# Initializing state variables to manage the internal state of the application
|
130 |
+
state = gr.State(-1) # State variable to track the current game state
|
131 |
+
difficulty = gr.State(-1) # State variable to track the difficulty level
|
132 |
+
hint = gr.State(False) # State variable to track if the hint is provided
|
133 |
|
134 |
+
# Initializing the game using the Semantrix class with default parameters
|
135 |
+
game = Semantrix(lang=0, model_type="SentenceTransformer")
|
136 |
|
137 |
+
# Creating a Markdown component to display the header
|
138 |
header = gr.Markdown(
|
139 |
"""
|
140 |
<p style="text-align:center"> """
|
|
|
143 |
"""
|
144 |
)
|
145 |
|
146 |
+
# Function to reset the game
|
147 |
def reset(difficulty, lang, model):
|
148 |
+
global Config, game, Menu # Declare global variables to modify them within the function
|
149 |
+
|
150 |
+
# Determine the language based on the input parameter
|
151 |
language = 1 if lang == "English" else 0
|
152 |
|
153 |
+
# Initialize the game object based on the selected model
|
154 |
if model == "Word2Vec":
|
155 |
+
game = Semantrix(language, "word2vec") # Use Word2Vec model
|
156 |
else:
|
157 |
+
game = Semantrix(
|
158 |
+
language, "SentenceTransformer"
|
159 |
+
) # Use Sentence Transformers model
|
160 |
|
161 |
+
# Set the configuration and menu based on the selected language
|
162 |
if language == 1:
|
163 |
Config = Config_full["ENG"]["Game"]
|
164 |
Menu = Config_full["ENG"]["Menu"]
|
|
|
166 |
Config = Config_full["SPA"]["Game"]
|
167 |
Menu = Config_full["SPA"]["Menu"]
|
168 |
|
169 |
+
# Prepare the game with the selected difficulty level
|
170 |
game.prepare_game(difficulty)
|
171 |
+
|
172 |
+
# Define the initial output components for the UI
|
173 |
output = [
|
174 |
-1,
|
175 |
gr.Textbox(visible=False),
|
|
|
188 |
),
|
189 |
]
|
190 |
|
191 |
+
# Return the initial output components
|
192 |
return output
|
193 |
|
194 |
+
# Function to change the state of the game
|
195 |
def change(state, inp):
|
196 |
+
# Increment the state by 1
|
197 |
state = state + 1
|
198 |
+
|
199 |
+
# Return the updated state and input component
|
200 |
return [state, inp]
|
201 |
|
202 |
+
# Function to update the game state based on the current state of the game
|
203 |
def update(state, radio, inp, hint):
|
204 |
global difficulty
|
205 |
+
|
206 |
+
# Define the difficulty state
|
207 |
dif_state = 4
|
208 |
+
|
209 |
+
# Initialize the output component list with the current state
|
210 |
output = [state]
|
211 |
|
212 |
state_int = state
|
213 |
|
214 |
+
# Define UI components for the initial state
|
215 |
if state_int == -1:
|
216 |
output.extend(
|
217 |
[
|
|
|
229 |
]
|
230 |
)
|
231 |
|
232 |
+
# Define UI components for the first state, ask the user if they want to know the rules
|
233 |
elif state_int == 1:
|
234 |
output.extend(
|
235 |
[
|
|
|
246 |
gr.Markdown(visible=False),
|
247 |
]
|
248 |
)
|
249 |
+
|
250 |
+
# Define UI components for the second state, Depending on the answer, show the rules or keep going
|
251 |
elif state_int == 2:
|
252 |
if radio == Menu["No"]:
|
253 |
output = [
|
|
|
283 |
gr.Markdown(visible=False),
|
284 |
]
|
285 |
)
|
286 |
+
|
287 |
+
# Define UI components for the difficulty state, ask the user to select the difficulty level
|
288 |
elif state_int == dif_state:
|
289 |
output.extend(
|
290 |
[
|
|
|
304 |
gr.Markdown(visible=False),
|
305 |
]
|
306 |
)
|
307 |
+
|
308 |
+
# Define UI components for the difficulty state + 1, prepare the game based on the selected difficulty level, and start the game
|
309 |
elif state_int == dif_state + 1:
|
310 |
if radio == Menu["Easy"]:
|
311 |
difficulty = 1
|
|
|
332 |
]
|
333 |
)
|
334 |
|
335 |
+
# Define UI components for the difficulty state + 2, play the game based on the selected difficulty level and prepare the game for the word guessing
|
336 |
elif state_int == dif_state + 2:
|
337 |
|
338 |
game.prepare_game(difficulty)
|
|
|
355 |
gr.Markdown(visible=False),
|
356 |
]
|
357 |
)
|
358 |
+
|
359 |
+
# Define UI components for the state greater than the difficulty state + 2, play the game and provide feedback based on the user input
|
360 |
elif state_int > dif_state + 2:
|
361 |
+
|
362 |
+
# Send the user input to the game and get the feedback from the game
|
363 |
feed = game.play_game(inp)
|
364 |
+
|
365 |
+
# Check if the feedback contains the ranking information and process it
|
366 |
feedback_trim = feed.split("[rank]")
|
367 |
if len(feedback_trim) > 1:
|
368 |
ranking_vis = True
|
|
|
372 |
ranking_vis = False
|
373 |
ranking_md = ""
|
374 |
|
375 |
+
# Check if the feedback contains a hint, win, or lose message
|
376 |
feedback = feedback_trim[0].split("[hint]")
|
377 |
win = feedback_trim[0].split("[win]")
|
378 |
lose = feedback_trim[0].split("[lose]")
|
379 |
+
|
380 |
+
# Check if the feedback contains a hint message
|
381 |
if len(feedback) > 1:
|
382 |
hint = True
|
383 |
+
hint_out = feedback[1]
|
384 |
+
feedback = feedback[0]
|
385 |
else:
|
386 |
hint = False
|
387 |
+
feedback = feedback[0]
|
388 |
|
389 |
+
# Check if the feedback contains a win or lose message and process it
|
390 |
if len(win) > 1 or len(lose) > 1:
|
391 |
+
|
392 |
+
# Check if the user won the game
|
393 |
won = True if len(win) > 1 else False
|
394 |
+
|
395 |
+
# Get the curiosity message from the game
|
396 |
curiosity = game.curiosity()
|
397 |
+
|
398 |
+
# Define the output components for the win or lose state
|
399 |
output.extend(
|
400 |
[
|
401 |
gr.Button(Menu["Send"], visible=False, variant="primary"),
|
|
|
415 |
gr.Markdown(visible=False),
|
416 |
]
|
417 |
)
|
418 |
+
|
419 |
return output
|
420 |
|
421 |
+
# Define the output components for the feedback and keep playing
|
422 |
output.extend(
|
423 |
[
|
424 |
gr.Button(Menu["Send"], visible=True, variant="primary"),
|
425 |
gr.Radio(label="", visible=False),
|
426 |
+
gr.Textbox(feedback, visible=True, label=""),
|
427 |
gr.Button(visible=True, variant="stop"),
|
428 |
gr.Textbox(value="", visible=True, placeholder=Menu["New_word"]),
|
429 |
gr.Image(logo_path, interactive=False, visible=False),
|
430 |
+
gr.Textbox(hint_out if hint else "", visible=hint, label="Pista"),
|
|
|
|
|
431 |
gr.Button(visible=False),
|
432 |
gr.Markdown(ranking_md, visible=ranking_vis),
|
433 |
]
|
434 |
)
|
435 |
|
436 |
+
# Define UI components for the rest of the states, state for showing basic text to the user
|
437 |
else:
|
438 |
output.extend(
|
439 |
[
|
|
|
450 |
gr.Markdown(visible=False),
|
451 |
]
|
452 |
)
|
453 |
+
|
454 |
+
# Return the output components
|
455 |
return output
|
456 |
|
457 |
+
# Define the UI layout for the gam
|
458 |
img = gr.Image(logo_path, height=430, interactive=False, visible=True)
|
459 |
ranking = gr.Markdown(visible=False)
|
460 |
|
461 |
with gr.Row():
|
462 |
out = gr.Textbox(visible=False, placeholder=Config[list(Config.keys())[0]])
|
463 |
hint_out = gr.Textbox(visible=False)
|
464 |
+
|
465 |
radio = gr.Radio(visible=False)
|
466 |
+
|
467 |
with gr.Row():
|
468 |
inp = gr.Textbox(visible=False, interactive=True, label="")
|
469 |
but = gr.Button(Menu["Start"])
|
470 |
give_up = gr.Button("Pista", visible=False)
|
471 |
reload = gr.Button(Menu["Play_again"], visible=False)
|
472 |
|
473 |
+
# Define the settings components for the game
|
474 |
with gr.Accordion("Configuración/Settings", open=False):
|
475 |
with gr.Row():
|
476 |
+
|
477 |
+
# Dropdown to select the model engine for the game
|
478 |
model = (
|
479 |
gr.Dropdown(
|
480 |
["Sentence Transformers", "Word2Vec"],
|
|
|
482 |
label="Embedding Model",
|
483 |
),
|
484 |
)
|
485 |
+
|
486 |
+
# Dropdown to select the language for the game
|
487 |
lang = (
|
488 |
gr.Dropdown(
|
489 |
["Español", "English"], value="Español", label="Idioma/Language"
|
490 |
),
|
491 |
)
|
492 |
|
493 |
+
# Define the UI events for the game
|
494 |
+
|
495 |
+
# Define events that trigger the game state change
|
496 |
inp.submit(change, inputs=[state, inp], outputs=[state, inp])
|
497 |
but.click(change, inputs=[state, inp], outputs=[state, inp])
|
498 |
give_up.click(
|
|
|
505 |
)
|
506 |
radio.input(change, inputs=[state, inp], outputs=[state, inp])
|
507 |
|
508 |
+
# Define events that trigger the game reset
|
509 |
reload.click(
|
510 |
reset,
|
511 |
inputs=[difficulty, lang[0], model[0]],
|
|
|
527 |
outputs=[state, out, inp, img, but, radio, hint_out, reload, header],
|
528 |
)
|
529 |
|
530 |
+
# Define events that trigger the game state update
|
531 |
state.change(
|
532 |
update,
|
533 |
inputs=[state, radio, inp, hint],
|
data/ranking.txt
CHANGED
@@ -1,5 +1,10 @@
|
|
1 |
-
['#
|
2 |
---------------------------
|
3 |
-
['#1', 'amigo',
|
4 |
-
['#2', 'loco',
|
5 |
-
['#
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
['#8', 'medium', 6.94]
|
2 |
---------------------------
|
3 |
+
['#1', 'amigo', 8.3]
|
4 |
+
['#2', 'loco', 7.64]
|
5 |
+
['#7', 'fantasma', 7.41]
|
6 |
+
['#8', 'medium', 6.94]
|
7 |
+
['#4', 'hermano', 6.81]
|
8 |
+
['#5', 'duelo', 5.76]
|
9 |
+
['#3', 'familia', 4.88]
|
10 |
+
['#6', 'divorcio', 1.67]
|
game_word2vec.py → game.py
RENAMED
@@ -1,4 +1,41 @@
|
|
1 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
import json
|
3 |
import random
|
4 |
from datetime import datetime
|
@@ -15,65 +52,102 @@ import warnings
|
|
15 |
warnings.filterwarnings(action="ignore", category=UserWarning, module="gensim")
|
16 |
|
17 |
|
|
|
18 |
class Semantrix:
|
19 |
|
20 |
-
|
21 |
-
|
22 |
-
)
|
23 |
|
|
|
24 |
config_file_path = "config/lang.json"
|
25 |
-
|
26 |
secret_file_path = "config/secret.json"
|
27 |
-
|
28 |
data_path = "data/"
|
29 |
|
|
|
30 |
class DictWrapper:
|
31 |
def __init__(self, data_dict):
|
32 |
self.__dict__.update(data_dict)
|
33 |
|
34 |
-
|
35 |
-
|
36 |
-
self.lang = lang
|
37 |
-
|
38 |
-
self.embeddings_dict = {}
|
39 |
|
|
|
40 |
with open(self.config_file_path, "r") as file:
|
41 |
self.Config_full = json.load(file)
|
42 |
|
|
|
43 |
with open(self.secret_file_path, "r") as file:
|
44 |
self.secret = json.load(file)
|
45 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
if self.lang == 1:
|
47 |
-
self.model = KeyedVectors.load("config/w2v_models/eng_w2v_model", mmap="r")
|
48 |
self.Config = self.DictWrapper(self.Config_full["ENG"]["Game"])
|
49 |
self.secret_dict = self.secret["ENG"]
|
50 |
else:
|
51 |
-
self.model = KeyedVectors.load("config/w2v_models/esp_w2v_model", mmap="r")
|
52 |
self.Config = self.DictWrapper(self.Config_full["SPA"]["Game"])
|
53 |
self.secret_dict = self.secret["SPA"]
|
54 |
|
|
|
55 |
with open(self.data_path + "ranking.txt", "w+") as file:
|
56 |
file.write("---------------------------")
|
57 |
|
|
|
58 |
def prepare_game(self, difficulty):
|
59 |
|
|
|
60 |
self.secret_list = (
|
61 |
self.secret_dict["basic"]
|
62 |
if difficulty <= 2
|
63 |
else self.secret_dict["advanced"]
|
64 |
)
|
65 |
|
|
|
66 |
self.secret = self.secret_list.pop(random.randint(0, len(self.secret_list) - 1))
|
67 |
self.secret = self.secret.lower()
|
68 |
|
|
|
69 |
self.words = [self.Config.secret_word]
|
|
|
|
|
70 |
self.scores = [10]
|
71 |
|
72 |
-
|
73 |
-
|
74 |
|
75 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
|
|
|
77 |
self.win = False
|
78 |
self.n = 0
|
79 |
self.recent_hint = 0
|
@@ -81,10 +155,12 @@ class Semantrix:
|
|
81 |
self.last_hint = -1
|
82 |
self.difficulty = difficulty
|
83 |
|
|
|
84 |
if self.difficulty == 1:
|
85 |
self.n = 3
|
86 |
|
87 |
-
|
|
|
88 |
ascending_indices = np.argsort(self.scores)
|
89 |
descending_indices = list(ascending_indices[::-1])
|
90 |
ranking_data = []
|
@@ -104,9 +180,13 @@ class Semantrix:
|
|
104 |
for item in ranking_data:
|
105 |
file.write("%s\n" % item)
|
106 |
|
|
|
107 |
def play_game(self, word):
|
108 |
|
|
|
109 |
word = word.lower()
|
|
|
|
|
110 |
if word == "give_up":
|
111 |
text = (
|
112 |
"[lose]"
|
@@ -117,14 +197,22 @@ class Semantrix:
|
|
117 |
)
|
118 |
return text
|
119 |
|
|
|
120 |
if word in self.words:
|
121 |
repeated = self.words.index(word)
|
122 |
else:
|
123 |
repeated = -1
|
124 |
self.words.append(word)
|
125 |
|
126 |
-
if word
|
127 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
128 |
self.words.pop(len(self.words) - 1)
|
129 |
feedback = (
|
130 |
"I don't know that word. Try again."
|
@@ -136,18 +224,23 @@ class Semantrix:
|
|
136 |
if len(self.words) > 1
|
137 |
else "\n\n"
|
138 |
)
|
139 |
-
|
140 |
return feedback
|
141 |
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
|
|
|
|
|
|
|
|
|
|
146 |
|
|
|
147 |
if repeated == -1:
|
148 |
-
self.word_vect.append(self.embeddings_dict[word].tolist())
|
149 |
self.scores.append(score)
|
150 |
|
|
|
151 |
if score <= 2.5:
|
152 |
feedback = self.Config.Feedback_0 + str(score)
|
153 |
elif score > 2.5 and score <= 4.0:
|
@@ -160,28 +253,38 @@ class Semantrix:
|
|
160 |
feedback = self.Config.Feedback_4 + str(score)
|
161 |
elif score > 8.0 and score < 10.0:
|
162 |
feedback = self.Config.Feedback_5 + str(score)
|
|
|
163 |
else:
|
164 |
self.win = True
|
165 |
feedback = "[win]" + self.Config.Feedback_8
|
166 |
self.words[0] = self.secret
|
167 |
self.words.pop(len(self.words) - 1)
|
168 |
-
self.word_vect.pop(len(self.word_vect) - 1)
|
169 |
self.scores.pop(len(self.scores) - 1)
|
170 |
|
|
|
171 |
if score > self.scores[len(self.scores) - 2] and self.win == False:
|
172 |
feedback += "\n" + self.Config.Feedback_6
|
173 |
elif score < self.scores[len(self.scores) - 2] and self.win == False:
|
174 |
feedback += "\n" + self.Config.Feedback_7
|
175 |
|
|
|
|
|
176 |
if self.difficulty != 4:
|
177 |
mov_avg = calculate_moving_average(self.scores[1:], 5)
|
178 |
|
|
|
179 |
if len(mov_avg) > 1 and self.win == False:
|
180 |
f_dev = calculate_tendency_slope(mov_avg)
|
181 |
f_dev_avg = calculate_moving_average(f_dev, 3)
|
|
|
|
|
182 |
if f_dev_avg[len(f_dev_avg) - 1] < 0 and self.recent_hint == 0:
|
|
|
|
|
183 |
i = random.randint(0, len(self.Config.hint_intro) - 1)
|
184 |
feedback += "\n\n[hint]" + self.Config.hint_intro[i]
|
|
|
|
|
185 |
hint_text, self.n, self.last_hint = hint(
|
186 |
self.secret,
|
187 |
self.n,
|
@@ -200,26 +303,30 @@ class Semantrix:
|
|
200 |
if self.recent_hint != 0:
|
201 |
self.recent_hint -= 1
|
202 |
|
203 |
-
|
|
|
204 |
|
|
|
205 |
feedback += "[rank]" + open(self.data_path + "ranking.txt", "r").read()
|
206 |
|
207 |
-
if
|
208 |
-
bold_display = 0
|
209 |
-
|
210 |
if self.win:
|
211 |
|
212 |
with open(self.data_path + "ranking.txt", "r") as original_file:
|
213 |
file_content = original_file.readlines()
|
214 |
|
215 |
new_file_name = self.secret + "_" + str(datetime.now()) + ".txt"
|
|
|
216 |
with open(self.data_path + "plays/" + new_file_name, "w+") as new_file:
|
217 |
new_file.writelines(file_content[2:])
|
218 |
|
|
|
219 |
return feedback
|
220 |
|
|
|
221 |
def curiosity(self):
|
222 |
|
|
|
223 |
feedback = curiosity(
|
224 |
self.secret,
|
225 |
(
|
@@ -229,4 +336,5 @@ class Semantrix:
|
|
229 |
),
|
230 |
)
|
231 |
|
|
|
232 |
return feedback
|
|
|
1 |
+
"""
|
2 |
+
Semantrix Game Module
|
3 |
+
|
4 |
+
This module defines the Semantrix class, which implements a word guessing game using word embeddings. The game can be configured to use either a Word2Vec model or a SentenceTransformer model for word embeddings. The game supports multiple languages and difficulty levels.
|
5 |
+
|
6 |
+
Classes:
|
7 |
+
Semantrix: A class that implements the Semantrix word guessing game.
|
8 |
+
Semantrix.DictWrapper: A helper class to wrap configuration dictionaries.
|
9 |
+
|
10 |
+
Functions:
|
11 |
+
__init__(self, lang=0, model_type="SentenceTransformer"): Initializes the Semantrix game with the specified language and model type.
|
12 |
+
prepare_game(self, difficulty): Prepares the game with the selected difficulty level.
|
13 |
+
gen_rank(self, repeated): Generates the ranking file based on the scores.
|
14 |
+
play_game(self, word): Plays the game with the selected word and returns feedback.
|
15 |
+
curiosity(self): Generates a curiosity hint about the secret word once the game is over.
|
16 |
+
|
17 |
+
Attributes:
|
18 |
+
model (KeyedVectors): The word embeddings model.
|
19 |
+
config_file_path (str): Path to the configuration file.
|
20 |
+
secret_file_path (str): Path to the secret words file.
|
21 |
+
data_path (str): Path to the data directory.
|
22 |
+
Config_full (dict): Full configuration data.
|
23 |
+
secret (dict): Secret words data.
|
24 |
+
lang (int): Language of the game (0 for Spanish, 1 for English).
|
25 |
+
model_type (str): Type of the model ("word2vec" or "SentenceTransformer").
|
26 |
+
Config (DictWrapper): Configuration data for the selected language.
|
27 |
+
secret_dict (dict): Secret words for the selected language.
|
28 |
+
secret_list (list): List of secret words for the selected difficulty.
|
29 |
+
words (list): List of words guessed by the player.
|
30 |
+
scores (list): List of scores for the guessed words.
|
31 |
+
win (bool): Indicates if the player has won the game.
|
32 |
+
n (int): Number of hints given.
|
33 |
+
recent_hint (int): Counter for recent hints.
|
34 |
+
f_dev_avg (float): Moving average of the tendency slope.
|
35 |
+
last_hint (int): Index of the last hint given.
|
36 |
+
difficulty (int): Difficulty level of the game.
|
37 |
+
"""
|
38 |
+
|
39 |
import json
|
40 |
import random
|
41 |
from datetime import datetime
|
|
|
52 |
warnings.filterwarnings(action="ignore", category=UserWarning, module="gensim")
|
53 |
|
54 |
|
55 |
+
# Define the class Semantrix
|
56 |
class Semantrix:
|
57 |
|
58 |
+
# Create empty KeyedVectors model with predefined size where the embeddings will be stored
|
59 |
+
model = KeyedVectors(768)
|
|
|
60 |
|
61 |
+
# Define the paths for the configuration files and the data
|
62 |
config_file_path = "config/lang.json"
|
|
|
63 |
secret_file_path = "config/secret.json"
|
|
|
64 |
data_path = "data/"
|
65 |
|
66 |
+
# Define the class DictWrapper to store the configuration data
|
67 |
class DictWrapper:
|
68 |
def __init__(self, data_dict):
|
69 |
self.__dict__.update(data_dict)
|
70 |
|
71 |
+
# Define the constructor of the class which loads the configuration files and initializes the class variables depending on the language parameter and the model type
|
72 |
+
def __init__(self, lang=0, model_type="SentenceTransformer"):
|
|
|
|
|
|
|
73 |
|
74 |
+
# Load the configuration files
|
75 |
with open(self.config_file_path, "r") as file:
|
76 |
self.Config_full = json.load(file)
|
77 |
|
78 |
+
# Load the secret file where the secret words are stored
|
79 |
with open(self.secret_file_path, "r") as file:
|
80 |
self.secret = json.load(file)
|
81 |
|
82 |
+
# Set the language of the game
|
83 |
+
self.lang = lang
|
84 |
+
|
85 |
+
# Set the model type
|
86 |
+
self.model_type = model_type
|
87 |
+
|
88 |
+
# Load word2vec model if needed
|
89 |
+
if self.model_type == "word2vec":
|
90 |
+
if self.lang == 1:
|
91 |
+
self.model = KeyedVectors.load(
|
92 |
+
"config/w2v_models/eng_w2v_model", mmap="r"
|
93 |
+
)
|
94 |
+
self.Config = self.DictWrapper(self.Config_full["ENG"]["Game"])
|
95 |
+
self.secret_dict = self.secret["ENG"]
|
96 |
+
else:
|
97 |
+
self.model = KeyedVectors.load(
|
98 |
+
"config/w2v_models/esp_w2v_model", mmap="r"
|
99 |
+
)
|
100 |
+
self.Config = self.DictWrapper(self.Config_full["SPA"]["Game"])
|
101 |
+
self.secret_dict = self.secret["SPA"]
|
102 |
+
else:
|
103 |
+
self.model_st = SentenceTransformer(
|
104 |
+
"sentence-transformers/paraphrase-multilingual-mpnet-base-v2"
|
105 |
+
)
|
106 |
+
|
107 |
+
# Set the configuration variables depending on the language
|
108 |
if self.lang == 1:
|
|
|
109 |
self.Config = self.DictWrapper(self.Config_full["ENG"]["Game"])
|
110 |
self.secret_dict = self.secret["ENG"]
|
111 |
else:
|
|
|
112 |
self.Config = self.DictWrapper(self.Config_full["SPA"]["Game"])
|
113 |
self.secret_dict = self.secret["SPA"]
|
114 |
|
115 |
+
# Create the ranking file
|
116 |
with open(self.data_path + "ranking.txt", "w+") as file:
|
117 |
file.write("---------------------------")
|
118 |
|
119 |
+
# Define the function to prepare the game with the selected difficulty
|
120 |
def prepare_game(self, difficulty):
|
121 |
|
122 |
+
# Set the secret list depending on the difficulty
|
123 |
self.secret_list = (
|
124 |
self.secret_dict["basic"]
|
125 |
if difficulty <= 2
|
126 |
else self.secret_dict["advanced"]
|
127 |
)
|
128 |
|
129 |
+
# Select a random secret word from the secret list
|
130 |
self.secret = self.secret_list.pop(random.randint(0, len(self.secret_list) - 1))
|
131 |
self.secret = self.secret.lower()
|
132 |
|
133 |
+
# Store the secret word in the words list
|
134 |
self.words = [self.Config.secret_word]
|
135 |
+
|
136 |
+
# Store the score in the scores list
|
137 |
self.scores = [10]
|
138 |
|
139 |
+
# Store the embedding of the secret word in the embeddings dictionary
|
140 |
+
if self.secret not in self.model.key_to_index.keys():
|
141 |
|
142 |
+
# Add the secret word to the KeyedVectors model if the model type is SentenceTransformer
|
143 |
+
# If the model type is word2vec, the secret word is already in the model
|
144 |
+
if self.model_type == "SentenceTransformer":
|
145 |
+
self.model.add_vector(
|
146 |
+
self.secret,
|
147 |
+
self.model_st.encode(self.secret, convert_to_tensor=True).tolist(),
|
148 |
+
)
|
149 |
|
150 |
+
# Initialize the game variables
|
151 |
self.win = False
|
152 |
self.n = 0
|
153 |
self.recent_hint = 0
|
|
|
155 |
self.last_hint = -1
|
156 |
self.difficulty = difficulty
|
157 |
|
158 |
+
# Set the number of hints depending on the difficulty
|
159 |
if self.difficulty == 1:
|
160 |
self.n = 3
|
161 |
|
162 |
+
# Define the function to generate the ranking file
|
163 |
+
def gen_rank(self, repeated):
|
164 |
ascending_indices = np.argsort(self.scores)
|
165 |
descending_indices = list(ascending_indices[::-1])
|
166 |
ranking_data = []
|
|
|
180 |
for item in ranking_data:
|
181 |
file.write("%s\n" % item)
|
182 |
|
183 |
+
# Define the function to play the game with the selected word
|
184 |
def play_game(self, word):
|
185 |
|
186 |
+
# Convert the word to lowercase
|
187 |
word = word.lower()
|
188 |
+
|
189 |
+
# Check if the user wants to give up
|
190 |
if word == "give_up":
|
191 |
text = (
|
192 |
"[lose]"
|
|
|
197 |
)
|
198 |
return text
|
199 |
|
200 |
+
# Check if the word is repeated
|
201 |
if word in self.words:
|
202 |
repeated = self.words.index(word)
|
203 |
else:
|
204 |
repeated = -1
|
205 |
self.words.append(word)
|
206 |
|
207 |
+
# Check if the word is in the model already
|
208 |
+
if word not in self.model.key_to_index.keys():
|
209 |
+
# Add the word to the KeyedVectors model if the model type is SentenceTransformer
|
210 |
+
if self.model_type == "SentenceTransformer":
|
211 |
+
self.model.add_vector(
|
212 |
+
word, self.model_st.encode(word, convert_to_tensor=True).tolist()
|
213 |
+
)
|
214 |
+
else:
|
215 |
+
# If the word is not in the model when using word2vec, remove it from the words list and provide feedback
|
216 |
self.words.pop(len(self.words) - 1)
|
217 |
feedback = (
|
218 |
"I don't know that word. Try again."
|
|
|
224 |
if len(self.words) > 1
|
225 |
else "\n\n"
|
226 |
)
|
|
|
227 |
return feedback
|
228 |
|
229 |
+
# Calculate the score of the word, apply logarithmic scaling, interpolate the score to a range from 0 to 10, and round it to two decimal places
|
230 |
+
score = round(
|
231 |
+
np.interp(
|
232 |
+
np.log(self.model.similarity(self.secret, word) * 10),
|
233 |
+
[0, np.log(10)],
|
234 |
+
[0, 10],
|
235 |
+
),
|
236 |
+
2,
|
237 |
+
)
|
238 |
|
239 |
+
# Remove the word from the score list if it is repeated
|
240 |
if repeated == -1:
|
|
|
241 |
self.scores.append(score)
|
242 |
|
243 |
+
# Generate the feedback message depending on the score
|
244 |
if score <= 2.5:
|
245 |
feedback = self.Config.Feedback_0 + str(score)
|
246 |
elif score > 2.5 and score <= 4.0:
|
|
|
253 |
feedback = self.Config.Feedback_4 + str(score)
|
254 |
elif score > 8.0 and score < 10.0:
|
255 |
feedback = self.Config.Feedback_5 + str(score)
|
256 |
+
# If the score is 10, the user wins the game
|
257 |
else:
|
258 |
self.win = True
|
259 |
feedback = "[win]" + self.Config.Feedback_8
|
260 |
self.words[0] = self.secret
|
261 |
self.words.pop(len(self.words) - 1)
|
|
|
262 |
self.scores.pop(len(self.scores) - 1)
|
263 |
|
264 |
+
# Generate the feedback message depending on the score and the previous score
|
265 |
if score > self.scores[len(self.scores) - 2] and self.win == False:
|
266 |
feedback += "\n" + self.Config.Feedback_6
|
267 |
elif score < self.scores[len(self.scores) - 2] and self.win == False:
|
268 |
feedback += "\n" + self.Config.Feedback_7
|
269 |
|
270 |
+
## Hint generation
|
271 |
+
# If the difficulty is not 4, calculate the moving average of the scores and the tendency slope
|
272 |
if self.difficulty != 4:
|
273 |
mov_avg = calculate_moving_average(self.scores[1:], 5)
|
274 |
|
275 |
+
# If the moving average has more than one element and the user has not won yet, calculate the tendency slope and the moving average of the tendency slope
|
276 |
if len(mov_avg) > 1 and self.win == False:
|
277 |
f_dev = calculate_tendency_slope(mov_avg)
|
278 |
f_dev_avg = calculate_moving_average(f_dev, 3)
|
279 |
+
|
280 |
+
# If the tendency slope is negative and the hint has not been given recently (at least three rounds earlier), generate a hint
|
281 |
if f_dev_avg[len(f_dev_avg) - 1] < 0 and self.recent_hint == 0:
|
282 |
+
|
283 |
+
# Generate a random hint intro from the hint list
|
284 |
i = random.randint(0, len(self.Config.hint_intro) - 1)
|
285 |
feedback += "\n\n[hint]" + self.Config.hint_intro[i]
|
286 |
+
|
287 |
+
# Generate a dynamic hint
|
288 |
hint_text, self.n, self.last_hint = hint(
|
289 |
self.secret,
|
290 |
self.n,
|
|
|
303 |
if self.recent_hint != 0:
|
304 |
self.recent_hint -= 1
|
305 |
|
306 |
+
# Generate the ranking file
|
307 |
+
self.gen_rank(repeated)
|
308 |
|
309 |
+
# Add the ranking file to the feedback message
|
310 |
feedback += "[rank]" + open(self.data_path + "ranking.txt", "r").read()
|
311 |
|
312 |
+
# Save the ranking file with the plays of the user if the user wins
|
|
|
|
|
313 |
if self.win:
|
314 |
|
315 |
with open(self.data_path + "ranking.txt", "r") as original_file:
|
316 |
file_content = original_file.readlines()
|
317 |
|
318 |
new_file_name = self.secret + "_" + str(datetime.now()) + ".txt"
|
319 |
+
|
320 |
with open(self.data_path + "plays/" + new_file_name, "w+") as new_file:
|
321 |
new_file.writelines(file_content[2:])
|
322 |
|
323 |
+
# Return the feedback message
|
324 |
return feedback
|
325 |
|
326 |
+
# Define the function to generate a curiosity hint once the game is over
|
327 |
def curiosity(self):
|
328 |
|
329 |
+
# Generate a curiosity aboyt the secret word
|
330 |
feedback = curiosity(
|
331 |
self.secret,
|
332 |
(
|
|
|
336 |
),
|
337 |
)
|
338 |
|
339 |
+
# Return the feedback message
|
340 |
return feedback
|
game_transformer.py
DELETED
@@ -1,228 +0,0 @@
|
|
1 |
-
# %%
|
2 |
-
import json
|
3 |
-
import re
|
4 |
-
import random
|
5 |
-
from datetime import datetime
|
6 |
-
import numpy as np
|
7 |
-
from gensim.models import KeyedVectors
|
8 |
-
from hints import curiosity, hint
|
9 |
-
from tracking import (
|
10 |
-
calculate_moving_average,
|
11 |
-
calculate_tendency_slope,
|
12 |
-
)
|
13 |
-
from sentence_transformers import SentenceTransformer
|
14 |
-
import warnings
|
15 |
-
|
16 |
-
warnings.filterwarnings(action="ignore", category=UserWarning, module="gensim")
|
17 |
-
|
18 |
-
|
19 |
-
class Semantrix:
|
20 |
-
model = KeyedVectors(768)
|
21 |
-
model_st = SentenceTransformer(
|
22 |
-
"sentence-transformers/paraphrase-multilingual-mpnet-base-v2"
|
23 |
-
)
|
24 |
-
|
25 |
-
config_file_path = "config/lang.json"
|
26 |
-
secret_file_path = "config/secret.json"
|
27 |
-
data_path = "data/"
|
28 |
-
|
29 |
-
class DictWrapper:
|
30 |
-
def __init__(self, data_dict):
|
31 |
-
self.__dict__.update(data_dict)
|
32 |
-
|
33 |
-
def __init__(self, lang=0):
|
34 |
-
|
35 |
-
self.embeddings_dict = {}
|
36 |
-
|
37 |
-
with open(self.config_file_path, "r") as file:
|
38 |
-
self.Config_full = json.load(file)
|
39 |
-
|
40 |
-
with open(self.secret_file_path, "r") as file:
|
41 |
-
self.secret = json.load(file)
|
42 |
-
|
43 |
-
self.lang = lang
|
44 |
-
|
45 |
-
if self.lang == 1:
|
46 |
-
self.Config = self.DictWrapper(self.Config_full["ENG"]["Game"])
|
47 |
-
self.secret_dict = self.secret["ENG"]
|
48 |
-
else:
|
49 |
-
self.Config = self.DictWrapper(self.Config_full["SPA"]["Game"])
|
50 |
-
self.secret_dict = self.secret["SPA"]
|
51 |
-
|
52 |
-
with open(self.data_path + "ranking.txt", "w+") as file:
|
53 |
-
file.write("---------------------------")
|
54 |
-
|
55 |
-
def prepare_game(self, difficulty):
|
56 |
-
|
57 |
-
self.secret_list = (
|
58 |
-
self.secret_dict["basic"]
|
59 |
-
if difficulty <= 2
|
60 |
-
else self.secret_dict["advanced"]
|
61 |
-
)
|
62 |
-
|
63 |
-
self.secret = self.secret_list.pop(random.randint(0, len(self.secret_list) - 1))
|
64 |
-
self.secret = self.secret.lower()
|
65 |
-
|
66 |
-
self.words = [self.Config.secret_word]
|
67 |
-
self.scores = [10]
|
68 |
-
|
69 |
-
if self.secret not in self.embeddings_dict.keys():
|
70 |
-
self.embeddings_dict[self.secret] = self.model_st.encode(
|
71 |
-
self.secret, convert_to_tensor=True
|
72 |
-
)
|
73 |
-
self.model.add_vector(
|
74 |
-
self.secret, self.embeddings_dict[self.secret].tolist()
|
75 |
-
)
|
76 |
-
|
77 |
-
self.word_vect = [self.embeddings_dict[self.secret].tolist()]
|
78 |
-
|
79 |
-
self.win = False
|
80 |
-
self.n = 0
|
81 |
-
self.recent_hint = 0
|
82 |
-
self.f_dev_avg = 0
|
83 |
-
self.last_hint = -1
|
84 |
-
self.difficulty = difficulty
|
85 |
-
|
86 |
-
if self.difficulty == 1:
|
87 |
-
self.n = 3
|
88 |
-
|
89 |
-
def preproc_vectors(self, repeated):
|
90 |
-
ascending_indices = np.argsort(self.scores)
|
91 |
-
descending_indices = list(ascending_indices[::-1])
|
92 |
-
ranking_data = []
|
93 |
-
k = len(self.words) - 1
|
94 |
-
if repeated != -1:
|
95 |
-
k = repeated
|
96 |
-
|
97 |
-
ranking_data.append(["#" + str(k), self.words[k], self.scores[k]])
|
98 |
-
|
99 |
-
ranking_data.append("---------------------------")
|
100 |
-
for i in descending_indices:
|
101 |
-
if i == 0:
|
102 |
-
continue
|
103 |
-
ranking_data.append(["#" + str(i), self.words[i], self.scores[i]])
|
104 |
-
|
105 |
-
with open(self.data_path + "ranking.txt", "w+") as file:
|
106 |
-
for item in ranking_data:
|
107 |
-
file.write("%s\n" % item)
|
108 |
-
|
109 |
-
def play_game(self, word):
|
110 |
-
|
111 |
-
word = word.lower()
|
112 |
-
if word == "give_up":
|
113 |
-
text = (
|
114 |
-
"[lose]"
|
115 |
-
+ self.Config.Feedback_9
|
116 |
-
+ self.secret
|
117 |
-
+ "\n\n"
|
118 |
-
+ self.Config.Feedback_10
|
119 |
-
)
|
120 |
-
return text
|
121 |
-
|
122 |
-
if word in self.words:
|
123 |
-
repeated = self.words.index(word)
|
124 |
-
else:
|
125 |
-
repeated = -1
|
126 |
-
self.words.append(word)
|
127 |
-
|
128 |
-
if word not in self.embeddings_dict.keys():
|
129 |
-
embedding = self.model_st.encode(word, convert_to_tensor=True)
|
130 |
-
self.embeddings_dict[word] = embedding
|
131 |
-
self.model.add_vector(word, embedding.tolist())
|
132 |
-
|
133 |
-
score = round(
|
134 |
-
np.interp(
|
135 |
-
np.log(self.model.similarity(self.secret, word) * 10),
|
136 |
-
[0, np.log(10)],
|
137 |
-
[0, 10],
|
138 |
-
),
|
139 |
-
2,
|
140 |
-
)
|
141 |
-
|
142 |
-
if repeated == -1:
|
143 |
-
self.word_vect.append(self.embeddings_dict[word].tolist())
|
144 |
-
self.scores.append(score)
|
145 |
-
|
146 |
-
if score <= 2.5:
|
147 |
-
feedback = self.Config.Feedback_0 + str(score)
|
148 |
-
elif score > 2.5 and score <= 4.0:
|
149 |
-
feedback = self.Config.Feedback_1 + str(score)
|
150 |
-
elif score > 4.0 and score <= 6.0:
|
151 |
-
feedback = self.Config.Feedback_2 + str(score)
|
152 |
-
elif score > 6.0 and score <= 7.5:
|
153 |
-
feedback = self.Config.Feedback_3 + str(score)
|
154 |
-
elif score > 7.5 and score <= 8.0:
|
155 |
-
feedback = self.Config.Feedback_4 + str(score)
|
156 |
-
elif score > 8.0 and score < 10.0:
|
157 |
-
feedback = self.Config.Feedback_5 + str(score)
|
158 |
-
else:
|
159 |
-
self.win = True
|
160 |
-
feedback = "[win]" + self.Config.Feedback_8
|
161 |
-
self.words[0] = self.secret
|
162 |
-
self.words.pop(len(self.words) - 1)
|
163 |
-
self.word_vect.pop(len(self.word_vect) - 1)
|
164 |
-
self.scores.pop(len(self.scores) - 1)
|
165 |
-
|
166 |
-
if score > self.scores[len(self.scores) - 2] and self.win == False:
|
167 |
-
feedback += "\n" + self.Config.Feedback_6
|
168 |
-
elif score < self.scores[len(self.scores) - 2] and self.win == False:
|
169 |
-
feedback += "\n" + self.Config.Feedback_7
|
170 |
-
|
171 |
-
if self.difficulty != 4:
|
172 |
-
mov_avg = calculate_moving_average(self.scores[1:], 5)
|
173 |
-
|
174 |
-
if len(mov_avg) > 1 and self.win == False:
|
175 |
-
f_dev = calculate_tendency_slope(mov_avg)
|
176 |
-
f_dev_avg = calculate_moving_average(f_dev, 3)
|
177 |
-
if f_dev_avg[len(f_dev_avg) - 1] < 0 and self.recent_hint == 0:
|
178 |
-
i = random.randint(0, len(self.Config.hint_intro) - 1)
|
179 |
-
feedback += "\n\n[hint]" + self.Config.hint_intro[i]
|
180 |
-
hint_text, self.n, self.last_hint = hint(
|
181 |
-
self.secret,
|
182 |
-
self.n,
|
183 |
-
self.model_st,
|
184 |
-
self.last_hint,
|
185 |
-
self.lang,
|
186 |
-
(
|
187 |
-
self.DictWrapper(self.Config_full["ENG"]["Hint"])
|
188 |
-
if self.lang == 1
|
189 |
-
else self.DictWrapper(self.Config_full["SPA"]["Hint"])
|
190 |
-
),
|
191 |
-
)
|
192 |
-
feedback += "\n" + hint_text
|
193 |
-
self.recent_hint = 3
|
194 |
-
|
195 |
-
if self.recent_hint != 0:
|
196 |
-
self.recent_hint -= 1
|
197 |
-
|
198 |
-
self.preproc_vectors(repeated)
|
199 |
-
|
200 |
-
feedback += "[rank]" + open(self.data_path + "ranking.txt", "r").read()
|
201 |
-
|
202 |
-
if self.win:
|
203 |
-
bold_display = 0
|
204 |
-
|
205 |
-
if self.win:
|
206 |
-
|
207 |
-
with open(self.data_path + "ranking.txt", "r") as original_file:
|
208 |
-
file_content = original_file.readlines()
|
209 |
-
|
210 |
-
new_file_name = self.secret + "_" + str(datetime.now()) + ".txt"
|
211 |
-
|
212 |
-
with open(self.data_path + "plays/" + new_file_name, "w+") as new_file:
|
213 |
-
new_file.writelines(file_content[2:])
|
214 |
-
|
215 |
-
return feedback
|
216 |
-
|
217 |
-
def curiosity(self):
|
218 |
-
|
219 |
-
feedback = curiosity(
|
220 |
-
self.secret,
|
221 |
-
(
|
222 |
-
self.DictWrapper(self.Config_full["ENG"]["Hint"])
|
223 |
-
if self.lang == 1
|
224 |
-
else self.DictWrapper(self.Config_full["SPA"]["Hint"])
|
225 |
-
),
|
226 |
-
)
|
227 |
-
|
228 |
-
return feedback
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
hints.py
CHANGED
@@ -1,24 +1,60 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
import openai
|
6 |
from sentence_transformers import util
|
7 |
|
8 |
-
|
|
|
9 |
|
|
|
|
|
10 |
|
11 |
-
|
12 |
-
|
13 |
|
14 |
-
#
|
15 |
if n >= 3:
|
16 |
j = random.randint(0, 2)
|
17 |
-
while j ==
|
18 |
j = random.randint(0, 2)
|
|
|
|
|
19 |
if j == 0:
|
20 |
response = openai.chat.completions.create(
|
21 |
-
model=
|
22 |
messages=[
|
23 |
{
|
24 |
"role": "user",
|
@@ -38,6 +74,7 @@ def hint(secret, n, model, last_pista, lang, Config):
|
|
38 |
output = str(response.choices[0].message.content)
|
39 |
output = output.replace('"', "").replace("'", "")
|
40 |
|
|
|
41 |
if lang == 0:
|
42 |
output = ireplace("la " + secret, "La palabra secreta", output)
|
43 |
output = ireplace("las " + secret, "La palabra secreta", output)
|
@@ -51,11 +88,13 @@ def hint(secret, n, model, last_pista, lang, Config):
|
|
51 |
output = ireplace("the " + secret, "The secret word", output)
|
52 |
output = ireplace("a " + secret, "The secret word", output)
|
53 |
|
54 |
-
|
55 |
-
|
|
|
|
|
56 |
elif j == 1:
|
57 |
response = openai.chat.completions.create(
|
58 |
-
model=
|
59 |
messages=[
|
60 |
{
|
61 |
"role": "user",
|
@@ -69,11 +108,13 @@ def hint(secret, n, model, last_pista, lang, Config):
|
|
69 |
presence_penalty=0,
|
70 |
)
|
71 |
output = str(response.choices[0].message.content)
|
72 |
-
|
73 |
-
|
|
|
|
|
74 |
elif j == 2:
|
75 |
response = openai.chat.completions.create(
|
76 |
-
model=
|
77 |
messages=[
|
78 |
{
|
79 |
"role": "user",
|
@@ -88,18 +129,20 @@ def hint(secret, n, model, last_pista, lang, Config):
|
|
88 |
)
|
89 |
output = str(response.choices[0].message.content)
|
90 |
|
91 |
-
|
92 |
|
93 |
-
|
94 |
-
#
|
95 |
else:
|
96 |
j = random.randint(3, 4)
|
97 |
-
while j ==
|
98 |
j = random.randint(3, 4)
|
|
|
|
|
99 |
if j == 3:
|
100 |
words = []
|
101 |
response = openai.chat.completions.create(
|
102 |
-
model=
|
103 |
messages=[
|
104 |
{
|
105 |
"role": "user",
|
@@ -116,7 +159,7 @@ def hint(secret, n, model, last_pista, lang, Config):
|
|
116 |
output = (output.replace(" ", "").replace(".", "")).lower()
|
117 |
words.extend(output.strip().split(","))
|
118 |
response = openai.chat.completions.create(
|
119 |
-
model=
|
120 |
messages=[
|
121 |
{
|
122 |
"role": "user",
|
@@ -145,7 +188,7 @@ def hint(secret, n, model, last_pista, lang, Config):
|
|
145 |
sum_scores = sum(scores)
|
146 |
normalized_scores = [round(score * 100 / sum_scores, 1) for score in scores]
|
147 |
|
148 |
-
|
149 |
|
150 |
max_len = -1
|
151 |
for ele in words:
|
@@ -156,19 +199,21 @@ def hint(secret, n, model, last_pista, lang, Config):
|
|
156 |
for i in range(len(words)):
|
157 |
|
158 |
word_hint = words[i].ljust(len(longest_word) + 1)
|
159 |
-
|
160 |
# word_hint[: len(longest_word)]
|
161 |
word_hint
|
162 |
+ "|"
|
163 |
-
+ ("🟩") * round(normalized_scores[i] * 0.
|
164 |
+ " "
|
165 |
+ str(normalized_scores[i])
|
166 |
+ "%\n"
|
167 |
)
|
168 |
-
|
|
|
|
|
169 |
elif j == 4:
|
170 |
response = openai.chat.completions.create(
|
171 |
-
model=
|
172 |
messages=[
|
173 |
{
|
174 |
"role": "user",
|
@@ -185,7 +230,7 @@ def hint(secret, n, model, last_pista, lang, Config):
|
|
185 |
)
|
186 |
film_title = str(response.choices[0].message.content).replace('"', "")
|
187 |
response = openai.chat.completions.create(
|
188 |
-
model=
|
189 |
messages=[
|
190 |
{
|
191 |
"role": "user",
|
@@ -201,16 +246,17 @@ def hint(secret, n, model, last_pista, lang, Config):
|
|
201 |
presence_penalty=0,
|
202 |
)
|
203 |
output = str(response.choices[0].message.content)
|
204 |
-
|
205 |
-
|
206 |
|
207 |
-
return
|
208 |
|
209 |
|
|
|
210 |
def curiosity(secret, Config):
|
211 |
|
212 |
response = openai.chat.completions.create(
|
213 |
-
model=
|
214 |
messages=[
|
215 |
{
|
216 |
"role": "user",
|
@@ -228,6 +274,7 @@ def curiosity(secret, Config):
|
|
228 |
return output
|
229 |
|
230 |
|
|
|
231 |
def ireplace(old, new, text):
|
232 |
idx = 0
|
233 |
while idx < len(text):
|
|
|
1 |
+
"""
|
2 |
+
This module provides functions to generate dynamic hints and curiosities about a secret word using llms.
|
3 |
+
|
4 |
+
Functions:
|
5 |
+
hint(secret, n, model, last_hint, lang, Config):
|
6 |
+
Generates a dynamic hint based on the secret word and the number of hints given.
|
7 |
+
Parameters:
|
8 |
+
secret (str): The secret word.
|
9 |
+
n (int): The number of hints already given.
|
10 |
+
model: The sentence transformer model used for encoding.
|
11 |
+
last_hint (int): The index of the last hint given.
|
12 |
+
lang (int): The language code (0 for Spanish, 1 for English).
|
13 |
+
Config: Configuration object containing hint templates.
|
14 |
+
Returns:
|
15 |
+
tuple: A tuple containing the generated hint (str), the updated number of hints (int), and the index of the last hint given (int).
|
16 |
+
|
17 |
+
curiosity(secret, Config):
|
18 |
+
Generates a curiosity about the secret word.
|
19 |
+
Parameters:
|
20 |
+
secret (str): The secret word.
|
21 |
+
Config: Configuration object containing the curiosity template.
|
22 |
+
Returns:
|
23 |
+
str: The generated curiosity.
|
24 |
|
25 |
+
ireplace(old, new, text):
|
26 |
+
Replaces all occurrences of a substring in a string, case-insensitively.
|
27 |
+
Parameters:
|
28 |
+
old (str): The substring to be replaced.
|
29 |
+
new (str): The substring to replace with.
|
30 |
+
text (str): The original string.
|
31 |
+
Returns:
|
32 |
+
str: The modified string with all occurrences of the old substring replaced by the new substring.
|
33 |
+
"""
|
34 |
+
|
35 |
+
import random
|
36 |
import openai
|
37 |
from sentence_transformers import util
|
38 |
|
39 |
+
gpt_model = "gpt-3.5-turbo"
|
40 |
+
|
41 |
|
42 |
+
# Dynamic hint function that returns a hint based on the secret word and the number of hints given
|
43 |
+
def hint(secret, n, model, last_hint, lang, Config):
|
44 |
|
45 |
+
# Initialize hint variable
|
46 |
+
hint = ""
|
47 |
|
48 |
+
# Advanced hints
|
49 |
if n >= 3:
|
50 |
j = random.randint(0, 2)
|
51 |
+
while j == last_hint:
|
52 |
j = random.randint(0, 2)
|
53 |
+
|
54 |
+
# Advanced hint 1: Definition of the secret word
|
55 |
if j == 0:
|
56 |
response = openai.chat.completions.create(
|
57 |
+
model=gpt_model,
|
58 |
messages=[
|
59 |
{
|
60 |
"role": "user",
|
|
|
74 |
output = str(response.choices[0].message.content)
|
75 |
output = output.replace('"', "").replace("'", "")
|
76 |
|
77 |
+
# Replace the secret word with "La palabra secreta" or "The secret word" just in case the model uses the secret word in the definition
|
78 |
if lang == 0:
|
79 |
output = ireplace("la " + secret, "La palabra secreta", output)
|
80 |
output = ireplace("las " + secret, "La palabra secreta", output)
|
|
|
88 |
output = ireplace("the " + secret, "The secret word", output)
|
89 |
output = ireplace("a " + secret, "The secret word", output)
|
90 |
|
91 |
+
hint += Config.hint_0_3 + output # type: ignore
|
92 |
+
last_hint = 0
|
93 |
+
|
94 |
+
# Advanced hint 2: Representation of the secret word with emojis
|
95 |
elif j == 1:
|
96 |
response = openai.chat.completions.create(
|
97 |
+
model=gpt_model,
|
98 |
messages=[
|
99 |
{
|
100 |
"role": "user",
|
|
|
108 |
presence_penalty=0,
|
109 |
)
|
110 |
output = str(response.choices[0].message.content)
|
111 |
+
hint += Config.hint_1_2 + output # type: ignore
|
112 |
+
last_hint = 1
|
113 |
+
|
114 |
+
# Advanced hint 3: Poem about the secret word
|
115 |
elif j == 2:
|
116 |
response = openai.chat.completions.create(
|
117 |
+
model=gpt_model,
|
118 |
messages=[
|
119 |
{
|
120 |
"role": "user",
|
|
|
129 |
)
|
130 |
output = str(response.choices[0].message.content)
|
131 |
|
132 |
+
hint += Config.hint_2_2 + output # type: ignore
|
133 |
|
134 |
+
last_hint = 2
|
135 |
+
# Initial hints
|
136 |
else:
|
137 |
j = random.randint(3, 4)
|
138 |
+
while j == last_hint:
|
139 |
j = random.randint(3, 4)
|
140 |
+
|
141 |
+
# Initial hint 1: Rank of four words related to the secret word
|
142 |
if j == 3:
|
143 |
words = []
|
144 |
response = openai.chat.completions.create(
|
145 |
+
model=gpt_model,
|
146 |
messages=[
|
147 |
{
|
148 |
"role": "user",
|
|
|
159 |
output = (output.replace(" ", "").replace(".", "")).lower()
|
160 |
words.extend(output.strip().split(","))
|
161 |
response = openai.chat.completions.create(
|
162 |
+
model=gpt_model,
|
163 |
messages=[
|
164 |
{
|
165 |
"role": "user",
|
|
|
188 |
sum_scores = sum(scores)
|
189 |
normalized_scores = [round(score * 100 / sum_scores, 1) for score in scores]
|
190 |
|
191 |
+
hint += Config.hint_3_3 # type: ignore
|
192 |
|
193 |
max_len = -1
|
194 |
for ele in words:
|
|
|
199 |
for i in range(len(words)):
|
200 |
|
201 |
word_hint = words[i].ljust(len(longest_word) + 1)
|
202 |
+
hint += (
|
203 |
# word_hint[: len(longest_word)]
|
204 |
word_hint
|
205 |
+ "|"
|
206 |
+
+ ("🟩") * round(normalized_scores[i] * 0.2)
|
207 |
+ " "
|
208 |
+ str(normalized_scores[i])
|
209 |
+ "%\n"
|
210 |
)
|
211 |
+
last_hint = 3
|
212 |
+
|
213 |
+
# Initial hint 2: Film representation with emojis with the secret word
|
214 |
elif j == 4:
|
215 |
response = openai.chat.completions.create(
|
216 |
+
model=gpt_model,
|
217 |
messages=[
|
218 |
{
|
219 |
"role": "user",
|
|
|
230 |
)
|
231 |
film_title = str(response.choices[0].message.content).replace('"', "")
|
232 |
response = openai.chat.completions.create(
|
233 |
+
model=gpt_model,
|
234 |
messages=[
|
235 |
{
|
236 |
"role": "user",
|
|
|
246 |
presence_penalty=0,
|
247 |
)
|
248 |
output = str(response.choices[0].message.content)
|
249 |
+
hint += Config.hint_4_4 + "\n" + output # type: ignore
|
250 |
+
last_hint = 4
|
251 |
|
252 |
+
return hint, n + 1, last_hint
|
253 |
|
254 |
|
255 |
+
# Tell a curiosity about the secret word
|
256 |
def curiosity(secret, Config):
|
257 |
|
258 |
response = openai.chat.completions.create(
|
259 |
+
model=gpt_model,
|
260 |
messages=[
|
261 |
{
|
262 |
"role": "user",
|
|
|
274 |
return output
|
275 |
|
276 |
|
277 |
+
# Replace all occurrences of a substring in a string
|
278 |
def ireplace(old, new, text):
|
279 |
idx = 0
|
280 |
while idx < len(text):
|
ranking.txt
DELETED
@@ -1 +0,0 @@
|
|
1 |
-
---------------------------
|
|
|
|
requirements.txt
CHANGED
@@ -3,5 +3,5 @@ sentence_transformers==2.2.2
|
|
3 |
openai==1.2.3
|
4 |
gradio==5.1.0
|
5 |
transformers==4.33.2
|
6 |
-
huggingface-hub==0.25.2
|
7 |
-
python-multipart==0.0.12
|
|
|
3 |
openai==1.2.3
|
4 |
gradio==5.1.0
|
5 |
transformers==4.33.2
|
6 |
+
# huggingface-hub==0.25.2
|
7 |
+
# python-multipart==0.0.12
|