Spaces:
Sleeping
Sleeping
import streamlit as st | |
import requests | |
import openai | |
from io import BytesIO | |
from PIL import Image | |
# Set page configuration as the first Streamlit command | |
st.set_page_config(page_title="Eco-Symphony", page_icon="π±", layout="centered") | |
# Set API keys from Streamlit Secrets | |
openai.api_key = st.secrets["OPENAI_API_KEY"] | |
OPENWEATHER_API_KEY = st.secrets["OPENWEATHER_API_KEY"] | |
HUGGINGFACE_API_KEY = st.secrets["HUGGINGFACE_API_KEY"] | |
# Hugging Face API URLs | |
MUSICGEN_API_URL = "https://api-inference.huggingface.co/models/facebook/musicgen-small" | |
IMAGEGEN_API_URL = "https://api-inference.huggingface.co/models/Artples/LAI-ImageGeneration-vSDXL-2" | |
# Headers for Hugging Face API requests | |
headers = {"Authorization": f"Bearer {HUGGINGFACE_API_KEY}"} | |
# Inject custom CSS for green theme | |
st.markdown(""" | |
<style> | |
body { | |
background-color: #ffffff; | |
} | |
.stApp { | |
color: #2e7d32; | |
font-family: 'Arial', sans-serif; | |
} | |
.stButton>button { | |
background-color: #66bb6a; | |
color: #fff; | |
font-weight: bold; | |
} | |
.stTextInput>div>input { | |
background-color: #e8f5e9; | |
color: #2e7d32; | |
} | |
.stMarkdown h1, .stMarkdown h2, .stMarkdown h3, .stMarkdown p { | |
color: #388e3c; | |
} | |
.stMarkdown h2 { | |
font-weight: bold; | |
} | |
</style> | |
""", unsafe_allow_html=True) | |
# Initialize session state variables | |
if "real_data" not in st.session_state: | |
st.session_state.real_data = {} | |
if "story" not in st.session_state: | |
st.session_state.story = "" | |
if "music_bytes" not in st.session_state: | |
st.session_state.music_bytes = None | |
if "image_bytes" not in st.session_state: | |
st.session_state.image_bytes = None | |
if "ngos" not in st.session_state: | |
st.session_state.ngos = [] | |
if "points" not in st.session_state: | |
st.session_state.points = 0 | |
if "daily_challenges" not in st.session_state: | |
st.session_state.daily_challenges = [] | |
# Function to generate daily eco-friendly challenges | |
def generate_daily_challenges() -> list: | |
prompt = "Give me 5 small, easy-to-do eco-friendly daily challenges that can be completed in a day." | |
response = openai.ChatCompletion.create( | |
model="gpt-3.5-turbo", | |
messages=[{"role": "user", "content": prompt}], | |
max_tokens=100, | |
temperature=0.8 | |
) | |
challenges = response.choices[0].message['content'].strip().split("\n") | |
return [challenge.strip() for challenge in challenges if challenge.strip()] | |
# Function to fetch weather data | |
def fetch_real_data(city: str) -> dict: | |
weather_url = f'https://api.openweathermap.org/data/2.5/weather?q={city}&appid={OPENWEATHER_API_KEY}&units=metric' | |
weather_response = requests.get(weather_url) | |
if weather_response.status_code != 200: | |
st.error("Error fetching weather data.") | |
return {} | |
weather_data = weather_response.json() | |
return { | |
"temperature": weather_data['main'].get('temp', 'Data not available'), | |
"humidity": weather_data['main'].get('humidity', 'Data not available'), | |
"weather_condition": weather_data['weather'][0].get('main', 'Data not available') | |
} | |
# Function to determine mood based on weather data | |
def determine_mood(data: dict) -> str: | |
weather_condition = data["weather_condition"].lower() | |
temperature = data["temperature"] | |
if "rain" in weather_condition: | |
return "rainy" | |
elif "clear" in weather_condition and temperature > 25: | |
return "sunny" | |
elif "cloud" in weather_condition: | |
return "cloudy" | |
elif temperature < 15: | |
return "cool" | |
else: | |
return "neutral" | |
# Function to create a narrative | |
def create_narrative(city: str, data: dict) -> str: | |
return f"In {city}, the weather is {data['weather_condition']} with a temperature of {data['temperature']}Β°C." | |
# Function to generate a story using OpenAI | |
def generate_story_with_ai(narrative: str, mood: str) -> str: | |
messages = [ | |
{"role": "system", "content": "You are a creative storyteller using characters and imagery."}, | |
{"role": "user", "content": f"{narrative} The mood is '{mood}', write a story about how the environment feels in 50 words."} | |
] | |
response = openai.ChatCompletion.create( | |
model="gpt-3.5-turbo", | |
messages=messages, | |
max_tokens=150, | |
temperature=0.7 | |
) | |
return response.choices[0].message['content'].strip() | |
# Function to generate music from Hugging Face API | |
def generate_music(description: str) -> bytes: | |
payload = {"inputs": description} | |
response = requests.post(MUSICGEN_API_URL, headers=headers, json=payload) | |
if response.status_code != 200: | |
st.error(f"Error generating music: {response.status_code} {response.text}") | |
return None | |
return response.content | |
# Function to generate an image based on the story | |
def generate_image(description: str) -> bytes: | |
payload = {"inputs": description} | |
response = requests.post(IMAGEGEN_API_URL, headers=headers, json=payload) | |
if response.status_code != 200: | |
st.error(f"Error generating image: {response.status_code} {response.text}") | |
return None | |
return response.content | |
# Function to fetch endangered species data | |
def fetch_endangered_species(city: str) -> dict: | |
prompt = f"Provide details of an endangered species which is highly specific in {city}, including its name, image description, and current population." | |
response = openai.ChatCompletion.create( | |
model="gpt-3.5-turbo", | |
messages=[{"role": "user", "content": prompt}], | |
max_tokens=150, | |
temperature=0.8 | |
) | |
response_content = response.choices[0].message['content'].strip() | |
try: | |
return eval(response_content) # Assuming the response is a JSON-like structure | |
except Exception as e: | |
st.error(f"Error parsing endangered species data: {e}") | |
return {} | |
# Function to fetch NGOs using OpenAI | |
def fetch_nearby_ngos_with_openai(city: str, interests: list) -> list: | |
prompt = ( | |
f"List NGOs near {city} that focus on {', '.join(interests)}. " | |
"Provide the names, locations, and focus areas in JSON format as a list of dictionaries." | |
) | |
response = openai.ChatCompletion.create( | |
model="gpt-3.5-turbo", | |
messages=[{"role": "user", "content": prompt}], | |
max_tokens=200, | |
temperature=0.7 | |
) | |
response_content = response.choices[0].message['content'].strip() | |
try: | |
ngo_list = eval(response_content) | |
if isinstance(ngo_list, list) and all(isinstance(ngo, dict) for ngo in ngo_list): | |
return ngo_list | |
else: | |
st.error("Unexpected response format. Could not parse NGO data.") | |
return [] | |
except Exception as e: | |
st.error(f"Error fetching NGO data: {e}") | |
return [] | |
# Streamlit UI | |
st.title("πΏ Eco-Symphony πΆ") | |
st.write("Enter a city to explore real-time environmental data, complete daily challenges, and unlock hidden content!") | |
city = st.text_input("Enter City Name:", placeholder="Type the name of a city...") | |
if st.button("Generate Environmental Data, Music, and Image"): | |
st.session_state.real_data = fetch_real_data(city) | |
if st.session_state.real_data: | |
# Generate narrative and mood | |
narrative = create_narrative(city, st.session_state.real_data) | |
mood = determine_mood(st.session_state.real_data) | |
# Generate AI story | |
st.session_state.story = generate_story_with_ai(narrative, mood) | |
# Generate Music and Image Based on Story and Mood | |
music_description = f"{mood} mood with {st.session_state.real_data['weather_condition'].lower()} weather" | |
st.session_state.music_bytes = generate_music(music_description) | |
st.session_state.image_bytes = generate_image(st.session_state.story) | |
# Display Music and Image at the Top | |
if st.session_state.music_bytes: | |
st.subheader("πΆ Generated Music") | |
st.audio(BytesIO(st.session_state.music_bytes), format="audio/wav") | |
if st.session_state.image_bytes: | |
st.subheader("πΌοΈ Generated Image") | |
st.image(Image.open(BytesIO(st.session_state.image_bytes)), caption="Generated Image based on Story", use_column_width=True) | |
# Display Environmental Narrative and Data | |
if st.session_state.real_data: | |
st.subheader("π Environmental Narrative") | |
narrative = create_narrative(city, st.session_state.real_data) | |
st.write(narrative) | |
st.subheader("π Real Weather Data") | |
st.write("Temperature (Β°C):", st.session_state.real_data.get("temperature", "Data not available")) | |
st.write("Humidity (%):", st.session_state.real_data.get("humidity", "Data not available")) | |
st.write("Weather Condition:", st.session_state.real_data.get("weather_condition", "Data not available")) | |
if st.session_state.story: | |
st.subheader("π AI-Generated Story") | |
st.write(st.session_state.story) | |
# Daily Challenges Section | |
st.subheader("π Daily Challenges") | |
if not st.session_state.daily_challenges: | |
st.session_state.daily_challenges = generate_daily_challenges() | |
completed_challenges = [] | |
for i, challenge in enumerate(st.session_state.daily_challenges): | |
if st.checkbox(challenge, key=f"challenge_{i}"): | |
completed_challenges.append(i) | |
# Update points based on completed challenges | |
st.session_state.points = len(completed_challenges) * 10 # 10 points per challenge | |
st.markdown(f"<h2 style='text-align: center;'>π° Points: {st.session_state.points}</h2>", unsafe_allow_html=True) | |
# Function to fetch endangered species data for a region | |
def fetch_all_endangered_species(city: str) -> list: | |
prompt = ( | |
f"Provide a list of endangered species found near {city}, " | |
"including their names, population estimates, and descriptions. " | |
"Return the data in JSON format as a list of dictionaries." | |
) | |
response = openai.ChatCompletion.create( | |
model="gpt-3.5-turbo", | |
messages=[{"role": "user", "content": prompt}], | |
max_tokens=300, | |
temperature=0.8 | |
) | |
response_content = response.choices[0].message['content'].strip() | |
try: | |
species_list = eval(response_content) # Assuming the response is a JSON-like structure | |
if isinstance(species_list, list) and all(isinstance(species, dict) for species in species_list): | |
return species_list | |
else: | |
st.error("Unexpected response format. Could not parse species data.") | |
return [] | |
except Exception as e: | |
st.error(f"Error fetching endangered species data: {e}") | |
return [] | |
# Display the endangered species section | |
if len(completed_challenges) == len(st.session_state.daily_challenges): | |
st.success("All challenges completed! π You've unlocked the secret section!") | |
# Fetch endangered species data for the user's city | |
species_data_list = fetch_all_endangered_species(city) | |
if species_data_list: | |
st.subheader("π¦ Endangered Species in Your Region") | |
for species_data in species_data_list: | |
species_name = species_data.get('name', 'Unknown') | |
st.write(f"**Species**: {species_name}") | |
st.write(f"**Population**: {species_data.get('population', 'Unknown')}") | |
st.write(f"**Description**: {species_data.get('description', 'No description available')}") | |
# Generate an image of each endangered species | |
image_description = f"Generate an image of the endangered species: {species_name}" | |
species_image_bytes = generate_image(image_description) | |
if species_image_bytes: | |
species_image = Image.open(BytesIO(species_image_bytes)) | |
st.image(species_image, caption=f"Endangered Species: {species_name}", use_column_width=True) | |
st.write("---") | |
# User's Environmental Interests Section | |
st.subheader("π Get Involved!") | |
st.write("Choose your areas of interest for saving the environment:") | |
interests = st.multiselect( | |
"Select Areas of Interest:", | |
["Afforestation", "Water Conservation", "Biodiversity Protection", "Recycling", "Climate Change Awareness"] | |
) | |
if st.button("Find Nearby NGOs"): | |
if interests: | |
st.session_state.ngos = fetch_nearby_ngos_with_openai(city, interests) | |
else: | |
st.warning("Please select at least one area of interest.") | |
# Display NGO information | |
if st.session_state.ngos: | |
st.subheader("π NGOs Near You") | |
for ngo in st.session_state.ngos: | |
st.write(f"**{ngo.get('name', 'Unknown NGO')}**") | |
st.write(f"π Location: {ngo.get('location', 'Unknown Location')}") | |
st.write(f"π± Focus Area: {ngo.get('focus', 'Unknown Focus Area')}") | |
st.write("---") |