hark130 / jack-in-the-box Goto Github PK
View Code? Open in Web Editor NEWConnecting Jackbox games to the OpenAI API
License: GNU General Public License v3.0
Connecting Jackbox games to the OpenAI API
License: GNU General Public License v3.0
JitbAi
is currently hard-coded to support Quiplash 3 even though Quiplash 2 support has already been implemented (and Joke Boat support is in progress).
Thinking about the current structure of the code, it might be best to allow the jitb_website
functionality to instantiate the AI object instead of in main()
... but you'll need to deconflict the teardown which was also happening in a finally
block in main()
I was running JITB in Windows. No Chrome installed. It hung. Couldn't kill it. No error message(?).
C:\Users\hark1\Documents\Personal\Programming\jack-in-the-box>python -m jitb --room klaf --user jitb --debug
Traceback (most recent call last):
File "C:\Program Files\Python39\lib\runpy.py", line 197, in _run_module_as_main
return _run_code(code, main_globals, None,
File "C:\Program Files\Python39\lib\runpy.py", line 87, in _run_code
exec(code, run_globals)
File "C:\Users\hark1\Documents\Personal\Programming\jack-in-the-box\jitb\__main__.py", line 10, in <module>
sys.exit(main())
File "C:\Users\hark1\Documents\Personal\Programming\jack-in-the-box\jitb\jitb_main.py", line 29, in main
play_the_game(room_code=room_code, username=username, ai_obj=client)
File "C:\Users\hark1\Documents\Personal\Programming\jack-in-the-box\jitb\jitb_website.py", line 106, in play_the_game
web_driver = join_room(room_code=room_code, username=username) # Webdriver for Jackbox Games
File "C:\Users\hark1\Documents\Personal\Programming\jack-in-the-box\jitb\jitb_website.py", line 81, in join_room
driver = webdriver.Chrome() # Webdriver object
File "C:\Users\hark1\AppData\Roaming\Python\Python39\site-packages\selenium\webdriver\chrome\webdriver.py", line 45, in __init__
super().__init__(
File "C:\Users\hark1\AppData\Roaming\Python\Python39\site-packages\selenium\webdriver\chromium\webdriver.py", line 61, in __init__
super().__init__(command_executor=executor, options=options)
File "C:\Users\hark1\AppData\Roaming\Python\Python39\site-packages\selenium\webdriver\remote\webdriver.py", line 208, in __init__
self.start_session(capabilities)
File "C:\Users\hark1\AppData\Roaming\Python\Python39\site-packages\selenium\webdriver\remote\webdriver.py", line 292, in start_session
response = self.execute(Command.NEW_SESSION, caps)["value"]
File "C:\Users\hark1\AppData\Roaming\Python\Python39\site-packages\selenium\webdriver\remote\webdriver.py", line 347, in execute
self.error_handler.check_response(response)
File "C:\Users\hark1\AppData\Roaming\Python\Python39\site-packages\selenium\webdriver\remote\errorhandler.py", line 229, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.SessionNotCreatedException: Message: session not created: DevToolsActivePort file doesn't exist
Stacktrace:
GetHandleVerifier [0x00007FF758AD7012+3522402]
(No symbol) [0x00007FF7586F8352]
(No symbol) [0x00007FF7585A5ABB]
(No symbol) [0x00007FF7585DB0FA]
(No symbol) [0x00007FF7585D4E3E]
(No symbol) [0x00007FF7585D2188]
(No symbol) [0x00007FF758619469]
(No symbol) [0x00007FF75860EE03]
(No symbol) [0x00007FF7585DF4D4]
(No symbol) [0x00007FF7585E05F1]
GetHandleVerifier [0x00007FF758B09B9D+3730157]
GetHandleVerifier [0x00007FF758B5F02D+4079485]
GetHandleVerifier [0x00007FF758B575D3+4048163]
GetHandleVerifier [0x00007FF75882A649+718233]
(No symbol) [0x00007FF758704A3F]
(No symbol) [0x00007FF7586FFA94]
(No symbol) [0x00007FF7586FFBC2]
(No symbol) [0x00007FF7586EF2E4]
BaseThreadInitThunk [0x00007FFF2D487344+20]
RtlUserThreadStart [0x00007FFF2E2C26B1+33]
Refactor JbgQ3
to use code from jitb_selenium
. Also, write unit tests for the legacy Quiplash 3 functionality for regression testing. Finally, probably entirely reorganize JbgQ3
to look more like JbgQ2
because I suspect JbgQ2
is an improvement.
These two tasks from the running To Do list in #9 commit messages got left on the table:
[ ] Refactor JbgQ3 to use jitb_selenium (and friends)
[ ] Write JbgQ3 unit tests
Everyone but my work wife thinks callbacks are funny.
Maybe, hint at it in OpenAI's prompt...
but only after #14 ... and then only if JitbAi
transitions to use a "stateful" API.
OpenAI has been adding a lot of trailing periods in recent games. Looks weird.
Add a Package-wide global constant to control the polling rate (and stop calling it sleep).
Running the unit tests resulted in some unexpected failures (on JITB-13
). Is this my problem? (Top of my head... am I not closing the debug log file?!) Is this the OS's problem? (I've got the --debug
flag turned on for all unit tests, even though I haven't used any of them in a while) If it's the OS's problem, I still need to work around it. Maybe I default all of these test clases to debug = False
but turn on unit test debugging, as needed.
SIDE NOTE: I've had some success in the past passing a command-line argument to the python -m test
command... Maybe that's the way to turn on unit test debugging.
======================================================================
ERROR: test_s07_round_3_prompt_1_v2 (unit_test.test_selenium.test_get_web_element_text.SpecialTestJitbSeleniumGetWebElementText)
KEY TEXT: Quiplash 2 Round 3 Last Lash prompt page v2; value state-answer-question.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/joe/Documents/Personal/Programming/jack-in-the-box/test/unit_test/test_jackbox_games.py", line 56, in setUp
Logger.initialize(debugging=True) # Enable DEBUG logging while testing
File "/home/joe/Documents/Personal/Programming/jack-in-the-box/jitb/jitb_logger.py", line 88, in initialize
File "/usr/lib/python3.10/logging/__init__.py", line 1169, in __init__
File "/usr/lib/python3.10/logging/__init__.py", line 1201, in _open
OSError: [Errno 24] Too many open files: '/tmp/jitb_20240305_124256.log'
======================================================================
ERROR: test_s08_round_3_prompt_1_v2_take_2 (unit_test.test_selenium.test_get_web_element_text.SpecialTestJitbSeleniumGetWebElementText)
KEY TEXT: Quiplash 2 Round 3 Last Lash prompt page v2; value question-text-alt.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/joe/Documents/Personal/Programming/jack-in-the-box/test/unit_test/test_jackbox_games.py", line 56, in setUp
Logger.initialize(debugging=True) # Enable DEBUG logging while testing
File "/home/joe/Documents/Personal/Programming/jack-in-the-box/jitb/jitb_logger.py", line 88, in initialize
File "/usr/lib/python3.10/logging/__init__.py", line 1169, in __init__
File "/usr/lib/python3.10/logging/__init__.py", line 1201, in _open
OSError: [Errno 24] Too many open files: '/tmp/jitb_20240305_124256.log'
======================================================================
ERROR: test_s09_round_3_vote_1_v1 (unit_test.test_selenium.test_get_web_element_text.SpecialTestJitbSeleniumGetWebElementText)
KEY TEXT: Quiplash 2 Round 3 Last Lash vote page v1; value state-vote.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/joe/Documents/Personal/Programming/jack-in-the-box/test/unit_test/test_jackbox_games.py", line 56, in setUp
Logger.initialize(debugging=True) # Enable DEBUG logging while testing
File "/home/joe/Documents/Personal/Programming/jack-in-the-box/jitb/jitb_logger.py", line 88, in initialize
File "/usr/lib/python3.10/logging/__init__.py", line 1169, in __init__
File "/usr/lib/python3.10/logging/__init__.py", line 1201, in _open
OSError: [Errno 24] Too many open files: '/tmp/jitb_20240305_124256.log'
======================================================================
ERROR: test_s11_round_3_vote_1_v2 (unit_test.test_selenium.test_get_web_element_text.SpecialTestJitbSeleniumGetWebElementText)
KEY TEXT: Quiplash 2 Round 3 Last Lash vote page v2; value state-vote.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/joe/Documents/Personal/Programming/jack-in-the-box/test/unit_test/test_jackbox_games.py", line 56, in setUp
Logger.initialize(debugging=True) # Enable DEBUG logging while testing
File "/home/joe/Documents/Personal/Programming/jack-in-the-box/jitb/jitb_logger.py", line 88, in initialize
File "/usr/lib/python3.10/logging/__init__.py", line 1169, in __init__
File "/usr/lib/python3.10/logging/__init__.py", line 1201, in _open
OSError: [Errno 24] Too many open files: '/tmp/jitb_20240305_124256.log'
======================================================================
ERROR: test_s13_non_jackbox_game_page (unit_test.test_selenium.test_get_web_element_text.SpecialTestJitbSeleniumGetWebElementText)
Non-Jackbox Games website.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/joe/Documents/Personal/Programming/jack-in-the-box/test/unit_test/test_jackbox_games.py", line 56, in setUp
Logger.initialize(debugging=True) # Enable DEBUG logging while testing
File "/home/joe/Documents/Personal/Programming/jack-in-the-box/jitb/jitb_logger.py", line 88, in initialize
File "/usr/lib/python3.10/logging/__init__.py", line 1169, in __init__
File "/usr/lib/python3.10/logging/__init__.py", line 1201, in _open
OSError: [Errno 24] Too many open files: '/tmp/jitb_20240305_124256.log'
Should be easy enough.
Add auto-support for the "audience" button, in addition to the join button, and then parse the pages as normal.
Legacy logic probably won't care if it doesn't see a prompt page.
Jackbox likes to throw game-playing usernames into dynamic prompts but the AI is unaware when a prompt is about it. Global find-and-replace the established --name
value with an appropriate pronoun in all prompts: answer or vote.
The AI likes to repeat the fill-in-the-blank precursor in it's answer.
For instance, ANSWERED A terrible idea for a children’s pop-up book: The Adventures of _______ with The Adventures of Booger Man!
Instead, do a strstr()
for words preceding the fill-in-the-blank and remove them.
The login page actually shows you the game being played once you type in a room code.
Currently, there's only support for Quiplash3... and we wouldn't want JITB playing games it shouldn't be.
Currently, it just logs to stdout(?).
It would be best if it could log to a timestamped log file in a predictable way.
Blocks #2
I encountered an issue with a large group playing Quiplash 3. (Which may actually be the cause for the #26 hang, now that I think about it)
The problem was that in between jitb
selecting an avatar and clicking the avatar button, someone else already chose it. It resulted in no avatar selection.
Seems like there should be some way to verify that one of the buttons is selected. Basically, keep clicking avatars until one turns up "selected".
Dynamically support JBG7 - Blather Round by parsing the login page's room code for game type.
Blocked by #9
Played legacy code against an online game of Quiplash 3.
Python hung.
Log was empty except for the room validation.
Got this when I sent a KeyboardInterrupt...
Traceback (most recent call last):
File "/home/joe/Documents/Personal/Programming/jack-in-the-box/jitb/jitb_website.py", line 71, in play_the_game
jbg_obj.play(web_driver=web_driver)
File "/home/joe/Documents/Personal/Programming/jack-in-the-box/jitb/jbgames/jbg_q3.py", line 33, in play
self.validate_status(web_driver=web_driver)
File "/home/joe/Documents/Personal/Programming/jack-in-the-box/jitb/jbgames/jbg_q3.py", line 178, in validate_status
self._check_web_driver(web_driver=web_driver)
File "/home/joe/Documents/Personal/Programming/jack-in-the-box/jitb/jbgames/jbg_abc.py", line 128, in _check_web_driver
temp_we = web_driver.find_element(By.ID, 'swal2-title')
File "/home/joe/.local/lib/python3.10/site-packages/selenium/webdriver/remote/webdriver.py", line 742, in find_element
return self.execute(Command.FIND_ELEMENT, {"using": by, "value": value})["value"]
File "/home/joe/.local/lib/python3.10/site-packages/selenium/webdriver/remote/webdriver.py", line 346, in execute
response = self.command_executor.execute(driver_command, params)
File "/home/joe/.local/lib/python3.10/site-packages/selenium/webdriver/remote/remote_connection.py", line 300, in execute
return self._request(command_info[0], url, body=data)
File "/home/joe/.local/lib/python3.10/site-packages/selenium/webdriver/remote/remote_connection.py", line 321, in _request
response = self._conn.request(method, url, body=body, headers=headers)
File "/usr/lib/python3/dist-packages/urllib3/request.py", line 78, in request
return self.request_encode_body(
File "/usr/lib/python3/dist-packages/urllib3/request.py", line 170, in request_encode_body
return self.urlopen(method, url, **extra_kw)
File "/usr/lib/python3/dist-packages/urllib3/poolmanager.py", line 375, in urlopen
response = conn.urlopen(method, u.request_uri, **kw)
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 700, in urlopen
httplib_response = self._make_request(
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 446, in _make_request
six.raise_from(e, None)
File "<string>", line 3, in raise_from
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 441, in _make_request
httplib_response = conn.getresponse()
File "/usr/lib/python3.10/http/client.py", line 1375, in getresponse
response.begin()
File "/usr/lib/python3.10/http/client.py", line 318, in begin
version, status, reason = self._read_status()
File "/usr/lib/python3.10/http/client.py", line 279, in _read_status
line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
File "/usr/lib/python3.10/socket.py", line 705, in readinto
return self._sock.recv_into(b)
KeyboardInterrupt
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/urllib3/connection.py", line 169, in _new_conn
conn = connection.create_connection(
File "/usr/lib/python3/dist-packages/urllib3/util/connection.py", line 96, in create_connection
raise err
File "/usr/lib/python3/dist-packages/urllib3/util/connection.py", line 86, in create_connection
sock.connect(sa)
ConnectionRefusedError: [Errno 111] Connection refused
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 700, in urlopen
httplib_response = self._make_request(
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 395, in _make_request
conn.request(method, url, **httplib_request_kw)
File "/usr/lib/python3/dist-packages/urllib3/connection.py", line 234, in request
super(HTTPConnection, self).request(method, url, body=body, headers=headers)
File "/usr/lib/python3.10/http/client.py", line 1283, in request
self._send_request(method, url, body, headers, encode_chunked)
File "/usr/lib/python3.10/http/client.py", line 1329, in _send_request
self.endheaders(body, encode_chunked=encode_chunked)
File "/usr/lib/python3.10/http/client.py", line 1278, in endheaders
self._send_output(message_body, encode_chunked=encode_chunked)
File "/usr/lib/python3.10/http/client.py", line 1038, in _send_output
self.send(msg)
File "/usr/lib/python3.10/http/client.py", line 976, in send
self.connect()
File "/usr/lib/python3/dist-packages/urllib3/connection.py", line 200, in connect
conn = self._new_conn()
File "/usr/lib/python3/dist-packages/urllib3/connection.py", line 181, in _new_conn
raise NewConnectionError(
urllib3.exceptions.NewConnectionError: <urllib3.connection.HTTPConnection object at 0x7a4dc80a7760>: Failed to establish a new connection: [Errno 111] Connection refused
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
exec(code, run_globals)
File "/home/joe/Documents/Personal/Programming/jack-in-the-box/jitb/__main__.py", line 10, in <module>
sys.exit(main())
File "/home/joe/Documents/Personal/Programming/jack-in-the-box/jitb/jitb_main.py", line 29, in main
play_the_game(room_code=room_code, username=username, ai_obj=client)
File "/home/joe/Documents/Personal/Programming/jack-in-the-box/jitb/jitb_website.py", line 75, in play_the_game
web_driver.close()
File "/home/joe/.local/lib/python3.10/site-packages/selenium/webdriver/remote/webdriver.py", line 459, in close
self.execute(Command.CLOSE)
File "/home/joe/.local/lib/python3.10/site-packages/selenium/webdriver/remote/webdriver.py", line 346, in execute
response = self.command_executor.execute(driver_command, params)
File "/home/joe/.local/lib/python3.10/site-packages/selenium/webdriver/remote/remote_connection.py", line 300, in execute
return self._request(command_info[0], url, body=data)
File "/home/joe/.local/lib/python3.10/site-packages/selenium/webdriver/remote/remote_connection.py", line 321, in _request
response = self._conn.request(method, url, body=body, headers=headers)
File "/usr/lib/python3/dist-packages/urllib3/request.py", line 74, in request
return self.request_encode_url(
File "/usr/lib/python3/dist-packages/urllib3/request.py", line 96, in request_encode_url
return self.urlopen(method, url, **extra_kw)
File "/usr/lib/python3/dist-packages/urllib3/poolmanager.py", line 375, in urlopen
response = conn.urlopen(method, u.request_uri, **kw)
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 784, in urlopen
return self.urlopen(
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 784, in urlopen
return self.urlopen(
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 784, in urlopen
return self.urlopen(
File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 756, in urlopen
retries = retries.increment(
File "/usr/lib/python3/dist-packages/urllib3/util/retry.py", line 574, in increment
raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPConnectionPool(host='localhost', port=46065): Max retries exceeded with url: /session/091cdcba9bb55067743d4d884c41c2c7/window (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7a4dc80a7760>: Failed to establish a new connection: [Errno 111] Connection refused'))
Current version of the hijacked prompt seems to cause the AI to give the answer everytime. See if you can change the prompt to get a better response. This may take a little live testing to get right.
When JITB dies, a common human response would be to restart JITB with the same command line arguments.
However, this puts JITB into Audience mode rather than recovering (missing cookies?)... which may be ok... but there should be a warning. That, or maybe a --spectate
mode to permit audience participation.
Why does my instinct tell me that the jitb_website._answer_prompt()
"Wait for it" logic should be closer to jitb_website._vote_answer()
's?
Dynamically support JBG6 - Job Job by parsing the login page's room code for game type.
Blocked by #9
Manual testing isn't getting very far on #1 so I think the plan is:
chat.completion
endpoint and try to use assistant
content, in the messages, to clue the AI in on how best to answer those types of questions (Downside... additional tokens wasted)SIDE NOTE: Manual testing on #1 looked like this:
import time
from jitb.jitb_openai import JitbAi
test = JitbAi()
test_cases = ['After the first seven, what are the next three deadly sins?', 'Three ways to take your next book club meeting up a notch', 'Three things that are considered bad etiquette at the gym', 'Three words you don’t want to hear someone use to describe your genitals', 'When going through airport security, make sure to remove your _______, _______, and _______', 'Three Chevy car models recalled for being “too awesome”', 'The three things you need to be good at to truly get ahead in life', 'Bad news: they now take away your “cool card” if you like _______, _______, or _______', 'You know you’re about to have a bad day on Twitter if you see these three hashtags', 'Three things Mars needs before we can live there', 'Three theme parks more dangerous than Jurassic Park']
test.generate_thriplash(prompt=test_cases[0])
for test_case in test_cases:
time.sleep(20)
test.generate_thriplash(prompt=test_case)
Output was:
['Snoring', 'Procrastination', 'Overindulgence']
['Booze and books!', 'Add a theme.', 'Bring snacks.']
['Grunting loudly', 'Not wiping sweat', 'Hogging equipment']
OpenAI generated more than just three lines here ['1. Small, shriveled, sad', '2. Moldy, crusty, stinky', '3. Flaccid, limp, lifeless', '4. Withered, wrinkly, dry', '5. Tiny, puny']
['Flaccid, limp, lifeless', 'Withered, wrinkly, dry', 'Tiny, puny']
['shoes', 'belt', 'liquids']
['Camaro', 'Corvette', 'Impala']
OpenAI generated more than just three lines here ['1. Lying, cheating, stealing', '2. Kissing, ass, networking', '3. Hustling, grinding, scheming', '4. Multitasking, bullshitting, bribing', '5. Manipulating, schmoo']
['Hustling, grinding, scheming', 'Multitasking, bullshitting, br', 'Manipulating, schmoo']
['- Nickelback', '- Crocs', '- Pineapple on pizza']
['#CancelCulture', '#TwitterFingers', '#TwitterMeltdown']
['Oxygen', 'Water', 'WiFi']
['Clown Carnage Land', 'Zombie Apocalypse World', 'T-Rex Terror Town']
Dynamically support JBG3 - Joke Boat by parsing the login page's room code for game type.
Blocked by #9
Dynamically support JBG6 - Dictionarium by parsing the login page's room code for game type.
Blocked by #9
Sometimes, the AI is playing a different game than the humans: gross, straight, hilarious, raunchy.
Fiddle with the prompt so that OpenAI's responses match the tone and style of the human answers it observes.
Also, ensure we're using an API capable of keeping a running history.
Couldn't be that hard to determine the interfaces for older versions of Quiplash and then implement them in a class, lookup table, mapping, etc.
Related to #9
Round 3 for Quiplash (legacy) is basically vote for your favorites. I think you can vote more than once for the same answer.
I should likely be merging dev
into main
every time I complete support for a new Jackbox game (for now).
I should also be updating the repo README.md
(because it's no longer entirely accurate).
Even better, I should devise a release checklist.
Even better still... what happened to my "release jitb as a wheel" backlog ticket. (This might be it, now)
I should start a CHANGELOG
as well.
Don't forget about jitb
dependencies.
Acceptance Criteria:
jitb
as a wheel__init__.py
contains adequate usage instructionsA declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.