Javierss commited on
Commit
0659ca5
·
1 Parent(s): 1fd4e85

Clone old repo

Browse files
.gitattributes CHANGED
@@ -33,3 +33,14 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ # *.gif filter=lfs diff=lfs merge=lfs -text
37
+ config/w2v_models/esp_w2v_model filter=lfs diff=lfs merge=lfs -text
38
+ config/w2v_models/eng_w2v_model filter=lfs diff=lfs merge=lfs -text
39
+ config/words.txt filter=lfs diff=lfs merge=lfs -text
40
+ config/words.gz filter=lfs diff=lfs merge=lfs -text
41
+ config/w2v_models/words.gz filter=lfs diff=lfs merge=lfs -text
42
+ config/possible_words.json filter=lfs diff=lfs merge=lfs -text
43
+ config/strans_models/. filter=lfs diff=lfs merge=lfs -text
44
+ config/strans_models/esp_strans_model filter=lfs diff=lfs merge=lfs -text
45
+ config/strans_models/esp_strans_model.vectors.npy filter=lfs diff=lfs merge=lfs -text
46
+ config/images/logo_win.gif filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ data/plays/*.txt
2
+ data/plays/*.json
3
+ data/plays/data/*.json
4
+ __pycache__/*
5
+ data/rankings/*.txt
6
+ config/*_models
README.md CHANGED
@@ -1,12 +1,114 @@
1
  ---
2
- title: Semantrix Cond3 Temp
3
- emoji: 📊
4
- colorFrom: red
5
- colorTo: green
6
  sdk: gradio
7
  sdk_version: 5.22.0
 
8
  app_file: app.py
9
  pinned: false
 
10
  ---
11
 
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Semantrix
3
+ emoji: 🔠
4
+ colorFrom: indigo
5
+ colorTo: pink
6
  sdk: gradio
7
  sdk_version: 5.22.0
8
+ python_version: 3.11.5
9
  app_file: app.py
10
  pinned: false
11
+ license: other
12
  ---
13
 
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.
app.py ADDED
@@ -0,0 +1,641 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 datetime import datetime, date
63
+ from game import Semantrix, Model_class
64
+ from huggingface_hub import CommitScheduler
65
+ import os
66
+ import logging
67
+
68
+ # Configure logging
69
+ logging.basicConfig(
70
+ level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
71
+ )
72
+ logger = logging.getLogger(__name__)
73
+
74
+
75
+ # File paths for configuration and images
76
+ base_path = os.path.dirname(os.path.abspath(__file__))
77
+ config_file_path = os.path.join(base_path, "config/lang.json")
78
+ logo_path = os.path.join(base_path, "config/images/logo.png")
79
+ logo_win_path = os.path.join(base_path, "config/images/logo_win.gif")
80
+ condition_config_path = os.path.join(base_path, "config/condition.json")
81
+ data_path = os.path.join(base_path, "data")
82
+ plays_path = os.path.join(data_path, "plays")
83
+
84
+ condition_name = "condition_3"
85
+ # Dynamically determine the condition name based on the folder name
86
+ # folder_name = os.path.basename(os.path.dirname(os.path.abspath(__file__)))
87
+ # condition = folder_name.split("_")[-1][-1]
88
+ # condition_name = "condition_" + condition
89
+
90
+
91
+ with open(condition_config_path, "r") as file:
92
+ condition_config = json.load(file)
93
+
94
+ model = condition_config[condition_name]["model"]
95
+ hints_enabled = condition_config[condition_name]["hints"]
96
+
97
+ # Loading the configuration file
98
+ with open(config_file_path, "r") as file:
99
+ Config_full = json.load(file)
100
+
101
+ scheduler = CommitScheduler(
102
+ repo_id="Jsevisal/semantrix_data_" + condition_name[-1],
103
+ repo_type="dataset",
104
+ folder_path=plays_path,
105
+ path_in_repo="data",
106
+ every=10,
107
+ )
108
+
109
+ lang = 0 # Language configuration flag (0 for Spanish, 1 for English)
110
+
111
+ # Setting the configuration based on the language flag
112
+ if lang == 1:
113
+ Config = Config_full["ENG"]["Game"]
114
+ Menu = Config_full["ENG"]["Menu"]
115
+ else:
116
+ Config = Config_full["SPA"]["Game"]
117
+ Menu = Config_full["SPA"]["Menu"]
118
+
119
+
120
+ # Function to convert text to centered markdown format
121
+ def convert_to_markdown_centered(text):
122
+ lines = text.strip().split("\n")
123
+
124
+ if not lines:
125
+ return ""
126
+
127
+ last_attempt = lines[0]
128
+ history_attempts = lines[2:12]
129
+ markdown = '<div align="center">\n\n'
130
+
131
+ markdown += "## " + Menu["Best_tries"] + "\n"
132
+ markdown += "<table>\n"
133
+ markdown += " <tr>\n"
134
+ markdown += " <th>" + Menu["N_try"] + "</th>\n"
135
+ markdown += " <th>" + Menu["Word"] + "</th>\n"
136
+ markdown += " <th>" + Menu["Score"] + "</th>\n"
137
+ markdown += " </tr>\n"
138
+
139
+ for line in history_attempts:
140
+ items = eval(line.strip())
141
+ markdown += " <tr>\n"
142
+ markdown += f" <td><strong>{items[0]}</strong></td>\n"
143
+ markdown += f" <td>{items[1]}</td>\n"
144
+ markdown += f" <td>{items[2]}</td>\n"
145
+ markdown += " </tr>\n"
146
+
147
+ markdown += "</table>\n\n"
148
+
149
+ last_items = eval(last_attempt)
150
+ markdown += f"## " + Menu["Last_try"] + "\n"
151
+ markdown += (
152
+ f"**{last_items[0]}:** {last_items[1]} - "
153
+ + Menu["Score"]
154
+ + f": {last_items[2]}\n\n"
155
+ )
156
+ markdown += "---\n\n"
157
+
158
+ markdown += "</div>"
159
+
160
+ return markdown
161
+
162
+
163
+ #
164
+ with gr.Blocks(
165
+ theme="ocean",
166
+ ) as demo:
167
+ # Initializing state variables to manage the internal state of the application
168
+ state = gr.State(-1) # State variable to track the current game state
169
+ difficulty = gr.State(-1) # State variable to track the difficulty level
170
+ hint = gr.State(False) # State variable to track if the hint is provided
171
+
172
+ secret_word_used = gr.BrowserState(
173
+ 0
174
+ ) # State variable to track the number of secret words used
175
+
176
+ # Initializing the game using the Semantrix class with default parameters
177
+ game_instances = {}
178
+ sessions_to_remove = {}
179
+ cooldown_time = 120 # Time in seconds to remove the session from the game_instances
180
+ model_class = Model_class(lang=0, model_type=model)
181
+
182
+ # Creating a Markdown component to display the header
183
+ header = gr.Markdown(
184
+ """
185
+ <p style="text-align:center"> """
186
+ + Menu["Header"]
187
+ + """ </p>
188
+ """
189
+ )
190
+
191
+ # Function to reset the game
192
+ def reset(reload, request: gr.Request):
193
+ global Config, game, Menu, model, lang # Declare global variables to modify them within the function
194
+
195
+ if reload:
196
+ game_instances[request.session_hash] = Semantrix(
197
+ lang=0, model_type=model, session_hash=request.session_hash
198
+ )
199
+ game_instances[request.session_hash].reset_game() # Reset the game state
200
+
201
+ logger.info("New session detected: %s", request.session_hash)
202
+ logger.info("Game instances: %s", game_instances)
203
+
204
+ # Define the initial output components for the UI
205
+ output = [
206
+ -1,
207
+ gr.Textbox(visible=False),
208
+ gr.Textbox(visible=False),
209
+ gr.Image(logo_path, visible=True, interactive=False),
210
+ gr.Button(Menu["Start"], visible=True, variant="secondary"),
211
+ gr.Radio(visible=False),
212
+ gr.Textbox(visible=False),
213
+ gr.Button(visible=False),
214
+ gr.Markdown(
215
+ """
216
+ <p style="text-align:center"> """
217
+ + Menu["Header"]
218
+ + """ </p>
219
+ """
220
+ ),
221
+ gr.Button(visible=False),
222
+ ]
223
+
224
+ # Return the initial output components
225
+ return output
226
+
227
+ def remove_game_instance(timer_tick=False, request: gr.Request | None = None):
228
+ request = None if timer_tick else request
229
+
230
+ if request is not None:
231
+ logger.info("Session on inactivity timer: %s", request.session_hash)
232
+ sessions_to_remove[request.session_hash] = datetime.now()
233
+ if len(sessions_to_remove.items()) > 0:
234
+ for session_hash, timestamp in list(sessions_to_remove.items()):
235
+ if (datetime.now() - timestamp).seconds > cooldown_time:
236
+ del sessions_to_remove[session_hash]
237
+
238
+ session_id = game_instances[session_hash].get_session_id()
239
+ del game_instances[session_hash]
240
+
241
+ # Delete ranking file if it exists
242
+ ranking_file = os.path.join(
243
+ data_path, f"rankings/ranking_{session_hash}.txt"
244
+ )
245
+ if os.path.exists(ranking_file):
246
+ os.remove(ranking_file)
247
+
248
+ # Delete plays files if it exists
249
+ session_files = [
250
+ f for f in os.listdir(plays_path) if f.startswith(session_id)
251
+ ]
252
+ for file_name in session_files:
253
+ with open(os.path.join(plays_path, file_name), "r") as file:
254
+ os.remove(os.path.join(plays_path, file_name))
255
+
256
+ logger.info("Deleted session: %s", session_hash)
257
+
258
+ # Function to change the state of the game
259
+ def change(state, inp):
260
+ # Increment the state by 1
261
+ state = state + 1
262
+
263
+ # Return the updated state and input component
264
+ return [state, inp]
265
+
266
+ # Function to update the game state based on the current state of the game
267
+ def update(state, radio, inp, hint, secret_word_used, request: gr.Request):
268
+ global difficulty, hints_enabled
269
+
270
+ # Define the difficulty state
271
+ dif_state = 3
272
+
273
+ # Initialize the output component list with the current state
274
+
275
+ state_int = state
276
+
277
+ output = [state]
278
+
279
+ if request.session_hash in sessions_to_remove:
280
+ sessions_to_remove.pop(request.session_hash)
281
+ logger.info("Session saved: %s", request.session_hash)
282
+
283
+ # Define UI components for the initial state
284
+ if state_int == -1:
285
+ output.extend(
286
+ [
287
+ gr.Button(Menu["Start"], visible=True),
288
+ gr.Radio(label="", visible=False),
289
+ gr.Textbox(
290
+ Config[list(Config.keys())[state_int]], visible=False, label=""
291
+ ),
292
+ gr.Button(Menu["Give_up"], visible=False),
293
+ gr.Textbox(visible=False),
294
+ gr.Image(interactive=False, visible=True),
295
+ gr.Textbox(visible=False),
296
+ gr.Button(visible=False),
297
+ gr.Markdown(visible=False),
298
+ gr.Button(visible=False),
299
+ secret_word_used,
300
+ ]
301
+ )
302
+
303
+ # Define UI components for the first state, ask the user if they want to know the rules
304
+ elif state_int == 1:
305
+ output.extend(
306
+ [
307
+ gr.Button(visible=False),
308
+ gr.Radio(
309
+ [Menu["Yes"], Menu["No"]], value=None, label="", visible=True
310
+ ),
311
+ gr.Textbox(
312
+ Config[list(Config.keys())[state_int]], visible=True, label=""
313
+ ),
314
+ gr.Button(Menu["Give_up"], visible=False),
315
+ gr.Textbox(visible=False),
316
+ gr.Image(interactive=False, visible=False),
317
+ gr.Textbox(visible=False),
318
+ gr.Button(visible=False),
319
+ gr.Markdown(visible=False),
320
+ gr.Button(visible=False),
321
+ secret_word_used,
322
+ ]
323
+ )
324
+
325
+ # Define UI components for the second state, Depending on the answer, show the rules or keep going
326
+ elif state_int == 2:
327
+ if radio == Menu["No"]:
328
+ output = [
329
+ dif_state,
330
+ gr.Button("Introducir", visible=True),
331
+ gr.Radio(visible=False),
332
+ gr.Textbox(
333
+ Config[list(Config.keys())[state_int]], visible=True, label=""
334
+ ),
335
+ gr.Button(Menu["Give_up"], visible=False),
336
+ gr.Textbox(visible=False),
337
+ gr.Image(interactive=False, visible=False),
338
+ gr.Textbox(visible=False),
339
+ gr.Button(visible=False),
340
+ gr.Markdown(visible=False),
341
+ gr.Button(visible=False),
342
+ secret_word_used,
343
+ ]
344
+
345
+ else:
346
+ output.extend(
347
+ [
348
+ gr.Button(Menu["Next"], visible=True),
349
+ gr.Radio(visible=False),
350
+ gr.Textbox(
351
+ Config[list(Config.keys())[state_int]],
352
+ visible=True,
353
+ label="",
354
+ ),
355
+ gr.Button(Menu["Give_up"], visible=False),
356
+ gr.Textbox(visible=False),
357
+ gr.Image(interactive=False, visible=False),
358
+ gr.Textbox(visible=False),
359
+ gr.Button(visible=False),
360
+ gr.Markdown(visible=False),
361
+ gr.Button(visible=False),
362
+ secret_word_used,
363
+ ]
364
+ )
365
+
366
+ # Define UI components for the difficulty state, ask the user to select the difficulty level
367
+ elif state_int == dif_state:
368
+ output.extend(
369
+ [
370
+ gr.Button(Menu["Start"], visible=True, variant="primary"),
371
+ gr.Radio(visible=False),
372
+ gr.Textbox(
373
+ Config[list(Config.keys())[state_int]], visible=True, label=""
374
+ ),
375
+ gr.Button(Menu["Give_up"], visible=False),
376
+ gr.Textbox(visible=False),
377
+ gr.Image(interactive=False, visible=False),
378
+ gr.Textbox(visible=False),
379
+ gr.Button(visible=False),
380
+ gr.Markdown(visible=False),
381
+ gr.Button(visible=False),
382
+ secret_word_used,
383
+ ]
384
+ )
385
+
386
+ # 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
387
+ elif state_int == dif_state + 1:
388
+
389
+ game_instances[request.session_hash].prepare_game(
390
+ secret_word_used, 2 if hints_enabled else 4
391
+ )
392
+
393
+ output.extend(
394
+ [
395
+ gr.Button(Menu["Send"], visible=True, variant="primary"),
396
+ gr.Radio(label="", visible=False),
397
+ gr.Textbox(visible=False, label=""),
398
+ gr.Button(visible=False, variant="stop"),
399
+ gr.Textbox(
400
+ value="",
401
+ visible=True,
402
+ autofocus=True,
403
+ placeholder=Menu["New_word"],
404
+ ),
405
+ gr.Image(interactive=False, visible=False),
406
+ gr.Textbox(visible=False),
407
+ gr.Button(visible=False),
408
+ gr.Markdown(visible=False),
409
+ gr.Button(visible=False),
410
+ secret_word_used + 1,
411
+ ]
412
+ )
413
+
414
+ # Define UI components for the state greater than the difficulty state + 2, play the game and provide feedback based on the user input
415
+ elif state_int > dif_state + 1:
416
+
417
+ # Send the user input to the game and get the feedback from the game
418
+ feed = game_instances[request.session_hash].play_game(inp, model_class)
419
+
420
+ # Check if the feedback contains the ranking information and process it
421
+ feedback_trim = feed.split("[rank]")
422
+ if len(feedback_trim) > 1:
423
+ ranking_vis = True
424
+ ranking_md = convert_to_markdown_centered(feedback_trim[1])
425
+
426
+ else:
427
+ ranking_vis = False
428
+ ranking_md = ""
429
+
430
+ # Check if the feedback contains a hint, win, or lose message
431
+ feedback = feedback_trim[0].split("[hint]")
432
+ win = feedback_trim[0].split("[win]")
433
+ lose = feedback_trim[0].split("[lose]")
434
+
435
+ # Check if the feedback contains a hint message
436
+ if len(feedback) > 1:
437
+ hint = True
438
+ hint_out = feedback[1]
439
+ feedback = feedback[0]
440
+ else:
441
+ hint = False
442
+ feedback = feedback[0]
443
+
444
+ # Check if the feedback contains a win or lose message and process it
445
+ if len(win) > 1 or len(lose) > 1:
446
+
447
+ # Check if the user won the game
448
+ won = True if len(win) > 1 else False
449
+
450
+ # Get the curiosity message from the game
451
+ curiosity = game_instances[request.session_hash].curiosity()
452
+
453
+ # Define the output components for the win or lose state
454
+ output.extend(
455
+ [
456
+ gr.Button(Menu["Send"], visible=False, variant="primary"),
457
+ gr.Radio(label="", visible=False),
458
+ gr.Textbox(win[1] if won else lose[1], visible=True, label=""),
459
+ gr.Button(visible=False, variant="stop"),
460
+ gr.Textbox(
461
+ value="", visible=False, placeholder=Menu["New_word"]
462
+ ),
463
+ gr.Image(
464
+ logo_win_path if won else logo_path,
465
+ interactive=False,
466
+ visible=True,
467
+ ),
468
+ gr.Textbox(curiosity, visible=True, label=Menu["Curiosity"]),
469
+ gr.Button(Menu["Play_again"], variant="primary", visible=True),
470
+ gr.Markdown(visible=False),
471
+ gr.Button(visible=True),
472
+ secret_word_used,
473
+ ]
474
+ )
475
+
476
+ return output
477
+
478
+ # Define the output components for the feedback and keep playing
479
+ output.extend(
480
+ [
481
+ gr.Button(Menu["Send"], visible=True, variant="primary"),
482
+ gr.Radio(label="", visible=False),
483
+ gr.Textbox(feedback, visible=True, label=""),
484
+ gr.Button(visible=True, variant="stop"),
485
+ gr.Textbox(value="", visible=True, placeholder=Menu["New_word"]),
486
+ gr.Image(logo_path, interactive=False, visible=False),
487
+ gr.Textbox(hint_out if hint else "", visible=hint, label="Pista"),
488
+ gr.Button(visible=False),
489
+ gr.Markdown(ranking_md, visible=ranking_vis),
490
+ gr.Button(visible=False),
491
+ secret_word_used,
492
+ ]
493
+ )
494
+
495
+ # Define UI components for the rest of the states, state for showing basic text to the user
496
+ else:
497
+ output.extend(
498
+ [
499
+ gr.Button(Menu["Next"], visible=True),
500
+ gr.Radio(label="", visible=False),
501
+ gr.Textbox(
502
+ Config[list(Config.keys())[state_int]], visible=True, label=""
503
+ ),
504
+ gr.Button("Pista", visible=False),
505
+ gr.Textbox(visible=False),
506
+ gr.Image(interactive=False, visible=False),
507
+ gr.Textbox(visible=False),
508
+ gr.Button(visible=False),
509
+ gr.Markdown(visible=False),
510
+ gr.Button(visible=False),
511
+ secret_word_used,
512
+ ]
513
+ )
514
+
515
+ # Return the output components
516
+ return output
517
+
518
+ def commit_data(request: gr.Request):
519
+ session_id = game_instances[request.session_hash].get_session_id()
520
+ session_files = [f for f in os.listdir(plays_path) if f.startswith(session_id)]
521
+ combined_data = []
522
+
523
+ for file_name in session_files:
524
+ with open(os.path.join(plays_path, file_name), "r") as file:
525
+ combined_data.append(json.load(file))
526
+ os.remove(os.path.join(plays_path, file_name))
527
+
528
+ combined_file_path = os.path.join(plays_path, f"{session_id}.json")
529
+ with open(combined_file_path, "w") as combined_file:
530
+ json.dump(combined_data, combined_file, indent=4)
531
+
532
+ scheduler.push_to_hub()
533
+
534
+ if os.path.exists(combined_file_path):
535
+ os.remove(combined_file_path)
536
+
537
+ return [
538
+ gr.Button(visible=False),
539
+ gr.Textbox(visible=False),
540
+ gr.Textbox(visible=False),
541
+ gr.Button(
542
+ "Rellenar cuestionario",
543
+ variant="primary",
544
+ link="https://docs.google.com/forms/d/e/1FAIpQLScqPES3cM6i7yS87_PZtD0T7Q0W-YynKBY_m-Frja3BL5t9Tw/viewform?usp=pp_url&entry.1903327713="
545
+ + session_id,
546
+ visible=True,
547
+ ),
548
+ ]
549
+
550
+ # Define the UI layout for the gam
551
+ img = gr.Image(logo_path, height=430, interactive=False, visible=True)
552
+ ranking = gr.Markdown(visible=False)
553
+
554
+ with gr.Row():
555
+ out = gr.Textbox(visible=False, placeholder=Config[list(Config.keys())[0]])
556
+ hint_out = gr.Textbox(visible=False)
557
+
558
+ radio = gr.Radio(visible=False)
559
+
560
+ with gr.Row():
561
+ inp = gr.Textbox(visible=False, interactive=True, label="")
562
+ but = gr.Button(Menu["Start"])
563
+ give_up = gr.Button("Pista", visible=False)
564
+ reload = gr.Button(Menu["Play_again"], visible=False)
565
+ finish = gr.Button(
566
+ "Terminar",
567
+ variant="stop",
568
+ # link="https://docs.google.com/forms/d/e/1FAIpQLSd0z8nI4hhOSR83yPIw_bR3KkSt25Lsq0ZXG1pZnkldeoceqA/viewform?usp=pp_url&entry.327829192=Condici%C3%B3n+1",
569
+ visible=False,
570
+ )
571
+
572
+ timer_delete = gr.Timer(value=30)
573
+
574
+ # Define the UI events for the game
575
+
576
+ # Define events that trigger the game state change
577
+ timer_delete.tick(remove_game_instance, inputs=[gr.State(True)])
578
+ inp.submit(
579
+ change,
580
+ inputs=[state, inp],
581
+ outputs=[state, inp],
582
+ concurrency_limit=5,
583
+ )
584
+ but.click(
585
+ change,
586
+ inputs=[state, inp],
587
+ outputs=[state, inp],
588
+ concurrency_limit=5,
589
+ )
590
+ give_up.click(
591
+ change,
592
+ inputs=[
593
+ state,
594
+ gr.Textbox("give_up", visible=False, interactive=True, label=""),
595
+ ],
596
+ outputs=[state, inp],
597
+ concurrency_limit=5,
598
+ )
599
+ radio.input(
600
+ change,
601
+ inputs=[state, inp],
602
+ outputs=[state, inp],
603
+ concurrency_limit=5,
604
+ )
605
+ finish.click(
606
+ commit_data, outputs=[reload, out, hint_out, finish]
607
+ ) # Define events that trigger the game reset
608
+ reload.click(
609
+ reset,
610
+ inputs=[gr.State(False)],
611
+ outputs=[state, out, inp, img, but, radio, hint_out, reload, header, finish],
612
+ )
613
+ demo.load(
614
+ reset,
615
+ inputs=[gr.State(True)],
616
+ outputs=[state, out, inp, img, but, radio, hint_out, reload, header, finish],
617
+ )
618
+ demo.unload(remove_game_instance)
619
+
620
+ # Define events that trigger the game state update
621
+ state.change(
622
+ update,
623
+ inputs=[state, radio, inp, hint, secret_word_used],
624
+ outputs=[
625
+ state,
626
+ but,
627
+ radio,
628
+ out,
629
+ give_up,
630
+ inp,
631
+ img,
632
+ hint_out,
633
+ reload,
634
+ ranking,
635
+ finish,
636
+ secret_word_used,
637
+ ],
638
+ )
639
+
640
+ if __name__ == "__main__":
641
+ demo.launch(debug=True)
config/condition.json ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "condition_0" : {
3
+ "model" : "SentenceTransformer",
4
+ "hints" : true
5
+ },
6
+ "condition_1" : {
7
+ "model" : "SentenceTransformer",
8
+ "hints" : false
9
+ },
10
+ "condition_2" : {
11
+ "model" : "word2vec",
12
+ "hints" : true
13
+ },
14
+ "condition_3" : {
15
+ "model" : "word2vec",
16
+ "hints" : false
17
+ }
18
+ }
19
+
config/images/logo.png ADDED
config/images/logo_win.gif ADDED

Git LFS Details

  • SHA256: 14510829d9433b8dc0fc36b07ffa9d079856bcc9d4b3ac28588ef896298fc92a
  • Pointer size: 133 Bytes
  • Size of remote file: 31.3 MB
config/lang.json ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "SPA": {
3
+ "Game": {
4
+ "Introduction_0": "Bienvenido a Semantrix, el emocionante Juego de la adivinanza semántica. \n\nTu misión es adivinar una palabra secreta que yo he escogido, pero no te preocupes, te ayudaré en el camino. \n\nLanza al aire la primera palabra que se te ocurra. Te daré pistas diciéndote si estás caliente, es decir muy cerca de adivinarla o frío, es decir, muy lejos de la palabra.",
5
+ "Introduction_1": "¿Quieres saber cómo se juega?",
6
+ "Rules": "Cada palabra que propongas recibirá una puntuación semántica entre 0 y 10, un puntaje alto significa que estás muy cerca de adivinar la palabra secreta\n\nSi veo que estás un poco perdido, estaré aquí para darte pistas que te ayudarán a acercarte a la palabra secreta.\n\nComo ayuda extra, mostraré un ranking de todas las palabras que has propuesto, ordenadas según su puntuación. Así podrás tener una idea mejor de qué tan cerca están y qué palabras funcionan mejor.\n\nGanarás cuando adivines correctamente la palabra secreta. ¡No desistas, lo tienes al alcance!",
7
+ "Begin": "¡Enciende tu mente, confía en tus ideas y sobre todo, pasa un buen rato! Este es un juego en el que cada palabra, cada puntuación y cada pista te acerca a tu victoria. ¡Mucha suerte!",
8
+ "New_word": "Nueva palabra: ",
9
+ "Feedback_0": "Helado, puntuación: ",
10
+ "Feedback_1": "Frío, puntuación: ",
11
+ "Feedback_2": "Templado, puntuación: ",
12
+ "Feedback_3": "Caliente, puntuación: ",
13
+ "Feedback_4": "Quemando, puntuación: ",
14
+ "Feedback_5": "Ardiendo, puntuación: ",
15
+ "Feedback_6": "Te estás acercando",
16
+ "Feedback_7": "Te estás alejando",
17
+ "Feedback_8": "¡Has ganado, ENHORABUENA!",
18
+ "Feedback_9": "La palabra secreta era: ",
19
+ "Feedback_10": "Aunque no fue una victoria esta vez, ¡no temas! ¡Cada intento es una nueva oportunidad para brillar! ¡Sigue adelante!",
20
+ "secret_word": "PALABRA SECRETA",
21
+ "hint_intro": [
22
+ "Parece que las palabras están jugando al escondite contigo. ¿Necesitas una ayudita? Aquí va una pista:",
23
+ "¡Vamos, estás tan cerca de descifrar el enigma semántico! Pero si sientes que te falta un empujón, aquí tienes una pista:",
24
+ "Tu mente está explorando este campo semántico como un detective, ¡pero incluso los detectives a veces necesitan pistas extra! Así que, aquí va una para ti:",
25
+ "El camino semántico puede volverse un poco sinuoso a veces. No te preocupes, estoy aquí para allanar el camino con una pista:",
26
+ "Las palabras son como piezas de un rompecabezas, y sé que estás cerca de completar la imagen. Aquí va una pista para encajar las piezas restantes:",
27
+ "Estás navegando por las aguas semánticas con destreza, ¡pero incluso los capitanes expertos pueden necesitar un faro de vez en cuando! Aquí está tu faro, tu pista:",
28
+ "La danza de las palabras puede ser complicada, pero no te preocupes, estoy aquí para ser tu guía de baile. Aquí tienes una pista para que sigas moviéndote con gracia:"
29
+ ]
30
+ },
31
+ "Hint": {
32
+ "secret_word": "La palabra secreta",
33
+ "hint_0_0": "Define brevemente \"",
34
+ "hint_0_1": "\" sin incluir la propia palabra ni palabras de su familia léxica. En caso de usarla refiérete a ",
35
+ "hint_0_2": " como \"la palabra secreta\":",
36
+ "hint_0_3": "Podría definir la palabra secreta como:\n",
37
+ "hint_1_0": "Representa la palabra ",
38
+ "hint_1_1": " con emojis:",
39
+ "hint_1_2": "Voy a intentar representarte la palabra usando emojis:\n",
40
+ "hint_2_0": "Da una pista en forma de poema de 4 versos sobre ",
41
+ "hint_2_1": " que no incluya la propia palabra:",
42
+ "hint_2_2": "Me he inspirado un poco, voy a recitar un poema sobre la palabra secreta:\n",
43
+ "hint_3_0": "Dime tres palabras aleatorias separadas por coma:",
44
+ "hint_3_1": "Dime una palabra relacionada con",
45
+ "hint_3_2": " pero no puede ser la propia palabra ni de su familia léxica. No añadas texto adicional",
46
+ "hint_3_3": "Voy a pensar cuatro palabras y te muestro entre ellas cual se acerca más a la palabra secreta:\n",
47
+ "hint_4_0": "Dime el título de una película real donde aparece ",
48
+ "hint_4_1": ". Di únicamente el título, nada mas:",
49
+ "hint_4_2": "Representa la película ",
50
+ "hint_4_3": " únicamente con unos pocos emojis:",
51
+ "hint_4_4": "He pensado en una película relacionada con la palabra secreta y te la voy a representar con emojis, la película es:\n",
52
+ "curiosity": "Cuéntame una curiosidad sobre \""
53
+ },
54
+ "Menu": {
55
+ "Header": "SEMANTRIX: EL JUEGO DE LAS PALABRAS",
56
+ "Start": "Empezar",
57
+ "Next": "Siguiente",
58
+ "Yes": "Sí",
59
+ "No": "No",
60
+ "Easy": "Fácil",
61
+ "Normal": "Normal",
62
+ "Hard": "Difícil",
63
+ "Expert": "Experto",
64
+ "New_word": "Nueva palabra",
65
+ "Send": "Enviar",
66
+ "Give_up": "Rendirse",
67
+ "Language": "Idioma",
68
+ "Best_tries": "Mejores intentos",
69
+ "N_try": "Intento nº",
70
+ "Word": "Palabra",
71
+ "Score": "Puntuación",
72
+ "Last_try": "Último intento",
73
+ "Curiosity": "Curiosidad",
74
+ "Play_again": "Jugar de nuevo"
75
+ }
76
+ },
77
+ "ENG": {
78
+ "Game": {
79
+
80
+ "Introduction_0": "Welcome to Semantrix, the exciting semantic guessing game.\n\nYour mission is to guess a secret word I've chosen, but don't worry, I'll help you along the way.\n\nThrow out the first word that comes to your mind. I'll give you clues by telling you if you're hot, meaning very close to guessing it, or cold, meaning far from the word.",
81
+ "Introduction_1": "Do you want to know how to play?",
82
+ "Rules": "Each word you propose will receive a semantic score between 0 and 10. A high score means you're very close to guessing the secret word.\n\nIf I see you're a bit lost, I'll be here to give you hints to help you get closer to the secret word.\n\nAs extra help, I'll show a ranking of all the words you've suggested, ordered by their score. This way, you can have a better idea of how close they are and which words work best.\n\nYou'll be the winner when you correctly guess the secret word. Don't give up, it's within your reach!",
83
+ "Begin": "Turn on your mind, trust your ideas, and above all, have a good time! This is a game where each word, each score, and each clue brings you closer to your victory. Good luck!",
84
+ "New_word": "New word: ",
85
+ "Feedback_0": "Ice-cold, score: ",
86
+ "Feedback_1": "Cold, score: ",
87
+ "Feedback_2": "Warm, score: ",
88
+ "Feedback_3": "Hot, score: ",
89
+ "Feedback_4": "Burning, score: ",
90
+ "Feedback_5": "On fire, score: ",
91
+ "Feedback_6": "You're getting closer",
92
+ "Feedback_7": "You're moving away",
93
+ "Feedback_8": "You've won, CONGRATULATIONS!",
94
+ "Feedback_9": "The secret word was: ",
95
+ "Feedback_10": "Though it wasn't a win this time, fear not! Each try is a new chance to shine! Keep going!",
96
+ "secret_word": "SECRET WORD",
97
+ "hint_intro": [
98
+ "It seems like the words are playing hide-and-seek with you. Need a little help? Here's a hint:",
99
+ "Come on, you're so close to unraveling the semantic mystery! But if you feel like you need a push, here's a hint:",
100
+ "Your mind is exploring this semantic field like a detective, but even detectives sometimes need extra clues! So, here's one for you:",
101
+ "The semantic path can get a bit winding at times. Don't worry, I'm here to smooth the way with a hint:",
102
+ "Words are like pieces of a puzzle, and I know you're close to completing the picture. Here's a hint to fit the remaining pieces:",
103
+ "You're navigating the semantic waters skillfully, but even expert captains may need a lighthouse now and then! Here's your lighthouse, your hint:",
104
+ "The dance of words can be intricate, but don't worry, I'm here to be your dance guide. Here's a hint to keep you moving with grace:"
105
+ ]
106
+ },
107
+ "Hint": {
108
+ "secret_word": "The secret word",
109
+ "hint_0_0": "Briefly define \"",
110
+ "hint_0_1": "\" without including the word itself or words from its lexical family. If using it, refer to ",
111
+ "hint_0_2": " as \"the secret word\":",
112
+ "hint_0_3": "I could define the secret word as:\n",
113
+ "hint_1_0": "Represent the word ",
114
+ "hint_1_1": " with emojis:",
115
+ "hint_1_2": "I'll try to represent the word using emojis:\n",
116
+ "hint_2_0": "Give a hint in the form of a 4-verse poem about ",
117
+ "hint_2_1": " that doesn't include the word itself:",
118
+ "hint_2_2": "I've been a bit inspired; I'll recite a poem about the secret word:\n",
119
+ "hint_3_0": "Tell me three random words separated by commas:",
120
+ "hint_3_1": "Tell me a word related to",
121
+ "hint_3_2": " but it can't be the word itself or from its lexical family. Don't add any additional text",
122
+ "hint_3_3": "I'll think of four words and show you which one comes closest to the secret word:\n",
123
+ "hint_4_0": "Tell me the title of a real movie where ",
124
+ "hint_4_1": ". Only say the title, nothing more:",
125
+ "hint_4_2": "Represent the movie ",
126
+ "hint_4_3": " only with a few emojis:",
127
+ "hint_4_4": "I've thought of a movie related to the secret word, and I'll represent it with emojis. The movie is:\n",
128
+ "curiosity": "Tell me an interesting fact about \""
129
+ },
130
+ "Menu": {
131
+ "Header": "SEMANTRIX: THE WORD GUESSING GAME",
132
+ "Start": "Start",
133
+ "Next": "Next",
134
+ "Yes": "Yes",
135
+ "No": "No",
136
+ "Easy": "Easy",
137
+ "Normal": "Normal",
138
+ "Hard": "Hard",
139
+ "Expert": "Expert",
140
+ "New_word": "New word",
141
+ "Send": "Send",
142
+ "Give_up": "Give up",
143
+ "Language": "Language",
144
+ "Best_tries": "Best tries",
145
+ "N_try": "Try nº",
146
+ "Word": "Word",
147
+ "Score": "Score",
148
+ "Last_try": "Last try",
149
+ "Curiosity": "Curiosity",
150
+ "Play_again": "Play again"
151
+ }
152
+ }
153
+ }
config/secret.json ADDED
@@ -0,0 +1,1035 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "ENG": {
3
+ "basic": [
4
+ "ant",
5
+ "tree",
6
+ "glass",
7
+ "mountains",
8
+ "dress",
9
+ "rain",
10
+ "soap",
11
+ "finger",
12
+ "man",
13
+ "earth",
14
+ "stick",
15
+ "office",
16
+ "sadness",
17
+ "radio",
18
+ "keyboard",
19
+ "dirt",
20
+ "plum",
21
+ "message",
22
+ "eel",
23
+ "king",
24
+ "wild boar",
25
+ "nut",
26
+ "planet",
27
+ "party",
28
+ "son",
29
+ "cellphone",
30
+ "visit",
31
+ "tab",
32
+ "elegance",
33
+ "gloves",
34
+ "turtle",
35
+ "lock",
36
+ "plane",
37
+ "leaf",
38
+ "suitcase",
39
+ "cookie",
40
+ "hand",
41
+ "lamp",
42
+ "woman",
43
+ "pen",
44
+ "mountain",
45
+ "leaves",
46
+ "wind",
47
+ "helmet",
48
+ "spring",
49
+ "atom",
50
+ "dad",
51
+ "father-in-law",
52
+ "watch",
53
+ "cabin",
54
+ "map",
55
+ "cow",
56
+ "rectangle",
57
+ "shoe",
58
+ "parrot",
59
+ "insect",
60
+ "letter",
61
+ "baby",
62
+ "keys",
63
+ "toucan",
64
+ "wall",
65
+ "jacket",
66
+ "waterfall",
67
+ "seat",
68
+ "ear",
69
+ "team",
70
+ "luck",
71
+ "soul",
72
+ "guitar",
73
+ "choir",
74
+ "summer",
75
+ "dream",
76
+ "button",
77
+ "chair",
78
+ "lamb",
79
+ "ease",
80
+ "notebook",
81
+ "curiosity",
82
+ "coin",
83
+ "hanger",
84
+ "violin",
85
+ "singer",
86
+ "camera",
87
+ "snow",
88
+ "pool",
89
+ "container",
90
+ "photograph",
91
+ "shelter",
92
+ "animal",
93
+ "fear",
94
+ "rat",
95
+ "plastic",
96
+ "debate",
97
+ "duck",
98
+ "feather",
99
+ "monkey",
100
+ "people",
101
+ "door",
102
+ "blind",
103
+ "nose",
104
+ "wood",
105
+ "leg",
106
+ "car",
107
+ "hair",
108
+ "key",
109
+ "stewardess",
110
+ "living room",
111
+ "forest",
112
+ "castle",
113
+ "salad",
114
+ "lock",
115
+ "carnation",
116
+ "molar",
117
+ "bird",
118
+ "table",
119
+ "beach",
120
+ "screen",
121
+ "agenda",
122
+ "person",
123
+ "idea",
124
+ "clothing",
125
+ "wheel",
126
+ "tool",
127
+ "aluminium",
128
+ "house",
129
+ "cup",
130
+ "clouds",
131
+ "jug",
132
+ "circle",
133
+ "brother",
134
+ "farm",
135
+ "sorrow",
136
+ "hook",
137
+ "iron",
138
+ "hump",
139
+ "sound",
140
+ "zoo",
141
+ "photo",
142
+ "toy",
143
+ "crib",
144
+ "war",
145
+ "dressing room",
146
+ "sheep",
147
+ "hail",
148
+ "pilot",
149
+ "grass",
150
+ "spider",
151
+ "hammer",
152
+ "last name",
153
+ "boat",
154
+ "armchair",
155
+ "plate",
156
+ "seal",
157
+ "tiger",
158
+ "lawn",
159
+ "dog",
160
+ "oil",
161
+ "bow",
162
+ "helm",
163
+ "school",
164
+ "can opener",
165
+ "chimney",
166
+ "match",
167
+ "molecule",
168
+ "shirt",
169
+ "hut",
170
+ "calculator",
171
+ "horse",
172
+ "pine grove",
173
+ "paper",
174
+ "ornament",
175
+ "church",
176
+ "uncle",
177
+ "pencil",
178
+ "pig",
179
+ "cheese",
180
+ "cream",
181
+ "time",
182
+ "field",
183
+ "pants",
184
+ "pen",
185
+ "cloud",
186
+ "friend",
187
+ "purse",
188
+ "competition",
189
+ "light",
190
+ "program",
191
+ "cable",
192
+ "key",
193
+ "writing",
194
+ "floor",
195
+ "job",
196
+ "compass",
197
+ "coaster",
198
+ "sun",
199
+ "lights",
200
+ "furniture",
201
+ "dogs",
202
+ "eye",
203
+ "rope",
204
+ "noodles",
205
+ "kindness",
206
+ "sailboat",
207
+ "bed",
208
+ "sand",
209
+ "corner",
210
+ "cat",
211
+ "honey",
212
+ "chocolate",
213
+ "bell",
214
+ "noise",
215
+ "pillar",
216
+ "child",
217
+ "street",
218
+ "rocket",
219
+ "herd",
220
+ "godfather",
221
+ "headphones",
222
+ "nephew",
223
+ "hospital",
224
+ "July",
225
+ "bunch",
226
+ "speaker",
227
+ "brother-in-law",
228
+ "coffee",
229
+ "satellite",
230
+ "screw",
231
+ "books",
232
+ "letter",
233
+ "folder",
234
+ "train",
235
+ "briefcase",
236
+ "school",
237
+ "picture",
238
+ "eagle",
239
+ "love",
240
+ "room",
241
+ "truck",
242
+ "newspapers",
243
+ "tablecloth",
244
+ "notes",
245
+ "heron",
246
+ "painting",
247
+ "fluff",
248
+ "tie",
249
+ "letters",
250
+ "printer",
251
+ "sofa",
252
+ "flower",
253
+ "weasel",
254
+ "lemon",
255
+ "mason",
256
+ "glass",
257
+ "meat",
258
+ "city",
259
+ "designer",
260
+ "lagoon",
261
+ "darkness",
262
+ "meadow",
263
+ "puma",
264
+ "ship",
265
+ "troop",
266
+ "lime",
267
+ "cage",
268
+ "sport",
269
+ "casino",
270
+ "building",
271
+ "firefighter",
272
+ "plant"
273
+ ],
274
+ "advanced": [
275
+ "accountant",
276
+ "hatred",
277
+ "engineer",
278
+ "viewer",
279
+ "window",
280
+ "substance",
281
+ "complaint",
282
+ "platform",
283
+ "toilet",
284
+ "Argentina",
285
+ "Guadeloupe",
286
+ "machinist",
287
+ "explosion",
288
+ "gas",
289
+ "presidency",
290
+ "lake",
291
+ "visit",
292
+ "speech",
293
+ "archipelago",
294
+ "entrepreneur",
295
+ "Temple",
296
+ "utensil",
297
+ "theater",
298
+ "classroom",
299
+ "television",
300
+ "glasses",
301
+ "reptile",
302
+ "whale",
303
+ "fauna",
304
+ "plane",
305
+ "stone",
306
+ "family",
307
+ "discotheque",
308
+ "bomb",
309
+ "waitress",
310
+ "candidate",
311
+ "triangle",
312
+ "famous",
313
+ "auction",
314
+ "belt",
315
+ "atom",
316
+ "bookstore",
317
+ "watch",
318
+ "music",
319
+ "Grandmother",
320
+ "candies",
321
+ "battery",
322
+ "brother",
323
+ "Colombia",
324
+ "hook",
325
+ "sound",
326
+ "government",
327
+ "note",
328
+ "hippopotamus",
329
+ "metal",
330
+ "happiness",
331
+ "baby",
332
+ "tiger",
333
+ "child",
334
+ "vocabulary",
335
+ "grapefruit",
336
+ "cloud",
337
+ "competition",
338
+ "cable",
339
+ "Mexico",
340
+ "program",
341
+ "writing",
342
+ "compass",
343
+ "coaster",
344
+ "program",
345
+ "writing",
346
+ "compass",
347
+ "coaster",
348
+ "lights",
349
+ "water",
350
+ "bottle",
351
+ "floor",
352
+ "rabbit",
353
+ "book",
354
+ "bridge",
355
+ "scarf",
356
+ "school",
357
+ "picture",
358
+ "notes",
359
+ "photo",
360
+ "toy",
361
+ "war",
362
+ "heron",
363
+ "carnation",
364
+ "enthusiasm",
365
+ "molar",
366
+ "bird",
367
+ "table",
368
+ "screen",
369
+ "agenda",
370
+ "person",
371
+ "idea",
372
+ "clothing",
373
+ "wheel",
374
+ "tool",
375
+ "aluminium",
376
+ "house",
377
+ "cup",
378
+ "clouds",
379
+ "jug",
380
+ "circle",
381
+ "Colombia",
382
+ "farm",
383
+ "sorrow",
384
+ "iron",
385
+ "hump",
386
+ "zoo",
387
+ "government",
388
+ "photo",
389
+ "toy",
390
+ "crib",
391
+ "war",
392
+ "dressing room",
393
+ "tornado",
394
+ "sheep",
395
+ "hail",
396
+ "pilot",
397
+ "grass",
398
+ "spider",
399
+ "anguish",
400
+ "hammer",
401
+ "statistics",
402
+ "last name",
403
+ "boat",
404
+ "armchair",
405
+ "plate",
406
+ "river",
407
+ "seal",
408
+ "rhinoceros",
409
+ "shirt",
410
+ "hut",
411
+ "calculator",
412
+ "horse",
413
+ "pine grove",
414
+ "paper",
415
+ "ornament",
416
+ "church",
417
+ "uncle",
418
+ "pencil",
419
+ "pig",
420
+ "cheese",
421
+ "cream",
422
+ "time",
423
+ "vocabulary",
424
+ "grapefruit",
425
+ "field",
426
+ "pants",
427
+ "pen",
428
+ "cloud",
429
+ "friend",
430
+ "purse",
431
+ "competition",
432
+ "light",
433
+ "program",
434
+ "cable",
435
+ "key",
436
+ "writing",
437
+ "Mexico",
438
+ "floor",
439
+ "job",
440
+ "compass",
441
+ "coaster",
442
+ "sun",
443
+ "lights",
444
+ "furniture",
445
+ "dogs",
446
+ "eye",
447
+ "rope",
448
+ "noodles",
449
+ "kindness",
450
+ "sailboat",
451
+ "bed",
452
+ "sand",
453
+ "corner",
454
+ "cat",
455
+ "honey",
456
+ "chocolate",
457
+ "bell",
458
+ "noise",
459
+ "pillar",
460
+ "child",
461
+ "street",
462
+ "rocket",
463
+ "herd",
464
+ "godfather",
465
+ "headphones",
466
+ "nephew",
467
+ "hospital",
468
+ "July",
469
+ "bunch",
470
+ "Chile",
471
+ "speaker",
472
+ "brother-in-law",
473
+ "coffee",
474
+ "satellite",
475
+ "screw",
476
+ "books",
477
+ "letter",
478
+ "folder",
479
+ "train",
480
+ "briefcase",
481
+ "school",
482
+ "picture",
483
+ "eagle",
484
+ "love",
485
+ "room",
486
+ "truck",
487
+ "newspapers",
488
+ "tablecloth",
489
+ "notes",
490
+ "heron",
491
+ "painting",
492
+ "fluff",
493
+ "tie",
494
+ "letters",
495
+ "printer",
496
+ "sofa",
497
+ "flower",
498
+ "weasel",
499
+ "lemon",
500
+ "mason",
501
+ "glass",
502
+ "meat",
503
+ "city",
504
+ "designer",
505
+ "lagoon",
506
+ "darkness",
507
+ "meadow",
508
+ "puma",
509
+ "ship",
510
+ "troop",
511
+ "lime",
512
+ "cage",
513
+ "sport",
514
+ "casino",
515
+ "building",
516
+ "firefighter",
517
+ "plant",
518
+ "clarity"
519
+ ]
520
+ },
521
+ "SPA": {
522
+ "basic": [
523
+ "vestido",
524
+ "lluvia",
525
+ "jabón",
526
+ "dedo",
527
+ "hombre",
528
+ "tierra",
529
+ "palo",
530
+ "oficina",
531
+ "tristeza",
532
+ "radio",
533
+ "teclado",
534
+ "tierra",
535
+ "ciruela",
536
+ "mensaje",
537
+ "anguila",
538
+ "rey",
539
+ "jabalí",
540
+ "nuez",
541
+ "planeta",
542
+ "fiesta",
543
+ "hijo",
544
+ "teléfono",
545
+ "visita",
546
+ "pestaña",
547
+ "elegancia",
548
+ "guantes",
549
+ "tortuga",
550
+ "cerradura",
551
+ "avión",
552
+ "hoja",
553
+ "maleta",
554
+ "galleta",
555
+ "mano",
556
+ "lámpara",
557
+ "mujer",
558
+ "pluma",
559
+ "montaña",
560
+ "hojas",
561
+ "viento",
562
+ "casco",
563
+ "primavera",
564
+ "átomo",
565
+ "papá",
566
+ "suegro",
567
+ "reloj",
568
+ "cabaña",
569
+ "mapa",
570
+ "vaca",
571
+ "rectángulo",
572
+ "zapato",
573
+ "loro",
574
+ "insecto",
575
+ "carta",
576
+ "bebé",
577
+ "llaves",
578
+ "tucán",
579
+ "pared",
580
+ "chaqueta",
581
+ "cascada",
582
+ "asiento",
583
+ "oreja",
584
+ "equipo",
585
+ "suerte",
586
+ "alma",
587
+ "guitarra",
588
+ "coro",
589
+ "verano",
590
+ "sueño",
591
+ "botón",
592
+ "silla",
593
+ "cordero",
594
+ "facilidad",
595
+ "cuaderno",
596
+ "curiosidad",
597
+ "moneda",
598
+ "percha",
599
+ "violín",
600
+ "cantante",
601
+ "cámara",
602
+ "nieve",
603
+ "piscina",
604
+ "contenedor",
605
+ "fotografía",
606
+ "refugio",
607
+ "animal",
608
+ "miedo",
609
+ "rata",
610
+ "plástico",
611
+ "debate",
612
+ "pato",
613
+ "pluma",
614
+ "mono",
615
+ "gente",
616
+ "puerta",
617
+ "persiana",
618
+ "nariz",
619
+ "madera",
620
+ "pierna",
621
+ "coche",
622
+ "cabello",
623
+ "llave",
624
+ "azafata",
625
+ "sala de estar",
626
+ "bosque",
627
+ "castillo",
628
+ "ensalada",
629
+ "cerradura",
630
+ "clavel",
631
+ "molar",
632
+ "pájaro",
633
+ "mesa",
634
+ "playa",
635
+ "pantalla",
636
+ "agenda",
637
+ "persona",
638
+ "idea",
639
+ "ropa",
640
+ "rueda",
641
+ "herramienta",
642
+ "aluminio",
643
+ "casa",
644
+ "taza",
645
+ "nubes",
646
+ "jarra",
647
+ "círculo",
648
+ "hermano",
649
+ "granja",
650
+ "pena",
651
+ "gancho",
652
+ "hierro",
653
+ "joroba",
654
+ "sonido",
655
+ "zoológico",
656
+ "foto",
657
+ "juguete",
658
+ "cuna",
659
+ "guerra",
660
+ "vestuario",
661
+ "oveja",
662
+ "granizo",
663
+ "piloto",
664
+ "césped",
665
+ "araña",
666
+ "martillo",
667
+ "apellido",
668
+ "barco",
669
+ "sillón",
670
+ "plato",
671
+ "foca",
672
+ "tigre",
673
+ "césped",
674
+ "perro",
675
+ "aceite",
676
+ "arco",
677
+ "timón",
678
+ "escuela",
679
+ "abrelatas",
680
+ "chimenea",
681
+ "fósforo",
682
+ "molécula",
683
+ "camisa",
684
+ "choza",
685
+ "calculadora",
686
+ "caballo",
687
+ "pinar",
688
+ "papel",
689
+ "adorno",
690
+ "iglesia",
691
+ "tío",
692
+ "lápiz",
693
+ "cerdo",
694
+ "queso",
695
+ "crema",
696
+ "tiempo",
697
+ "campo",
698
+ "pantalones",
699
+ "pluma",
700
+ "nube",
701
+ "amigo",
702
+ "bolso",
703
+ "competencia",
704
+ "luz",
705
+ "programa",
706
+ "cable",
707
+ "llave",
708
+ "escritura",
709
+ "piso",
710
+ "trabajo",
711
+ "brújula",
712
+ "posavasos",
713
+ "sol",
714
+ "luces",
715
+ "muebles",
716
+ "perros",
717
+ "ojo",
718
+ "cuerda",
719
+ "fideos",
720
+ "bondad",
721
+ "velero",
722
+ "cama",
723
+ "arena",
724
+ "esquina",
725
+ "gato",
726
+ "miel",
727
+ "chocolate",
728
+ "campana",
729
+ "ruido",
730
+ "pilar",
731
+ "niño",
732
+ "calle",
733
+ "cohete",
734
+ "manada",
735
+ "padrino",
736
+ "auriculares",
737
+ "sobrino",
738
+ "hospital",
739
+ "julio",
740
+ "ramo",
741
+ "altavoz",
742
+ "cuñado",
743
+ "café",
744
+ "satélite",
745
+ "tornillo",
746
+ "libros",
747
+ "carta",
748
+ "carpeta",
749
+ "tren",
750
+ "maletín",
751
+ "escuela",
752
+ "imagen",
753
+ "águila",
754
+ "amor",
755
+ "habitación",
756
+ "camión",
757
+ "periódicos",
758
+ "mantel",
759
+ "notas",
760
+ "garza",
761
+ "pintura",
762
+ "pelusa",
763
+ "corbata",
764
+ "letras",
765
+ "impresora",
766
+ "sofá",
767
+ "flor",
768
+ "comadreja",
769
+ "limón",
770
+ "albañil",
771
+ "vidrio",
772
+ "carne",
773
+ "ciudad",
774
+ "diseñador",
775
+ "laguna",
776
+ "oscuridad",
777
+ "prado",
778
+ "puma",
779
+ "barco",
780
+ "tropa",
781
+ "lima",
782
+ "jaula",
783
+ "deporte",
784
+ "casino",
785
+ "edificio",
786
+ "bombero",
787
+ "planta"
788
+ ],
789
+ "advanced": [
790
+ "contador",
791
+ "odio",
792
+ "ingeniero",
793
+ "espectador",
794
+ "ventana",
795
+ "sustancia",
796
+ "queja",
797
+ "plataforma",
798
+ "inodoro",
799
+ "Argentina",
800
+ "Guadalupe",
801
+ "mecánico",
802
+ "explosión",
803
+ "gas",
804
+ "presidencia",
805
+ "lago",
806
+ "visita",
807
+ "discurso",
808
+ "archipiélago",
809
+ "empresario",
810
+ "templo",
811
+ "utensilio",
812
+ "teatro",
813
+ "aula",
814
+ "televisión",
815
+ "gafas",
816
+ "reptil",
817
+ "ballena",
818
+ "fauna",
819
+ "avión",
820
+ "piedra",
821
+ "familia",
822
+ "discoteca",
823
+ "bomba",
824
+ "mesera",
825
+ "candidato",
826
+ "triángulo",
827
+ "famoso",
828
+ "subasta",
829
+ "cinturón",
830
+ "átomo",
831
+ "librería",
832
+ "reloj",
833
+ "música",
834
+ "abuela",
835
+ "caramelos",
836
+ "batería",
837
+ "hermano",
838
+ "Colombia",
839
+ "gancho",
840
+ "sonido",
841
+ "gobierno",
842
+ "nota",
843
+ "hipopótamo",
844
+ "metal",
845
+ "felicidad",
846
+ "bebé",
847
+ "tigre",
848
+ "niño",
849
+ "vocabulario",
850
+ "pomelo",
851
+ "nube",
852
+ "competencia",
853
+ "cable",
854
+ "México",
855
+ "programa",
856
+ "escritura",
857
+ "brújula",
858
+ "posavasos",
859
+ "programa",
860
+ "escritura",
861
+ "brújula",
862
+ "posavasos",
863
+ "luces",
864
+ "agua",
865
+ "botella",
866
+ "piso",
867
+ "conejo",
868
+ "libro",
869
+ "puente",
870
+ "bufanda",
871
+ "escuela",
872
+ "imagen",
873
+ "notas",
874
+ "foto",
875
+ "juguete",
876
+ "guerra",
877
+ "garza",
878
+ "clavel",
879
+ "entusiasmo",
880
+ "molar",
881
+ "pájaro",
882
+ "mesa",
883
+ "pantalla",
884
+ "agenda",
885
+ "persona",
886
+ "idea",
887
+ "ropa",
888
+ "rueda",
889
+ "herramienta",
890
+ "aluminio",
891
+ "casa",
892
+ "taza",
893
+ "nubes",
894
+ "jarra",
895
+ "círculo",
896
+ "Colombia",
897
+ "granja",
898
+ "pena",
899
+ "hierro",
900
+ "joroba",
901
+ "zoológico",
902
+ "gobierno",
903
+ "foto",
904
+ "juguete",
905
+ "cuna",
906
+ "guerra",
907
+ "vestuario",
908
+ "oveja",
909
+ "granizo",
910
+ "piloto",
911
+ "césped",
912
+ "araña",
913
+ "angustia",
914
+ "martillo",
915
+ "estadísticas",
916
+ "apellido",
917
+ "barco",
918
+ "sillón",
919
+ "plato",
920
+ "río",
921
+ "foca",
922
+ "rinoceronte",
923
+ "camisa",
924
+ "choza",
925
+ "calculadora",
926
+ "caballo",
927
+ "pinar",
928
+ "papel",
929
+ "adorno",
930
+ "iglesia",
931
+ "tío",
932
+ "lápiz",
933
+ "cerdo",
934
+ "queso",
935
+ "crema",
936
+ "tiempo",
937
+ "vocabulario",
938
+ "pomelo",
939
+ "campo",
940
+ "pantalones",
941
+ "pluma",
942
+ "nube",
943
+ "amigo",
944
+ "bolso",
945
+ "competencia",
946
+ "luz",
947
+ "programa",
948
+ "cable",
949
+ "llave",
950
+ "escritura",
951
+ "México",
952
+ "piso",
953
+ "trabajo",
954
+ "brújula",
955
+ "posavasos",
956
+ "sol",
957
+ "luces",
958
+ "muebles",
959
+ "perros",
960
+ "ojo",
961
+ "cuerda",
962
+ "fideos",
963
+ "bondad",
964
+ "velero",
965
+ "cama",
966
+ "arena",
967
+ "esquina",
968
+ "gato",
969
+ "miel",
970
+ "chocolate",
971
+ "campana",
972
+ "ruido",
973
+ "pilar",
974
+ "niño",
975
+ "calle",
976
+ "cohete",
977
+ "manada",
978
+ "padrino",
979
+ "auriculares",
980
+ "sobrino",
981
+ "hospital",
982
+ "julio",
983
+ "ramo",
984
+ "Chile",
985
+ "altavoz",
986
+ "cuñado",
987
+ "café",
988
+ "satélite",
989
+ "tornillo",
990
+ "libros",
991
+ "carta",
992
+ "carpeta",
993
+ "tren",
994
+ "maletín",
995
+ "escuela",
996
+ "imagen",
997
+ "águila",
998
+ "amor",
999
+ "habitación",
1000
+ "camión",
1001
+ "periódicos",
1002
+ "mantel",
1003
+ "notas",
1004
+ "garza",
1005
+ "pintura",
1006
+ "pelusa",
1007
+ "corbata",
1008
+ "letras",
1009
+ "impresora",
1010
+ "sofá",
1011
+ "flor",
1012
+ "comadreja",
1013
+ "limón",
1014
+ "albañil",
1015
+ "vidrio",
1016
+ "carne",
1017
+ "ciudad",
1018
+ "diseñador",
1019
+ "laguna",
1020
+ "oscuridad",
1021
+ "prado",
1022
+ "puma",
1023
+ "barco",
1024
+ "tropa",
1025
+ "lima",
1026
+ "jaula",
1027
+ "deporte",
1028
+ "casino",
1029
+ "edificio",
1030
+ "bombero",
1031
+ "planta",
1032
+ "claridad"
1033
+ ]
1034
+ }
1035
+ }
data/plays/__init__.py ADDED
File without changes
data/rankings/__init__.py ADDED
File without changes
game.py ADDED
@@ -0,0 +1,417 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3.10
2
+
3
+ # """
4
+ # Semantrix Game Module
5
+
6
+ # 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.
7
+
8
+ # Classes:
9
+ # Semantrix: A class that implements the Semantrix word guessing game.
10
+ # Semantrix.DictWrapper: A helper class to wrap configuration dictionaries.
11
+
12
+ # Functions:
13
+ # __init__(self, lang=0, model_type="SentenceTransformer"): Initializes the Semantrix game with the specified language and model type.
14
+ # prepare_game(self, difficulty): Prepares the game with the selected difficulty level.
15
+ # gen_rank(self, repeated): Generates the ranking file based on the scores.
16
+ # play_game(self, word): Plays the game with the selected word and returns feedback.
17
+ # curiosity(self): Generates a curiosity hint about the secret word once the game is over.
18
+
19
+ # Attributes:
20
+ # model (KeyedVectors): The word embeddings model.
21
+ # config_file_path (str): Path to the configuration file.
22
+ # secret_file_path (str): Path to the secret words file.
23
+ # data_path (str): Path to the data directory.
24
+ # Config_full (dict): Full configuration data.
25
+ # secret (dict): Secret words data.
26
+ # lang (int): Language of the game (0 for Spanish, 1 for English).
27
+ # model_type (str): Type of the model ("word2vec" or "SentenceTransformer").
28
+ # Config (DictWrapper): Configuration data for the selected language.
29
+ # secret_dict (dict): Secret words for the selected language.
30
+ # secret_list (list): List of secret words for the selected difficulty.
31
+ # words (list): List of words guessed by the player.
32
+ # scores (list): List of scores for the guessed words.
33
+ # win (bool): Indicates if the player has won the game.
34
+ # n (int): Number of hints given.
35
+ # recent_hint (int): Counter for recent hints.
36
+ # f_dev_avg (float): Moving average of the tendency slope.
37
+ # last_hint (int): Index of the last hint given.
38
+ # difficulty (int): Difficulty level of the game.
39
+ # """
40
+
41
+ import os
42
+ import sys
43
+ import json
44
+ import uuid
45
+ import random
46
+ from datetime import datetime
47
+ import time
48
+ from tqdm import tqdm
49
+ import numpy as np
50
+ from gensim.models import KeyedVectors
51
+ from hints import curiosity, hint
52
+ from tracking import (
53
+ calculate_moving_average,
54
+ calculate_tendency_slope,
55
+ )
56
+ from sentence_transformers import SentenceTransformer, util
57
+ import warnings
58
+ from huggingface_hub import snapshot_download
59
+
60
+
61
+ warnings.filterwarnings(action="ignore", category=UserWarning, module="gensim")
62
+
63
+
64
+ class Model_class:
65
+
66
+ base_path = os.path.dirname(os.path.abspath(__file__))
67
+
68
+ def __init__(self, lang=0, model_type="SentenceTransformer"):
69
+
70
+ if model_type == "SentenceTransformer":
71
+ repo_url = "Jsevisal/strans_models"
72
+
73
+ else:
74
+ repo_url = "Jsevisal/w2v_models"
75
+
76
+ # Check if the model exists, clone it if it doesn't
77
+ if not os.path.exists(
78
+ os.path.join(self.base_path, "config/strans_models/")
79
+ ) or not os.path.exists(os.path.join(self.base_path, "config/w2v_models/")):
80
+ model_path = snapshot_download(repo_id=repo_url)
81
+
82
+ if lang == 1:
83
+ if model_type == "word2vec":
84
+ self.model = KeyedVectors.load(
85
+ os.path.join(model_path, "eng_w2v_model"),
86
+ mmap="r",
87
+ )
88
+ elif model_type == "SentenceTransformer":
89
+ self.model = KeyedVectors.load(
90
+ os.path.join(model_path, "eng_strans_model"),
91
+ mmap="r",
92
+ )
93
+
94
+ else:
95
+ if model_type == "word2vec":
96
+ self.model = KeyedVectors.load(
97
+ os.path.join(model_path, "esp_w2v_model"),
98
+ mmap="r",
99
+ )
100
+
101
+ elif model_type == "SentenceTransformer":
102
+ self.model = KeyedVectors.load(
103
+ os.path.join(model_path, "esp_strans_model"),
104
+ mmap="r",
105
+ )
106
+
107
+ self.model_st = SentenceTransformer(
108
+ "sentence-transformers/paraphrase-multilingual-mpnet-base-v2"
109
+ )
110
+
111
+
112
+ # Define the class Semantrix
113
+ class Semantrix:
114
+
115
+ # Define the paths for the configuration files and the data
116
+ base_path = os.path.dirname(os.path.abspath(__file__))
117
+ config_file_path = os.path.join(base_path, "config/")
118
+ config_file_path = os.path.join(base_path, "config/lang.json")
119
+ secret_file_path = os.path.join(base_path, "config/secret.json")
120
+ data_path = os.path.join(base_path, "data/")
121
+
122
+ # Define the class DictWrapper to store the configuration data
123
+ class DictWrapper:
124
+ def __init__(self, data_dict):
125
+ self.__dict__.update(data_dict)
126
+
127
+ # 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
128
+ def __init__(self, lang=0, model_type="SentenceTransformer", session_hash=None):
129
+
130
+ # Load the configuration files
131
+ with open(self.config_file_path, "r") as file:
132
+ self.Config_full = json.load(file)
133
+
134
+ # Load the secret file where the secret words are stored
135
+ with open(self.secret_file_path, "r") as file:
136
+ self.secret = json.load(file)
137
+
138
+ # Set the language of the game
139
+ self.lang = lang
140
+
141
+ self.session_id = str(uuid.uuid4().hex)
142
+
143
+ # Set the model type
144
+ self.model_type = model_type
145
+
146
+ self.session_hash = session_hash
147
+ self.ranking_path = "rankings/ranking_" + str(self.session_hash) + ".txt"
148
+
149
+ self.ranking_data = []
150
+ self.ranking_msg = ""
151
+
152
+ if lang == 1:
153
+ self.Config = self.DictWrapper(self.Config_full["ENG"]["Game"])
154
+ self.secret_dict = self.secret["ENG"]
155
+ self.secret_list = self.secret_dict["basic"]
156
+ else:
157
+ self.Config = self.DictWrapper(self.Config_full["SPA"]["Game"])
158
+ self.secret_dict = self.secret["SPA"]
159
+ self.secret_list = self.secret_dict["basic"]
160
+
161
+ # Create the ranking file
162
+ with open(self.data_path + self.ranking_path, "w+") as file:
163
+ file.write("---------------------------")
164
+
165
+ def reset_game(self):
166
+ self.session_id = str(uuid.uuid4().hex)
167
+ # Load the secret file where the secret words are stored
168
+ with open(self.secret_file_path, "r") as file:
169
+ self.secret = json.load(file)
170
+ self.secret_dict = self.secret["SPA"]
171
+ self.secret_list = self.secret_dict["basic"]
172
+
173
+ def generate_gensim_model(self, model_class, batch_size=32):
174
+ from tqdm import tqdm
175
+
176
+ self.model_trans = KeyedVectors(768)
177
+
178
+ self.model_trans.init_sims(replace=True)
179
+ words = list(model_class.model.key_to_index.keys())
180
+ num_batches = (
181
+ len(words) + batch_size - 1
182
+ ) // batch_size # Calculate the number of batches
183
+
184
+ for batch_index in tqdm(range(num_batches)):
185
+ # Get the batch of words
186
+ start_index = batch_index * batch_size
187
+ end_index = min(start_index + batch_size, len(words))
188
+ batch_words = words[start_index:end_index]
189
+
190
+ # Encode the batch of words
191
+ encoded_vectors = model_class.model_st.encode(
192
+ batch_words,
193
+ convert_to_tensor=True,
194
+ prompt="Encuentra el valor semántico de la palabra: ",
195
+ ).tolist()
196
+
197
+ # # Add vectors to the model
198
+ self.model_trans.add_vectors(batch_words, encoded_vectors)
199
+
200
+ self.model_trans.save("config/strans_models/esp_strans_model_prompt")
201
+
202
+ # Define the function to prepare the game with the selected difficulty
203
+ def prepare_game(self, secret_word_used, difficulty):
204
+
205
+ # Set the secret list depending on the difficulty
206
+ self.secret = self.secret_list[secret_word_used]
207
+ self.secret = self.secret.lower()
208
+
209
+ self.init_time = time.time()
210
+
211
+ # Store the secret word in the words list
212
+ self.words = [self.Config.secret_word]
213
+
214
+ # Store the score in the scores list
215
+ self.scores = [10]
216
+
217
+ # Initialize the game variables
218
+ self.win = False
219
+ self.n = 0
220
+ self.recent_hint = 0
221
+ self.f_dev_avg = 0
222
+ self.last_hint = -1
223
+ self.difficulty = difficulty
224
+
225
+ # Set the number of hints depending on the difficulty
226
+ if self.difficulty == 1:
227
+ self.n = 3
228
+
229
+ # Define the function to generate the ranking file
230
+ def gen_rank(self, repeated):
231
+ ascending_indices = np.argsort(self.scores)
232
+ descending_indices = list(ascending_indices[::-1])
233
+ self.ranking_data.clear()
234
+ k = len(self.words) - 1
235
+ if repeated != -1:
236
+ k = repeated
237
+
238
+ self.ranking_data.append(["#" + str(k), self.words[k], self.scores[k]])
239
+
240
+ self.ranking_data.append("---------------------------")
241
+ for i in descending_indices:
242
+ if i == 0:
243
+ continue
244
+ self.ranking_data.append(["#" + str(i), self.words[i], self.scores[i]])
245
+
246
+ with open(self.data_path + self.ranking_path, "w+") as file:
247
+ for item in self.ranking_data:
248
+ file.write("%s\n" % item)
249
+
250
+ self.ranking_msg = ""
251
+ for item in self.ranking_data:
252
+ self.ranking_msg += f"{item}\n"
253
+
254
+ # Define the function to play the game with the selected word
255
+ def play_game(self, word, model_class):
256
+
257
+ # Convert the word to lowercase
258
+ word = word.lower().strip()
259
+
260
+ # Check if the user wants to give up
261
+ if word == "give_up":
262
+ text = (
263
+ "[lose]"
264
+ + str(self.Config.Feedback_9)
265
+ + self.secret
266
+ + "\n\n"
267
+ + self.Config.Feedback_10
268
+ )
269
+ return text
270
+
271
+ # Check if the word is repeated
272
+ if word in self.words:
273
+ repeated = self.words.index(word)
274
+ else:
275
+ repeated = -1
276
+ self.words.append(word)
277
+
278
+ # Check if the word is in the model already
279
+ if word not in model_class.model.key_to_index.keys():
280
+ # If the word is not in the model, remove it from the words list and provide feedback
281
+ self.words.pop(len(self.words) - 1)
282
+ feedback = (
283
+ "I don't know that word. Try another word."
284
+ if self.lang == 1
285
+ else "No conozco esa palabra. Prueba con otra palabra."
286
+ )
287
+
288
+ feedback += "[rank]" + self.ranking_msg if len(self.words) > 1 else "\n\n"
289
+ return feedback
290
+
291
+ similarity = model_class.model.similarity(self.secret, word)
292
+
293
+ if self.model_type == "word2vec":
294
+ score = np.round(similarity * 10, 2)
295
+ else:
296
+ # log_similarity = np.log10(similarity * 10) if np.any(similarity > 0) else 0
297
+ # score = np.round(
298
+ # np.interp(
299
+ # log_similarity,
300
+ # [0, np.log10(10)],
301
+ # [0, 10],
302
+ # ),
303
+ # 2,
304
+ # )
305
+ score = np.round(similarity * 10, 2)
306
+
307
+ # Remove the word from the score list if it is repeated
308
+ if repeated == -1:
309
+ self.scores.append(score)
310
+
311
+ # Generate the feedback message depending on the score
312
+ if score <= 2.5:
313
+ feedback = self.Config.Feedback_0 + str(score)
314
+ elif score > 2.5 and score <= 6.0:
315
+ feedback = self.Config.Feedback_1 + str(score)
316
+ elif score > 6.0 and score <= 7.0:
317
+ feedback = self.Config.Feedback_2 + str(score)
318
+ elif score > 7.0 and score <= 8:
319
+ feedback = self.Config.Feedback_3 + str(score)
320
+ elif score > 8 and score <= 9.0:
321
+ feedback = self.Config.Feedback_4 + str(score)
322
+ elif score > 9.0 and score < 10.0:
323
+ feedback = self.Config.Feedback_5 + str(score)
324
+ # If the score is 10, the user wins the game
325
+ else:
326
+ self.win = True
327
+ feedback = "[win]" + self.Config.Feedback_8
328
+ self.words[0] = self.secret
329
+ self.words.pop(len(self.words) - 1)
330
+ self.scores.pop(len(self.scores) - 1)
331
+
332
+ # Generate the feedback message depending on the score and the previous score
333
+ if score > self.scores[len(self.scores) - 2] and self.win == False:
334
+ feedback += "\n" + self.Config.Feedback_6
335
+ elif score < self.scores[len(self.scores) - 2] and self.win == False:
336
+ feedback += "\n" + self.Config.Feedback_7
337
+
338
+ ## Hint generation
339
+ # If the difficulty is not 4, calculate the moving average of the scores and the tendency slope
340
+ if self.difficulty != 4 and len(self.scores) > 1:
341
+ mov_avg = calculate_moving_average(self.scores[1:], 5)
342
+
343
+ # 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
344
+ if len(mov_avg) > 1 and self.win == False:
345
+ f_dev = calculate_tendency_slope(mov_avg)
346
+ f_dev_avg = calculate_moving_average(f_dev, 3)
347
+
348
+ # If the tendency slope is negative and the hint has not been given recently (at least three rounds earlier), generate a hint
349
+ if f_dev_avg[len(f_dev_avg) - 1] < 0 and self.recent_hint == 0:
350
+
351
+ # Generate a random hint intro from the hint list
352
+ i = random.randint(0, len(self.Config.hint_intro) - 1)
353
+ feedback += "\n\n[hint]" + self.Config.hint_intro[i]
354
+
355
+ # Generate a dynamic hint
356
+ hint_text, self.n, self.last_hint = hint(
357
+ self.secret,
358
+ self.n,
359
+ model_class.model_st,
360
+ self.last_hint,
361
+ self.lang,
362
+ (
363
+ self.DictWrapper(self.Config_full["ENG"]["Hint"])
364
+ if self.lang == 1
365
+ else self.DictWrapper(self.Config_full["SPA"]["Hint"])
366
+ ),
367
+ )
368
+ feedback += "\n" + hint_text
369
+ self.recent_hint = 3
370
+
371
+ if self.recent_hint != 0:
372
+ self.recent_hint -= 1
373
+
374
+ # Generate the ranking file
375
+ self.gen_rank(repeated)
376
+
377
+ # Add the ranking file to the feedback message
378
+ feedback += "[rank]" + self.ranking_msg if len(self.words) > 1 else "\n\n"
379
+
380
+ # Return the feedback message
381
+ return feedback
382
+
383
+ # Define the function to generate a curiosity hint once the game is over
384
+ def curiosity(self):
385
+
386
+ # Generate a curiosity aboyt the secret word
387
+ feedback = curiosity(
388
+ self.secret,
389
+ (
390
+ self.DictWrapper(self.Config_full["ENG"]["Hint"])
391
+ if self.lang == 1
392
+ else self.DictWrapper(self.Config_full["SPA"]["Hint"])
393
+ ),
394
+ )
395
+
396
+ # Save the ranking file with the plays of the user if the user wins
397
+ with open(self.data_path + self.ranking_path, "r") as original_file:
398
+ file_content = original_file.readlines()[2:]
399
+ new_file_name = f"{self.session_id}-{self.secret}.json"
400
+ play_data = {
401
+ "session_id": self.session_id,
402
+ "datetime": str(datetime.now()),
403
+ "time": time.time() - self.init_time,
404
+ "data": file_content,
405
+ "win": self.win,
406
+ "secret": self.secret,
407
+ "number_of_hints": self.n,
408
+ }
409
+
410
+ with open(self.data_path + "plays/" + new_file_name, "w") as new_file:
411
+ json.dump(play_data, new_file, indent=4)
412
+
413
+ # Return the feedback message
414
+ return feedback
415
+
416
+ def get_session_id(self):
417
+ return self.session_id
gen_model.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # %%
2
+ from game import Semantrix, Model_class
3
+
4
+ # %%
5
+ model = "word2vec"
6
+ model_class = Model_class(lang=0, model_type=model)
7
+
8
+ sem = Semantrix(lang=1, model_type="SentenceTransformer")
9
+
10
+ # %%
11
+ sem.generate_gensim_model(batch_size=128, model_class=model_class)
12
+
13
+ # %%
hints.py ADDED
@@ -0,0 +1,286 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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",
61
+ "content": Config.hint_0_0 # type: ignore
62
+ + secret
63
+ + Config.hint_0_1 # type: ignore
64
+ + secret
65
+ + Config.hint_0_2, # type: ignore
66
+ }
67
+ ],
68
+ temperature=1,
69
+ max_tokens=256,
70
+ top_p=1,
71
+ frequency_penalty=0.5,
72
+ presence_penalty=0,
73
+ )
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)
81
+ output = ireplace("el " + secret, "La palabra secreta", output)
82
+ output = ireplace("los " + secret, "La palabra secreta", output)
83
+ output = ireplace("un " + secret, "La palabra secreta", output)
84
+ output = ireplace("una " + secret, "La palabra secreta", output)
85
+ output = ireplace("unos " + secret, "La palabra secreta", output)
86
+ output = ireplace("unas " + secret, "La palabra secreta", output)
87
+ elif lang == 1:
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",
101
+ "content": Config.hint_1_0 + secret + Config.hint_1_1, # type: ignore
102
+ }
103
+ ],
104
+ temperature=1,
105
+ max_tokens=256,
106
+ top_p=1,
107
+ frequency_penalty=0,
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",
121
+ "content": Config.hint_2_0 + secret + Config.hint_2_1, # type: ignore
122
+ }
123
+ ],
124
+ temperature=1,
125
+ max_tokens=256,
126
+ top_p=1,
127
+ frequency_penalty=0,
128
+ presence_penalty=0,
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",
149
+ "content": Config.hint_3_0, # type: ignore
150
+ }
151
+ ],
152
+ temperature=1.25,
153
+ max_tokens=256,
154
+ top_p=1,
155
+ frequency_penalty=0,
156
+ presence_penalty=0,
157
+ )
158
+ output = str(response.choices[0].message.content)
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",
166
+ "content": Config.hint_3_1 # type: ignore
167
+ + secret
168
+ + Config.hint_3_2, # type: ignore
169
+ }
170
+ ],
171
+ temperature=1.1,
172
+ max_tokens=256,
173
+ top_p=1,
174
+ frequency_penalty=0,
175
+ presence_penalty=0,
176
+ )
177
+ output = str(response.choices[0].message.content)
178
+ output = (output.replace(".", "")).lower()
179
+ words.append(output) # type: ignore
180
+ random.shuffle(words)
181
+ sentences1 = [secret, secret, secret, secret]
182
+ sentences2 = words
183
+ embeddings1 = model.encode(sentences1, convert_to_tensor=True)
184
+ embeddings2 = model.encode(sentences2, convert_to_tensor=True)
185
+
186
+ cosine_scores = util.cos_sim(embeddings1, embeddings2)
187
+ scores = cosine_scores[0].tolist()
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:
195
+ if len(ele) > max_len:
196
+ max_len = len(ele)
197
+ longest_word = ele
198
+
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",
220
+ "content": Config.hint_4_0 # type: ignore
221
+ + secret
222
+ + Config.hint_4_1, # type: ignore
223
+ }
224
+ ],
225
+ temperature=1,
226
+ max_tokens=256,
227
+ top_p=1,
228
+ frequency_penalty=0,
229
+ presence_penalty=0,
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",
237
+ "content": Config.hint_4_2 # type: ignore
238
+ + film_title
239
+ + Config.hint_4_3, # type: ignore
240
+ }
241
+ ],
242
+ temperature=1,
243
+ max_tokens=256,
244
+ top_p=1,
245
+ frequency_penalty=0,
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",
263
+ "content": Config.curiosity + secret + '".',
264
+ }
265
+ ],
266
+ temperature=1,
267
+ max_tokens=256,
268
+ top_p=1,
269
+ frequency_penalty=0,
270
+ presence_penalty=0,
271
+ )
272
+ output = str(response.choices[0].message.content)
273
+
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):
281
+ index_l = text.lower().find(old.lower(), idx)
282
+ if index_l == -1:
283
+ return text
284
+ text = text[:index_l] + new + text[index_l + len(old) :]
285
+ idx = index_l + len(new)
286
+ return text
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ gensim==4.3.0
2
+ sentence_transformers==3.4.1
3
+ openai==1.2.3
4
+ gradio==5.21.0
5
+ transformers==4.49.0
6
+ huggingface-hub==0.28.1
7
+ python-multipart==0.0.18
8
+ httpx==0.27.2
tracking.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+
3
+
4
+ def calculate_moving_average(scores, window_size):
5
+ # Convert the scores list to a NumPy array for better performance
6
+ scores_array = np.array(scores)
7
+
8
+ # Create an array of rolling windows using the np.convolve function
9
+ moving_averages = np.around(
10
+ np.convolve(scores_array, np.ones(window_size) / window_size, mode="valid"), 2
11
+ )
12
+
13
+ return list(moving_averages)
14
+
15
+
16
+ def calculate_tendency_slope(scores):
17
+ # Convert the scores list to a NumPy array for better performance
18
+ scores_array = np.array(scores)
19
+
20
+ # Calculate the first derivative (slope) of the scores
21
+ derivative = np.around(np.gradient(scores_array), 2)
22
+
23
+ return list(derivative)