chess / chessfenbot /chessbot.py
rosenthal's picture
v1 of chess space
e936283
raw
history blame contribute delete
No virus
5.5 kB
#!/usr/bin/env python
# ChessFenBot daemon
# Finds submissions with chessboard images in them,
# use a tensorflow convolutional neural network to predict pieces and return
# a lichess analysis link and FEN diagram of chessboard
# Run with --dry to dry run without actual submissions
from __future__ import print_function
import praw
import requests
import socket
import time
from datetime import datetime
import argparse
import tensorflow_chessbot # For neural network model
from helper_functions_chessbot import *
from helper_functions import shortenFEN
from cfb_helpers import * # logging, comment waiting and self-reply helpers
def generateResponseMessage(submission, predictor):
print("\n---\nImage URL: %s" % submission.url)
# Use CNN to make a prediction
fen, certainty, visualize_link = predictor.makePrediction(submission.url)
if fen is None:
print("> %s - Couldn't generate FEN, skipping..." % datetime.now())
print("\n---\n")
return None
fen = shortenFEN(fen) # ex. '111pq11r' -> '3pq2r'
print("Predicted FEN: %s" % fen)
print("Certainty: %.4f%%" % (certainty*100))
# Get side from title or fen
side = getSideToPlay(submission.title, fen)
# Generate response message
msg = generateMessage(fen, certainty, side, visualize_link)
print("fen: %s\nside: %s\n" % (fen, side))
return msg
def processSubmission(submission, cfb, predictor, args, reply_wait_time=10):
# Check if submission passes requirements and wasn't already replied to
if isPotentialChessboardTopic(submission):
if not previouslyRepliedTo(submission, cfb):
# Generate response
response = generateResponseMessage(submission, predictor)
if response is None:
logMessage(submission,"[NO-FEN]") # Skip since couldn't generate FEN
return
# Reply to submission with response
if not args.dry:
logMessage(submission,"[REPLIED]")
submission.reply(response)
else:
logMessage(submission,"[DRY-RUN-REPLIED]")
# Wait after submitting to not overload
waitWithComments(reply_wait_time)
else:
logMessage(submission,"[SKIP]") # Skip since replied to already
else:
logMessage(submission)
time.sleep(1) # Wait a second between normal submissions
def main(args):
resetTensorflowGraph()
running = True
reddit = praw.Reddit('CFB') # client credentials set up in local praw.ini file
cfb = reddit.user.me() # ChessFenBot object
subreddit = reddit.subreddit('chess+chessbeginners+AnarchyChess+betterchess+chesspuzzles')
predictor = tensorflow_chessbot.ChessboardPredictor()
while running:
# Start live stream on all submissions in the subreddit
stream = subreddit.stream.submissions()
try:
for submission in stream:
processSubmission(submission, cfb, predictor, args)
except (socket.error, requests.exceptions.ReadTimeout,
requests.packages.urllib3.exceptions.ReadTimeoutError,
requests.exceptions.ConnectionError) as e:
print(
"> %s - Connection error, skipping and continuing in 30 seconds: %s" % (
datetime.now(), e))
time.sleep(30)
continue
except Exception as e:
print("Unknown Error, skipping and continuing in 30 seconds:",e)
time.sleep(30)
continue
except KeyboardInterrupt:
print("Keyboard Interrupt: Exiting...")
running = False
break
predictor.close()
print('Finished')
def resetTensorflowGraph():
"""WIP needed to restart predictor after an error"""
import tensorflow as tf
print('Reset TF graph')
tf.reset_default_graph() # clear out graph
def runSpecificSubmission(args):
resetTensorflowGraph()
reddit = praw.Reddit('CFB') # client credentials set up in local praw.ini file
cfb = reddit.user.me() # ChessFenBot object
predictor = tensorflow_chessbot.ChessboardPredictor()
submission = reddit.submission(args.sub)
print("URL: ", submission.url)
if submission:
print('Processing...')
processSubmission(submission, cfb, predictor, args)
predictor.close()
print('Done')
def dryRunTest(submission='5tuerh'):
resetTensorflowGraph()
reddit = praw.Reddit('CFB') # client credentials set up in local praw.ini file
predictor = tensorflow_chessbot.ChessboardPredictor()
# Use a specific submission
submission = reddit.submission(submission)
print('Loading %s' % submission.id)
# Check if submission passes requirements and wasn't already replied to
if isPotentialChessboardTopic(submission):
# Generate response
response = generateResponseMessage(submission, predictor)
print("RESPONSE:\n")
print('-----------------------------')
print(response)
print('-----------------------------')
else:
print('Submission not considered chessboard topic')
predictor.close()
print('Finished')
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--dry', help='dry run (don\'t actually submit replies)',
action="store_true", default=False)
parser.add_argument('--test', help='Dry run test on pre-existing comment)',
action="store_true", default=False)
parser.add_argument('--sub', help='Pass submission string to process')
args = parser.parse_args()
if args.test:
print('Doing dry run test on submission')
if args.sub:
dryRunTest(args.sub)
else:
dryRunTest()
elif args.sub is not None:
runSpecificSubmission(args)
else:
main(args)