# Project export: MoodMuse: AI Art & Music Based on Your Vibe

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: UC Berkeley AI Hackathon 2025
- Tagline: AI for automated music playing and artwork generation. Take a selfie anytime and get music and art that matches your mood!
- Devpost: https://devpost.com/software/moodmuse-ai-art-music-based-on-your-vibe
- GitHub: https://github.com/zhenga1/moodmuse
- Team: 1 GitHub contributor(s) — Aaron Zheng (1 commits)

## Devpost submission (written by the team)

### Inspiration

I really like playing music and I was sad that there was no software that would play music automatically based on my mood. But then I also don't want to write out my mood. I want to be able to do something like take a photo and have the AI play existing songs from my playlist, without me having to think

### What it does

Plays music that adapts to your (real-time) mood!

### How we built it

Python + Streamlit tech stack. DeepFace API and google generative ai python API for AI Vibe coding.

### Challenges we ran into

The art generation doesn't work yet because Google AI Studio does not give python API access to its text-to-image model :-(

### Accomplishments we're proud of

Real-time video emotion detection accomplished!

### What we learned

How to use DeepFace to do emotion detection, collecting data in Streamlit.

### What's next

Integrate the AI art generation! Generate music instead of selecting from songs in a playlist.

## README (from the GitHub repository)

No README available.

## Detected evidence (automated analysis)

