Upload folder using huggingface_hub
Browse files- .gitignore +223 -0
- README.md +25 -8
- Try Gemma-2-9B.ipynb +218 -0
- __init__.py +0 -0
- agent.py +0 -0
- environment.yml +9 -0
- gdrive_try.ipynb +1 -0
- generate.py +51 -0
- model_outputs/results_batch_api_openai_gpt-4o-mini-2024-07-18.jsonl +0 -0
- oauth_environ_google.sh +1 -0
- play.py +89 -0
- play.sh +3 -0
- play_gradio.py +77 -0
- play_helper.py +213 -77
- play_with_auth.py +158 -0
- read_pkl.py +11 -0
- textgames/__init__.py +8 -6
- textgames/base_game.py +4 -7
- textgames/ordering_text/ordering_text.py +1 -1
- textgames_userauth_generate.py +44 -0
.gitignore
ADDED
@@ -0,0 +1,223 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
*/*.DS_Store
|
2 |
+
.DS_Store
|
3 |
+
|
4 |
+
ssl/
|
5 |
+
problemsets_*
|
6 |
+
|
7 |
+
user_outputs/
|
8 |
+
|
9 |
+
.idea/
|
10 |
+
|
11 |
+
# Created by https://www.gitignore.io/api/macos,linux,django,python,pycharm
|
12 |
+
|
13 |
+
### Django ###
|
14 |
+
*.log
|
15 |
+
*.pot
|
16 |
+
*.pyc
|
17 |
+
__pycache__/
|
18 |
+
local_settings.py
|
19 |
+
db.sqlite3
|
20 |
+
media
|
21 |
+
|
22 |
+
### Linux ###
|
23 |
+
*~
|
24 |
+
|
25 |
+
# temporary files which can be created if a process still has a handle open of a deleted file
|
26 |
+
.fuse_hidden*
|
27 |
+
|
28 |
+
# KDE directory preferences
|
29 |
+
.directory
|
30 |
+
|
31 |
+
# Linux trash folder which might appear on any partition or disk
|
32 |
+
.Trash-*
|
33 |
+
|
34 |
+
# .nfs files are created when an open file is removed but is still being accessed
|
35 |
+
.nfs*
|
36 |
+
|
37 |
+
### macOS ###
|
38 |
+
*.DS_Store
|
39 |
+
.AppleDouble
|
40 |
+
.LSOverride
|
41 |
+
|
42 |
+
# Icon must end with two \r
|
43 |
+
Icon
|
44 |
+
|
45 |
+
# Thumbnails
|
46 |
+
._*
|
47 |
+
|
48 |
+
# Files that might appear in the root of a volume
|
49 |
+
.DocumentRevisions-V100
|
50 |
+
.fseventsd
|
51 |
+
.Spotlight-V100
|
52 |
+
.TemporaryItems
|
53 |
+
.Trashes
|
54 |
+
.VolumeIcon.icns
|
55 |
+
.com.apple.timemachine.donotpresent
|
56 |
+
|
57 |
+
# Directories potentially created on remote AFP share
|
58 |
+
.AppleDB
|
59 |
+
.AppleDesktop
|
60 |
+
Network Trash Folder
|
61 |
+
Temporary Items
|
62 |
+
.apdisk
|
63 |
+
|
64 |
+
### PyCharm ###
|
65 |
+
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
66 |
+
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
67 |
+
|
68 |
+
# User-specific stuff:
|
69 |
+
.idea/**/workspace.xml
|
70 |
+
.idea/**/tasks.xml
|
71 |
+
.idea/dictionaries
|
72 |
+
|
73 |
+
# Sensitive or high-churn files:
|
74 |
+
.idea/**/dataSources/
|
75 |
+
.idea/**/dataSources.ids
|
76 |
+
.idea/**/dataSources.xml
|
77 |
+
.idea/**/dataSources.local.xml
|
78 |
+
.idea/**/sqlDataSources.xml
|
79 |
+
.idea/**/dynamic.xml
|
80 |
+
.idea/**/uiDesigner.xml
|
81 |
+
|
82 |
+
# Gradle:
|
83 |
+
.idea/**/gradle.xml
|
84 |
+
.idea/**/libraries
|
85 |
+
|
86 |
+
# CMake
|
87 |
+
cmake-build-debug/
|
88 |
+
|
89 |
+
# Mongo Explorer plugin:
|
90 |
+
.idea/**/mongoSettings.xml
|
91 |
+
|
92 |
+
## File-based project format:
|
93 |
+
*.iws
|
94 |
+
|
95 |
+
## Plugin-specific files:
|
96 |
+
|
97 |
+
# IntelliJ
|
98 |
+
/out/
|
99 |
+
|
100 |
+
# mpeltonen/sbt-idea plugin
|
101 |
+
.idea_modules/
|
102 |
+
|
103 |
+
# JIRA plugin
|
104 |
+
atlassian-ide-plugin.xml
|
105 |
+
|
106 |
+
# Cursive Clojure plugin
|
107 |
+
.idea/replstate.xml
|
108 |
+
|
109 |
+
# Crashlytics plugin (for Android Studio and IntelliJ)
|
110 |
+
com_crashlytics_export_strings.xml
|
111 |
+
crashlytics.properties
|
112 |
+
crashlytics-build.properties
|
113 |
+
fabric.properties
|
114 |
+
|
115 |
+
### PyCharm Patch ###
|
116 |
+
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
|
117 |
+
|
118 |
+
# *.iml
|
119 |
+
# modules.xml
|
120 |
+
# .idea/misc.xml
|
121 |
+
# *.ipr
|
122 |
+
|
123 |
+
# Sonarlint plugin
|
124 |
+
.idea/sonarlint
|
125 |
+
|
126 |
+
### Python ###
|
127 |
+
# Byte-compiled / optimized / DLL files
|
128 |
+
*.py[cod]
|
129 |
+
*$py.class
|
130 |
+
|
131 |
+
# C extensions
|
132 |
+
*.so
|
133 |
+
|
134 |
+
# Distribution / packaging
|
135 |
+
.Python
|
136 |
+
env/
|
137 |
+
build/
|
138 |
+
develop-eggs/
|
139 |
+
dist/
|
140 |
+
downloads/
|
141 |
+
eggs/
|
142 |
+
.eggs/
|
143 |
+
lib/
|
144 |
+
lib64/
|
145 |
+
parts/
|
146 |
+
sdist/
|
147 |
+
var/
|
148 |
+
wheels/
|
149 |
+
*.egg-info/
|
150 |
+
.installed.cfg
|
151 |
+
*.egg
|
152 |
+
|
153 |
+
# PyInstaller
|
154 |
+
# Usually these files are written by a python script from a template
|
155 |
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
156 |
+
*.manifest
|
157 |
+
*.spec
|
158 |
+
|
159 |
+
# Installer logs
|
160 |
+
pip-log.txt
|
161 |
+
pip-delete-this-directory.txt
|
162 |
+
|
163 |
+
# Unit test / coverage reports
|
164 |
+
htmlcov/
|
165 |
+
.tox/
|
166 |
+
.coverage
|
167 |
+
.coverage.*
|
168 |
+
.cache
|
169 |
+
nosetests.xml
|
170 |
+
coverage.xml
|
171 |
+
*,cover
|
172 |
+
.hypothesis/
|
173 |
+
|
174 |
+
# Translations
|
175 |
+
*.mo
|
176 |
+
|
177 |
+
# Django stuff:
|
178 |
+
|
179 |
+
# Flask stuff:
|
180 |
+
instance/
|
181 |
+
.webassets-cache
|
182 |
+
|
183 |
+
# Scrapy stuff:
|
184 |
+
.scrapy
|
185 |
+
|
186 |
+
# Sphinx documentation
|
187 |
+
docs/_build/
|
188 |
+
|
189 |
+
# PyBuilder
|
190 |
+
target/
|
191 |
+
|
192 |
+
# Jupyter Notebook
|
193 |
+
.ipynb_checkpoints
|
194 |
+
|
195 |
+
# pyenv
|
196 |
+
.python-version
|
197 |
+
|
198 |
+
# celery beat schedule file
|
199 |
+
celerybeat-schedule
|
200 |
+
|
201 |
+
# SageMath parsed files
|
202 |
+
*.sage.py
|
203 |
+
|
204 |
+
# dotenv
|
205 |
+
.env
|
206 |
+
*.env
|
207 |
+
|
208 |
+
# virtualenv
|
209 |
+
.venv
|
210 |
+
venv/
|
211 |
+
ENV/
|
212 |
+
|
213 |
+
# Spyder project settings
|
214 |
+
.spyderproject
|
215 |
+
.spyproject
|
216 |
+
|
217 |
+
# Rope project settings
|
218 |
+
.ropeproject
|
219 |
+
|
220 |
+
# mkdocs documentation
|
221 |
+
/site
|
222 |
+
|
223 |
+
# End of https://www.gitignore.io/api/macos,linux,django,python,pycharm
|
README.md
CHANGED
@@ -1,12 +1,29 @@
|
|
1 |
---
|
2 |
-
title:
|
3 |
-
|
4 |
-
colorFrom: blue
|
5 |
-
colorTo: red
|
6 |
sdk: gradio
|
7 |
-
sdk_version: 5.
|
8 |
-
app_file: app.py
|
9 |
-
pinned: false
|
10 |
---
|
|
|
11 |
|
12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
---
|
2 |
+
title: textgames
|
3 |
+
app_file: play_gradio.py
|
|
|
|
|
4 |
sdk: gradio
|
5 |
+
sdk_version: 5.8.0
|
|
|
|
|
6 |
---
|
7 |
+
# TextGames
|
8 |
|
9 |
+
## Setup
|
10 |
+
```
|
11 |
+
❱❱❱ pip install -r requirements.txt
|
12 |
+
```
|
13 |
+
|
14 |
+
## Play (Terminal)
|
15 |
+
```
|
16 |
+
❱❱❱ python play.py
|
17 |
+
```
|
18 |
+
|
19 |
+
## Play (Web UI)
|
20 |
+
```
|
21 |
+
❱❱❱ pip install gradio
|
22 |
+
❱❱❱ GRADIO_SERVER_PORT=1080 python play_gradio.py
|
23 |
+
```
|
24 |
+
Open `localhost:1080` to access.
|
25 |
+
|
26 |
+
## Optional Environment Varibles
|
27 |
+
```
|
28 |
+
TEXTGAMES_SHOW_HIDDEN_LEVEL=1
|
29 |
+
```
|
Try Gemma-2-9B.ipynb
ADDED
@@ -0,0 +1,218 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"nbformat": 4,
|
3 |
+
"nbformat_minor": 0,
|
4 |
+
"metadata": {
|
5 |
+
"colab": {
|
6 |
+
"private_outputs": true,
|
7 |
+
"provenance": [],
|
8 |
+
"authorship_tag": "ABX9TyPmvDoFpmwAf1QFBJZy7XSQ"
|
9 |
+
},
|
10 |
+
"kernelspec": {
|
11 |
+
"name": "python3",
|
12 |
+
"display_name": "Python 3"
|
13 |
+
},
|
14 |
+
"language_info": {
|
15 |
+
"name": "python"
|
16 |
+
}
|
17 |
+
},
|
18 |
+
"cells": [
|
19 |
+
{
|
20 |
+
"cell_type": "code",
|
21 |
+
"execution_count": null,
|
22 |
+
"metadata": {
|
23 |
+
"id": "Rli_enT6lBDT"
|
24 |
+
},
|
25 |
+
"outputs": [],
|
26 |
+
"source": [
|
27 |
+
"##%%\n",
|
28 |
+
"import os\n",
|
29 |
+
"import torch\n",
|
30 |
+
"import random\n",
|
31 |
+
"import numpy as np\n",
|
32 |
+
"import argparse\n",
|
33 |
+
"import json\n",
|
34 |
+
"import cohere\n",
|
35 |
+
"from openai import OpenAI\n"
|
36 |
+
]
|
37 |
+
},
|
38 |
+
{
|
39 |
+
"cell_type": "code",
|
40 |
+
"source": [
|
41 |
+
"##%%\n",
|
42 |
+
"from tqdm import tqdm\n",
|
43 |
+
"\n",
|
44 |
+
"from collections import Counter\n",
|
45 |
+
"\n",
|
46 |
+
"from transformers import LlamaForCausalLM, AutoTokenizer, AutoModelForCausalLM, AutoModelForSeq2SeqLM\n",
|
47 |
+
"import hashlib\n",
|
48 |
+
"\n",
|
49 |
+
"from textgames import GAME_NAMES, GAME_IDS, LEVELS, LEVELS_HIDDEN, LEVEL_IDS, new_game\n"
|
50 |
+
],
|
51 |
+
"metadata": {
|
52 |
+
"id": "dp1F32B8oSfD"
|
53 |
+
},
|
54 |
+
"execution_count": null,
|
55 |
+
"outputs": []
|
56 |
+
},
|
57 |
+
{
|
58 |
+
"cell_type": "code",
|
59 |
+
"source": [
|
60 |
+
"##%%\n",
|
61 |
+
"gen_model_checkpoint = \"google/gemma-2-9b-it\"\n",
|
62 |
+
"quantize = True"
|
63 |
+
],
|
64 |
+
"metadata": {
|
65 |
+
"id": "jZF8bkUcojTX"
|
66 |
+
},
|
67 |
+
"execution_count": null,
|
68 |
+
"outputs": []
|
69 |
+
},
|
70 |
+
{
|
71 |
+
"cell_type": "code",
|
72 |
+
"source": [
|
73 |
+
"kwargs = {\n",
|
74 |
+
" \"device_map\": \"auto\",\n",
|
75 |
+
"} if quantize else {}"
|
76 |
+
],
|
77 |
+
"metadata": {
|
78 |
+
"id": "VAF5sR9arYzS"
|
79 |
+
},
|
80 |
+
"execution_count": null,
|
81 |
+
"outputs": []
|
82 |
+
},
|
83 |
+
{
|
84 |
+
"cell_type": "code",
|
85 |
+
"source": [
|
86 |
+
"##%%\n",
|
87 |
+
"gen_model = AutoModelForCausalLM.from_pretrained(gen_model_checkpoint, **kwargs)\n",
|
88 |
+
"tokenizer = AutoTokenizer.from_pretrained(gen_model_checkpoint, **kwargs)"
|
89 |
+
],
|
90 |
+
"metadata": {
|
91 |
+
"id": "tzqldl8ooRVL"
|
92 |
+
},
|
93 |
+
"execution_count": null,
|
94 |
+
"outputs": []
|
95 |
+
},
|
96 |
+
{
|
97 |
+
"cell_type": "code",
|
98 |
+
"source": [
|
99 |
+
"gen_model.device"
|
100 |
+
],
|
101 |
+
"metadata": {
|
102 |
+
"id": "FeBUXdkWsWrL"
|
103 |
+
},
|
104 |
+
"execution_count": null,
|
105 |
+
"outputs": []
|
106 |
+
},
|
107 |
+
{
|
108 |
+
"cell_type": "code",
|
109 |
+
"source": [
|
110 |
+
"def get_gemma_response(text):\n",
|
111 |
+
" # global gen_model, tokenizer\n",
|
112 |
+
" messages = [\n",
|
113 |
+
" {\"role\": \"user\", \"content\": text},\n",
|
114 |
+
" ]\n",
|
115 |
+
"\n",
|
116 |
+
" input_ids = tokenizer.apply_chat_template(\n",
|
117 |
+
" messages,\n",
|
118 |
+
" add_generation_prompt=True,\n",
|
119 |
+
" return_tensors=\"pt\"\n",
|
120 |
+
" ).to(gen_model.device)\n",
|
121 |
+
"\n",
|
122 |
+
" terminators = [\n",
|
123 |
+
" tokenizer.eos_token_id,\n",
|
124 |
+
" tokenizer.convert_tokens_to_ids(\"<|eot_id|>\")\n",
|
125 |
+
" ]\n",
|
126 |
+
"\n",
|
127 |
+
" outputs = gen_model.generate(\n",
|
128 |
+
" input_ids,\n",
|
129 |
+
" max_new_tokens=100,\n",
|
130 |
+
" eos_token_id=terminators,\n",
|
131 |
+
" do_sample=True,\n",
|
132 |
+
" temperature=0.2,\n",
|
133 |
+
" top_p=1\n",
|
134 |
+
" )\n",
|
135 |
+
"\n",
|
136 |
+
" response = outputs[0][input_ids.shape[-1]:]\n",
|
137 |
+
" return tokenizer.decode(response, skip_special_tokens=True)"
|
138 |
+
],
|
139 |
+
"metadata": {
|
140 |
+
"id": "R5D4K-P2sPaj"
|
141 |
+
},
|
142 |
+
"execution_count": null,
|
143 |
+
"outputs": []
|
144 |
+
},
|
145 |
+
{
|
146 |
+
"cell_type": "code",
|
147 |
+
"source": [
|
148 |
+
"text = \\\n",
|
149 |
+
"\"\"\"\n",
|
150 |
+
"Given a set of rules to calculate point, sort the set of words in decreasing order.\n",
|
151 |
+
"When there 2 or more words with same point, sort lexicographically.\n",
|
152 |
+
"\n",
|
153 |
+
"Rules:\n",
|
154 |
+
"- every pair of consecutive consonant gets 5 points\n",
|
155 |
+
"- every pair of consecutive vowel gets 3 points\n",
|
156 |
+
"- add 1 point if there exists exactly 1 'g' in the word\n",
|
157 |
+
"- word less than 5 characters gets 10 points\n",
|
158 |
+
"- word starts with gen gets 100 points\n",
|
159 |
+
"- word ends with ta gets -1000 point\n",
|
160 |
+
"\n",
|
161 |
+
"Words:\n",
|
162 |
+
"- genta\n",
|
163 |
+
"- winata\n",
|
164 |
+
"- hudi\n",
|
165 |
+
"- alham\n",
|
166 |
+
"- aji\n",
|
167 |
+
"- ruochen\n",
|
168 |
+
"\n",
|
169 |
+
"Print only the answer.\n",
|
170 |
+
"\"\"\"\n",
|
171 |
+
"\n",
|
172 |
+
"# Answer:\n",
|
173 |
+
"# - aji 10\n",
|
174 |
+
"# - hudi 10\n",
|
175 |
+
"# - ruochen 5 3\n",
|
176 |
+
"# - alham 5\n",
|
177 |
+
"# - genta 5 1 100 -1000\n",
|
178 |
+
"# - winata -1000"
|
179 |
+
],
|
180 |
+
"metadata": {
|
181 |
+
"id": "T_tk4hTGsxsR"
|
182 |
+
},
|
183 |
+
"execution_count": null,
|
184 |
+
"outputs": []
|
185 |
+
},
|
186 |
+
{
|
187 |
+
"cell_type": "code",
|
188 |
+
"source": [
|
189 |
+
"print(get_gemma_response(text))"
|
190 |
+
],
|
191 |
+
"metadata": {
|
192 |
+
"id": "05OI36v6vGoY"
|
193 |
+
},
|
194 |
+
"execution_count": null,
|
195 |
+
"outputs": []
|
196 |
+
},
|
197 |
+
{
|
198 |
+
"cell_type": "code",
|
199 |
+
"source": [
|
200 |
+
"print(get_gemma_response(text))"
|
201 |
+
],
|
202 |
+
"metadata": {
|
203 |
+
"id": "riwXqTc-tmNr"
|
204 |
+
},
|
205 |
+
"execution_count": null,
|
206 |
+
"outputs": []
|
207 |
+
},
|
208 |
+
{
|
209 |
+
"cell_type": "code",
|
210 |
+
"source": [],
|
211 |
+
"metadata": {
|
212 |
+
"id": "T72sUG4_vYUa"
|
213 |
+
},
|
214 |
+
"execution_count": null,
|
215 |
+
"outputs": []
|
216 |
+
}
|
217 |
+
]
|
218 |
+
}
|
__init__.py
ADDED
File without changes
|
agent.py
ADDED
File without changes
|
environment.yml
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# conda env create -f <this_file>
|
2 |
+
name: textgame
|
3 |
+
channels:
|
4 |
+
- conda-forge
|
5 |
+
dependencies:
|
6 |
+
- python=3.11
|
7 |
+
- pip
|
8 |
+
- pip:
|
9 |
+
- -r requirements.txt
|
gdrive_try.ipynb
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[]},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"code","source":["# %load_ext autoreload\n","# %autoreload 2"],"metadata":{"id":"mAaspsfqKYkA"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# %load_ext gradio"],"metadata":{"id":"8fBrlr18CB3F"},"execution_count":null,"outputs":[]},{"cell_type":"code","execution_count":null,"metadata":{"id":"6l8QdIpAB5j_"},"outputs":[],"source":["# %%blocks\n","\n","# from play_gradio import demo"]},{"cell_type":"markdown","source":["---"],"metadata":{"id":"2KNPZna6wl7f"}},{"cell_type":"code","source":["# !pip install -U google-api-python-client google-auth-httplib2 google-auth-oauthlib"],"metadata":{"id":"ExtfLnlMprwD"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["import os.path\n","\n","from google.auth.transport.requests import Request\n","from google.oauth2.credentials import Credentials\n","from google_auth_oauthlib.flow import InstalledAppFlow\n","from googleapiclient.discovery import build\n","from googleapiclient.errors import HttpError"],"metadata":{"id":"ADy9dN7bo_TC"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# If modifying these scopes, delete the file token.json.\n","SCOPES = [\"https://www.googleapis.com/auth/drive.metadata.readonly\"]"],"metadata":{"id":"-1BrLvGaWxZ2"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["def main():\n"," \"\"\"Shows basic usage of the Drive v3 API.\n"," Prints the names and ids of the first 10 files the user has access to.\n"," \"\"\"\n"," creds = None\n"," # The file token.json stores the user's access and refresh tokens, and is\n"," # created automatically when the authorization flow completes for the first\n"," # time.\n"," if os.path.exists(\"token.json\"):\n"," creds = Credentials.from_authorized_user_file(\"token.json\", SCOPES)\n"," # If there are no (valid) credentials available, let the user log in.\n"," if not creds or not creds.valid:\n"," if creds and creds.expired and creds.refresh_token:\n"," creds.refresh(Request())\n"," else:\n"," flow = InstalledAppFlow.from_client_secrets_file(\n"," \"credentials.json\", SCOPES\n"," )\n"," creds = flow.run_local_server(port=0)\n"," # Save the credentials for the next run\n"," with open(\"token.json\", \"w\") as token:\n"," token.write(creds.to_json())\n","\n"," try:\n"," service = build(\"drive\", \"v3\", credentials=creds)\n","\n"," # Call the Drive v3 API\n"," results = (\n"," service.files()\n"," .list(pageSize=10, fields=\"nextPageToken, files(id, name)\")\n"," .execute()\n"," )\n"," items = results.get(\"files\", [])\n","\n"," if not items:\n"," print(\"No files found.\")\n"," return\n"," print(\"Files:\")\n"," for item in items:\n"," print(f\"{item['name']} ({item['id']})\")\n"," except HttpError as error:\n"," # TODO(developer) - Handle errors from drive API.\n"," print(f\"An error occurred: {error}\")"],"metadata":{"id":"-qwFweRKqBZ0"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["main()"],"metadata":{"id":"x62A2GyFqH19"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["if __name__ == \"__main__\":\n"," main()"],"metadata":{"id":"6mwHQ-vFqF-y"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":[],"metadata":{"id":"xqVim7U8qBRn"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":[],"metadata":{"id":"KrIr5DqVwFPR"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["import google.auth\n","from googleapiclient.discovery import build\n","from googleapiclient.errors import HttpError\n","from googleapiclient.http import MediaFileUpload"],"metadata":{"id":"bKn3EWoHtIw3"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["creds, _ = google.auth.default()"],"metadata":{"id":"siH9BRzptIhS"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["creds"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"Bhz_xW99tLDS","executionInfo":{"status":"ok","timestamp":1736790633770,"user_tz":-540,"elapsed":8,"user":{"displayName":"Frederikus Hudi","userId":"06823040510862360282"}},"outputId":"3271b64c-82cd-466f-8321-b5d0ddc884d6"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["<google.oauth2.service_account.Credentials at 0x108b81d90>"]},"metadata":{},"execution_count":3}]},{"cell_type":"code","source":["service = build(\"drive\", \"v3\", credentials=creds)"],"metadata":{"id":"Z3UPsS57tIaP"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["service"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"FhPuaL29ziYw","executionInfo":{"status":"ok","timestamp":1736791252169,"user_tz":-540,"elapsed":9,"user":{"displayName":"Frederikus Hudi","userId":"06823040510862360282"}},"outputId":"66e7a320-3133-4647-9a73-94b4f65ca898"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["<googleapiclient.discovery.Resource at 0x108b8f550>"]},"metadata":{},"execution_count":11}]},{"cell_type":"code","source":["file_metadata = {\"name\": \"wow.txt\"}\n","media = MediaFileUpload(\"wow.txt\")"],"metadata":{"id":"sckvnGYtqBKw"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["media"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"xjvE-Mva03L0","executionInfo":{"status":"ok","timestamp":1736791259359,"user_tz":-540,"elapsed":9,"user":{"displayName":"Frederikus Hudi","userId":"06823040510862360282"}},"outputId":"5eac30fc-1da6-48c3-93ca-40e0174d1816"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["<googleapiclient.http.MediaFileUpload at 0x108c223d0>"]},"metadata":{},"execution_count":12}]},{"cell_type":"code","source":["dir(media)"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"qK-N7udo7u1i","executionInfo":{"status":"ok","timestamp":1736793093612,"user_tz":-540,"elapsed":27,"user":{"displayName":"Frederikus Hudi","userId":"06823040510862360282"}},"outputId":"a961fd11-4fae-4473-94ab-9bc775a6335e"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["['__class__',\n"," '__del__',\n"," '__delattr__',\n"," '__dict__',\n"," '__dir__',\n"," '__doc__',\n"," '__eq__',\n"," '__format__',\n"," '__ge__',\n"," '__getattribute__',\n"," '__getstate__',\n"," '__gt__',\n"," '__hash__',\n"," '__init__',\n"," '__init_subclass__',\n"," '__le__',\n"," '__lt__',\n"," '__module__',\n"," '__ne__',\n"," '__new__',\n"," '__reduce__',\n"," '__reduce_ex__',\n"," '__repr__',\n"," '__setattr__',\n"," '__sizeof__',\n"," '__str__',\n"," '__subclasshook__',\n"," '__weakref__',\n"," '_chunksize',\n"," '_fd',\n"," '_filename',\n"," '_mimetype',\n"," '_resumable',\n"," '_size',\n"," '_to_json',\n"," 'chunksize',\n"," 'from_json',\n"," 'getbytes',\n"," 'has_stream',\n"," 'mimetype',\n"," 'new_from_json',\n"," 'resumable',\n"," 'size',\n"," 'stream',\n"," 'to_json']"]},"metadata":{},"execution_count":49}]},{"cell_type":"code","source":["f = (\n"," service.files()\n"," .create(body=file_metadata, media_body=media, fields=\"id\")\n"," .execute()\n"," )\n","print(f'File ID: {file.get(\"id\")}')"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"HipJX087zir2","executionInfo":{"status":"ok","timestamp":1736792615979,"user_tz":-540,"elapsed":2189,"user":{"displayName":"Frederikus Hudi","userId":"06823040510862360282"}},"outputId":"19a11b14-cc18-455a-a4f1-d1a69f69c72f"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["File ID: 1Rnx0_wttlDG8XiyA_44yHBJeQBHvR_xh\n"]}]},{"cell_type":"code","source":["f.get(\"id\"), type(f)"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"GoMMo7qX5-OH","executionInfo":{"status":"ok","timestamp":1736792629838,"user_tz":-540,"elapsed":10,"user":{"displayName":"Frederikus Hudi","userId":"06823040510862360282"}},"outputId":"ade9f343-a514-4e61-97f9-2550ed55223c"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["('1rE4uYBWAQBFVVB6m7jGqAJncIohTJrWp', dict)"]},"metadata":{},"execution_count":22}]},{"cell_type":"code","source":["f = file.get(\"id\")"],"metadata":{"id":"usWmDGQjzijj"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["f"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"PFCzbG0v0nZ-","executionInfo":{"status":"ok","timestamp":1736791193891,"user_tz":-540,"elapsed":4,"user":{"displayName":"Frederikus Hudi","userId":"06823040510862360282"}},"outputId":"9c8456bd-9996-40a4-e3e6-1e3eb0aafbe9"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["'1Rnx0_wttlDG8XiyA_44yHBJeQBHvR_xh'"]},"metadata":{},"execution_count":9}]},{"cell_type":"code","source":["files = service.files()"],"metadata":{"id":"oh18pUBj3Hn4"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["dir(service)"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"LRsVc6pQ6c_1","executionInfo":{"status":"ok","timestamp":1736792725586,"user_tz":-540,"elapsed":4,"user":{"displayName":"Frederikus Hudi","userId":"06823040510862360282"}},"outputId":"c9ba40eb-f159-4f05-f5b1-53e5e81916da"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["['__class__',\n"," '__delattr__',\n"," '__dict__',\n"," '__dir__',\n"," '__doc__',\n"," '__enter__',\n"," '__eq__',\n"," '__exit__',\n"," '__format__',\n"," '__ge__',\n"," '__getattribute__',\n"," '__getstate__',\n"," '__gt__',\n"," '__hash__',\n"," '__init__',\n"," '__init_subclass__',\n"," '__le__',\n"," '__lt__',\n"," '__module__',\n"," '__ne__',\n"," '__new__',\n"," '__reduce__',\n"," '__reduce_ex__',\n"," '__repr__',\n"," '__setattr__',\n"," '__setstate__',\n"," '__sizeof__',\n"," '__str__',\n"," '__subclasshook__',\n"," '__weakref__',\n"," '_add_basic_methods',\n"," '_add_nested_resources',\n"," '_add_next_methods',\n"," '_baseUrl',\n"," '_credentials_validated',\n"," '_developerKey',\n"," '_dynamic_attrs',\n"," '_http',\n"," '_model',\n"," '_requestBuilder',\n"," '_resourceDesc',\n"," '_rootDesc',\n"," '_schema',\n"," '_set_dynamic_attr',\n"," '_set_service_methods',\n"," '_universe_domain',\n"," '_validate_credentials',\n"," 'about',\n"," 'accessproposals',\n"," 'apps',\n"," 'changes',\n"," 'channels',\n"," 'close',\n"," 'comments',\n"," 'drives',\n"," 'files',\n"," 'new_batch_http_request',\n"," 'operation',\n"," 'operations',\n"," 'permissions',\n"," 'replies',\n"," 'revisions',\n"," 'teamdrives']"]},"metadata":{},"execution_count":31}]},{"cell_type":"code","source":["dir(service.files())"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"40nai28V7Q9B","executionInfo":{"status":"ok","timestamp":1736792941319,"user_tz":-540,"elapsed":14,"user":{"displayName":"Frederikus Hudi","userId":"06823040510862360282"}},"outputId":"4e9488bc-9370-44a3-c5cc-8d009630dc2c"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["['__class__',\n"," '__delattr__',\n"," '__dict__',\n"," '__dir__',\n"," '__doc__',\n"," '__enter__',\n"," '__eq__',\n"," '__exit__',\n"," '__format__',\n"," '__ge__',\n"," '__getattribute__',\n"," '__getstate__',\n"," '__gt__',\n"," '__hash__',\n"," '__init__',\n"," '__init_subclass__',\n"," '__le__',\n"," '__lt__',\n"," '__module__',\n"," '__ne__',\n"," '__new__',\n"," '__reduce__',\n"," '__reduce_ex__',\n"," '__repr__',\n"," '__setattr__',\n"," '__setstate__',\n"," '__sizeof__',\n"," '__str__',\n"," '__subclasshook__',\n"," '__weakref__',\n"," '_add_basic_methods',\n"," '_add_nested_resources',\n"," '_add_next_methods',\n"," '_baseUrl',\n"," '_credentials_validated',\n"," '_developerKey',\n"," '_dynamic_attrs',\n"," '_http',\n"," '_model',\n"," '_requestBuilder',\n"," '_resourceDesc',\n"," '_rootDesc',\n"," '_schema',\n"," '_set_dynamic_attr',\n"," '_set_service_methods',\n"," '_universe_domain',\n"," '_validate_credentials',\n"," 'close',\n"," 'copy',\n"," 'create',\n"," 'delete',\n"," 'download',\n"," 'emptyTrash',\n"," 'export',\n"," 'export_media',\n"," 'generateIds',\n"," 'get',\n"," 'get_media',\n"," 'list',\n"," 'listLabels',\n"," 'listLabels_next',\n"," 'list_next',\n"," 'modifyLabels',\n"," 'update',\n"," 'watch']"]},"metadata":{},"execution_count":34}]},{"cell_type":"code","source":["files.delete(fileId=\"1Rnx0_wttlDG8XiyA_44yHBJeQBHvR_xh\").execute()"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"9zlanjZ96Yz9","executionInfo":{"status":"ok","timestamp":1736793000575,"user_tz":-540,"elapsed":896,"user":{"displayName":"Frederikus Hudi","userId":"06823040510862360282"}},"outputId":"d6ed9310-2efb-48d1-90e5-d5b0bd9536f6"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["''"]},"metadata":{},"execution_count":40}]},{"cell_type":"code","source":["files.list().execute()"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"4guAyYqt7ehH","executionInfo":{"status":"ok","timestamp":1736793001570,"user_tz":-540,"elapsed":441,"user":{"displayName":"Frederikus Hudi","userId":"06823040510862360282"}},"outputId":"d96fe0c6-71b7-4bc3-8add-afbff7bbb054"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["{'kind': 'drive#fileList',\n"," 'incompleteSearch': False,\n"," 'files': [{'kind': 'drive#file',\n"," 'mimeType': 'application/vnd.google-apps.folder',\n"," 'id': '1qStKuVerAQPsXagngfzlNg8PdAR5hupA',\n"," 'name': 'afureteshimau'}]}"]},"metadata":{},"execution_count":41}]},{"cell_type":"code","source":["ret = (\n"," files\n"," .create(body=, media_body=media)\n"," .execute()\n",")"],"metadata":{"id":"qS4ithoH7lBq"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["results = (\n"," service.files()\n"," .list(pageSize=10, fields=\"nextPageToken, files(id, name)\")\n"," .execute()\n"," )"],"metadata":{"id":"DJQwlCAq1IDz"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["results.get(\"files\", [])"],"metadata":{"id":"kKSZI82R1J2s"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":[],"metadata":{"id":"qED1Eo_zKI4o"},"execution_count":null,"outputs":[]}]}
|
generate.py
ADDED
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import random
|
3 |
+
import numpy as np
|
4 |
+
import torch
|
5 |
+
import json
|
6 |
+
|
7 |
+
from tqdm import tqdm
|
8 |
+
from pathlib import Path
|
9 |
+
from textgames import GAME_NAMES, LEVEL_IDS, new_game, game_filename
|
10 |
+
|
11 |
+
|
12 |
+
def set_seed(seed):
|
13 |
+
random.seed(seed)
|
14 |
+
np.random.seed(seed)
|
15 |
+
torch.manual_seed(seed)
|
16 |
+
torch.cuda.manual_seed(seed)
|
17 |
+
|
18 |
+
|
19 |
+
#generate()
|
20 |
+
if __name__ == '__main__':
|
21 |
+
outdir = Path(os.getenv("TEXTGAMES_LOADGAME_DIR", "problemsets"))
|
22 |
+
# os.system(f"rm -rfd {outdir}")
|
23 |
+
os.makedirs(outdir, exist_ok=False) # exists_ok is set to False, making sure regeneration.
|
24 |
+
set_seed(42)
|
25 |
+
|
26 |
+
# level_ids = LEVEL_IDS
|
27 |
+
level_ids = ["1", "2", "3"]
|
28 |
+
session_ids = [
|
29 |
+
f"session_{sid:04}" for sid in range(os.getenv("TEXTGAMES_GENERATE_N", 1000))
|
30 |
+
]
|
31 |
+
|
32 |
+
count_duplicate = 0
|
33 |
+
for game_name in GAME_NAMES:
|
34 |
+
prompts_map = dict()
|
35 |
+
for level_id in level_ids:
|
36 |
+
os.environ["TEXTGAMES_NEWGAME_ERRFILE"] = f"{outdir}/{game_filename(game_name)}_{level_id}.err"
|
37 |
+
for sid in tqdm(session_ids, desc=f"{game_name}_{level_id}"):
|
38 |
+
while True:
|
39 |
+
cur_game = new_game(game_name, level_id)
|
40 |
+
prompt = cur_game._get_prompt()
|
41 |
+
if prompt not in prompts_map:
|
42 |
+
break
|
43 |
+
count_duplicate += 1
|
44 |
+
prompts_map[prompt] = sid
|
45 |
+
print(f"[{game_name}_{level_id}] Duplicate #: {count_duplicate:-4}")
|
46 |
+
|
47 |
+
json_object = json.dumps({sid: prompt for prompt, sid in prompts_map.items()}, indent=4)
|
48 |
+
with open(outdir / f"{game_filename(game_name)}_{level_id}.json", "w") as outfile:
|
49 |
+
outfile.write(json_object)
|
50 |
+
|
51 |
+
print(f"duplicates:{count_duplicate}")
|
model_outputs/results_batch_api_openai_gpt-4o-mini-2024-07-18.jsonl
ADDED
The diff for this file is too large to render.
See raw diff
|
|
oauth_environ_google.sh
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
export $(cat oauth_environ_google.env | xargs)
|
play.py
ADDED
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from termcolor import colored
|
2 |
+
from textgames import GAME_IDS, GAME_NAMES, LEVEL_IDS, LEVELS, new_game, LEVELS_HIDDEN, SINGLE_LINE_GAME_IDS
|
3 |
+
|
4 |
+
import os
|
5 |
+
|
6 |
+
|
7 |
+
def print_text_green(string):
|
8 |
+
print(colored(string, "light_green"))
|
9 |
+
|
10 |
+
def print_text_cyan(string):
|
11 |
+
print(colored(string, "cyan"))
|
12 |
+
|
13 |
+
def print_text_white(string):
|
14 |
+
print(colored(string, "white"))
|
15 |
+
|
16 |
+
|
17 |
+
if __name__ == "__main__":
|
18 |
+
print_text_green("#" * 20)
|
19 |
+
print_text_cyan(" Welcome to")
|
20 |
+
print(" 🎮 " + colored("Text", "white")+ colored("Games", "yellow"))
|
21 |
+
print_text_green("#" * 20)
|
22 |
+
print_text_green("Games:")
|
23 |
+
for i, game_name in zip(range(len(GAME_NAMES)), GAME_NAMES):
|
24 |
+
print_text_green(f"{i+1}. {game_name}")
|
25 |
+
print_text_green("#" * 20)
|
26 |
+
|
27 |
+
cur_game_id = os.getenv("GAME_ID", None)
|
28 |
+
difficulty_level = os.getenv("GAME_LEVEL", None)
|
29 |
+
while cur_game_id is None:
|
30 |
+
user_input = str(input(f"Choose the game> "))
|
31 |
+
|
32 |
+
if user_input in GAME_IDS:
|
33 |
+
cur_game_id = user_input
|
34 |
+
|
35 |
+
print_text_green("#" * 20)
|
36 |
+
print_text_green("Difficulty Levels:")
|
37 |
+
for i, l in zip(LEVEL_IDS, LEVELS):
|
38 |
+
print_text_green(f"{i}. {l}")
|
39 |
+
print_text_green("#" * 20)
|
40 |
+
|
41 |
+
while difficulty_level is None:
|
42 |
+
user_input = str(input(f"Choose the difficulty level> "))
|
43 |
+
if user_input in LEVEL_IDS:
|
44 |
+
difficulty_level = user_input
|
45 |
+
else:
|
46 |
+
print("The difficulty level option is not available.")
|
47 |
+
else:
|
48 |
+
arr = user_input.split("-")
|
49 |
+
if len(arr) == 2 and isinstance(arr[0], str) and isinstance(arr[1], str):
|
50 |
+
if arr[0] in GAME_IDS and arr[1] in LEVEL_IDS:
|
51 |
+
cur_game_id = arr[0]
|
52 |
+
difficulty_level = arr[1]
|
53 |
+
else:
|
54 |
+
print("The game option is not available.")
|
55 |
+
cur_game = None
|
56 |
+
|
57 |
+
this_game_name = GAME_NAMES[GAME_IDS.index(cur_game_id)]
|
58 |
+
this_difficulty_level = (LEVELS + LEVELS_HIDDEN)[LEVEL_IDS.index(difficulty_level)].replace("\t", " ")
|
59 |
+
print_text_green(f"Game chosen: {this_game_name} and Difficulty Level: {this_difficulty_level}")
|
60 |
+
|
61 |
+
solved = False
|
62 |
+
cur_game = new_game(this_game_name, difficulty_level)
|
63 |
+
print(colored("######## Game Start !! ########", "light_green"))
|
64 |
+
print(cur_game.get_prompt())
|
65 |
+
while not solved:
|
66 |
+
contents = []
|
67 |
+
while True:
|
68 |
+
try:
|
69 |
+
line = str(input("\t" if contents else f"Guess>\t"))
|
70 |
+
# automatic break for some games:
|
71 |
+
if cur_game_id in SINGLE_LINE_GAME_IDS:
|
72 |
+
contents.append(line)
|
73 |
+
break
|
74 |
+
if len(line) == 0:
|
75 |
+
break
|
76 |
+
except EOFError:
|
77 |
+
break
|
78 |
+
contents.append(line)
|
79 |
+
|
80 |
+
user_input = '\n'.join(contents)
|
81 |
+
solved, val_msg = cur_game.validate(user_input)
|
82 |
+
if val_msg:
|
83 |
+
print(val_msg)
|
84 |
+
print(f"Attempt #{len(cur_game.attempt_timestamps)}:", "Correct guess" if solved else "Bad guess", end="\n\n")
|
85 |
+
|
86 |
+
print(f"Time to solve: {round(cur_game.attempt_timestamps[-1] - cur_game.start_timestamp, 1)}s")
|
87 |
+
print("Thank you for playing!")
|
88 |
+
|
89 |
+
|
play.sh
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
cur_datetime="$(date '+%Y%m%d_%H%M%S')";
|
2 |
+
echo "Current Time: ${cur_datetime}";
|
3 |
+
python -u play_gradio.py | tee "log/run_${cur_datetime}.log"
|
play_gradio.py
ADDED
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#%%
|
2 |
+
import os
|
3 |
+
# os.environ.setdefault("GRADIO_SERVER_PORT", "1080")
|
4 |
+
# os.environ.setdefault("TEXTGAMES_SHOW_HIDDEN_LEVEL", "1")
|
5 |
+
os.environ.setdefault("TEXTGAMES_LOADGAME_DIR", "problemsets")
|
6 |
+
os.environ.setdefault("TEXTGAMES_LOADGAME_ID", "42")
|
7 |
+
os.environ.setdefault("TEXTGAMES_MOCKUSER", "")
|
8 |
+
os.environ.setdefault("TEXTGAMES_OUTPUT_DIR", "user_outputs")
|
9 |
+
favicon_path = "textgames-scrabble-black2-ss.png"
|
10 |
+
|
11 |
+
#%%
|
12 |
+
from play_helper import css, declare_components, start_new_game, download_from_drive
|
13 |
+
import pandas as pd
|
14 |
+
import gradio as gr
|
15 |
+
|
16 |
+
|
17 |
+
#%%
|
18 |
+
fp_user_auth = f"{os.getenv('TEXTGAMES_OUTPUT_DIR')}/textgames_userauth.tsv"
|
19 |
+
# fp_user_auth_id = "13RLyxV3ys5DGgRIJt5_tO-ILllJ1LDPGasobagZyVLU"
|
20 |
+
fp_user_auth_mime_type = "text/tab-separated-values"
|
21 |
+
|
22 |
+
|
23 |
+
#%%
|
24 |
+
def file_based_auth(username, password):
|
25 |
+
if os.getenv('TEXTGAMES_MOCKUSER', ''):
|
26 |
+
return True
|
27 |
+
download_from_drive(fp_user_auth, mime_type=fp_user_auth_mime_type)
|
28 |
+
df_auth = pd.read_csv(fp_user_auth, sep="\t").dropna(how="any")
|
29 |
+
return len(df_auth.loc[(df_auth.EMAIL == username) & (df_auth.PASSWORD == password)]) > 0
|
30 |
+
|
31 |
+
|
32 |
+
#%%
|
33 |
+
def greet(request: gr.Request):
|
34 |
+
email = os.getenv('TEXTGAMES_MOCKUSER', '')
|
35 |
+
if email:
|
36 |
+
user = {'email': email, 'name': "mockuser"}
|
37 |
+
else:
|
38 |
+
df_auth = pd.read_csv(fp_user_auth, sep="\t").dropna(how="any").drop_duplicates(subset=['EMAIL'])
|
39 |
+
r = df_auth.loc[df_auth.EMAIL == request.username].iloc[0]
|
40 |
+
user = {'email': r.EMAIL, 'name': r.NAME}
|
41 |
+
return f"""
|
42 |
+
Welcome to TextGames, {user['name']}!<br/><{user['email'].replace('@', '{at}')}>
|
43 |
+
""", user, user['email']
|
44 |
+
|
45 |
+
# return f"""
|
46 |
+
# Welcome to TextGames, {user['name']}!<br />
|
47 |
+
# <{user['email'].replace('@', '{at}')}> ({'' if user['email_verified'] else 'NON-'}verified email)
|
48 |
+
# """, None, None
|
49 |
+
|
50 |
+
|
51 |
+
#%%
|
52 |
+
with gr.Blocks(title="TextGames", css=css, delete_cache=(3600, 3600)) as demo:
|
53 |
+
((m, logout_btn, solved_games_df, game_radio, level_radio, new_game_btn, render_toggle),
|
54 |
+
(session_state, is_solved, solved_games, user_state, uid_state),
|
55 |
+
) = declare_components(demo, greet)
|
56 |
+
|
57 |
+
@gr.render(inputs=[game_radio, level_radio, user_state, session_state, uid_state], triggers=[render_toggle.change])
|
58 |
+
def _start_new_game(game_name, level, user, _session_state, _uid_state):
|
59 |
+
if _session_state in [1, 2]:
|
60 |
+
start_new_game(game_name, level, session_state, is_solved, solved_games, user=user, uid=_uid_state)
|
61 |
+
|
62 |
+
demo.launch(
|
63 |
+
auth=file_based_auth,
|
64 |
+
favicon_path=favicon_path if os.path.exists(favicon_path) else None,
|
65 |
+
share=True,
|
66 |
+
)
|
67 |
+
|
68 |
+
|
69 |
+
#%%
|
70 |
+
|
71 |
+
|
72 |
+
#%%
|
73 |
+
|
74 |
+
|
75 |
+
#%%
|
76 |
+
|
77 |
+
|
play_helper.py
CHANGED
@@ -3,11 +3,8 @@ import os
|
|
3 |
import time
|
4 |
import pandas as pd
|
5 |
import gradio as gr
|
6 |
-
|
7 |
-
import
|
8 |
-
from googleapiclient.discovery import build
|
9 |
-
from googleapiclient.errors import HttpError
|
10 |
-
from googleapiclient.http import MediaFileUpload
|
11 |
|
12 |
from textgames import GAME_NAMES, LEVEL_IDS, LEVELS, new_game, preload_game, game_filename
|
13 |
from textgames.islands.islands import Islands
|
@@ -17,7 +14,14 @@ from textgames.ordering_text.ordering_text import OrderingTextGame
|
|
17 |
|
18 |
|
19 |
# %%
|
20 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
with gr.Row():
|
22 |
with gr.Column(scale=1):
|
23 |
m = gr.Markdown("Welcome to TextGames!", elem_id="md-greeting")
|
@@ -29,10 +33,44 @@ def declare_components():
|
|
29 |
level_radio = gr.Radio(LEVELS, label="Level", elem_id="radio-level-name")
|
30 |
new_game_btn = gr.Button("Start Game", elem_id="btn-start-game")
|
31 |
render_toggle = gr.Checkbox(False, visible=False, interactive=False)
|
32 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
|
34 |
|
35 |
# %%
|
|
|
|
|
|
|
|
|
|
|
36 |
_creds_dict = {
|
37 |
"type": "service_account",
|
38 |
"project_id": os.getenv("GOOGLE_AUTH_CREDS_PROJECT_ID", ""),
|
@@ -51,6 +89,14 @@ _service = build("drive", "v3", credentials=_creds)
|
|
51 |
_files = _service.files()
|
52 |
|
53 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
# %%
|
55 |
js_remove_input_helper = """(s) => {
|
56 |
var el = document.getElementById('lintao-container');
|
@@ -84,9 +130,10 @@ function island() {{
|
|
84 |
container.style.display = 'grid';
|
85 |
container.style.gridTemplateColumns = container.style.gridTemplateRows = `repeat(${{grid_N}}, ${{grid_px}}px)`;
|
86 |
container.style.gap = '1px';
|
87 |
-
container.style.border = '2px solid
|
88 |
container.style.width = 'max-content';
|
89 |
container.style.margin = '5px 0px 5px 40px';
|
|
|
90 |
container.id = 'lintao-container';
|
91 |
|
92 |
for (let i = 0; i < grid_N; ++i) {{
|
@@ -98,7 +145,7 @@ function island() {{
|
|
98 |
cell.style.alignItems = 'center';
|
99 |
cell.style.justifyContent = 'center';
|
100 |
cell.style.fontSize = `${{grid_px/2}}px`;
|
101 |
-
cell.style.border = '1px solid
|
102 |
cell.style.cursor = 'pointer';
|
103 |
cell.id = `lintao-cell-${{i}}-${{j}}`;
|
104 |
|
@@ -130,6 +177,8 @@ function island() {{
|
|
130 |
|
131 |
js_island_submit = """
|
132 |
function island_submit(textarea, io_history) {{
|
|
|
|
|
133 |
const grid_N = {N};
|
134 |
var ret = "";
|
135 |
for (let i = 0; i < grid_N; ++i) {{
|
@@ -149,7 +198,7 @@ function sudoku() {{
|
|
149 |
const N = {N};
|
150 |
const grid_N = N*N,
|
151 |
grid_px = 50,
|
152 |
-
border_px =
|
153 |
const mat = {mat};
|
154 |
|
155 |
let is_numeric_sudoku = false;
|
@@ -165,16 +214,17 @@ function sudoku() {{
|
|
165 |
const container = document.createElement('div');
|
166 |
container.style.display = 'grid';
|
167 |
container.style.gridTemplateColumns = container.style.gridTemplateRows = `repeat(${{grid_N}}, ${{grid_px}}px)`;
|
168 |
-
container.style.
|
169 |
-
container.style.border = '${{border_px}}px solid white';
|
170 |
container.style.width = 'max-content';
|
171 |
container.style.margin = '5px 0px 5px 40px';
|
|
|
172 |
container.id = 'lintao-container';
|
173 |
|
174 |
// Generate the grid
|
|
|
175 |
for (let i = 0; i < grid_N; ++i) {{
|
176 |
for (let j = 0; j < grid_N; ++j) {{
|
177 |
-
const cell = document.createElement('
|
178 |
cell.type = 'text';
|
179 |
cell.maxLength = 1;
|
180 |
cell.style.width = cell.style.height = `${{grid_px}}px`;
|
@@ -183,32 +233,35 @@ function sudoku() {{
|
|
183 |
cell.style.justifyContent = 'center';
|
184 |
cell.style.textAlign = 'center';
|
185 |
cell.style.fontSize = `${{grid_px/2}}px`;
|
186 |
-
cell.style.border = '1px solid
|
187 |
-
cell.style.
|
188 |
-
cell.style.
|
|
|
|
|
189 |
cell.id = `lintao-cell-${{i}}-${{j}}`;
|
190 |
|
191 |
if (mat[i][j] != '_') {{
|
192 |
-
cell.
|
193 |
-
cell.style.color = '
|
194 |
cell.disabled = true;
|
|
|
|
|
|
|
195 |
}}
|
196 |
|
197 |
-
//cell.style.color = 'black';
|
198 |
-
//cell.style.outline = 'none';
|
199 |
|
200 |
-
if (j % N === 0) cell.style.borderLeft = `${{border_px}}px solid
|
201 |
-
if (j % N === (N-1)) cell.style.borderRight = `${{border_px}}px solid
|
202 |
-
if (i % N === 0) cell.style.borderTop = `${{border_px}}px solid
|
203 |
-
if (i % N === (N-1)) cell.style.borderBottom = `${{border_px}}px solid
|
204 |
|
205 |
// Allow only numbers 1-9 or A-I
|
206 |
cell.addEventListener('input', (e) => {{
|
207 |
-
if ((N === 2 && (!(is_numeric_sudoku?/^[1-4]$/:/^[A-Da-d]$/).test(e.target.
|
208 |
-
(N === 3 && (!(is_numeric_sudoku?/^[1-9]$/:/^[A-Ia-i]$/).test(e.target.
|
209 |
-
e.target.
|
210 |
}}
|
211 |
-
e.target.
|
212 |
}});
|
213 |
|
214 |
container.appendChild(cell);
|
@@ -228,16 +281,16 @@ function sudoku() {{
|
|
228 |
const currentCol = i % grid_N;
|
229 |
|
230 |
if (currentRow === row || currentCol === col || (Math.floor(currentRow / N) === Math.floor(row / N) && Math.floor(currentCol / N) === Math.floor(col / N))) {{
|
231 |
-
cell.
|
232 |
}} else {{
|
233 |
-
cell.
|
234 |
}}
|
235 |
}}
|
236 |
}});
|
237 |
|
238 |
container.addEventListener('focusout', () => {{
|
239 |
for (let i = 0; i < grid_N * grid_N; i++) {{
|
240 |
-
container.children[i].
|
241 |
}}
|
242 |
}});
|
243 |
|
@@ -248,13 +301,15 @@ function sudoku() {{
|
|
248 |
|
249 |
js_sudoku_submit = """
|
250 |
function sudoku_submit(textarea, io_history) {{
|
|
|
|
|
251 |
const N = {N};
|
252 |
const grid_N = N*N;
|
253 |
var ret = "";
|
254 |
for (let i = 0; i < grid_N; ++i) {{
|
255 |
if (i > 0) ret += '\\n';
|
256 |
for (let j = 0; j < grid_N; ++j) {{
|
257 |
-
ret += document.getElementById(`lintao-cell-${{i}}-${{j}}`).
|
258 |
}}
|
259 |
}}
|
260 |
return [ret, io_history];
|
@@ -272,9 +327,10 @@ function crossword() {{
|
|
272 |
container.style.display = 'grid';
|
273 |
container.style.gridTemplateColumns = container.style.gridTemplateRows = `repeat(${{grid_N}}, ${{grid_px}}px)`;
|
274 |
container.style.gap = '1px';
|
275 |
-
container.style.border = '2px solid
|
276 |
container.style.width = 'max-content';
|
277 |
container.style.margin = '5px 0px 5px 40px';
|
|
|
278 |
container.id = 'lintao-container';
|
279 |
|
280 |
// Generate the grid
|
@@ -290,8 +346,8 @@ function crossword() {{
|
|
290 |
cell.style.justifyContent = 'center';
|
291 |
cell.style.textAlign = 'center';
|
292 |
cell.style.fontSize = `${{grid_px/2}}px`;
|
293 |
-
cell.style.border = '1px solid
|
294 |
-
cell.style.backgroundColor = '
|
295 |
cell.style.cursor = 'pointer';
|
296 |
cell.id = `lintao-cell-${{i}}-${{j}}`;
|
297 |
|
@@ -313,6 +369,8 @@ function crossword() {{
|
|
313 |
|
314 |
js_crossword_submit = """
|
315 |
function crossword_submit(textarea, io_history) {{
|
|
|
|
|
316 |
const grid_N = {N};
|
317 |
var ret = "";
|
318 |
for (let i = 0; i < grid_N; ++i) {{
|
@@ -333,7 +391,7 @@ function ordering() {{
|
|
333 |
listContainer.style.listStyle = 'none';
|
334 |
listContainer.style.padding = '0';
|
335 |
listContainer.style.width = '20em';
|
336 |
-
listContainer.style.border = '2px solid
|
337 |
listContainer.style.margin = '5px 0px 5px 40px';
|
338 |
listContainer.id = 'lintao-container';
|
339 |
|
@@ -346,9 +404,9 @@ function ordering() {{
|
|
346 |
listItem.textContent = itemText;
|
347 |
listItem.draggable = true;
|
348 |
listItem.style.padding = '10px';
|
349 |
-
listItem.style.border = '1px solid
|
350 |
listItem.style.margin = '3px';
|
351 |
-
listItem.style.backgroundColor = '
|
352 |
listItem.style.cursor = 'grab';
|
353 |
listItem.id = `lintao-item-${{index}}`;
|
354 |
|
@@ -356,16 +414,16 @@ function ordering() {{
|
|
356 |
listItem.addEventListener('dragstart', (e) => {{
|
357 |
const draggedIndex = Array.from(listContainer.children).indexOf(listItem);
|
358 |
e.dataTransfer.setData('text/plain', draggedIndex);
|
359 |
-
listItem.style.backgroundColor = '
|
360 |
}});
|
361 |
|
362 |
listItem.addEventListener('dragover', (e) => {{
|
363 |
e.preventDefault();
|
364 |
-
listItem.style.backgroundColor = '
|
365 |
}});
|
366 |
|
367 |
listItem.addEventListener('dragleave', () => {{
|
368 |
-
listItem.style.backgroundColor = '
|
369 |
}});
|
370 |
|
371 |
listItem.addEventListener('drop', (e) => {{
|
@@ -379,11 +437,11 @@ function ordering() {{
|
|
379 |
listContainer.insertBefore(draggedItem, targetIndex > draggedIndex ? listItem.nextSibling : listItem);
|
380 |
}}
|
381 |
|
382 |
-
listItem.style.backgroundColor = '
|
383 |
}});
|
384 |
|
385 |
listItem.addEventListener('dragend', () => {{
|
386 |
-
listItem.style.backgroundColor = '
|
387 |
}});
|
388 |
|
389 |
listContainer.appendChild(listItem);
|
@@ -396,9 +454,10 @@ function ordering() {{
|
|
396 |
|
397 |
js_ordering_submit = """
|
398 |
function ordering_submit(textarea, io_history) {{
|
|
|
|
|
399 |
var ret = "";
|
400 |
-
|
401 |
-
document.getElementById("lintao-container").childNodes.forEach(
|
402 |
(c, i) => {{
|
403 |
if (i>0) ret += '\\n';
|
404 |
ret += c.textContent;
|
@@ -424,6 +483,68 @@ def _get_file_output(game_name, level_id, fn_prefix):
|
|
424 |
return f"{fd}/{fn_prefix}_-_{game_filename(game_name)}_{level_id}.pkl"
|
425 |
|
426 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
427 |
# %%
|
428 |
def start_new_game(game_name, level, session_state_component, is_solved_component, solved_games_component,
|
429 |
user=None, show_timer=False, uid=None):
|
@@ -441,9 +562,12 @@ def start_new_game(game_name, level, session_state_component, is_solved_componen
|
|
441 |
preload_game(game_name, difficulty_level, user)
|
442 |
)
|
443 |
cur_game.attach_stats_output_(fp_out)
|
444 |
-
cur_game.flush_stats_(
|
445 |
|
446 |
def add_msg(new_msg, prev_msg):
|
|
|
|
|
|
|
447 |
user_input = '\n'.join(new_msg.split())
|
448 |
solved, val_msg = cur_game.validate(user_input)
|
449 |
response = ("Correct guess" if solved else "Bad guess (Wrong Answer)") + "\n" + val_msg
|
@@ -455,10 +579,8 @@ def start_new_game(game_name, level, session_state_component, is_solved_componen
|
|
455 |
|
456 |
gr.Markdown(
|
457 |
"""
|
458 |
-
> ### ‼️ Do
|
459 |
> #### ⚠️ Refreshing the page equals "Give-up 😭" ⚠️
|
460 |
-
|
461 |
-
|
462 |
"""
|
463 |
)
|
464 |
showhide_helper_btn = gr.Button("Show Input Helper (disabling manual input)", elem_id="lintao-helper-btn")
|
@@ -500,48 +622,52 @@ def start_new_game(game_name, level, session_state_component, is_solved_componen
|
|
500 |
|
501 |
def _forfeiting(confirmed, _solved_games):
|
502 |
if confirmed:
|
|
|
503 |
cur_game.finish_stats_(forfeit=True)
|
504 |
-
if level in LEVELS
|
505 |
_solved_games[game_name].append(level)
|
|
|
506 |
return 0, _solved_games
|
507 |
return 1, _solved_games
|
508 |
-
give_up_checkbox.change(
|
509 |
-
|
|
|
|
|
|
|
|
|
|
|
510 |
|
511 |
-
def game_is_solved(_is_solved, _session_state, _solved_games):
|
512 |
if _is_solved:
|
513 |
-
if level in LEVELS
|
514 |
_solved_games[game_name].append(level)
|
515 |
return (
|
516 |
2,
|
517 |
gr.update(visible=False, interactive=False),
|
518 |
gr.update(visible=False, interactive=False),
|
519 |
-
gr.update(visible=True, interactive=True),
|
520 |
_solved_games,
|
|
|
521 |
)
|
522 |
else:
|
523 |
return (
|
524 |
-
_session_state, gr.update(), gr.update(), gr.update()
|
525 |
)
|
526 |
|
527 |
-
def
|
528 |
-
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
_files.create(body=file_metadata, media_body=media).execute()
|
534 |
-
except HttpError as error:
|
535 |
-
print(f"An error occurred: {error}")
|
536 |
|
537 |
is_solved_component.change(
|
538 |
game_is_solved,
|
539 |
[is_solved_component, session_state_component, solved_games_component],
|
540 |
-
[session_state_component, submit_btn, give_up_btn,
|
|
|
|
|
541 |
)
|
542 |
finish_btn.click(
|
543 |
-
upload_to_drive, None, None,
|
544 |
-
).then(
|
545 |
lambda: (0, 0), None, [session_state_component, is_solved_component]
|
546 |
)
|
547 |
|
@@ -556,24 +682,34 @@ def check_to_start_new_game(game_name, level, user=None, uid=None):
|
|
556 |
raise gr.Error(f"You have done this game already.<br/>{game_name} - {level}")
|
557 |
if user is None:
|
558 |
gr.Warning("no user, game will be generated randomly")
|
559 |
-
else:
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
return 1
|
565 |
|
566 |
|
567 |
# %%
|
568 |
-
def check_played_game(solved_games, uid):
|
|
|
|
|
|
|
|
|
569 |
ret = dict()
|
570 |
for game_name in solved_games.keys():
|
571 |
cur = []
|
572 |
-
for level, level_id in zip(LEVELS
|
573 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
574 |
cur.append(level)
|
575 |
ret[game_name] = cur
|
576 |
-
return ret
|
577 |
|
578 |
|
579 |
# %%
|
|
|
3 |
import time
|
4 |
import pandas as pd
|
5 |
import gradio as gr
|
6 |
+
import hashlib
|
7 |
+
from io import BytesIO
|
|
|
|
|
|
|
8 |
|
9 |
from textgames import GAME_NAMES, LEVEL_IDS, LEVELS, new_game, preload_game, game_filename
|
10 |
from textgames.islands.islands import Islands
|
|
|
14 |
|
15 |
|
16 |
# %%
|
17 |
+
import google.auth
|
18 |
+
from googleapiclient.discovery import build
|
19 |
+
from googleapiclient.errors import HttpError
|
20 |
+
from googleapiclient.http import MediaFileUpload, MediaIoBaseDownload
|
21 |
+
|
22 |
+
|
23 |
+
# %%
|
24 |
+
def declare_components(demo, greet):
|
25 |
with gr.Row():
|
26 |
with gr.Column(scale=1):
|
27 |
m = gr.Markdown("Welcome to TextGames!", elem_id="md-greeting")
|
|
|
33 |
level_radio = gr.Radio(LEVELS, label="Level", elem_id="radio-level-name")
|
34 |
new_game_btn = gr.Button("Start Game", elem_id="btn-start-game")
|
35 |
render_toggle = gr.Checkbox(False, visible=False, interactive=False)
|
36 |
+
|
37 |
+
# cur_game_start = gr.BrowserState()
|
38 |
+
session_state = gr.State(0) # 0: menu selection, 1: game is ongoing, 2: game is solved.
|
39 |
+
is_solved = gr.State(0)
|
40 |
+
solved_games = gr.State({g: [] for _, g in game_radio.choices})
|
41 |
+
user_state = gr.State()
|
42 |
+
uid_state = gr.State()
|
43 |
+
|
44 |
+
session_state.change(
|
45 |
+
lambda s: session_state_change_fn(s, 2, 0, 2, 0),
|
46 |
+
[session_state], [game_radio, level_radio, new_game_btn, logout_btn], js=js_remove_input_helper,
|
47 |
+
)
|
48 |
+
new_game_btn.click(check_to_start_new_game, [game_radio, level_radio, user_state, uid_state], [session_state])
|
49 |
+
solved_games.change(solved_games_change_fn, solved_games, solved_games_df)
|
50 |
+
session_state.change(lambda s, r: (not r if s in [0, 1] else r), [session_state, render_toggle], [render_toggle])
|
51 |
+
|
52 |
+
demo.load(
|
53 |
+
greet, None, [m, user_state, uid_state], js=js_solved_games_df_and_remove_footers
|
54 |
+
).then(
|
55 |
+
lambda: gr.update(interactive=False), None, [new_game_btn],
|
56 |
+
).then(
|
57 |
+
check_played_game, [solved_games, uid_state], [solved_games, solved_games_df]
|
58 |
+
).then(
|
59 |
+
lambda: gr.update(interactive=True), None, [new_game_btn],
|
60 |
+
)
|
61 |
+
|
62 |
+
return (
|
63 |
+
(m, logout_btn, solved_games_df, game_radio, level_radio, new_game_btn, render_toggle),
|
64 |
+
(session_state, is_solved, solved_games, user_state, uid_state),
|
65 |
+
)
|
66 |
|
67 |
|
68 |
# %%
|
69 |
+
_cksm_methods, _cksm_methods_str = (
|
70 |
+
[hashlib.md5, hashlib.sha1], "md5Checksum, sha1Checksum",
|
71 |
+
# [hashlib.md5, hashlib.sha1, hashlib.sha256], "md5Checksum, sha1Checksum, sha256Checksum",
|
72 |
+
)
|
73 |
+
_folder_id = "1qStKuVerAQPsXagngfzlNg8PdAR5hupA"
|
74 |
_creds_dict = {
|
75 |
"type": "service_account",
|
76 |
"project_id": os.getenv("GOOGLE_AUTH_CREDS_PROJECT_ID", ""),
|
|
|
89 |
_files = _service.files()
|
90 |
|
91 |
|
92 |
+
#%%
|
93 |
+
css = """
|
94 |
+
#lintao-helper-btn {background: darkgreen; color: white;}
|
95 |
+
.lintao-cell-highlight {background: var(--border-color-primary);}
|
96 |
+
//.lintao-border {border-style: solid; border-color: var(--body-text-color-subdued);}
|
97 |
+
"""
|
98 |
+
|
99 |
+
|
100 |
# %%
|
101 |
js_remove_input_helper = """(s) => {
|
102 |
var el = document.getElementById('lintao-container');
|
|
|
130 |
container.style.display = 'grid';
|
131 |
container.style.gridTemplateColumns = container.style.gridTemplateRows = `repeat(${{grid_N}}, ${{grid_px}}px)`;
|
132 |
container.style.gap = '1px';
|
133 |
+
container.style.border = '2px solid';
|
134 |
container.style.width = 'max-content';
|
135 |
container.style.margin = '5px 0px 5px 40px';
|
136 |
+
container.style.padding = '1px';
|
137 |
container.id = 'lintao-container';
|
138 |
|
139 |
for (let i = 0; i < grid_N; ++i) {{
|
|
|
145 |
cell.style.alignItems = 'center';
|
146 |
cell.style.justifyContent = 'center';
|
147 |
cell.style.fontSize = `${{grid_px/2}}px`;
|
148 |
+
cell.style.border = '1px solid var(--body-text-color-subdued)';
|
149 |
cell.style.cursor = 'pointer';
|
150 |
cell.id = `lintao-cell-${{i}}-${{j}}`;
|
151 |
|
|
|
177 |
|
178 |
js_island_submit = """
|
179 |
function island_submit(textarea, io_history) {{
|
180 |
+
const container = document.getElementById("lintao-container")
|
181 |
+
if (container === null) return [textarea, io_history];
|
182 |
const grid_N = {N};
|
183 |
var ret = "";
|
184 |
for (let i = 0; i < grid_N; ++i) {{
|
|
|
198 |
const N = {N};
|
199 |
const grid_N = N*N,
|
200 |
grid_px = 50,
|
201 |
+
border_px = 2;
|
202 |
const mat = {mat};
|
203 |
|
204 |
let is_numeric_sudoku = false;
|
|
|
214 |
const container = document.createElement('div');
|
215 |
container.style.display = 'grid';
|
216 |
container.style.gridTemplateColumns = container.style.gridTemplateRows = `repeat(${{grid_N}}, ${{grid_px}}px)`;
|
217 |
+
container.style.border = `${{border_px}}px solid`;
|
|
|
218 |
container.style.width = 'max-content';
|
219 |
container.style.margin = '5px 0px 5px 40px';
|
220 |
+
container.style.padding = '0px';
|
221 |
container.id = 'lintao-container';
|
222 |
|
223 |
// Generate the grid
|
224 |
+
const highlightClass = 'lintao-cell-highlight';
|
225 |
for (let i = 0; i < grid_N; ++i) {{
|
226 |
for (let j = 0; j < grid_N; ++j) {{
|
227 |
+
const cell = document.createElement('div');
|
228 |
cell.type = 'text';
|
229 |
cell.maxLength = 1;
|
230 |
cell.style.width = cell.style.height = `${{grid_px}}px`;
|
|
|
233 |
cell.style.justifyContent = 'center';
|
234 |
cell.style.textAlign = 'center';
|
235 |
cell.style.fontSize = `${{grid_px/2}}px`;
|
236 |
+
cell.style.border = '1px solid var(--body-text-color-subdued)';
|
237 |
+
cell.style.margin = '0px';
|
238 |
+
//cell.style.outline = 'none';
|
239 |
+
//cell.style.color = 'var(--body-text-color)';
|
240 |
+
//cell.style.backgroundColor = 'black';
|
241 |
cell.id = `lintao-cell-${{i}}-${{j}}`;
|
242 |
|
243 |
if (mat[i][j] != '_') {{
|
244 |
+
cell.textContent = mat[i][j];
|
245 |
+
cell.style.color = 'var(--block-title-text-color)';
|
246 |
cell.disabled = true;
|
247 |
+
}} else {{
|
248 |
+
cell.style.cursor = 'pointer';
|
249 |
+
cell.contentEditable = "true";
|
250 |
}}
|
251 |
|
|
|
|
|
252 |
|
253 |
+
if (j % N === 0) cell.style.borderLeft = `${{border_px}}px solid var(--body-text-color)`;
|
254 |
+
if (j % N === (N-1)) cell.style.borderRight = `${{border_px}}px solid var(--body-text-color)`;
|
255 |
+
if (i % N === 0) cell.style.borderTop = `${{border_px}}px solid var(--body-text-color)`;
|
256 |
+
if (i % N === (N-1)) cell.style.borderBottom = `${{border_px}}px solid var(--body-text-color)`;
|
257 |
|
258 |
// Allow only numbers 1-9 or A-I
|
259 |
cell.addEventListener('input', (e) => {{
|
260 |
+
if ((N === 2 && (!(is_numeric_sudoku?/^[1-4]$/:/^[A-Da-d]$/).test(e.target.textContent))) ||
|
261 |
+
(N === 3 && (!(is_numeric_sudoku?/^[1-9]$/:/^[A-Ia-i]$/).test(e.target.textContent)))) {{
|
262 |
+
e.target.textContent = '';
|
263 |
}}
|
264 |
+
e.target.textContent = e.target.textContent.toUpperCase();
|
265 |
}});
|
266 |
|
267 |
container.appendChild(cell);
|
|
|
281 |
const currentCol = i % grid_N;
|
282 |
|
283 |
if (currentRow === row || currentCol === col || (Math.floor(currentRow / N) === Math.floor(row / N) && Math.floor(currentCol / N) === Math.floor(col / N))) {{
|
284 |
+
cell.classList.add(highlightClass);
|
285 |
}} else {{
|
286 |
+
cell.classList.remove(highlightClass);
|
287 |
}}
|
288 |
}}
|
289 |
}});
|
290 |
|
291 |
container.addEventListener('focusout', () => {{
|
292 |
for (let i = 0; i < grid_N * grid_N; i++) {{
|
293 |
+
container.children[i].classList.remove(highlightClass);
|
294 |
}}
|
295 |
}});
|
296 |
|
|
|
301 |
|
302 |
js_sudoku_submit = """
|
303 |
function sudoku_submit(textarea, io_history) {{
|
304 |
+
const container = document.getElementById("lintao-container")
|
305 |
+
if (container === null) return [textarea, io_history];
|
306 |
const N = {N};
|
307 |
const grid_N = N*N;
|
308 |
var ret = "";
|
309 |
for (let i = 0; i < grid_N; ++i) {{
|
310 |
if (i > 0) ret += '\\n';
|
311 |
for (let j = 0; j < grid_N; ++j) {{
|
312 |
+
ret += document.getElementById(`lintao-cell-${{i}}-${{j}}`).textContent;
|
313 |
}}
|
314 |
}}
|
315 |
return [ret, io_history];
|
|
|
327 |
container.style.display = 'grid';
|
328 |
container.style.gridTemplateColumns = container.style.gridTemplateRows = `repeat(${{grid_N}}, ${{grid_px}}px)`;
|
329 |
container.style.gap = '1px';
|
330 |
+
container.style.border = '2px solid';
|
331 |
container.style.width = 'max-content';
|
332 |
container.style.margin = '5px 0px 5px 40px';
|
333 |
+
container.style.padding = '1px';
|
334 |
container.id = 'lintao-container';
|
335 |
|
336 |
// Generate the grid
|
|
|
346 |
cell.style.justifyContent = 'center';
|
347 |
cell.style.textAlign = 'center';
|
348 |
cell.style.fontSize = `${{grid_px/2}}px`;
|
349 |
+
cell.style.border = '1px solid var(--body-text-color-subdued)';
|
350 |
+
cell.style.backgroundColor = 'var(--body-background-fill)';
|
351 |
cell.style.cursor = 'pointer';
|
352 |
cell.id = `lintao-cell-${{i}}-${{j}}`;
|
353 |
|
|
|
369 |
|
370 |
js_crossword_submit = """
|
371 |
function crossword_submit(textarea, io_history) {{
|
372 |
+
const container = document.getElementById("lintao-container")
|
373 |
+
if (container === null) return [textarea, io_history];
|
374 |
const grid_N = {N};
|
375 |
var ret = "";
|
376 |
for (let i = 0; i < grid_N; ++i) {{
|
|
|
391 |
listContainer.style.listStyle = 'none';
|
392 |
listContainer.style.padding = '0';
|
393 |
listContainer.style.width = '20em';
|
394 |
+
listContainer.style.border = '2px solid';
|
395 |
listContainer.style.margin = '5px 0px 5px 40px';
|
396 |
listContainer.id = 'lintao-container';
|
397 |
|
|
|
404 |
listItem.textContent = itemText;
|
405 |
listItem.draggable = true;
|
406 |
listItem.style.padding = '10px';
|
407 |
+
listItem.style.border = '1px solid';
|
408 |
listItem.style.margin = '3px';
|
409 |
+
//listItem.style.backgroundColor = 'var(--body-background-fill)';
|
410 |
listItem.style.cursor = 'grab';
|
411 |
listItem.id = `lintao-item-${{index}}`;
|
412 |
|
|
|
414 |
listItem.addEventListener('dragstart', (e) => {{
|
415 |
const draggedIndex = Array.from(listContainer.children).indexOf(listItem);
|
416 |
e.dataTransfer.setData('text/plain', draggedIndex);
|
417 |
+
listItem.style.backgroundColor = 'var(--block-background-fill)';
|
418 |
}});
|
419 |
|
420 |
listItem.addEventListener('dragover', (e) => {{
|
421 |
e.preventDefault();
|
422 |
+
listItem.style.backgroundColor = 'var(--border-color-primary)';
|
423 |
}});
|
424 |
|
425 |
listItem.addEventListener('dragleave', () => {{
|
426 |
+
listItem.style.backgroundColor = 'var(--body-background-fill)';
|
427 |
}});
|
428 |
|
429 |
listItem.addEventListener('drop', (e) => {{
|
|
|
437 |
listContainer.insertBefore(draggedItem, targetIndex > draggedIndex ? listItem.nextSibling : listItem);
|
438 |
}}
|
439 |
|
440 |
+
listItem.style.backgroundColor = 'var(--body-background-fill)';
|
441 |
}});
|
442 |
|
443 |
listItem.addEventListener('dragend', () => {{
|
444 |
+
listItem.style.backgroundColor = 'var(--body-background-fill)';
|
445 |
}});
|
446 |
|
447 |
listContainer.appendChild(listItem);
|
|
|
454 |
|
455 |
js_ordering_submit = """
|
456 |
function ordering_submit(textarea, io_history) {{
|
457 |
+
const container = document.getElementById("lintao-container")
|
458 |
+
if (container === null) return [textarea, io_history];
|
459 |
var ret = "";
|
460 |
+
container.childNodes.forEach(
|
|
|
461 |
(c, i) => {{
|
462 |
if (i>0) ret += '\\n';
|
463 |
ret += c.textContent;
|
|
|
483 |
return f"{fd}/{fn_prefix}_-_{game_filename(game_name)}_{level_id}.pkl"
|
484 |
|
485 |
|
486 |
+
# %%
|
487 |
+
def _is_checksum_same(fp_out, matches=None, mime_type="application/octet-stream"):
|
488 |
+
if matches is None:
|
489 |
+
matches = _files.list(
|
490 |
+
q=f"'{_folder_id}' in parents and mimeType='{mime_type}' and name = '{fp_out.rsplit('/', 1)[-1]}'",
|
491 |
+
fields=f"files(name, id, {_cksm_methods_str})",
|
492 |
+
).execute()['files']
|
493 |
+
if not os.path.exists(fp_out):
|
494 |
+
return None, None, matches
|
495 |
+
with open(fp_out, "rb") as o:
|
496 |
+
_local = BytesIO(o.read()).getvalue()
|
497 |
+
_local_hash = [m(_local).hexdigest() for m in _cksm_methods]
|
498 |
+
for i, match in enumerate(matches):
|
499 |
+
if all(a == b for a, b in zip(_local_hash, [match[k] for k in _cksm_methods_str.split(", ")])):
|
500 |
+
return True, i, matches
|
501 |
+
return False, -1, matches
|
502 |
+
|
503 |
+
|
504 |
+
# %%
|
505 |
+
def upload_to_drive(fp_out, matches=None, mime_type="application/octet-stream", compare_checksum=True):
|
506 |
+
if compare_checksum:
|
507 |
+
same_checksum, _, _ = _is_checksum_same(fp_out, matches, mime_type)
|
508 |
+
# same_checksum, _, _ = _is_checksum_same(
|
509 |
+
# fp_out, **{k: v for k, v in [('matches', matches), ('mime_type', mime_type)] if v})
|
510 |
+
if same_checksum:
|
511 |
+
return
|
512 |
+
fn = fp_out.rsplit("/", 1)[-1]
|
513 |
+
file_metadata = {"name": fn, "parents": [_folder_id]}
|
514 |
+
media = MediaFileUpload(fp_out)
|
515 |
+
try:
|
516 |
+
_files.create(body=file_metadata, media_body=media).execute()
|
517 |
+
except HttpError as error:
|
518 |
+
msg = f"Failed to upload the file, error: {error}"
|
519 |
+
print(msg)
|
520 |
+
gr.Error(msg)
|
521 |
+
|
522 |
+
|
523 |
+
# %%
|
524 |
+
def download_from_drive(fp_out, matches=None, mime_type="application/octet-stream", compare_checksum=True):
|
525 |
+
if compare_checksum and os.path.exists(fp_out):
|
526 |
+
same_checksum, i, matches = _is_checksum_same(fp_out, matches, mime_type)
|
527 |
+
if same_checksum:
|
528 |
+
return
|
529 |
+
if matches is None:
|
530 |
+
_, _, matches = _is_checksum_same(fp_out, matches, mime_type)
|
531 |
+
if len(matches) == 0:
|
532 |
+
return
|
533 |
+
else:
|
534 |
+
if len(matches) > 1:
|
535 |
+
gr.Warning(f"Multiple matches found! {fp_out.rsplit('/', 1)[-1].split('_-_', 1)[-1]}")
|
536 |
+
b_io, request = BytesIO(), _files.get_media(fileId=matches[0]['id'])
|
537 |
+
downloader = MediaIoBaseDownload(b_io, request)
|
538 |
+
if os.path.exists(fp_out):
|
539 |
+
print(f"Deleting and re-download... ({fp_out})")
|
540 |
+
os.remove(fp_out)
|
541 |
+
done = False
|
542 |
+
while not done:
|
543 |
+
status, done = downloader.next_chunk()
|
544 |
+
with open(fp_out, "ab") as o:
|
545 |
+
o.write(b_io.getvalue())
|
546 |
+
|
547 |
+
|
548 |
# %%
|
549 |
def start_new_game(game_name, level, session_state_component, is_solved_component, solved_games_component,
|
550 |
user=None, show_timer=False, uid=None):
|
|
|
562 |
preload_game(game_name, difficulty_level, user)
|
563 |
)
|
564 |
cur_game.attach_stats_output_(fp_out)
|
565 |
+
cur_game.flush_stats_(user_info_to_flush=user)
|
566 |
|
567 |
def add_msg(new_msg, prev_msg):
|
568 |
+
if len(new_msg) > 200:
|
569 |
+
new_msg = new_msg[:200]
|
570 |
+
gr.Warning("your input is too long! It has been truncated.")
|
571 |
user_input = '\n'.join(new_msg.split())
|
572 |
solved, val_msg = cur_game.validate(user_input)
|
573 |
response = ("Correct guess" if solved else "Bad guess (Wrong Answer)") + "\n" + val_msg
|
|
|
579 |
|
580 |
gr.Markdown(
|
581 |
"""
|
582 |
+
> ### ‼️ Do ***<span style="color:red">NOT</span>*** refresh this page. ‼️<br>
|
583 |
> #### ⚠️ Refreshing the page equals "Give-up 😭" ⚠️
|
|
|
|
|
584 |
"""
|
585 |
)
|
586 |
showhide_helper_btn = gr.Button("Show Input Helper (disabling manual input)", elem_id="lintao-helper-btn")
|
|
|
622 |
|
623 |
def _forfeiting(confirmed, _solved_games):
|
624 |
if confirmed:
|
625 |
+
gr.Info("Sad to see you go... Wrapping things up...")
|
626 |
cur_game.finish_stats_(forfeit=True)
|
627 |
+
if level in LEVELS and level not in _solved_games[game_name]:
|
628 |
_solved_games[game_name].append(level)
|
629 |
+
upload_to_drive(fp_out)
|
630 |
return 0, _solved_games
|
631 |
return 1, _solved_games
|
632 |
+
give_up_checkbox.change(
|
633 |
+
lambda: (gr.update(interactive=False), gr.update(interactive=False)), None, [submit_btn, give_up_btn]
|
634 |
+
).then(
|
635 |
+
_forfeiting, [give_up_checkbox, solved_games_component], [session_state_component, solved_games_component]
|
636 |
+
).then(
|
637 |
+
lambda: (gr.update(interactive=True), gr.update(interactive=True)), None, [submit_btn, give_up_btn]
|
638 |
+
)
|
639 |
|
640 |
+
def game_is_solved(_is_solved, _session_state, _solved_games, progress=gr.Progress()):
|
641 |
if _is_solved:
|
642 |
+
if level in LEVELS and level not in _solved_games[game_name]:
|
643 |
_solved_games[game_name].append(level)
|
644 |
return (
|
645 |
2,
|
646 |
gr.update(visible=False, interactive=False),
|
647 |
gr.update(visible=False, interactive=False),
|
|
|
648 |
_solved_games,
|
649 |
+
gr.update(visible=True, interactive=False),
|
650 |
)
|
651 |
else:
|
652 |
return (
|
653 |
+
_session_state, gr.update(), gr.update(), _solved_games, gr.update()
|
654 |
)
|
655 |
|
656 |
+
def finalize_game(_is_solved):
|
657 |
+
if _is_solved:
|
658 |
+
gr.Info("Reporting... Please click the button when available...")
|
659 |
+
upload_to_drive(fp_out)
|
660 |
+
return gr.update(interactive=True)
|
661 |
+
return gr.update()
|
|
|
|
|
|
|
662 |
|
663 |
is_solved_component.change(
|
664 |
game_is_solved,
|
665 |
[is_solved_component, session_state_component, solved_games_component],
|
666 |
+
[session_state_component, submit_btn, give_up_btn, solved_games_component, finish_btn],
|
667 |
+
).then(
|
668 |
+
finalize_game, [is_solved_component], [finish_btn],
|
669 |
)
|
670 |
finish_btn.click(
|
|
|
|
|
671 |
lambda: (0, 0), None, [session_state_component, is_solved_component]
|
672 |
)
|
673 |
|
|
|
682 |
raise gr.Error(f"You have done this game already.<br/>{game_name} - {level}")
|
683 |
if user is None:
|
684 |
gr.Warning("no user, game will be generated randomly")
|
685 |
+
# else:
|
686 |
+
# if not user['email_verified']:
|
687 |
+
# gr.Warning("please verify your email address")
|
688 |
+
# elif user['email_verified'] == "mockuser":
|
689 |
+
# gr.Info("game will load with a mocked-up user")
|
690 |
return 1
|
691 |
|
692 |
|
693 |
# %%
|
694 |
+
def check_played_game(solved_games, uid, progress=gr.Progress()):
|
695 |
+
matches = _files.list(
|
696 |
+
q=f"'{_folder_id}' in parents and mimeType='application/octet-stream' and name contains '{uid}_-_'",
|
697 |
+
fields=f"files(name, id, {_cksm_methods_str})",
|
698 |
+
).execute()['files']
|
699 |
ret = dict()
|
700 |
for game_name in solved_games.keys():
|
701 |
cur = []
|
702 |
+
for level, level_id in zip(LEVELS, LEVEL_IDS):
|
703 |
+
fp_out = _get_file_output(game_name, level_id, uid)
|
704 |
+
_matches = list(filter(lambda m: fp_out.endswith(m['name']), matches))
|
705 |
+
if os.path.exists(fp_out):
|
706 |
+
upload_to_drive(fp_out, _matches)
|
707 |
+
else:
|
708 |
+
download_from_drive(fp_out, _matches)
|
709 |
+
if os.path.exists(fp_out):
|
710 |
cur.append(level)
|
711 |
ret[game_name] = cur
|
712 |
+
return ret, gr.update()
|
713 |
|
714 |
|
715 |
# %%
|
play_with_auth.py
ADDED
@@ -0,0 +1,158 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
+
# os.environ.setdefault("GRADIO_SERVER_PORT", "1080")
|
4 |
+
# os.environ.setdefault("TEXTGAMES_SHOW_HIDDEN_LEVEL", "1")
|
5 |
+
os.environ.setdefault("TEXTGAMES_LOADGAME_DIR", "problemsets")
|
6 |
+
os.environ.setdefault("TEXTGAMES_LOADGAME_ID", "42")
|
7 |
+
os.environ.setdefault("TEXTGAMES_MOCKUSER", "")
|
8 |
+
os.environ.setdefault("TEXTGAMES_OUTPUT_DIR", "user_outputs")
|
9 |
+
os.environ.setdefault("TEXTGAMES_HASH_USER", "")
|
10 |
+
favicon_path = "textgames-scrabble-black2-ss.png"
|
11 |
+
|
12 |
+
#%%
|
13 |
+
from play_helper import css, declare_components, start_new_game
|
14 |
+
from typing import Optional
|
15 |
+
import gradio as gr
|
16 |
+
import hashlib
|
17 |
+
|
18 |
+
|
19 |
+
#%%
|
20 |
+
import uvicorn
|
21 |
+
from fastapi import FastAPI, Depends, Request
|
22 |
+
from starlette.config import Config
|
23 |
+
from starlette.responses import RedirectResponse, FileResponse
|
24 |
+
from starlette.middleware.sessions import SessionMiddleware
|
25 |
+
from authlib.integrations.starlette_client import OAuth, OAuthError
|
26 |
+
|
27 |
+
app = FastAPI()
|
28 |
+
|
29 |
+
# Replace these with your own OAuth settings
|
30 |
+
GOOGLE_CLIENT_ID = os.environ.get("GOOGLE_CLIENT_ID")
|
31 |
+
GOOGLE_CLIENT_SECRET = os.environ.get("GOOGLE_CLIENT_SECRET")
|
32 |
+
SECRET_KEY = os.environ.get("SECRET_KEY", "a_very_secret_key")
|
33 |
+
|
34 |
+
# Set up OAuth
|
35 |
+
config_data = {'GOOGLE_CLIENT_ID': GOOGLE_CLIENT_ID, 'GOOGLE_CLIENT_SECRET': GOOGLE_CLIENT_SECRET}
|
36 |
+
starlette_config = Config(environ=config_data)
|
37 |
+
oauth = OAuth(starlette_config)
|
38 |
+
oauth.register(
|
39 |
+
name='google',
|
40 |
+
server_metadata_url='https://accounts.google.com/.well-known/openid-configuration',
|
41 |
+
client_kwargs={'scope': 'openid email profile'},
|
42 |
+
)
|
43 |
+
|
44 |
+
app.add_middleware(SessionMiddleware, secret_key=SECRET_KEY)
|
45 |
+
|
46 |
+
_HASHER = (hashlib.blake2b, {"digest_size": 16, "key": SECRET_KEY.encode('utf-8')})
|
47 |
+
|
48 |
+
|
49 |
+
def _hash_msg(msg):
|
50 |
+
if isinstance(msg, str):
|
51 |
+
msg = msg.encode('utf-8')
|
52 |
+
m = _HASHER[0](**_HASHER[1])
|
53 |
+
m.update(msg)
|
54 |
+
return m.hexdigest()
|
55 |
+
|
56 |
+
|
57 |
+
# Dependency to get the current user
|
58 |
+
def get_user(request: Request) -> Optional[dict]:
|
59 |
+
if user := request.session.get('user'):
|
60 |
+
return user
|
61 |
+
elif username := os.getenv("TEXTGAMES_MOCKUSER", ""):
|
62 |
+
return {'name': username, 'email': username, 'email_verified': False}
|
63 |
+
else:
|
64 |
+
return
|
65 |
+
|
66 |
+
|
67 |
+
def get_username(request: Request):
|
68 |
+
user = get_user(request)
|
69 |
+
if user:
|
70 |
+
return user['email']
|
71 |
+
return None
|
72 |
+
|
73 |
+
|
74 |
+
@app.get('/favicon.ico', include_in_schema=False)
|
75 |
+
async def favicon():
|
76 |
+
return FileResponse(favicon_path)
|
77 |
+
|
78 |
+
|
79 |
+
@app.get('/')
|
80 |
+
def public(user: str = Depends(get_username)):
|
81 |
+
if user:
|
82 |
+
return RedirectResponse(url='/TextGames')
|
83 |
+
else:
|
84 |
+
return RedirectResponse(url='/login')
|
85 |
+
|
86 |
+
|
87 |
+
@app.route('/logout')
|
88 |
+
async def logout(request: Request):
|
89 |
+
request.session.pop('user', None)
|
90 |
+
if os.getenv('TEXTGAMES_MOCKUSER', ''):
|
91 |
+
os.environ['TEXTGAMES_MOCKUSER'] = ''
|
92 |
+
return RedirectResponse(url='/')
|
93 |
+
|
94 |
+
|
95 |
+
@app.route('/do-login')
|
96 |
+
async def login(request: Request):
|
97 |
+
redirect_uri = request.url_for('auth')
|
98 |
+
# If your app is running on https, you should ensure that the
|
99 |
+
# `redirect_uri` is https, e.g. uncomment the following lines:
|
100 |
+
|
101 |
+
from urllib.parse import urlparse, urlunparse
|
102 |
+
redirect_uri = urlunparse(urlparse(str(redirect_uri))._replace(scheme='https'))
|
103 |
+
return await oauth.google.authorize_redirect(request, redirect_uri)
|
104 |
+
|
105 |
+
|
106 |
+
@app.route('/auth')
|
107 |
+
async def auth(request: Request):
|
108 |
+
try:
|
109 |
+
access_token = await oauth.google.authorize_access_token(request)
|
110 |
+
except OAuthError:
|
111 |
+
return RedirectResponse(url='/')
|
112 |
+
request.session['user'] = dict(access_token)["userinfo"]
|
113 |
+
return RedirectResponse(url='/')
|
114 |
+
|
115 |
+
|
116 |
+
def greet(request: gr.Request):
|
117 |
+
user = get_user(request.request)
|
118 |
+
uid = _hash_msg(user['email']) if os.getenv("TEXTGAMES_HASH_USER", "") else user['email']
|
119 |
+
return f"""
|
120 |
+
Welcome to TextGames, {user['name']}!<br />
|
121 |
+
<{user['email'].replace('@', '{at}')}> ({'' if user['email_verified'] else 'NON-'}verified email)
|
122 |
+
""", user, uid
|
123 |
+
|
124 |
+
|
125 |
+
with gr.Blocks(title="TextGames") as login_demo:
|
126 |
+
gr.Markdown("Welcome to TextGames!")
|
127 |
+
# gr.Button("Login", link="/do-login")
|
128 |
+
gr.Button("🚪\tLogin", link="/do-login", icon=None)
|
129 |
+
|
130 |
+
app = gr.mount_gradio_app(app, login_demo, path="/login")
|
131 |
+
|
132 |
+
with gr.Blocks(title="TextGames", css=css, delete_cache=(3600, 3600)) as demo:
|
133 |
+
((m, logout_btn, solved_games_df, game_radio, level_radio, new_game_btn, render_toggle),
|
134 |
+
(session_state, is_solved, solved_games, user_state, uid_state),
|
135 |
+
) = declare_components(demo, greet)
|
136 |
+
|
137 |
+
@gr.render(inputs=[game_radio, level_radio, user_state, session_state, uid_state], triggers=[render_toggle.change])
|
138 |
+
def _start_new_game(game_name, level, user, _session_state, _uid_state):
|
139 |
+
if _session_state in [1, 2]:
|
140 |
+
start_new_game(game_name, level, session_state, is_solved, solved_games, user=user, uid=_uid_state)
|
141 |
+
|
142 |
+
|
143 |
+
app = gr.mount_gradio_app(app, demo, path="/TextGames", auth_dependency=get_username)
|
144 |
+
|
145 |
+
if __name__ == '__main__':
|
146 |
+
uvicorn.run(app,
|
147 |
+
port=int(os.getenv("GRADIO_SERVER_PORT", "7860")),
|
148 |
+
host=os.getenv("UVICORN_SERVER_HOST", "127.0.0.1"),
|
149 |
+
ssl_keyfile=os.getenv("SSL_KEYFILE", None),
|
150 |
+
ssl_certfile=os.getenv("SSL_CERTFILE", None),
|
151 |
+
)
|
152 |
+
|
153 |
+
|
154 |
+
#%%
|
155 |
+
|
156 |
+
|
157 |
+
#%%
|
158 |
+
|
read_pkl.py
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pickle
|
2 |
+
|
3 |
+
def read_pkl(fp):
|
4 |
+
with open(fp, "rb") as f:
|
5 |
+
data = []
|
6 |
+
try:
|
7 |
+
while True:
|
8 |
+
data.append(pickle.load(f))
|
9 |
+
except EOFError as e:
|
10 |
+
pass
|
11 |
+
return data
|
textgames/__init__.py
CHANGED
@@ -34,9 +34,9 @@ SINGLE_LINE_GAME_IDS = list(map(lambda g: GAME_IDS[GAME_NAMES.index(g.get_game_n
|
|
34 |
[PasswordGame, BracketGame, StringSearch, AnagramScribble]
|
35 |
))
|
36 |
|
37 |
-
LEVEL_IDS = ["
|
38 |
-
LEVELS = ["
|
39 |
-
LEVELS_HIDDEN = ["🌌\tInsane", "🔰\tSample #2"]
|
40 |
_show_hidden_level_ = os.getenv("TEXTGAMES_SHOW_HIDDEN_LEVEL", False)
|
41 |
if _show_hidden_level_:
|
42 |
LEVELS, LEVELS_HIDDEN = LEVELS + LEVELS_HIDDEN, []
|
@@ -62,14 +62,16 @@ def _game_class_from_name(game_name):
|
|
62 |
|
63 |
def preload_game(game_name, level_id, user):
|
64 |
game_cls = _game_class_from_name(game_name)
|
65 |
-
email_sid_dict = read_csv(
|
|
|
|
|
66 |
sid = email_sid_dict.get(user["email"])
|
67 |
-
print(f"preload_game('{game_name}', '{level_id}', '{user['email']}')
|
68 |
|
69 |
with open(f"problemsets/{game_filename(game_name)}_{level_id}.json", "r", encoding="utf8") as f:
|
70 |
sid_prompt_dict = json.load(f)
|
71 |
prompt = sid_prompt_dict.get(sid)
|
72 |
-
print("Loaded prompt:", prompt, sep="\n")
|
73 |
|
74 |
return _reload(prompt, game_cls)
|
75 |
|
|
|
34 |
[PasswordGame, BracketGame, StringSearch, AnagramScribble]
|
35 |
))
|
36 |
|
37 |
+
LEVEL_IDS = ["1", "2", "3", "4", "0", "00"]
|
38 |
+
LEVELS = ["🚅\tEasy", "🚀\tMedium", "🛸\tHard"]
|
39 |
+
LEVELS_HIDDEN = ["🌌\tInsane", "🔰\tSample #1", "🔰\tSample #2"]
|
40 |
_show_hidden_level_ = os.getenv("TEXTGAMES_SHOW_HIDDEN_LEVEL", False)
|
41 |
if _show_hidden_level_:
|
42 |
LEVELS, LEVELS_HIDDEN = LEVELS + LEVELS_HIDDEN, []
|
|
|
62 |
|
63 |
def preload_game(game_name, level_id, user):
|
64 |
game_cls = _game_class_from_name(game_name)
|
65 |
+
email_sid_dict = read_csv(
|
66 |
+
f"{os.getenv('TEXTGAMES_OUTPUT_DIR')}/textgames_userauth.tsv", sep='\t'
|
67 |
+
).dropna().set_index("EMAIL").SID.to_dict()
|
68 |
sid = email_sid_dict.get(user["email"])
|
69 |
+
print(f"preload_game('{game_name}', '{level_id}', '{user['email']}') on {sid}")
|
70 |
|
71 |
with open(f"problemsets/{game_filename(game_name)}_{level_id}.json", "r", encoding="utf8") as f:
|
72 |
sid_prompt_dict = json.load(f)
|
73 |
prompt = sid_prompt_dict.get(sid)
|
74 |
+
# print("Loaded prompt:", prompt, sep="\n")
|
75 |
|
76 |
return _reload(prompt, game_cls)
|
77 |
|
textgames/base_game.py
CHANGED
@@ -42,11 +42,11 @@ class BaseGame:
|
|
42 |
assert not self.stats_filepath
|
43 |
self.stats_filepath = filepath
|
44 |
|
45 |
-
def flush_stats_(self,
|
46 |
if self.stats_filepath:
|
47 |
with open(self.stats_filepath, mode='ab') as o:
|
48 |
-
if
|
49 |
-
pickle.dump((time.time(),
|
50 |
else:
|
51 |
pickle.dump((
|
52 |
time.time(),
|
@@ -112,7 +112,4 @@ def _is_game_reloadable(original_game: BaseGame) -> bool:
|
|
112 |
original_game_states = {k: v for k, v in vars(original_game).items() if k not in exclude_states}
|
113 |
loaded_game_states = {k: v for k, v in vars(loaded_game).items() if k not in exclude_states}
|
114 |
|
115 |
-
|
116 |
-
if not ret:
|
117 |
-
pass
|
118 |
-
return ret
|
|
|
42 |
assert not self.stats_filepath
|
43 |
self.stats_filepath = filepath
|
44 |
|
45 |
+
def flush_stats_(self, user_info_to_flush=None):
|
46 |
if self.stats_filepath:
|
47 |
with open(self.stats_filepath, mode='ab') as o:
|
48 |
+
if user_info_to_flush:
|
49 |
+
pickle.dump((time.time(), user_info_to_flush), o)
|
50 |
else:
|
51 |
pickle.dump((
|
52 |
time.time(),
|
|
|
112 |
original_game_states = {k: v for k, v in vars(original_game).items() if k not in exclude_states}
|
113 |
loaded_game_states = {k: v for k, v in vars(loaded_game).items() if k not in exclude_states}
|
114 |
|
115 |
+
return (original_game_states == loaded_game_states) and (original_game.get_prompt() == loaded_game.get_prompt())
|
|
|
|
|
|
textgames/ordering_text/ordering_text.py
CHANGED
@@ -170,7 +170,7 @@ class ConsecutiveScoring(Scoring):
|
|
170 |
pattern += cur_pattern
|
171 |
pattern += f"{{{n}}}" if (n > 1) else ""
|
172 |
n = 1
|
173 |
-
self._pattern = re.compile(pattern)
|
174 |
|
175 |
self.prompt = None
|
176 |
|
|
|
170 |
pattern += cur_pattern
|
171 |
pattern += f"{{{n}}}" if (n > 1) else ""
|
172 |
n = 1
|
173 |
+
self._pattern = re.compile(f"(?=({pattern}))")
|
174 |
|
175 |
self.prompt = None
|
176 |
|
textgames_userauth_generate.py
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import pandas as pd
|
3 |
+
from dotenv import load_dotenv
|
4 |
+
|
5 |
+
# %%
|
6 |
+
load_dotenv("oauth_environ_google.env")
|
7 |
+
|
8 |
+
# %%
|
9 |
+
os.system("python ~/pwd_generator.py --spchar \"+()!#$%&@?.;/\" -n 1000 -r 3 -l 24 > textgames_passwords.txt")
|
10 |
+
|
11 |
+
# %%
|
12 |
+
with open("textgames_passwords.txt", "r", encoding="utf8") as i:
|
13 |
+
passwords = [("", "", l.strip(), f"session_{k:04}") for k, l in enumerate(i)]
|
14 |
+
|
15 |
+
# %%
|
16 |
+
df = pd.DataFrame(passwords, columns=["EMAIL", "NAME", "PASSWORD", "SID"])
|
17 |
+
|
18 |
+
# %%
|
19 |
+
df.to_csv("textgames_userauth.tsv", index=False, sep="\t")
|
20 |
+
|
21 |
+
# %%
|
22 |
+
|
23 |
+
|
24 |
+
# %%
|
25 |
+
|
26 |
+
|
27 |
+
# %%
|
28 |
+
|
29 |
+
|
30 |
+
# %%
|
31 |
+
|
32 |
+
|
33 |
+
# %%
|
34 |
+
|
35 |
+
|
36 |
+
# %%
|
37 |
+
|
38 |
+
|
39 |
+
# %%
|
40 |
+
|
41 |
+
|
42 |
+
# %%
|
43 |
+
|
44 |
+
|