­

Auto-Tinder-训练AI玩打火机刷卡游戏

  • 2019 年 10 月 31 日
  • 筆記

在本文档中,将解释创建自动绑定所需的以下步骤:

  • 分析tinder网页以找出tinder内部API调用的内容,在Postman中重构API调用并分析其内容
  • 在python中建立一个API包装器类别,使用Tinder API进行喜欢/不喜欢/比赛等。
  • 下载一堆附近人的图像
  • 编写简单的鼠标单击分类器来标记我们的图像
  • 开发一个使用tensorflow对象检测API的预处理器以仅裁剪图像中的人物
  • 训练Inceptionv3(一种深度卷积神经网络),以学习分类数据
  • 将分类器与tinder API包装器结合使用播放tinder

https://www.getpostman.com/

步骤0:动机和免责声明

Auto Tinder是一个纯粹出于娱乐和教育目的而创建的概念项目。绝不能滥用它来伤害任何人或向平台发送垃圾邮件。自动绑定脚本不应与您的绑定文件一起使用,因为它们肯定违反了绑定服务条款。

编写此软件的原因主要有两个:

  • 因为可以,创建它很有趣:)
  • 想弄清楚一个AI是否真的能够了解我的另一性,并成为我可靠的左右滑动伙伴。

步骤1:分析Tinder API

第一步是找出tinder应用程序如何与tender后端服务器进行通信。由于tinder提供其门户网站的网络版本,因此与访问tinder.com一样简单,它可以打开chrome devtools并快速查看网络协议。

上图中显示的内容是从请求发送到链接的请求,该请求是在tinder.com着陆页加载时发出的。显然,tinder具有某种内部API,正在使用它们在前端和后端之间进行通信。

https://api.gotinder.com/v2/recs/core

通过分析/ recs / core的内容,可以清楚地看到此API端点返回附近人员的用户个人资料列表。

该数据包括(在许多其他字段中)以下数据:

{      "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": []                  }              }          ]      }  }

这里有几件事非常有趣(请注意,更改了所有数据以不侵犯此人的隐私):

  • 所有图像均可公开访问。如果复制图像URL并在私人窗口中打开它,它仍然会立即加载-这意味着tinder将所有用户图像公开上传到Internet,任何人都可以自由查看。
  • 通过API可访问的原始照片具有极高的分辨率。如果将照片上传到tinder,将按比例缩小以适合应用程序内使用,但会将原始版本公开存储在其服务器上,任何人都可以访问。
  • 即使您选择“ show_gender_on_profile”,每个人仍然可以通过API查看性别(“性别”:1,其中1 =女人,0 =男人)
  • 如果连续向tinder API发送多个请求,则始终会得到不同的结果(例如,不同的配置文件)。因此,可以反复地将此端点称为“农场”一堆图片,以后可以用来训练神经网络。

通过分析内容标头,我们可以快速找到私有API密钥:X-Auth-Token。

通过复制此令牌并转到Postman,可以验证确实可以仅使用正确的URL和auth令牌与tinder API自由通信。

通过一点点单击tinders webapp,很快发现了所有相关的API端点:

第2步:在Python中构建API包装器

因此进入代码。为了方便起见,将使用python Requests库与API通信并在其周围编写一个API包装器类。

https://requests.kennethreitz.org/en/master/

同样,编写了一个小的Person类,该类从Tinder接收代表一个Person的API响应,并提供了一些与Tinder API的基本接口。

从Person类开始。它应接收API数据,tinder-api对象,并将所有相关数据保存到实例变量中。它还将提供一些基本功能,例如“喜欢”或“不喜欢”,这些请求向tinder-api发出了请求,这使能够方便地使用“ some_person.like()”来喜欢发现有趣的配置文件。

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)

API包装器不过是使用类调用tinder API的理想方式:

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"]))

现在,可以使用API查找附近的人,并查看个人资料,甚至可以查看所有人。将API令牌替换为之前在chrome开发者控制台中找到的X-Auth-Token。

if __name__ == "__main__":      token = "YOUR-API-TOKEN"      api = tinderAPI(token)        while True:          persons = api.nearby_persons()          for person in persons:              print(person)              # person.like()

第3步:下载附近人的图像

接下来,要自动下载附近的人的一些图像,以用于训练AI。“有些”是指1500-2500张图像。

首先,通过一个允许下载图像的函数来扩展Person类。

# 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+"rn")          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)

请注意,在这里和那里添加了一些随机睡眠,这是因为如果向垃圾邮件CDN发送垃圾邮件并在短短几秒钟内下载许多图片,可能会被阻止。

将所有人员档案ID写入名为“ profiles.txt”的文件中。通过首先扫描文档中是否已存在某个特定人员,可以跳过已经遇到的人员,并确保不会对人员进行多次分类(将在后面看到为什么会有这种风险)。

现在,可以遍历附近的人,并将图像下载到“未分类”文件夹中。

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)

现在,可以简单地启动此脚本,并使其运行几个小时,以获取附近人员的一些Hundret个人资料图片。如果是tinder PRO用户,请立即更新位置,然后结识新朋友。

步骤4:手动分类图像

现在有很多图像可以使用,构建一个非常简单且丑陋的分类器。

