File size: 4,140 Bytes
90a5359
8343d7f
 
f0ae214
8343d7f
 
f0ae214
8343d7f
3f14974
 
 
 
 
 
 
 
 
 
 
 
f0ae214
fae1db2
f0ae214
 
 
 
8343d7f
3f14974
8343d7f
f0ae214
3f14974
409a47c
 
 
 
3f14974
858a92e
3f14974
 
fae1db2
f0ae214
8343d7f
f0ae214
8343d7f
fae1db2
 
 
8343d7f
 
fae1db2
f0ae214
8343d7f
3f14974
fae1db2
c7325c8
4cd9408
3f14974
8343d7f
3f14974
 
 
 
f0ae214
 
 
fae1db2
f0ae214
3f14974
f0ae214
 
fae1db2
 
f0ae214
 
3f14974
f0ae214
 
 
fae1db2
 
3f14974
f0ae214
fae1db2
 
 
 
 
 
f0ae214
fae1db2
 
 
3f14974
fae1db2
 
 
 
3f14974
fae1db2
f0ae214
 
 
 
 
fae1db2
 
3f14974
f0ae214
 
fae1db2
 
 
 
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
import streamlit as st
from transformers import pipeline
from PIL import Image
import datetime

# --- PAGE CONFIG ---
st.set_page_config(page_title="SaaS Media Vault", layout="wide")

# Custom CSS to prevent layout shifting and "shaking"
st.markdown("""
    <style>
    .stColumn {
        transition: none !important;
    }
    div[data-testid="stVerticalBlock"] > div {
        animation: none !important;
    }
    </style>
    """, unsafe_allow_html=True)

st.title("πŸ—„οΈ SaaS Media Intelligence Vault")
st.markdown("Analyze, store, and **search** your media assets using AI-generated metadata.")

# --- INITIALIZE SESSION STATE ---
if "media_library" not in st.session_state:
    st.session_state.media_library = []

# --- MODEL LOADING ---
@st.cache_resource
def load_models():
    # CLIP for general categorization
    classifier = pipeline("zero-shot-image-classification", 
                          model="openai/clip-vit-base-patch32", 
                          device=-1)
    
    # BLIP for natural language description
    captioner = pipeline("image-text-to-text", 
                          model="Salesforce/blip-image-captioning-base", 
                          device=-1)
    
    return classifier, captioner

classifier, captioner = load_models()

# --- SIDEBAR: UPLOAD & SETTINGS ---
st.sidebar.header("πŸ“₯ Asset Management")
uploaded_file = st.sidebar.file_uploader("Add New Image", type=["jpg", "png", "jpeg"])

if uploaded_file:
    if st.sidebar.button("Process & Index Asset"):
        image = Image.open(uploaded_file)
        
        with st.spinner("AI is indexing..."):
            # 1. BLIP Description
            prompt = "a photo of"
            caption_out = captioner(image, text=prompt, max_new_tokens=30)
            description = caption_out[0]['generated_text'].replace("a photo of ", "")
            
            # 2. Internal Auto-Tagging (Replaces the manual keywords input)
            # We use a broad set of categories to give the AI context without user input
            auto_labels = ["object", "person", "place", "nature", "technology", "document"]
            clip_out = classifier(image, candidate_labels=auto_labels)
            top_label = clip_out[0]['label']
            top_score = clip_out[0]['score']

            # 3. SAVE TO ARRAY
            asset_data = {
                "id": f"{datetime.datetime.now().timestamp()}", # Unique ID to prevent UI jitter
                "timestamp": datetime.datetime.now().strftime("%H:%M:%S"),
                "image": image,
                "description": description.lower(),
                "tag": top_label.lower(),
                "confidence": top_score
            }
            # Insert at the top
            st.session_state.media_library.insert(0, asset_data)
        st.sidebar.success("Asset Cataloged!")

# --- MAIN SECTION: SEARCH & RETRIEVAL ---
st.subheader("πŸ” Intelligent Retrieval")
search_query = st.text_input("Search the vault (e.g., 'flowers', 'tech', 'laptop')", "").lower()

# --- FILTER LOGIC ---
if search_query:
    filtered_items = [
        item for item in st.session_state.media_library 
        if search_query in item["description"] or search_query in item["tag"]
    ]
else:
    filtered_items = st.session_state.media_library

# --- DISPLAY VAULT ---
st.write(f"Showing **{len(filtered_items)}** assets")

if not filtered_items:
    st.info("No matching assets found in the vault.")
else:
    # Using a container with a fixed key helps Streamlit manage the DOM state better
    for item in filtered_items:
        with st.container():
            col1, col2 = st.columns([1, 3])
            with col1:
                st.image(item["image"], use_container_width=True)
            with col2:
                st.write(f"**πŸ•’ Logged:** {item['timestamp']}")
                st.info(f"**AI Description:** {item['description'].capitalize()}")
                st.write(f"**🏷️ Type:** `{item['tag']}` ({round(item['confidence']*100, 1)}%)")
            st.divider()

# --- CLEAR UTILITY ---
if st.sidebar.button("πŸ—‘οΈ Wipe Vault Memory"):
    st.session_state.media_library = []
    st.rerun()