-
Notifications
You must be signed in to change notification settings - Fork 0
/
twitter.py
228 lines (162 loc) · 6.88 KB
/
twitter.py
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
#!/usr/bin/env python2
# -*- coding: utf-8 -*- #
import compliments
import core
import cv2
from facerec import FaceRecognizer
from functools import partial
import logging
import os
import psycopg2 as pg
import requests
from store import Store
from twitterbot import TwitterBot
import uuid
def openshift_wake_up():
if os.environ.get('OPENSHIFT_PYTHON_IP', False):
requests.get('http://autofriend-wohanley.rhcloud.com/')
def get_photos(tweet):
if hasattr(tweet, 'extended_entities'):
entities = tweet.extended_entities
else:
entities = tweet.entities
return filter(
lambda media: media.get('type', None) == 'photo',
entities.get('media', []))
def get_photo_url(media_item):
return media_item['media_url'] + ':large'
def download_file(url):
fileName = 'temp-' + str(uuid.uuid4())
with open(fileName, 'wb') as f:
for chunk in requests.get(url).iter_content():
f.write(chunk)
return fileName
class DownloadedFile():
def __init__(self, url):
self.url = url
def __enter__(self):
self._fileName = download_file(self.url)
return self._fileName
def __exit__(self, exc_type, exc_value, traceback):
os.remove(self._fileName)
def get_photos_from_tweet(tweet):
photos = []
for url in [get_photo_url(photo) for photo in get_photos(tweet)]:
with DownloadedFile(url) as downloaded:
photos.append(cv2.imread(downloaded, cv2.CV_LOAD_IMAGE_GRAYSCALE))
return photos
class Autofriend(TwitterBot):
def bot_init(self):
############################
# REQUIRED: LOGIN DETAILS! #
############################
self.config['api_key'] = os.environ['TWITTER_API_KEY']
self.config['api_secret'] = os.environ['TWITTER_API_SECRET']
self.config['access_key'] = os.environ['TWITTER_ACCESS_KEY']
self.config['access_secret'] = os.environ['TWITTER_ACCESS_SECRET']
######################################
# SEMI-OPTIONAL: OTHER CONFIG STUFF! #
######################################
# how often to tweet, in seconds
self.config['tweet_interval'] = 30 * 60 # default: 30 minutes
# only include bot followers (and original tweeter) in @-replies
self.config['reply_followers_only'] = True
# fav any tweets that mention this bot?
self.config['autofav_mentions'] = False
# fav any tweets containing these keywords?
self.config['autofav_keywords'] = []
# follow back all followers?
self.config['autofollow'] = True
###########################################
# CUSTOM: your bot's own state variables! #
###########################################
self.register_custom_handler(openshift_wake_up, 60 * 60 * 12)
self.face_regions = partial(
core.face_regions,
core.load_face_detector())
self.face_recognizer = FaceRecognizer()
self.store = Store()
def get_confidence(self):
return float(os.environ.get('AUTOFRIEND_CONFIDENCE') or 50)
def on_scheduled_tweet(self):
pass
def on_follow(self, follower_id):
TwitterBot.on_follow(self, follower_id)
try:
self.store.save_friend((follower_id,))
except pg.IntegrityError:
# aborting is harmless, most likely an unfollow/refollow
self.log("tried to add duplicate twitter friend %s" % follower_id)
def _process_photo(self, friend_id, url):
with DownloadedFile(url) as downloaded:
if self.store.photo_seen(downloaded):
logging.info(
'{} tried to add duplicate photo'.format(friend_id))
else:
face_regions = self.face_regions(
core.prepare_image(downloaded))
self.face_recognizer.update(
[(face_region, friend_id)
for face_region in face_regions])
self.store.remember_photo(downloaded)
def on_direct_message(self, dm):
media = dm.entities.get('media', [])
photo = media[0] if len(media) > 0 else None
if photo:
friend_id = self.store.get_or_create_twitter_friend(
dm.sender.id)['id']
self._process_photo(friend_id, get_photo_url(photo))
self.send_direct_message(dm.sender, compliments.get_compliment())
def on_mention(self, tweet, prefix):
if 'PLEASE FORGET ME' in tweet.text.upper():
self.store.forget_friend(
self.store.get_twitter_friend(tweet.author.id))
self.api.destroy_friendship(tweet.author.id)
else:
friend_id = self.store.get_or_create_twitter_friend(
tweet.author.id)['id']
photo_urls = [get_photo_url(photo) for photo in get_photos(tweet)]
for url in photo_urls:
self._process_photo(friend_id, url)
self.favorite_tweet(tweet)
def on_timeline(self, tweet, prefix):
"""
Defines actions to take on a timeline tweet.
tweet - a tweepy.Status object. You can access the text with
tweet.text
prefix - the @-mentions for this reply. No need to include this in the
reply string; it's provided so you can use it to make sure the value
you return is within the 140 character limit with this.
It's up to you to ensure that the prefix and tweet are less than 140
characters.
When calling post_tweet, you MUST include reply_to=tweet, or
Twitter won't count it as a reply.
"""
photos = get_photos_from_tweet(tweet)
face_regions = core.flatten(
[self.face_regions(photo) for photo in photos])
recognitions = []
for region in face_regions:
try:
recognitions.append(
self.face_recognizer.recognize_face(region))
except cv2.error as e:
logging.error("Error recognizing face region: " + e.message)
likely_recognitions = filter(
lambda (_, margin): margin < self.get_confidence(),
recognitions)
recognized_labels = set([label for (label, _) in likely_recognitions])
for label in recognized_labels:
recognized = self.store.get_friend(label)
# it's possible someone is in the model but not in the database,
# e.g. people that asked to be forgotten
if recognized and recognized.get('twitter_id', None):
twitter_friend = self.api.get_user(recognized['twitter_id'])
self.favorite_tweet(tweet)
self.post_tweet(
prefix +
' ' + compliments.get_compliment() + ' ' +
'@' + twitter_friend.screen_name,
reply_to=tweet)
if __name__ == '__main__':
Autofriend().run()