Test_AI_or_Real / app.py
HotshotGoku's picture
changed display res of demo_
26884f2
import os, random, json
from datetime import datetime
from PIL import Image, ImageOps
import numpy as np
import gradio as gr
from gspread import service_account_from_dict
from huggingface_hub import HfApi, hf_hub_download
# -------- Configuration --------
HF_TOKEN = os.environ["HF_TOKEN"]
api = HfApi(token=HF_TOKEN)
REPO_ID = "HotshotGoku/Images_Test_AI_or_Real"
# List files in the dataset
all_files = api.list_repo_files(
repo_id=REPO_ID,
repo_type="dataset"
)
# Get the AI vs Real folders
ai_remote = [f for f in all_files if f.startswith("AI/")]
real_remote = [f for f in all_files if f.startswith("Real/")]
ai_files = [hf_hub_download(repo_id=REPO_ID, repo_type="dataset",filename=path, token=HF_TOKEN) for path in ai_remote]
real_files = [hf_hub_download(repo_id=REPO_ID, repo_type="dataset",filename=path, token=HF_TOKEN) for path in real_remote]
# Load a sample real image for the demo
real_demo_path= hf_hub_download(repo_id=REPO_ID, repo_type="dataset",filename="Experiment_grid_3x3.png", token=HF_TOKEN)
real_demo = Image.open(real_demo_path).convert("RGB")
real_demo.thumbnail((500, 500), resample=Image.LANCZOS) # now ≤500×500
# 2) Turn it into a numpy array
real_demo_small = np.array(real_demo)
history_file = "history_state.json"
# --------------------------------
# ——— Google Sheets setup ———
# load service‐account JSON from HF secret
info = json.loads(os.environ["JSON_ACCESS"])
# info = json.loads('service_account.json') # for local testing only
gc = service_account_from_dict(info)
# open by key for stability
ws = gc.open_by_key("1lfhomrFnhmRIxQvdJZr-7gASA3sONBT_mblHNreMKvc").sheet1
def record_run(name, session_start, attempt_num, elapsed_sec, familiarity, correct_count, wrong_list):
"""
Append one row with exactly:
Name | StartTime | #Attempt | ElapsedSec | Familiarity | AttemptsList | WrongsList
"""
ws.append_row([
name,
session_start, # when that grid/timer started
attempt_num, # 1, 2, 3, …
elapsed_sec, # seconds for this attempt
familiarity, # slider value
json.dumps([correct_count]), # e.g. [9]
json.dumps(wrong_list) # e.g. ["217_1.png","243_2.png"]
])
def get_new_grid(state=None):
"""
Generate a fresh 4×4 grid:
- Preserve attempt_count
- **Reset** timer_start to "now" whenever the user hits Retry (i.e. state is not None)
- Leave timer_start unset on initial load (so they must click Start or first Fake?)
"""
attempt_count = (state or {}).get("attempt_count", 0)
t = random.randint(4, 12)
sel_ai = random.sample(ai_files, t)
sel_real = random.sample(real_files, 16 - t)
combo = [(p, False) for p in sel_ai] + [(p, True) for p in sel_real]
random.shuffle(combo)
paths, truth = zip(*combo)
# 3) Build thumbnails + reset flags
thumbs = [np.array(Image.open(p).convert("RGB")) for p in paths]
resets = [False] * 16
new_state = {
"paths": paths,
"truth": truth,
"attempt_count": attempt_count , # increment attempt count,
"timer_start": datetime.now().isoformat()
}
return (*thumbs, *resets, new_state)
def evaluate(
sel0, sel1, sel2, sel3,
sel4, sel5, sel6, sel7,
sel8, sel9, sel10, sel11,
sel12, sel13, sel14, sel15,
state,
user_name,
familiarity
):
# 1) Increment the simple count
attempt_count = state.get("attempt_count", 0) + 1
state["attempt_count"] = attempt_count
# 2) Border logic as before...
sels = [sel0, sel1, sel2, sel3, sel4, sel5, sel6, sel7,
sel8, sel9, sel10, sel11, sel12, sel13, sel14, sel15]
bordered, wrong_list = [], []
correct_count = 0
for i, chosen in enumerate(sels):
img = Image.open(state["paths"][i]).convert("RGB")
is_real = state["truth"][i]
correct = chosen == (not is_real)
color = "green" if correct else "red"
if correct:
correct_count += 1
else:
wrong_list.append(os.path.basename(state["paths"][i]))
bordered.append(np.array(ImageOps.expand(img, border=5, fill=color)))
# 3) Timer logic
timer_iso = state.get("timer_start")
elapsed = (datetime.now() - datetime.fromisoformat(timer_iso)).total_seconds() if timer_iso else 0.0
# incremented earlier in evaluate:
attempt_num = state["attempt_count"]
record_run(
user_name, # your textbox input
state["timer_start"], # ISO start time for this grid
attempt_num, # 1, 2, 3, ...
elapsed, # per‐attempt elapsed
familiarity, # slider input
correct_count, # how many correct this try
wrong_list # which files were wrong
)
# 5) Summary text
pct = correct_count / 16 * 100
summary = f"Attempt {attempt_count}: {correct_count}/16 correct ({pct:.1f}%), time {elapsed:.1f}s. \n Retry to improve your score! (The grid of images will refresh )"
return (*bordered, state, summary)
with gr.Blocks(fill_width=True) as demo:
# Terms & Conditions gate
terms_cb = gr.Checkbox(
label="I agree that my game data can be used for downstream analysis purposes.",
value=False
)
# Main UI hidden until terms are accepted
with gr.Column(visible=False) as main_ui:
gr.Markdown("# Identify the Fake \nEnter your name, then play:")
user_name = gr.Textbox(label="Your name", placeholder="e.g. Can be anonymous ex: 'Trisolaris123'")
gr.Markdown("# Instructions: Click the images you think are AI-generated. \nWhen you are done, click 'Submit' to record your results.\nClick 'Retry' to get a new set of images and improve your score (infinite retries). ")
# Familiarity slider (1=first time, 10=expert)
familiarity = gr.Slider(
minimum=1, maximum=10, step=1, value=1,
label="How familiar are you with P. aeruginosa patterns? 1: First time seeing these 10: Have worked with these patterns before",
interactive=True
)
state = gr.State(None)
example_ui = gr.Column(visible=True)
with example_ui:
gr.Markdown("### Before you begin: This are what *Real* Images look like. Click start to begin the game. ")
gr.Image(value=real_demo_small, show_label=False) #.style(
# width=300, # px
# height=300 # px
# ) # set desired display height)
gr.Markdown("---")
# Add a Start button that WILL load images and start the timer
start_btn = gr.Button("Start")
# Now wrap the grid + controls in a hidden Column
with gr.Column(visible=False) as grid_ui:
image_components = []
checkbox_components = []
for row in range(4):
with gr.Row():
for col in range(4):
idx = row * 4 + col
with gr.Column(min_width=200, scale=1):
img = gr.Image(type="numpy", interactive=False, show_label=False)
cb = gr.Checkbox(label="Fake?", elem_id=f"cb_{idx}")
image_components.append(img)
checkbox_components.append(cb)
submit_btn = gr.Button("Submit")
retry_btn = gr.Button("Retry")
score_out = gr.Textbox(label="Score & Time", interactive=False)
retry_btn.click(
fn=get_new_grid,
inputs=[state],
outputs=[*image_components, *checkbox_components, state]
)
submit_btn.click(
fn=evaluate,
inputs=[*checkbox_components, state,user_name, familiarity],
outputs=[*image_components, state,score_out]
)
# Wire start_btn to both load the grid _and_ reveal it
start_btn.click(
fn=get_new_grid,
inputs=[state],
outputs=[*image_components, *checkbox_components, state]
)
start_btn.click(
fn=lambda _: gr.update(visible=True),
inputs=[],
outputs=[grid_ui]
)
start_btn.click(
fn=lambda _: gr.update(visible=False),
inputs=[],
outputs=[example_ui]
)
# Reveal main UI only after agreeing to terms
terms_cb.change(
fn=lambda agreed: gr.update(visible=agreed),
inputs=[terms_cb],
outputs=[main_ui]
)
demo.launch()