File size: 5,986 Bytes
88373da
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9fb1d73
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
import streamlit as st
import requests
import json
import time
import base64
from PIL import Image
from io import BytesIO
from transformers import pipeline
from concurrent.futures import ThreadPoolExecutor

# --- 1. CONFIGURATION & SECRETS ---
# Add your key to Streamlit/HuggingFace Secrets as 'SERPER_API_KEY' for safety
try:
    SERPER_API_KEY = st.secrets["SERPER_API_KEY"]
except:
    # Fallback for local testing
    SERPER_API_KEY = "827d931e4257327f4bcc9a35b2995001a68635d0"

SERPER_URL = "https://google.serper.dev/images"
BG_IMAGE = "vecteezy_abstract-background-design-background-texture-design-with_18752866-1.jpg"
LOADING_VIDEO = "vecteezy_loading-bar-animation_26651030.mp4"

# --- Page Config & Browser Icon ---
st.set_page_config(
    page_title="Bouncer",
    page_icon=BG_IMAGE,  # Sets your custom background as the browser tab icon
    layout="wide"
)

# --- 2. CUSTOM BACKGROUND STYLING ---
def add_custom_style(image_file):
    with open(image_file, "rb") as image:
        encoded_string = base64.b64encode(image.read()).decode()
    st.markdown(
        f"""
        <style>
        .stApp {{
            background-image: url("data:image/jpg;base64,{encoded_string}");
            background-attachment: fixed;
            background-size: cover;
        }}
        /* Sidebar Glassmorphism effect */
        [data-testid="stSidebar"] {{
            background-color: rgba(255, 255, 255, 0.05) !important;
            backdrop-filter: blur(15px);
            border-right: 1px solid rgba(255, 255, 255, 0.1);
        }}
        /* Title shadows for readability */
        h1 {{ color: white !important; text-shadow: 2px 2px 8px #000000; }}
        </style>
        """,
        unsafe_allow_html=True
    )

try:
    add_custom_style(BG_IMAGE)
except:
    st.warning("Background image not found. Ensure the filename is correct.")

# --- 3. AI MODELS ---
@st.cache_resource
def load_models():
    style_pipe = pipeline("zero-shot-image-classification", model="google/siglip-base-patch16-224", device=-1)
    anime_ai_pipe = pipeline("image-classification", model="legekka/AI-Anime-Image-Detector-ViT", device=-1)
    photo_ai_pipe = pipeline("image-classification", model="Ateeqq/ai-vs-human-image-detector", device=-1)
    return style_pipe, anime_ai_pipe, photo_ai_pipe

style_classifier, anime_ai_detector, photo_ai_detector = load_models()

# --- 4. PROCESSING LOGIC ---
def get_score(preds, target_labels):
    for p in preds:
        if p['label'].lower() in target_labels: return p['score']
    return 0.0

def download_and_process(item, tolerance):
    url = item.get("imageUrl") 
    try:
        response = requests.get(url, timeout=5)
        # Robust opening to handle transparency
        raw_img = Image.open(BytesIO(response.content))
        img = raw_img.convert("RGBA").convert("RGB")
        img_small = img.resize((224, 224))
        
        style_results = style_classifier(img_small, candidate_labels=["anime illustration", "real photo"])
        top_style = style_results[0]['label']
        
        if top_style == "anime illustration":
            preds = anime_ai_detector(img_small)
            # Model uses 'natural' for human art
            human_score = get_score(preds, ['natural', 'human', 'real'])
        else:
            preds = photo_ai_detector(img_small)
            human_score = get_score(preds, ['human', 'real', 'natural'])
            
        if human_score >= tolerance:
            return {"img": img, "score": human_score, "url": url, "style": top_style}
    except: return None

# --- 5. SIDEBAR CONTROLS ---
with st.sidebar:
    st.title("Toggle go vurrrr")
    query = st.text_input("What are you looking for?", "Concept Art")

    # Target Count with Help
    c1, c2 = st.columns([4, 1])
    target_count = c1.slider("Results", 1, 40, 6)
    if c2.button("❓", key="h_count"):
        st.info("The number of human-made images you want to see.")

    # Strictness with Help
    s1, s2 = st.columns([4, 1])
    tolerance = s1.slider("Strictness", 0.0, 1.0, 0.5)
    if s2.button("❓", key="h_strict"):
        st.info("How sure the AI must be. 0.8+ is strict; 0.2 is loose.")

    # Threads with Help
    t1, t2 = st.columns([4, 1])
    workers = t1.slider("Threads", 2, 16, 8)
    if t2.button("❓", key="h_thread"):
        st.info("Processing speed. Higher is faster but heavier on memory.")

    start_search = st.button("Scanning the Internet for Target", use_container_width=True)

# --- 6. MAIN DISPLAY & LOADING BAR ---
st.markdown("Bouncer")
st.write("Creativity shall not yeild to none")

if start_search and query:
    start_time = time.time()
    
    # Custom Video Loading Bar
    loading_placeholder = st.empty()
    with loading_placeholder.container():
        st.video(LOADING_VIDEO, autoplay=True, loop=True, muted=True)
        st.write("### Cleaning Slop")

    # Fetch and process
    payload = json.dumps({"q": query, "num": target_count * 3})
    headers = {'X-API-KEY': SERPER_API_KEY, 'Content-Type': 'application/json'}
    response = requests.post(SERPER_URL, headers=headers, data=payload)
    raw_results = response.json().get("images", [])

    if raw_results:
        with ThreadPoolExecutor(max_workers=workers) as executor:
            results = list(executor.map(lambda r: download_and_process(r, tolerance), raw_results))
            final_images = [r for r in results if r is not None][:target_count]

        # Remove the loading video once finished
        loading_placeholder.empty()

        if final_images:
            st.success(f"Verified {len(final_images)} images in {time.time() - start_time:.1f}s")
            cols = st.columns(3)
            for i, item in enumerate(final_images):
                with cols[i % 3]:
                    st.image(item["img"], use_container_width=True)
                    st.caption(f"Human Confidence: {item['score']:.0%}")
        else:
            st.warning("No images passed the AI filter. Try lowering 'Strictness'.")