kneasle / wheatley Goto Github PK
View Code? Open in Web Editor NEWAn AI for Ringing Room that can ring any number of bells to increase the scope of practices.
Home Page: https://pypi.org/project/wheatley/
License: MIT License
An AI for Ringing Room that can ring any number of bells to increase the scope of practices.
Home Page: https://pypi.org/project/wheatley/
License: MIT License
A sensitivity arg would, I think, be between 0.0
and 1.0
and will override the other regression parameters with something that will result in a reasonable estimate for that level of sensitivity to speed changes.
This will help #65 because if fewer human ringers are ringing, they will make up a much smaller proportion of the dataset, and Wheatley will therefore pay them less attention.
I'm happy to do this :)
In my testing, the bot always used an "up, down, & off" handbell-ish start style, rather than waiting for the Go command (i.e. it started the method a whole-pull after the Treble's Going command took effect).
Perhaps this could be tied to whether the tower is in Tower or Hand mode, or could just be something set from the CLI?
As they're not part of the generated row, they aren't expected once in the method.
I'd started refactoring to fix this, but will wait for #111 first.
Apparently someone tried to do this, so we should probably remove the assert
s that make sure that lead heads are always handstrokes.
This will probably be another command in the --method/--comp
group.
Currently prints upto a row of
ERROR:TOWER:Bell 1 on opposite stroke
ERROR:TOWER:Bell 2 on opposite stroke
ERROR:TOWER:Bell 3 on opposite stroke
ERROR:TOWER:Bell 4 on opposite stroke
and keeps going / waiting
Also there isn't a INFO:TOWER:RECEIVED:
line for set at hand
Currently RowGeneration is done with bells numbered 1 .. n, e.g. [1, 2, 3, 4]
RingingRoom generally refer to bells this way (e.g. on bell assignment or who rang) and it feels much more natural to me to read and reason about.
e.g.
INFO:TOWER:RECEIVED: Assigned bell '1' to 'BOT'
INFO:TOWER:RECEIVED: Assigned bell '2' to 'BOT'
I would read as Treble and Second have been assigned.
The Bot currently uses bells numbered 0 .. n - 1, e.g. [0, 1, 2, 3]. This seems to me like an implementation details of how certain pieces of data are stored and a potential source of off by 1 errors.
Currently the only thing that seems to depend on the bell number being 0 based is RingingRoomTower._bell_state
, other usages (e.g. assigned_bells
or Rhythm
) are just storing whichever bell is passed to them.
I propose exposing
class RingingRoomTower:
def get_stroke(self, bell: int):
if bell > len(self._bell_state) or bell <= 0:
self.logger.error(f"Bell {bell} not in tower")
return None
return self._bell_state[bell - 1]
And using 1 based for the bell ints everywhere.
This will discover the kinds of simple-to-fix crashes that are so easy to get in Python
If Wheatley is given a peal speed and the user is assigned 1 and 2 then we would expect it to still ring at the expected peal speed, regardless of what 1 and 2 do.
If few human ringers are ringing, the sensitivity controls should automatically be adjusted towards having Wheatley be less sensitive to human ringers.
Things that cause obscure error messages:
https://
I can't think of any more - if anyone thinks of any, make a comment on this issue and I'll add it to this list.
Currently the bot rings all unassigned bells.
Add an optional argument --name
that when specified means the bot just rings bells assigned to the given username.
Non goal:
Logging in from the command line + adding the username to the list of users. A user would have to log in with a browser first (and keep the browser open to avoid triggering a leaving event)
I think the best strategy for this is to have Wheatley want to return to the set peal speed - so if people slow down temporarily, Wheatley will gradually return to a normal speed once those datapoints get too old and leave the dataset.
Allow accessing of CompLib comps from their URLs as well as IDs (by inserting /rows
before the access key to access private compositions). For example:
https://complib.org/composition/66852?accessKey=5d642941de62cd8810189d25df28cca0fad92c07
goes to:
https://complib.org/composition/66852/rows?accessKey=5d642941de62cd8810189d25df28cca0fad92c07
and does indeed load the correct rows.
The CompLib API also works.
Currently a place notation block is assumed to be asymmetric unless it starts with &
. This is the prefix used in microSIRIL (though that tends to require +
for asymmetric parts.)
To match Method XML format specification. we should treat sections as symmetric if there is a ,
.
The examples it gives are Cambridge Surprise Minor -36-14-12-36-14-56,12
and Grandsire Doubles 3,1.5.1.5.1
.
The specification only allows for at most one ,
. On Complib if you try and enter multiple ,
s it just ignores the extras on parsing
I.e. -1-1,4.5,-3
becomes -18-18,14.58-38
when displayed / saved. I don't think we need to match behaviour here, it's probably easier not to.
&
to signal a symmetric block?+
to signal an asymmetric block? e.g. -1-1,+4.5
-> -1-1-1-4.5
It would be nice to have a way for Wheatley to ignore time paused under the debugger and continue sensibly rather than start firing all the bells.
Plain Hunt
is not in the CC database, so we should probably make a special case and convert it to Original
behind the scenes for the user.
If the PN parser is given a method that contains multiple x
s, if will expand into too many copies of the x
. Noticeable for methods like Tulkinghorn Treble Bob Minimus.
Advantages over the current API:
An example: https://rsw.me.uk/blueline/methods/search.json?q=st%20clements%20college%20bo%20major
To make Bobs/Singles work we could return the custom PlaceNotationGenerators for these very common methods.
Attempting to ring Kent TB6. Initially people on 2,3,4,6 with bot on 1,5. Bot rang 1 but crashed on 5 (1st handstroke). Repeated with people on 2,3,4 and bot on 1,5,6; same. Output attached.
wheatley-kent-20201005.txt
Tower bell mode = Pull off in rounds until "go" is called, then ring changes until "that's all is called" and stand when "stand" is called.
Hand bell mode = Up/down/in, stop at first rounds after starting changes.
Possible enhancement would be to have hand bell mode continue if people ring after rounds.
This will provide better behaviour in cases where there are internal rounds, or the touch comes round at handstroke.
Make the bot ring with a mocked 'sleep' function that returns instantly and feed it with randomly perturbed ringing for a while. We don't really care what it ends up doing, so long as it never hangs or gets itself into a loop where it rings really fast.
On a clean python install it currently fails:
rr-bot -h
Traceback (most recent call last):
File "c:\python38\lib\runpy.py", line 193, in _run_module_as_main
return _run_code(code, main_globals, None,
File "c:\python38\lib\runpy.py", line 86, in run_code
exec(code, run_globals)
File "C:\Python38\Scripts\rr-bot.exe_main.py", line 5, in
File "c:\python38\lib\site-packages\rr_bot\main.py", line 11, in
from rr_bot.rhythm import RegressionRhythm, WaitForUserRhythm
File "c:\python38\lib\site-packages\rr_bot\rhythm.py", line 13, in
from rr_bot.regression import calculate_regression
File "c:\python38\lib\site-packages\rr_bot\regression.py", line 5, in
import numpy
ModuleNotFoundError: No module named 'numpy'
I suspect it will need other packages as well
I think Wheatley needs to subscribe to s_user_left
Required if we're going to work on #15, since restarting a GUI is far more annoying than restarting a terminal command.
The main issue is that the SocketIO client can crash in the background, e.g.
Exception in thread Thread-4:
Traceback (most recent call last):
File "/usr/lib/python3.8/threading.py", line 932, in _bootstrap_inner
self.run()
File "/usr/lib/python3.8/threading.py", line 870, in run
self._target(*self._args, **self._kwargs)
File "/srv/www/ringingroom/venv/lib/python3.8/site-packages/engineio/client.py", line 574, in _read_loop_polling
self._receive_packet(pkt)
File "/srv/www/ringingroom/venv/lib/python3.8/site-packages/engineio/client.py", line 456, in _receive_packet
self._trigger_event('message', pkt.data, run_async=True)
File "/srv/www/ringingroom/venv/lib/python3.8/site-packages/engineio/client.py", line 494, in _trigger_event
return self.start_background_task(self.handlers[event], *args)
File "/srv/www/ringingroom/venv/lib/python3.8/site-packages/engineio/client.py", line 260, in start_background_task
th.start()
File "/usr/lib/python3.8/threading.py", line 852, in start
_start_new_thread(self._bootstrap, ())
RuntimeError: can't start new thread
This results in a infinite loop, as the client exists and the emit methods don't seem to throw. It just will never receive bell state.
Lines 144 to 156 in 533f617
Some thoughts
This means you can't ring things like anti-April-Day (Grandsire with Plain Bob calls).
A solution could be that we turn generator_from_special_title
into a function that takes a method title and optional calls and always returns a RowGenerator. We should also remove the defaults of 14
/1234
calls, and have the generator_from_special_title
replacement decide on the custom calls.
An option to be able to assign the ringing speed from the command line interface would be lovely :)
This appears to be a bug with the WaitForUserRhythm
class, since this bug only happened after it was made the default.
Because Go
and Stand
have two changes warning, there's a possibility that an early call will take place straight away and scupper the ringing. I think the best way to prevent this is to add a slight delay to the call input, so that they appear in the right handstroke/backstroke
pair.
I was only able to use the bot successfully in the default Bot Testing Ground tower. When I used my own custom ID (472681395), it didn't seem to connect to the correct tower — it always found 8 bells and never received other commands.
Remove default values for:
--id
--method
/--comp
As the ringing room api gets added and becomes more stable we should move to using it
Endpoint | Method | Description |
---|---|---|
/api/tokens | POST | Get bearer token |
/api/tokens | DELETE | Revoke bearer token |
/api/user | GET | Get current user details |
/api/user | POST | Register new user |
/api/user | PUT | Modify user settings |
/api/user | DELETE | Delete user account |
/api/tower/<tower_id> | GET | Get connection details for tower_id |
/api/tower/<tower_id> | GET
to get the correct url instead of parsing it off the page/api/tokens | POST
to get a user token. This might need to change --name
to --email
and --password
and use /api/user | GET
to get the nameA 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.