Auto-Tinder dibuat untuk melatih API menggunakan TensorFlow dan Python3 yang mempelajari minat Anda dan secara otomatis memainkan permainan geser Tinder untuk Anda.

Dalam dokumen ini, saya akan menjelaskan langkah-langkah berikut yang diperlukan untuk membuat auto-tinder:
Auto Tinder adalah proyek konsep yang dibuat murni untuk tujuan yang menyenangkan dan pendidikan. Tidak akan pernah disalahgunakan untuk menyakiti siapa pun atau spam platform. Script Auto-Tinder tidak boleh digunakan dengan profil Tinder Anda karena mereka pasti melanggar Ketentuan Layanan Tinders.
Saya telah menulis perangkat lunak ini terutama dari dua alasan:
Langkah pertama adalah mengetahui bagaimana aplikasi Tinder berkomunikasi ke Tinders Backend Server. Karena Tinder menawarkan versi web portal, ini semudah pergi ke Tinder.com, membuka Chrome Devtools dan melihat secara cepat protokol jaringan.
Konten yang ditunjukkan pada gambar di atas adalah dari permintaan ke https://api.gotinder.com/v2/recs/core yang dibuat ketika halaman pendaratan Tinder.com memuat. Jelas, Tinder memiliki semacam API internal yang mereka gunakan untuk berkomunikasi antara bagian depan dan backend.
Dengan menganalisis konten /recs /core , menjadi jelas bahwa titik akhir API ini mengembalikan daftar profil pengguna orang di dekatnya.
Data termasuk (di antara banyak bidang lainnya), data berikut:
{
"meta" : {
"status" : 200
},
"data" : {
"results" : [
{
"type" : " user " ,
"user" : {
"_id" : " 4adfwe547s8df64df " ,
"bio" : " 19y. " ,
"birth_date" : " 1997-17-06T18:21:44.654Z " ,
"name" : " Anna " ,
"photos" : [
{
"id" : " 879sdfert-lskdföj-8asdf879-987sdflkj " ,
"crop_info" : {
"user" : {
"width_pct" : 1 ,
"x_offset_pct" : 0 ,
"height_pct" : 0.8 ,
"y_offset_pct" : 0.08975463
},
"algo" : {
"width_pct" : 0.45674357 ,
"x_offset_pct" : 0.984341657 ,
"height_pct" : 0.234165403 ,
"y_offset_pct" : 0.78902343
},
"processed_by_bullseye" : true ,
"user_customized" : false
},
"url" : " https://images-ssl.gotinder.com/4adfwe547s8df64df/original_879sdfert-lskdföj-8asdf879-987sdflkj.jpeg " ,
"processedFiles" : [
{
"url" : " https://images-ssl.gotinder.com/4adfwe547s8df64df/640x800_879sdfert-lskdföj-8asdf879-987sdflkj.jpg " ,
"height" : 800 ,
"width" : 640
},
{
"url" : " https://images-ssl.gotinder.com/4adfwe547s8df64df/320x400_879sdfert-lskdföj-8asdf879-987sdflkj.jpg " ,
"height" : 400 ,
"width" : 320
},
{
"url" : " https://images-ssl.gotinder.com/4adfwe547s8df64df/172x216_879sdfert-lskdföj-8asdf879-987sdflkj.jpg " ,
"height" : 216 ,
"width" : 172
},
{
"url" : " https://images-ssl.gotinder.com/4adfwe547s8df64df/84x106_879sdfert-lskdföj-8asdf879-987sdflkj.jpg " ,
"height" : 106 ,
"width" : 84
}
],
"last_update_time" : " 2019-10-03T16:18:30.532Z " ,
"fileName" : " 879sdfert-lskdföj-8asdf879-987sdflkj.webp " ,
"extension" : " jpg,webp " ,
"webp_qf" : [
75
]
}
],
"gender" : 1 ,
"jobs" : [],
"schools" : [],
"show_gender_on_profile" : false
},
"facebook" : {
"common_connections" : [],
"connection_count" : 0 ,
"common_interests" : []
},
"spotify" : {
"spotify_connected" : false
},
"distance_mi" : 1 ,
"content_hash" : " slkadjfiuwejsdfuzkejhrsdbfskdzufiuerwer " ,
"s_number" : 9876540657341 ,
"teaser" : {
"string" : " "
},
"teasers" : [],
"snap" : {
"snaps" : []
}
}
]
}
}
Beberapa hal sangat menarik di sini (perhatikan bahwa saya mengubah semua data untuk tidak melanggar privasi orang ini) :
Dengan menganalisis header konten, kami dengan cepat menemukan kunci API pribadi kami: X-Auth-Token .
Dengan menyalin token ini dan pergi ke tukang pos, kami dapat memvalidasi bahwa kami memang dapat berkomunikasi dengan bebas dengan API Tinder dengan URL yang tepat dan token auth kami.
Dengan mengklik sedikit melalui Tinders Webapp, saya segera menemukan semua titik akhir API yang relevan:
| Jenis | Url | Keterangan |
|---|---|---|
| MENDAPATKAN | /v2/recs/core | Mengembalikan daftar orang di dekatnya |
| MENDAPATKAN | /v2/profil? Termasuk = akun%2cuser | Mengembalikan semua informasi tentang profil Anda sendiri |
| MENDAPATKAN | /v2/cocok | Mengembalikan daftar semua orang yang cocok dengan Anda |
| MENDAPATKAN | /suka/{user_id} | Menyukai orang dengan user_id yang diberikan |
| MENDAPATKAN | /pass/{user_id} | Melewati orang dengan user_id yang diberikan |
Jadi mari kita masuk ke kode. Kami akan menggunakan perpustakaan permintaan Python untuk berkomunikasi dengan API dan menulis kelas pembungkus API di sekitarnya untuk kenyamanan.
Demikian pula, kami menulis kelas orang kecil yang mengambil respons API dari Tinder yang mewakili seseorang dan menawarkan beberapa antarmuka dasar ke API Tinder.
Mari kita mulai dengan kelas orang. Ini akan menerima data API, objek Tinder-API dan menyimpan semua data yang relevan ke dalam variabel instan. Lebih lanjut akan menawarkan beberapa fitur dasar seperti "seperti" atau "tidak suka" yang membuat permintaan ke Tinder-API, yang memungkinkan kami untuk menggunakan "some_person.," "dengan mudah untuk menyukai profil yang kami anggap menarik.
import datetime
from geopy . geocoders import Nominatim
TINDER_URL = "https://api.gotinder.com"
geolocator = Nominatim ( user_agent = "auto-tinder" )
PROF_FILE = "./images/unclassified/profiles.txt"
class Person ( object ):
def __init__ ( self , data , api ):
self . _api = api
self . id = data [ "_id" ]
self . name = data . get ( "name" , "Unknown" )
self . bio = data . get ( "bio" , "" )
self . distance = data . get ( "distance_mi" , 0 ) / 1.60934
self . birth_date = datetime . datetime . strptime ( data [ "birth_date" ], '%Y-%m-%dT%H:%M:%S.%fZ' ) if data . get (
"birth_date" , False ) else None
self . gender = [ "Male" , "Female" , "Unknown" ][ data . get ( "gender" , 2 )]
self . images = list ( map ( lambda photo : photo [ "url" ], data . get ( "photos" , [])))
self . jobs = list (
map ( lambda job : { "title" : job . get ( "title" , {}). get ( "name" ), "company" : job . get ( "company" , {}). get ( "name" )}, data . get ( "jobs" , [])))
self . schools = list ( map ( lambda school : school [ "name" ], data . get ( "schools" , [])))
if data . get ( "pos" , False ):
self . location = geolocator . reverse ( f' { data [ "pos" ][ "lat" ] } , { data [ "pos" ][ "lon" ] } ' )
def __repr__ ( self ):
return f" { self . id } - { self . name } ( { self . birth_date . strftime ( '%d.%m.%Y' ) } )"
def like ( self ):
return self . _api . like ( self . id )
def dislike ( self ):
return self . _api . dislike ( self . id )Pembungkus API kami tidak lebih dari cara yang mewah untuk menyebut Tinder API menggunakan kelas:
import requests
TINDER_URL = "https://api.gotinder.com"
class tinderAPI ():
def __init__ ( self , token ):
self . _token = token
def profile ( self ):
data = requests . get ( TINDER_URL + "/v2/profile?include=account%2Cuser" , headers = { "X-Auth-Token" : self . _token }). json ()
return Profile ( data [ "data" ], self )
def matches ( self , limit = 10 ):
data = requests . get ( TINDER_URL + f"/v2/matches?count= { limit } " , headers = { "X-Auth-Token" : self . _token }). json ()
return list ( map ( lambda match : Person ( match [ "person" ], self ), data [ "data" ][ "matches" ]))
def like ( self , user_id ):
data = requests . get ( TINDER_URL + f"/like/ { user_id } " , headers = { "X-Auth-Token" : self . _token }). json ()
return {
"is_match" : data [ "match" ],
"liked_remaining" : data [ "likes_remaining" ]
}
def dislike ( self , user_id ):
requests . get ( TINDER_URL + f"/pass/ { user_id } " , headers = { "X-Auth-Token" : self . _token }). json ()
return True
def nearby_persons ( self ):
data = requests . get ( TINDER_URL + "/v2/recs/core" , headers = { "X-Auth-Token" : self . _token }). json ()
return list ( map ( lambda user : Person ( user [ "user" ], self ), data [ "data" ][ "results" ]))Kita sekarang dapat menggunakan API untuk menemukan orang di dekatnya dan melihat profil mereka, atau bahkan seperti mereka semua. Ganti-api-Token Anda dengan X-Auth-Token yang Anda temukan di konsol Dev Chrome sebelumnya.
if __name__ == "__main__" :
token = "YOUR-API-TOKEN"
api = tinderAPI ( token )
while True :
persons = api . nearby_persons ()
for person in persons :
print ( person )
# person.like() Selanjutnya, kami ingin secara otomatis mengunduh beberapa gambar orang di dekatnya yang dapat kami gunakan untuk melatih AI kami. Dengan 'beberapa', maksud saya seperti 1500-2500 gambar.
Pertama, mari kita memperpanjang kelas orang kita dengan fungsi yang memungkinkan kita mengunduh gambar.
# At the top of auto_tinder.py
PROF_FILE = "./images/unclassified/profiles.txt"
# inside the Person-class
def download_images ( self , folder = "." , sleep_max_for = 0 ):
with open ( PROF_FILE , "r" ) as f :
lines = f . readlines ()
if self . id in lines :
return
with open ( PROF_FILE , "a" ) as f :
f . write ( self . id + " r n " )
index = - 1
for image_url in self . images :
index += 1
req = requests . get ( image_url , stream = True )
if req . status_code == 200 :
with open ( f" { folder } / { self . id } _ { self . name } _ { index } .jpeg" , "wb" ) as f :
f . write ( req . content )
sleep ( random () * sleep_max_for )Perhatikan bahwa saya menambahkan beberapa tidur acak di sana -sini, hanya karena kami kemungkinan akan diblokir jika kami spam Tinder CDN dan mengunduh banyak gambar hanya dalam beberapa detik.
Kami menulis semua ID profil orang ke dalam file yang disebut "Profiles.txt". Dengan terlebih dahulu memindai dokumen apakah orang tertentu sudah ada di sana, kami dapat melewatkan orang yang sudah kami temui, dan kami memastikan bahwa kami tidak mengklasifikasikan orang beberapa kali (Anda akan melihat nanti mengapa ini adalah risiko).
Kami sekarang hanya dapat mengulangi orang -orang terdekat dan mengunduh gambar mereka ke folder "tidak diklasifikasikan".
if __name__ == "__main__" :
token = "YOUR-API-TOKEN"
api = tinderAPI ( token )
while True :
persons = api . nearby_persons ()
for person in persons :
person . download_images ( folder = "./images/unclassified" , sleep_max_for = random () * 3 )
sleep ( random () * 10 )
sleep ( random () * 10 )Kita sekarang dapat dengan mudah memulai skrip ini dan membiarkannya berjalan selama beberapa jam untuk mendapatkan beberapa gambar profil hundret orang di dekatnya. Jika Anda adalah pengguna Tinder Pro, perbarui lokasi Anda sekarang dan kemudian untuk mendapatkan orang baru.
Sekarang kita memiliki banyak gambar untuk dikerjakan, mari kita membangun classifier yang sangat sederhana dan jelek.
Ini hanya akan mengulangi semua gambar di folder "tidak diklasifikasikan" kami dan membuka gambar di jendela GUI. Dengan mengklik kanan seseorang, kita dapat menandai orang itu sebagai "tidak suka", sementara klik kiri menandai orang itu sebagai "seperti". Ini akan diwakili dalam nama file nanti: 4tz3kjldfj3482.jpg akan diganti namanya menjadi 1_4tz3kjldfj3482.jpg jika kita menandai gambar sebagai "seperti", atau 0_4tz3kjldfj3482.jpg sebaliknya. Label seperti/tidak suka dikodekan sebagai 1/0 di awal filenmae.
Mari kita gunakan Tkinter untuk menulis GUI ini dengan cepat:
from os import listdir , rename
from os . path import isfile , join
import tkinter as tk
from PIL import ImageTk , Image
IMAGE_FOLDER = "./images/unclassified"
images = [ f for f in listdir ( IMAGE_FOLDER ) if isfile ( join ( IMAGE_FOLDER , f ))]
unclassified_images = filter ( lambda image : not ( image . startswith ( "0_" ) or image . startswith ( "1_" )), images )
current = None
def next_img ():
global current , unclassified_images
try :
current = next ( unclassified_images )
except StopIteration :
root . quit ()
print ( current )
pil_img = Image . open ( IMAGE_FOLDER + "/" + current )
width , height = pil_img . size
max_height = 1000
if height > max_height :
resize_factor = max_height / height
pil_img = pil_img . resize (( int ( width * resize_factor ), int ( height * resize_factor )), resample = Image . LANCZOS )
img_tk = ImageTk . PhotoImage ( pil_img )
img_label . img = img_tk
img_label . config ( image = img_label . img )
def positive ( arg ):
global current
rename ( IMAGE_FOLDER + "/" + current , IMAGE_FOLDER + "/1_" + current )
next_img ()
def negative ( arg ):
global current
rename ( IMAGE_FOLDER + "/" + current , IMAGE_FOLDER + "/0_" + current )
next_img ()
if __name__ == "__main__" :
root = tk . Tk ()
img_label = tk . Label ( root )
img_label . pack ()
img_label . bind ( "<Button-1>" , positive )
img_label . bind ( "<Button-3>" , negative )
btn = tk . Button ( root , text = 'Next image' , command = next_img )
next_img () # load first image
root . mainloop ()Kami memuat semua gambar yang tidak diklasifikasikan ke dalam daftar "unclasified_images", membuka jendela Tkinter, mengemas gambar pertama ke dalamnya dengan memanggil next_img () dan mengubah ukuran gambar agar sesuai dengan layar. Kemudian, kami mendaftarkan dua klik, tombol mouse kiri dan kanan, dan memanggil fungsi positif/negatif yang mengganti nama gambar sesuai dengan label mereka dan menunjukkan gambar berikutnya.
Jelek tapi efektif.
Untuk langkah selanjutnya, kita perlu membawa data gambar kita ke dalam format yang memungkinkan kita melakukan klasifikasi. Ada beberapa kesulitan yang harus kami pertimbangkan mengingat dataset kami.
Kami memerangi tantangan ini dengan:

Bagian pertama semudah menggunakan bantal untuk membuka gambar kami dan mengubahnya menjadi greyscale. Untuk bagian kedua, kami menggunakan API Deteksi Objek TensorFlow dengan Arsitektur Jaringan MobileNet, pretrain pada dataset Coco yang juga berisi label untuk "orang".
Skrip kami untuk deteksi orang memiliki empat bagian:
Anda menemukan file .bp untuk grafik TensorFlow MobileNet Coco di repositori GitHub saya. Mari buka sebagai grafik TensorFlow:
import tensorflow as tf
def open_graph ():
detection_graph = tf . Graph ()
with detection_graph . as_default ():
od_graph_def = tf . GraphDef ()
with tf . gfile . GFile ( 'ssd_mobilenet_v1_coco_2017_11_17/frozen_inference_graph.pb' , 'rb' ) as fid :
serialized_graph = fid . read ()
od_graph_def . ParseFromString ( serialized_graph )
tf . import_graph_def ( od_graph_def , name = '' )
return detection_graphKami menggunakan bantal untuk manipulasi gambar. Karena TensorFlow membutuhkan array Numpy mentah untuk bekerja dengan data, mari kita tulis fungsi kecil yang mengubah gambar bantal menjadi array numpy:
import numpy as np
def load_image_into_numpy_array ( image ):
( im_width , im_height ) = image . size
return np . array ( image . getdata ()). reshape (
( im_height , im_width , 3 )). astype ( np . uint8 )Fungsi berikutnya mengambil gambar dan grafik TensorFlow, menjalankan sesi TensorFlow menggunakannya dan mengembalikan semua informasi tentang kelas yang terdeteksi (tipe objek), kotak pembatas dan skor (kepastian bahwa objek dideteksi dengan benar).
import numpy as np
from object_detection . utils import ops as utils_ops
import tensorflow as tf
def run_inference_for_single_image ( image , sess ):
ops = tf . get_default_graph (). get_operations ()
all_tensor_names = { output . name for op in ops for output in op . outputs }
tensor_dict = {}
for key in [
'num_detections' , 'detection_boxes' , 'detection_scores' ,
'detection_classes' , 'detection_masks'
]:
tensor_name = key + ':0'
if tensor_name in all_tensor_names :
tensor_dict [ key ] = tf . get_default_graph (). get_tensor_by_name (
tensor_name )
if 'detection_masks' in tensor_dict :
# The following processing is only for single image
detection_boxes = tf . squeeze ( tensor_dict [ 'detection_boxes' ], [ 0 ])
detection_masks = tf . squeeze ( tensor_dict [ 'detection_masks' ], [ 0 ])
# Reframe is required to translate mask from box coordinates to image coordinates and fit the image size.
real_num_detection = tf . cast ( tensor_dict [ 'num_detections' ][ 0 ], tf . int32 )
detection_boxes = tf . slice ( detection_boxes , [ 0 , 0 ], [ real_num_detection , - 1 ])
detection_masks = tf . slice ( detection_masks , [ 0 , 0 , 0 ], [ real_num_detection , - 1 , - 1 ])
detection_masks_reframed = utils_ops . reframe_box_masks_to_image_masks (
detection_masks , detection_boxes , image . shape [ 1 ], image . shape [ 2 ])
detection_masks_reframed = tf . cast (
tf . greater ( detection_masks_reframed , 0.5 ), tf . uint8 )
# Follow the convention by adding back the batch dimension
tensor_dict [ 'detection_masks' ] = tf . expand_dims (
detection_masks_reframed , 0 )
image_tensor = tf . get_default_graph (). get_tensor_by_name ( 'image_tensor:0' )
# Run inference
output_dict = sess . run ( tensor_dict ,
feed_dict = { image_tensor : image })
# all outputs are float32 numpy arrays, so convert types as appropriate
output_dict [ 'num_detections' ] = int ( output_dict [ 'num_detections' ][ 0 ])
output_dict [ 'detection_classes' ] = output_dict [
'detection_classes' ][ 0 ]. astype ( np . int64 )
output_dict [ 'detection_boxes' ] = output_dict [ 'detection_boxes' ][ 0 ]
output_dict [ 'detection_scores' ] = output_dict [ 'detection_scores' ][ 0 ]
if 'detection_masks' in output_dict :
output_dict [ 'detection_masks' ] = output_dict [ 'detection_masks' ][ 0 ]
return output_dictLangkah terakhir adalah menulis fungsi yang mengambil jalur gambar, membukanya menggunakan bantal, memanggil antarmuka API deteksi objek dan memotong gambar sesuai dengan kotak pembatas orang yang terdeteksi.
import numpy as np
from PIL import Image
PERSON_CLASS = 1
SCORE_THRESHOLD = 0.5
def get_person ( image_path , sess ):
img = Image . open ( image_path )
image_np = load_image_into_numpy_array ( img )
image_np_expanded = np . expand_dims ( image_np , axis = 0 )
output_dict = run_inference_for_single_image ( image_np_expanded , sess )
persons_coordinates = []
for i in range ( len ( output_dict [ "detection_boxes" ])):
score = output_dict [ "detection_scores" ][ i ]
classtype = output_dict [ "detection_classes" ][ i ]
if score > SCORE_THRESHOLD and classtype == PERSON_CLASS :
persons_coordinates . append ( output_dict [ "detection_boxes" ][ i ])
w , h = img . size
for person_coordinate in persons_coordinates :
cropped_img = img . crop ((
int ( w * person_coordinate [ 1 ]),
int ( h * person_coordinate [ 0 ]),
int ( w * person_coordinate [ 3 ]),
int ( h * person_coordinate [ 2 ]),
))
return cropped_img
return NoneSebagai langkah terakhir, kami menulis skrip yang mengulangi semua gambar di folder "tidak diklasifikasikan", memeriksa apakah mereka memiliki label yang dikodekan dalam nama salinan gambar di folder "diklasifikasikan" menurut dengan menerapkan langkah preprocessing yang dikembangkan sebelumnya:
import os
import person_detector
import tensorflow as tf
IMAGE_FOLDER = "./images/unclassified"
POS_FOLDER = "./images/classified/positive"
NEG_FOLDER = "./images/classified/negative"
if __name__ == "__main__" :
detection_graph = person_detector . open_graph ()
images = [ f for f in os . listdir ( IMAGE_FOLDER ) if os . path . isfile ( os . path . join ( IMAGE_FOLDER , f ))]
positive_images = filter ( lambda image : ( image . startswith ( "1_" )), images )
negative_images = filter ( lambda image : ( image . startswith ( "0_" )), images )
with detection_graph . as_default ():
with tf . Session () as sess :
for pos in positive_images :
old_filename = IMAGE_FOLDER + "/" + pos
new_filename = POS_FOLDER + "/" + pos [: - 5 ] + ".jpg"
if not os . path . isfile ( new_filename ):
img = person_detector . get_person ( old_filename , sess )
if not img :
continue
img = img . convert ( 'L' )
img . save ( new_filename , "jpeg" )
for neg in negative_images :
old_filename = IMAGE_FOLDER + "/" + neg
new_filename = NEG_FOLDER + "/" + neg [: - 5 ] + ".jpg"
if not os . path . isfile ( new_filename ):
img = person_detector . get_person ( old_filename , sess )
if not img :
continue
img = img . convert ( 'L' )
img . save ( new_filename , "jpeg" )Ketika kami menjalankan skrip ini, semua gambar berlabel sedang diproses dan dipindahkan ke subfolder yang sesuai di direktori "diklasifikasikan".
Untuk bagian pelatihan ulang, kami hanya akan menggunakan skrip TensorFlows Retrain.py dengan model InceptionV3.
Hubungi skrip di direktori root proyek Anda dengan parameter berikut:
python retrain.py --bottleneck_dir=tf/training_data/bottlenecks --model_dir=tf/training_data/inception --summaries_dir=tf/training_data/summaries/basic --output_graph=tf/training_output/retrained_graph.pb --output_labels=tf/training_output/retrained_labels.txt --image_dir=./images/classified --how_many_training_steps=50000 --testing_percentage=20 --learning_rate=0.001Pembelajaran memakan waktu sekitar 15 menit pada GTX 1080 Ti, dengan akurasi akhir sekitar 80% untuk dataset berlabel saya, tetapi ini sangat tergantung pada kualitas data input Anda dan pelabelan Anda.
Hasil dari proses pelatihan adalah model InceptionV3 yang dilatih kembali dalam file "TF/Training_output/Retrained_Graph.pb". Kita sekarang harus menulis kelas classifier yang secara efisien menggunakan bobot baru dalam grafik TensorFlow untuk membuat prediksi klasifikasi.
Mari kita tulis kelas classifier yang membuka grafik sebagai sesi dan menawarkan metode "klasifikasi" dengan file gambar yang mengembalikan dikt dengan nilai-nilai pasti yang cocok dengan label kami "positif" dan "negatif".
Kelas mengambil sebagai memasukkan jalur ke grafik maupun jalur ke file label, keduanya duduk di folder "TF/Training_Output/" kami. Kami mengembangkan fungsi helper untuk mengonversi file gambar ke tensor yang dapat kami masukkan ke dalam grafik kami, fungsi pembantu untuk memuat grafik dan label dan fungsi kecil yang penting untuk menutup grafik kami setelah kami selesai menggunakannya.
import numpy as np
import tensorflow as tf
class Classifier ():
def __init__ ( self , graph , labels ):
self . _graph = self . load_graph ( graph )
self . _labels = self . load_labels ( labels )
self . _input_operation = self . _graph . get_operation_by_name ( "import/Placeholder" )
self . _output_operation = self . _graph . get_operation_by_name ( "import/final_result" )
self . _session = tf . Session ( graph = self . _graph )
def classify ( self , file_name ):
t = self . read_tensor_from_image_file ( file_name )
# Open up a new tensorflow session and run it on the input
results = self . _session . run ( self . _output_operation . outputs [ 0 ], { self . _input_operation . outputs [ 0 ]: t })
results = np . squeeze ( results )
# Sort the output predictions by prediction accuracy
top_k = results . argsort ()[ - 5 :][:: - 1 ]
result = {}
for i in top_k :
result [ self . _labels [ i ]] = results [ i ]
# Return sorted result tuples
return result
def close ( self ):
self . _session . close ()
@ staticmethod
def load_graph ( model_file ):
graph = tf . Graph ()
graph_def = tf . GraphDef ()
with open ( model_file , "rb" ) as f :
graph_def . ParseFromString ( f . read ())
with graph . as_default ():
tf . import_graph_def ( graph_def )
return graph
@ staticmethod
def load_labels ( label_file ):
label = []
proto_as_ascii_lines = tf . gfile . GFile ( label_file ). readlines ()
for l in proto_as_ascii_lines :
label . append ( l . rstrip ())
return label
@ staticmethod
def read_tensor_from_image_file ( file_name ,
input_height = 299 ,
input_width = 299 ,
input_mean = 0 ,
input_std = 255 ):
input_name = "file_reader"
file_reader = tf . read_file ( file_name , input_name )
image_reader = tf . image . decode_jpeg (
file_reader , channels = 3 , name = "jpeg_reader" )
float_caster = tf . cast ( image_reader , tf . float32 )
dims_expander = tf . expand_dims ( float_caster , 0 )
resized = tf . image . resize_bilinear ( dims_expander , [ input_height , input_width ])
normalized = tf . divide ( tf . subtract ( resized , [ input_mean ]), [ input_std ])
sess = tf . Session ()
result = sess . run ( normalized )
return result Sekarang setelah kita memiliki classifier kita di tempat, mari kita memperpanjang kelas "orang" dari sebelumnya dan memperpanjangnya dengan fungsi "prediksi_likeliness" yang menggunakan instance classifier untuk memverifikasi apakah orang tertentu harus disukai atau tidak.
# In the Person class
def predict_likeliness ( self , classifier , sess ):
ratings = []
for image in self . images :
req = requests . get ( image , stream = True )
tmp_filename = f"./images/tmp/run.jpg"
if req . status_code == 200 :
with open ( tmp_filename , "wb" ) as f :
f . write ( req . content )
img = person_detector . get_person ( tmp_filename , sess )
if img :
img = img . convert ( 'L' )
img . save ( tmp_filename , "jpeg" )
certainty = classifier . classify ( tmp_filename )
pos = certainty [ "positive" ]
ratings . append ( pos )
ratings . sort ( reverse = True )
ratings = ratings [: 5 ]
if len ( ratings ) == 0 :
return 0.001
return ratings [ 0 ] * 0.6 + sum ( ratings [ 1 :]) / len ( ratings [ 1 :]) * 0.4Sekarang kita harus menyatukan semua potongan puzzle.
Pertama, mari inisialisasi API Tinder dengan token API kami. Kemudian, kami membuka grafik TensorFlow klasifikasi kami sebagai sesi TensorFlow menggunakan grafik dan label yang dilatih kembali. Kemudian, kami menjemput orang di dekatnya dan membuat prediksi kemungkinan.
Sebagai bonus kecil, saya menambahkan kemungkinan-multiplier dari 1.2 jika orang di Tinder pergi ke universitas yang sama seperti saya, sehingga saya lebih cenderung cocok dengan siswa setempat.
Untuk semua orang yang memiliki skor kemungkinan yang diprediksi 0,8, saya sebut sejenisnya, untuk yang lainnya tidak suka.
Saya mengembangkan skrip untuk bermain otomatis selama 2 jam ke depan setelah dimulai.
from likeliness_classifier import Classifier
import person_detector
import tensorflow as tf
from time import time
if __name__ == "__main__" :
token = "YOUR-API-TOKEN"
api = tinderAPI ( token )
detection_graph = person_detector . open_graph ()
with detection_graph . as_default ():
with tf . Session () as sess :
classifier = Classifier ( graph = "./tf/training_output/retrained_graph.pb" ,
labels = "./tf/training_output/retrained_labels.txt" )
end_time = time () + 60 * 60 * 2
while time () < end_time :
try :
persons = api . nearby_persons ()
pos_schools = [ "Universität Zürich" , "University of Zurich" , "UZH" ]
for person in persons :
score = person . predict_likeliness ( classifier , sess )
for school in pos_schools :
if school in person . schools :
print ()
score *= 1.2
print ( "-------------------------" )
print ( "ID: " , person . id )
print ( "Name: " , person . name )
print ( "Schools: " , person . schools )
print ( "Images: " , person . images )
print ( score )
if score > 0.8 :
res = person . like ()
print ( "LIKE" )
else :
res = person . dislike ()
print ( "DISLIKE" )
except Exception :
pass
classifier . close ()Itu saja! Kita sekarang dapat membiarkan skrip kita berjalan selama kita suka dan bermain Tinder tanpa menyalahgunakan ibu jari kita!
Jika Anda memiliki pertanyaan atau menemukan bug, jangan ragu untuk berkontribusi pada repositori GitHub saya.
Lisensi MIT
Hak Cipta (C) 2018 Joel Barmettler
Izin dengan ini diberikan, gratis, kepada siapa pun yang mendapatkan salinan perangkat lunak ini dan file dokumentasi terkait ("Perangkat Lunak"), untuk menangani perangkat lunak tanpa pembatasan, termasuk tanpa batasan hak untuk menggunakan, menyalin, memodifikasi, menggabungkan , menerbitkan, mendistribusikan, sublisense, dan/atau menjual salinan perangkat lunak, dan untuk mengizinkan orang -orang yang dilengkapi dengan perangkat lunak untuk melakukannya, tunduk pada kondisi berikut:
Pemberitahuan hak cipta di atas dan pemberitahuan izin ini harus dimasukkan dalam semua salinan atau bagian substansial dari perangkat lunak.
Perangkat lunak ini disediakan "sebagaimana adanya", tanpa jaminan apa pun, tersurat maupun tersirat, termasuk tetapi tidak terbatas pada jaminan dapat diperjualbelikan, kebugaran untuk tujuan tertentu dan nonpringement. Dalam hal apa pun penulis atau pemegang hak cipta tidak akan bertanggung jawab atas klaim, kerusakan atau tanggung jawab lainnya, baik dalam tindakan kontrak, gugatan atau sebaliknya, timbul dari, di luar atau sehubungan dengan perangkat lunak atau penggunaan atau transaksi lain dalam PERANGKAT LUNAK.
Pekerjakan kami: Perangkat lunak Entwickler di Zürich!