├── .python-version ├── runtime.txt ├── requirements.txt ├── render.yaml └── app.py /.python-version: -------------------------------------------------------------------------------- 1 | 3.10 2 | -------------------------------------------------------------------------------- /runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.10.13 2 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy==1.23.5 2 | streamlit==1.19.0 3 | deepface==0.0.79 4 | tensorflow==2.10.1 5 | keras==2.10.0 6 | protobuf==3.19.6 7 | opencv-python-headless 8 | requests 9 | altair==4.2.0 10 | vega_datasets==0.9.0 11 | praw 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /render.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | - type: web 3 | name: deepface-streamlit-app 4 | env: python 5 | buildCommand: pip install -r requirements.txt 6 | startCommand: streamlit run app.py --server.port=10000 --server.address=0.0.0.0 7 | runtime: python 8 | pythonVersion: 3.9 9 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | import streamlit as st 2 | import requests 3 | from deepface import DeepFace 4 | import tempfile 5 | import os 6 | import sys 7 | import time 8 | import praw 9 | 10 | 11 | st.set_page_config(page_title="Retrackt: Trace and Report Non Consensual Images on Reddit", layout="centered") 12 | st.write("Python version:", sys.version) 13 | st.title("Find out if your photograph has been reposted on Reddit without your consent") 14 | 15 | reddit = praw.Reddit( 16 | client_id="f2FzYrvaaYz4UFZpr2e0Yg", 17 | client_secret="-3d6VLPEchC7zQ8YoCFNNmYaAhiJOg", 18 | user_agent="Retrackt by u/jeremiahdoe" 19 | ) 20 | 21 | insta_url = st.text_input("Enter Instagram Image URL (direct .jpg/.png preferred):") 22 | insta_username = st.text_input("Enter your Instagram username:") 23 | full_name = st.text_input("Enter your full name:") 24 | uploaded_file = st.file_uploader("Or upload an image", type=["jpg", "jpeg", "png"]) 25 | subreddit = st.text_input("Enter subreddit name to scan:", "BeautifulIndianWomen") 26 | 27 | def download_image(url): 28 | try: 29 | response = requests.get(url, timeout=10) 30 | if response.status_code == 200: 31 | temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".jpg") 32 | temp_file.write(response.content) 33 | temp_file.close() 34 | return temp_file.name 35 | except: 36 | return None 37 | 38 | 39 | def get_all_reddit_images(subreddit_name="BeautifulIndianWomen", limit=1000): 40 | images = [] 41 | 42 | try: 43 | subreddit = reddit.subreddit(subreddit_name) 44 | for submission in subreddit.new(limit=limit): 45 | if submission.url.lower().endswith((".jpg", ".jpeg", ".png")): 46 | images.append({ 47 | "title": submission.title, 48 | "url": submission.url, 49 | "permalink": f"https://reddit.com{submission.permalink}" 50 | }) 51 | except Exception as e: 52 | st.error(f"Failed to fetch Reddit posts: {e}") 53 | 54 | return images 55 | 56 | 57 | if st.button("Find Matches") and (insta_url or uploaded_file): 58 | with st.spinner("Matching... this may take a while"): 59 | 60 | if insta_url: 61 | insta_img_path = download_image(insta_url) 62 | elif uploaded_file: 63 | temp_file = tempfile.NamedTemporaryFile(delete=False) 64 | temp_file.write(uploaded_file.read()) 65 | temp_file.close() 66 | insta_img_path = temp_file.name 67 | else: 68 | st.error("No image provided") 69 | st.stop() 70 | 71 | 72 | reddit_posts = get_all_reddit_images(subreddit_name=subreddit) 73 | 74 | if not reddit_posts: 75 | st.warning("No image posts found in the subreddit.") 76 | st.stop() 77 | 78 | matched = [] 79 | 80 | for idx, post in enumerate(reddit_posts): 81 | try: 82 | reddit_img_path = download_image(post["url"]) 83 | if not reddit_img_path: 84 | continue 85 | 86 | result = DeepFace.verify(insta_img_path, reddit_img_path, enforce_detection=False) 87 | 88 | if result['verified']: 89 | matched.append({ 90 | "reddit_url": post["permalink"], 91 | "image_url": post["url"], 92 | "distance": result["distance"], 93 | "title": post["title"] 94 | }) 95 | 96 | os.remove(reddit_img_path) 97 | 98 | if (idx + 1) % 50 == 0: 99 | st.write(f"Processed {idx + 1} images...") 100 | 101 | except Exception as e: 102 | continue 103 | 104 | os.remove(insta_img_path) 105 | 106 | 107 | if matched: 108 | matched = sorted(matched, key=lambda x: x["distance"])[:3] 109 | st.success(f"Found top {len(matched)} matches:") 110 | 111 | for match in matched: 112 | st.markdown(f"**[{match['title']}]({match['reddit_url']})**") 113 | st.image(match["image_url"], width=300) 114 | st.markdown(f"**Similarity Distance**: `{match['distance']:.3f}`") 115 | st.markdown("---") 116 | else: 117 | st.warning("No matches found.") 118 | --------------------------------------------------------------------------------