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)