Roshanurs commited on
Commit
7078f15
Β·
verified Β·
1 Parent(s): 5cf0296

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +71 -28
app.py CHANGED
@@ -11,12 +11,49 @@ st.title("πŸ“½οΈ Horror Reference Library")
11
  st.markdown("### Search 11,500+ Cinematic AI-Tagged Comic Panels")
12
 
13
  # ==========================================
14
- # 2. DATA LOADING
15
  # ==========================================
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  @st.cache_data
17
  def load_data():
18
- # This loads the CSV "Map" you uploaded to the Space
19
  df = pd.read_csv("horror_shot_database.csv")
 
 
 
 
 
 
 
20
  return df
21
 
22
  try:
@@ -30,54 +67,62 @@ except Exception as e:
30
  # ==========================================
31
  st.sidebar.header("πŸ” Search Library")
32
 
33
- # 1. The Global Text Search Bar
34
- search_query = st.sidebar.text_input("Keyword Search", placeholder="e.g., monster, shadow, running...")
35
  st.sidebar.write("---")
36
 
37
  st.sidebar.header("πŸ“‚ Filter Categories")
38
 
39
- # 2. Expandable Category: Camera
40
- with st.sidebar.expander("πŸŽ₯ Camera & Framing"):
41
- all_angles = ["Any"] + sorted(df['camera_angle'].dropna().unique().tolist())
42
- selected_angle = st.selectbox("Camera Angle", all_angles)
43
 
44
- # 3. Expandable Category: Mood & Emotion
45
- with st.sidebar.expander("🎭 Mood & Character"):
46
- all_moods = ["Any"] + sorted(df['mood'].dropna().unique().tolist())
47
- selected_mood = st.selectbox("Lighting/Mood", all_moods)
48
-
49
- all_emotions = ["Any"] + sorted(df['emotion'].dropna().unique().tolist())
50
- selected_emotion = st.selectbox("Character Emotion", all_emotions)
51
 
52
- # Add more expanders here later if you add things like "Time of Day" or "Location"!
 
 
 
53
 
54
  # ==========================================
55
- # 4. FILTERING LOGIC (Connecting to Dataset)
56
  # ==========================================
57
  results = df.copy()
58
 
59
- # Apply the text search (searches the AI description column)
60
  if search_query:
61
  results = results[results['description'].str.contains(search_query, case=False, na=False)]
62
 
63
- # Apply the dropdown filters
64
  if selected_angle != "Any":
65
- results = results[results['camera_angle'] == selected_angle]
 
 
66
  if selected_mood != "Any":
67
- results = results[results['mood'] == selected_mood]
68
- if selected_emotion != "Any":
69
- results = results[results['emotion'] == selected_emotion]
70
 
71
- # --- KEEP YOUR EXISTING URL CONSTRUCTOR BELOW THIS ---
72
  base_url = "https://huggingface.co/datasets/Roshanurs/Horror-Reference-Data/resolve/main/Panels_Out"
73
 
74
- # ... (The rest of your code stays exactly the same!)
 
 
 
 
 
 
 
 
 
 
75
 
76
  # ==========================================
77
  # 5. THE MASONRY GALLERY
78
  # ==========================================
79
  if len(valid_images) > 0:
80
- # We show the first 100 results to keep the page fast
81
  display_limit = 100
82
  display_list = valid_images[:display_limit]
83
 
@@ -85,10 +130,8 @@ if len(valid_images) > 0:
85
 
86
  for index, img_data in enumerate(display_list):
87
  with cols[index % 4]:
88
- # Streamlit fetches the image directly from the Dataset URL
89
  st.image(img_data["url"], use_container_width=True)
90
 