Indexed codebase: 2 recognized source files, 12 KB.
- Python (language) — detected in the code
- Streamlit (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (4 of 4)

```
.gitignore
.streamlit/secrets.toml
main.py
scrap_codes.py
```

### Dependencies

No dependency index available.

### Recent commits (newest first)

- code done

## Key source files (fetched from GitHub, selected and truncated for size)

### main.py

```python
import streamlit as st
from deepface import DeepFace
from google.generativeai import configure, GenerativeModel
import requests
from PIL import Image
import numpy as np
import cv2
import io
import av
import os
from datetime import datetime
import cv2
from streamlit_webrtc import webrtc_streamer, VideoProcessorBase
import tempfile
import numpy as np
from PIL import Image

def extract_first_frame(video_bytes) -> Image.Image:
    # Write to a temp file so OpenCV can read it
    tfile = tempfile.NamedTemporaryFile(delete=False)
    tfile.write(video_bytes)
    tfile.close()

    cap = cv2.VideoCapture(tfile.name)
    success, frame = cap.read()
    cap.release()

    if success:
        frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        return Image.fromarray(frame_rgb)
    else:
        return None

class VideoRecorder(VideoProcessorBase):
    def __init__(self):
        self.video_writer = None
    def recv(self, frame, filename=None):
        img = frame.to_ndarray(format="bgr24")
        default_filename = f"recordings/video_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4"
        if self.video_writer is None:
            # Create a VideoWriter object
            fourcc = cv2.VideoWriter_fourcc(*'mp4v')
            if filename is None:
                filename = default_filename
            self.video_writer = cv2.VideoWriter("output.mp4", fourcc, 20.0, (640, 480))
        self.video_writer.write(img)
        return av.VideoFrame.from_ndarray(img, format="bgr24")
        
class EmotionVideoAnalyzer(VideoProcessorBase):
    def __init__(self):
        self.video_writer = None
        self.detected_emotion = None
        self.frame_saved = False
        self.output_frame = None
    
    def recv(self, frame):
        img = frame.to_ndarray(format="bgr24")
        self.analyzing = False
        
        if self.detected_emotion is None:
            try:
                result = DeepFace.analyze(img, actions=['emotion'], enforce_detection=False)
                mood = result[0]['dominant_emotion'].capitalize()
                if mood:
                    self.detected_emotion = mood
                    cv2.putText(img, f"Detected Mood: {mood}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
                    self.output_frame = img.copy()
                    self.save_frame()
                    
            except Exception as e:
                print("DeepFace has some error ", e)
        
        # Overlay the detected mood on the frame
        if self.detected_emotion:
            cv2.putText(img, f"Detected Mood: {self.detected_emotion}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

        return av.VideoFrame.from_ndarray(img, format="bgr24")
    def save_frame(self):  
        # # Convert to RGB for DeepFace
        # result = DeepFace.analyze(img, actions=['emotion'], enforce_detection=False)
                
        # if mood:
        #     self.detected_emotion = mood
        #     cv2.putText(img, f"Detected Mood: {mood}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
        if self.frame_saved:
            return
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        filename = f"recordings/detected_{self.detected_emotion}_{timestamp}.jpg"
        cv2.imwrite(filename, self.output_frame)
        print(f"Saved image with emotion: {self.detected_emotion} → {filename}")
        self.frame_saved = True

def video_frame_callback(frame):
    img = frame.to_ndarray(format="bgr24")

    global video_writer
    if video_writer is not None:
        video_writer.write(img)

    # optional overlay 
    cv2.putText(img, "Live Webcam", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
    return av.VideoFrame.from_ndarray(img, format="bgr24")

# Create a folder to store videos
os.makedirs("recordings", exist_ok=True)

# Path for saving output
# filename = f"recordings/video_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4"
# fourcc = cv2.VideoWriter_fourcc(*'mp4v')
# video_writer = cv2.VideoWriter(filename, fourcc, 20.0, (640, 480))  # 20 FPS, 640x480


# Title
st.set_page_config(page_title="MoodMuse 🎶🖼️", layout="centered")
st.title("🧠 MoodMuse: AI Art & Music Based on Your Vibe")

with st.spinner("Initializing emotion scanner..."):
    ctx = webrtc_streamer(
        key="example",
        video_processor_factory=EmotionVideoAnalyzer
        #video_processor_factory=VideoRecorder
        #video_frame_callback=video_frame_callback
    )
    if ctx and ctx.video_processor:
        vp = ctx.video_processor

        if vp.detected_emotion:
            # Stop webcam stream
            if ctx.state.playing:
                ctx.stop()
                st.session_state.show_stream = False

            # Notify and play music
            st.success(f"Detected emotion: {vp.detected_emotion}")
            #st.audio(MUSIC_PATH, format="audio/mp3")
            mood = vp.detected_emotion

#AIzaSyAflW8bWFG3r2BaZPJJiPwawzsRc1nd5K0
GEMINI_API_KEY = st.secrets["gemini"]["api_key"]
GEMINI_API_URL = "https://api.gemini.com/v1/"
# Upload or Take Photo
uploaded_file = st.file_uploader("📸 Upload a selfie or a portrait image", type=["jpg", "jpeg", "png"])

st.markdown("## 🎥 Upload or Record a Short Video")
video_file = st.file_uploader("Upload a video (MP4/MOV)", type=["mp4", "mov", "webm"])

if video_file:
    frame_img = extract_first_frame(video_file.read())
    if frame_img:
        st.image(frame_img, caption="Frame Extracted from Video")
        
        # Pass to DeepFace or your vision model
        result = DeepFace.analyze(np.array(frame_img), actions=["emotion"], enforce_detection=False)
        mood = result[0]['dominant_emotion'].capitalize()
        st.success(f"Detected Mood: **{mood}**")
    else:
        st.error("Failed to extract frame from video.")

record_video = st.button("🎥 Record a Video")
from streamlit_webrtc import webrtc_streamer
if record_video:
    st.markdown("## 📹 Live Video (Experimental)")
    webrtc_streamer(key="video")
[truncated — 3121 more characters]
```

### scrap_codes.py

```python
# Generate Art (Placeholder)
    if st.button("🎨 Generate AI Art"):
        with st.spinner("Generating art..."):
            # Replace this with your real image generation call
            # image_url = "https://source.unsplash.com/800x400/?" + mood.lower()
            # st.image(image_url, caption="Generated Art", use_column_width=True)
            # Mood-to-Art Generation
            mood_to_prompt = {
                "Happy": "A vibrant, joyful digital painting full of color and sunshine, warm tones, fantasy style",
                "Joyful": "A festive outdoor scene with laughter, balloons, bright colors, and celebration",
                "Playful": "A whimsical cartoon-style landscape with floating objects, toys, and animals having fun",

                "Sad": "A grayscale rainy cityscape at night, empty streets, melancholic atmosphere, cinematic lighting",
                "Melancholy": "A lone figure sitting on a bench in autumn, leaves falling, moody impressionist style",
                "Lonely": "A dimly lit cabin in a foggy forest, minimal color, solitude and quiet, hyperrealistic",

                "Calm": "A serene mountain lake at sunset, pastel colors, watercolor style, tranquil scenery",
                "Peaceful": "A zen garden with bonsai trees, soft morning light, high-detail nature art",
                "Content": "A warm cozy home interior with a cup of tea, glowing fireplace, soft lighting",

                "Angry": "Red and black chaotic abstract painting with harsh lines and explosive brush strokes",
                "Frustrated": "A stormy sea under a dark sky, high waves crashing, symbolic frustration, digital art",
                "Intense": "Close-up of a lion roaring, intense contrast, dynamic motion blur, epic illustration",

                "Neutral": "Modern minimalist abstract art with soft grays and balanced composition",
                "Balanced": "Yin-yang inspired artwork with smooth gradients, geometric symmetry, digital design",

                "Surprise": "A burst of confetti in space, surreal bright colors, comic book pop-art style",
                "Shocked": "A wide-eyed anime character in a swirling vortex, glitch effects, neon explosion",
                "Excited": "Fireworks over a crowd of people, bright flashes of color and energy, high saturation",

                "Fear": "A shadowy figure in a misty alley, eerie lighting, psychological horror vibe",
                "Tense": "A detective walking through a noir-style city at night, dramatic shadows, suspenseful",
                "Suspense": "A foggy forest path with flickering lanterns, hidden figures, gothic fantasy art"
            }
            prompt = mood_to_prompt.get(mood, "Abstract art representing the blend of all possible human emotions and experiences.")

            st.markdown(f"🎨 Generating artwork for: **{mood}**")
            #from google.cloud import aiplatform
            import google.generativeai as genai

            genai.configure(api_key=st.secrets["gemini"]["api_key"])

            model = genai.GenerativeModel("gemini-1.5-flash")
            response = model.generate_content(prompt, response_mime_type="image/png")
            with open("mood_artwork.png", "wb") as f:
                f.write(response.image)
            #aiplatform.init(project="image_generation", location="us-central1")

            #model = aiplatform.TextToImageModel("models/google-flash")

            # response = model.predict(prompt=prompt)
            # image = response.generated_images[0]
            # with open("cat_astronaut.png", "wb") as f:
            #     f.write(image)
```