它将仅循环遍历“未分类”文件夹中的所有图像,并在GUI窗口中打开该图像。通过右键单击某个人,可以将该人标记为“不喜欢”,而单击鼠标左键将该人标记为“喜欢”。这将在文件名后上表示:4tz3kjldfj3482.jpg将被更名为1_4tz3kjldfj3482.jpg如果纪念像为“像”,或0_4tz3kjldfj3482.jpg否则。标签like / dislike在文件名的开头编码为1/0。

使用tkinter快速编写此GUI:

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()

将所有未分类的图像加载到“ unclassified_images”列表中,打开一个tkinter窗口,通过调用next_img()将第一张图像打包到其中,并调整图像的大小以适合屏幕。然后,单击鼠标左键和鼠标右键两次,并调用正/负函数,该函数会根据其标签重命名图像并显示下一张图像。

丑陋但有效。

第5步:开发预处理程序以仅裁剪图像中的人物

下一步,需要将图像数据转换为允许分类的格式。给定数据集,必须考虑一些困难。

  • 数据集大小:数据集相对较小。考虑到图像的复杂性,处理+ -2000张图像,这被认为是非常少量的数据(高分辨率的RGB图像)
  • 数据差异:这些图片有时包含来自背后的人物,有时仅包含面孔,有时甚至根本没有人物。
  • 数据噪音:大多数图片不仅包含人物本身,而且通常包含周围的环境,这可能分散四个AI的注意力。

通过以下方式应对这些挑战:

  • 将图像转换为灰度,以将AI必须学习的信息量减少三倍(RGB到G)
  • 仅切出图像中实际包含该人的部分,仅此而已

第一部分就像使用“枕头”打开图像并将其转换为灰度图一样容易。对于第二部分,将 Tensorflow对象检测API与mobilenet网络体系结构一起使用,在可可数据集上进行了预训练,该数据集还包含“人”的标签。

https://github.com/tensorflow/models/tree/master/research/object_detection

人检测脚本包含四个部分:

第1部分:打开预训练的mobilenet可可数据集作为Tensorflow图

可以在Github存储库中找到tensorflow mobilenet可可图的.bp文件。将其作为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_graph

第2部分:以numpy数组的形式加载图像

使用枕头进行图像处理。由于tensorflow需要原始的numpy数组来处理数据,因此编写一个小函数将Pillow图像转换为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)

第3部分:调用对象检测API

下一个函数获取图像和张量流图,使用它运行一个张量流会话,并返回有关检测到的类(对象类型),边界框和得分(确定正确检测到对象的确定性)的所有信息。

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_dict 

第4部分:将所有内容组合在一起以找到人

最后一步是编写一个获取图像路径的函数,使用Pillow将其打开,调用对象检测api接口,并根据检测到的人的边界框裁剪图像。

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 None

第5部分:将所有图像移动到分类文件夹中

最后一步,编写一个脚本来循环遍历“未分类”文件夹中的所有图像,并使用先前开发的预处理步骤检查它们是否在名称中具有编码标签,从而将图像复制到“已分类”文件夹中的图像中:

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")

每当运行此脚本时,所有标记的图像都将被处理并移入“分类”目录中的相应子文件夹中。

步骤6:重新训练inceptionv3并编写分类器

对于重新训练部分,将仅将tensorflows retrain.py 脚本与inceptionv3模型一起使用。

https://github.com/tensorflow/hub/blob/master/examples/image_retraining/retrain.py

使用以下参数在项目根目录中调用脚本:

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.001

在GTX 1080 ti上,学习大约需要15分钟,对于标记的数据集,最终精度约为80%,但这在很大程度上取决于输入数据和标记的质量。

训练过程的结果是“ tf / training_output / retrained_graph.pb”文件中的重新训练的inceptionV3模型。现在必须编写一个分类器类,该类可以有效地使用张量流图中的新权重进行分类预测。

写一个Classifier-Class,它以会话形式打开图形,并提供带有图像文件的“ classify”方法,该图像文件将返回具有与标签“ positive”和“ negative”相匹配的确定性值的dict。

该类将图的路径以及标签文件的路径作为输入,它们都位于“ tf / training_output /”文件夹中。开发了用于将图像文件转换为张量的辅助函数,可以将其馈入到图形中,还提供了用于加载图形和标签的辅助函数,以及一个重要的小函数,用于在完成使用后关闭图形。

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

第7步:使用所有这些内容自动播放Tinder

现在已经有了分类器,从前面扩展“ Person”类,并使用“ predict_likeliness”函数对其进行扩展,该函数使用分类器实例来验证是否应喜欢给定的人。

# 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.4

现在,必须将所有拼图组合在一起。

首先,使用api令牌初始化tinder API。然后使用重新训练的图和标签将分类张量流图打开为张量流会话。然后获取附近的人员并进行可能性预测。

作为一个小小的奖励,如果Tinder上的人和我上同一所大学,添加了1.2的似然倍数,这样就更有可能与本地学生匹配。

对于所有预测的可能性得分为0.8的人,称其为“喜欢”,而其他所有人则为“不喜欢”。

将脚本开发为可以在脚本启动后的两个小时内自动播放。

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()

现在可以让脚本运行任意长的时间,并在不拖累拇指的情况下玩弄Tinder!

如果有任何疑问或发现错误,请随时为Github存储库做出贡献。

https://github.com/joelbarmettlerUZH/auto-tinder