91
- # Download button that opens the raw image in a new tab
92
  st.markdown(
93
  f'<a href="{img_data["url"]}" target="_blank">'
94
  f'<button style="width:100%; padding:8px; border-radius:4px; border:1px solid #444; background:#222; color:white; cursor:pointer;">'
 
11
  st.markdown("### Search 11,500+ Cinematic AI-Tagged Comic Panels")
12
 
13
  # ==========================================
14
+ # 2. DATA BUCKETING & CLEANING
15
  # ==========================================
16
+ # This groups the messy AI tags into clean, professional cinematic categories
17
+ def categorize_camera(text):
18
+ text = str(text).lower()
19
+ if 'dutch' in text: return 'Dutch Angle'
20
+ elif 'extreme close' in text or 'ecu' in text: return 'Extreme Close Up'
21
+ elif 'close' in text or 'cu' in text: return 'Close Up'
22
+ elif 'wide' in text or 'long' in text or 'establishing' in text: return 'Wide Shot'
23
+ elif 'mid' in text or 'medium' in text: return 'Mid Shot'
24
+ elif 'low angle' in text or 'looking up' in text: return 'Low Angle'
25
+ elif 'high angle' in text or 'looking down' in text: return 'High Angle'
26
+ elif 'pov' in text or 'point of view' in text: return 'Point of View'
27
+ else: return 'Other / Mixed'
28
+
29
+ def categorize_mood(text):
30
+ text = str(text).lower()
31
+ if 'tense' in text or 'suspense' in text or 'anxiety' in text: return 'Tense & Suspenseful'
32
+ elif 'action' in text or 'chaos' in text or 'dynamic' in text: return 'Action & Chaos'
33
+ elif 'creepy' in text or 'eerie' in text or 'ominous' in text: return 'Creepy & Eerie'
34
+ elif 'gore' in text or 'violent' in text or 'blood' in text: return 'Gore & Violence'
35
+ elif 'sad' in text or 'melancholy' in text or 'somber' in text: return 'Somber & Melancholic'
36
+ else: return 'Neutral / Standard'
37
+
38
+ def categorize_lighting(text):
39
+ text = str(text).lower()
40
+ if 'silhouette' in text: return 'Silhouetted'
41
+ elif 'high contrast' in text or 'chiaroscuro' in text: return 'High Contrast'
42
+ elif 'low key' in text or 'shadow' in text or 'dark' in text: return 'Low Key (Shadowy)'
43
+ elif 'harsh' in text or 'bright' in text: return 'Harsh & Bright'
44
+ elif 'flat' in text or 'even' in text: return 'Flat Lighting'
45
+ else: return 'Standard Lighting'
46
+
47
  @st.cache_data
48
  def load_data():
 
49
  df = pd.read_csv("horror_shot_database.csv")
50
+
51
+ # Create new "Clean" columns for the UI
52
+ df['broad_camera'] = df['camera_angle'].apply(categorize_camera)
53
+ df['broad_mood'] = df['mood'].apply(categorize_mood)
54
+ # We search both mood and description to figure out the lighting
55
+ df['broad_lighting'] = (df['mood'].fillna('') + " " + df['description'].fillna('')).apply(categorize_lighting)
56
+
57
  return df
58
 
59
  try:
 
67
  # ==========================================
68
  st.sidebar.header("πŸ” Search Library")
69
 
70
+ # The Global Text Search Bar
71
+ search_query = st.sidebar.text_input("Keyword Search", placeholder="e.g., monster, running, eyes...")
72
  st.sidebar.write("---")
73
 
74
  st.sidebar.header("πŸ“‚ Filter Categories")
75
 
76
+ # Expandable Category: Camera
77
+ with st.sidebar.expander("πŸŽ₯ Camera & Framing", expanded=True):
78
+ all_angles = ["Any"] + sorted(df['broad_camera'].unique().tolist())
79
+ selected_angle = st.selectbox("Shot Type", all_angles)
80
 
81
+ # Expandable Category: Lighting
82
+ with st.sidebar.expander("πŸ’‘ Lighting Style"):
83
+ all_lighting = ["Any"] + sorted(df['broad_lighting'].unique().tolist())
84
+ selected_lighting = st.selectbox("Lighting Category", all_lighting)
 
 
 
85
 
86
+ # Expandable Category: Mood
87
+ with st.sidebar.expander("🎭 Scene Mood"):
88
+ all_moods = ["Any"] + sorted(df['broad_mood'].unique().tolist())
89
+ selected_mood = st.selectbox("Atmosphere", all_moods)
90
 
91
  # ==========================================
92
+ # 4. FILTERING LOGIC
93
  # ==========================================
94
  results = df.copy()
95
 
96
+ # Apply the text search
97
  if search_query:
98
  results = results[results['description'].str.contains(search_query, case=False, na=False)]
99
 
100
+ # Apply the clean dropdown filters
101
  if selected_angle != "Any":
102
+ results = results[results['broad_camera'] == selected_angle]
103
+ if selected_lighting != "Any":
104
+ results = results[results['broad_lighting'] == selected_lighting]
105
  if selected_mood != "Any":
106
+ results = results[results['broad_mood'] == selected_mood]
 
 
107
 
 
108
  base_url = "https://huggingface.co/datasets/Roshanurs/Horror-Reference-Data/resolve/main/Panels_Out"
109
 
110
+ valid_images = []
111
+ for idx, row in results.iterrows():
112
+ img_url = f"{base_url}/{row['filename']}"
113
+ valid_images.append({
114
+ "url": img_url,
115
+ "filename": row['filename'],
116
+ "desc": row['description']
117
+ })
118
+
119
+ st.markdown(f"**Found {len(valid_images)} matching shots**")
120
+ st.write("---")
121
 
122
  # ==========================================
123
  # 5. THE MASONRY GALLERY
124
  # ==========================================
125
  if len(valid_images) > 0:
 
126
  display_limit = 100
127
  display_list = valid_images[:display_limit]
128
 
 
130
 
131
  for index, img_data in enumerate(display_list):
132
  with cols[index % 4]:
 
133
  st.image(img_data["url"], use_container_width=True)
134
 
 
135
  st.markdown(
136
  f'<a href="{img_data["url"]}" target="_blank">'
137
  f'<button style="width:100%; padding:8px; border-radius:4px; border:1px solid #444; background:#222; color:white; cursor:pointer;">'