File size: 5,504 Bytes
e936283 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
#!/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)
|