Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import random | |
| import os | |
| import re | |
| from groq import Groq | |
| import base64 | |
| # Set your GROQ API Key | |
| GROQ_API_KEY = os.getenv("GROQ_API_KEY", "your_groq_api_key_here") # Replace with your actual key or set via environment | |
| client = Groq(api_key=GROQ_API_KEY) | |
| # Stickers for response - using more reliable CDN URLs | |
| stickers = [ | |
| "https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f60a.png", # Smiling face | |
| "https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f31f.png", # Glowing star | |
| "https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f338.png", # Cherry blossom | |
| "https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/1f31c.png", # Moon face | |
| "https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72/2728.png" # Sparkles | |
| ] | |
| # Streamlit UI setup | |
| st.set_page_config(page_title="SkinSense AI", layout="centered") | |
| st.markdown("<h1 style='text-align:center; color:#4CAF50;'>πΏ SkinSense AI β Skincare Buddy</h1>", unsafe_allow_html=True) | |
| # Input form | |
| name = st.text_input("Your Name") | |
| gender = st.radio("Gender", ["Female", "Male", "Other"]) | |
| age = st.slider("Age", 12, 100, 25) | |
| skin_concern = st.selectbox("Main Skin Concern", ["Acne", "Dryness", "Oiliness", "Pores", "Dullness", "Pigmentation", "Other"]) | |
| description = st.text_area("Describe Your Skin Problem", placeholder="e.g. Small white pimples under skin for 2 weeks...") | |
| image = st.file_uploader("Or upload a picture of your skin", type=["jpg", "jpeg", "png"]) | |
| duration = st.selectbox("How long has this been a concern?", ["Less than 1 week", "1-2 weeks", "More than 2 weeks"]) | |
| sensitivity = st.radio("Is your skin sensitive?", ["Yes", "No", "Not Sure"]) | |
| routine = st.text_input("Do you follow a routine?", placeholder="e.g. Facewash, moisturizer, sunscreen") | |
| submit = st.button("β¨ Generate Skincare Advice") | |
| # Core function | |
| def skincare_advice(name, gender, age, skin_concern, description, duration, sensitivity, routine, image): | |
| if not name.strip(): | |
| return "<span style='color:red;'>β Please enter your name.</span>" | |
| sticker = random.choice(stickers) | |
| # Determine concern text | |
| if description.strip(): | |
| concern_text = description.strip() | |
| elif image is not None: | |
| concern_text = "The user uploaded an image showing their skin issue. Please base your suggestions on typical visible skin concerns." | |
| else: | |
| concern_text = skin_concern | |
| # Prompt for the model | |
| prompt = f""" | |
| A user named {name} (Gender: {gender}, Age: {age}) is experiencing a skin issue: "{concern_text}". | |
| Duration: {duration}, Sensitive skin: {sensitivity}, Routine followed: {routine}. | |
| Write a response in sections using emojis and headings only for: | |
| π Greeting | |
| π©Ί Skin Issue Summary | |
| π Global Insight | |
| π§΄ Daily Skincare Routine | |
| πΏ Natural Remedy | |
| π‘ Lifestyle Tips | |
| π¬ Motivational Quote | |
| Each section should start with a title (e.g., πΏ Natural Remedy) on one line, then 2β4 lines of helpful content below it in plain text or bullet points. | |
| Do not use bold, underline, or any extra styling. | |
| """ | |
| try: | |
| response = client.chat.completions.create( | |
| model="llama3-8b-8192", | |
| messages=[{"role": "user", "content": prompt}] | |
| ) | |
| raw = response.choices[0].message.content | |
| except Exception as e: | |
| return f"<span style='color:red;'>β Error: {str(e)}</span>" | |
| # Clean the raw response first - remove any HTML tags that might be in the AI response | |
| import html | |
| raw = html.unescape(raw) # Decode HTML entities | |
| raw = re.sub(r'<[^>]+>', '', raw) # Remove any HTML tags | |
| # Format response using markdown and simple text formatting | |
| lines = raw.strip().split("\n") | |
| formatted_content = "" | |
| section_colors = { | |
| "π": "#E53935", "π©Ί": "#D81B60", "π": "#5E35B1", | |
| "π§΄": "#F57C00", "πΏ": "#43A047", "π‘": "#039BE5", "π¬": "#6D4C41" | |
| } | |
| for line in lines: | |
| stripped = line.strip() | |
| if not stripped: | |
| continue | |
| # Skip lines that look like HTML code or contain style attributes | |
| if '<' in stripped and ('style=' in stripped or '/>' in stripped or '</p>' in stripped): | |
| continue | |
| # Check if this line is a section header (starts with emoji and contains expected keywords) | |
| is_section_header = False | |
| for emoji in section_colors: | |
| if stripped.startswith(emoji): | |
| # Additional check to ensure it's actually a header and not content | |
| header_keywords = ["Greeting", "Skin Issue Summary", "Global Insight", "Daily Skincare Routine", | |
| "Natural Remedy", "Lifestyle Tips", "Motivational Quote"] | |
| if any(keyword.lower() in stripped.lower() for keyword in header_keywords): | |
| is_section_header = True | |
| color = section_colors[emoji] | |
| # Use HTML span for colored headers | |
| formatted_content += f"<br><span style='color:{color}; font-weight:bold; font-size:18px;'>{stripped}</span><br>\n" | |
| break | |
| # If not a section header, treat as regular content | |
| if not is_section_header: | |
| # Clean content and add as regular text | |
| clean_content = stripped.replace('<', '<').replace('>', '>') | |
| formatted_content += f"{clean_content}<br>\n" | |
| # Build the final response with proper HTML structure | |
| html_output = f""" | |
| <div style='margin: 10px 0;'> | |
| {formatted_content} | |
| </div> | |
| """ | |
| # Embed uploaded image | |
| image_html = "" | |
| if image is not None: | |
| mime = image.type | |
| img_bytes = image.read() | |
| img_b64 = base64.b64encode(img_bytes).decode() | |
| image_html = f"<img src='data:{mime};base64,{img_b64}' style='max-width:100%; border-radius:12px; margin:15px 0;'>" | |
| # Final HTML layout with fallback for sticker | |
| final_html = f""" | |
| <div style='font-family:Arial, sans-serif; color:#111; background:#fff; padding:20px; | |
| border-radius:12px; border:1px solid #ccc; box-shadow:0 2px 6px rgba(0,0,0,0.1);'> | |
| <div style='display:flex; align-items:center; justify-content:space-between; margin-bottom:20px;'> | |
| <h2 style='color:#000; margin:0;'>π€ <b>{name}</b> | {gender}, {age} yrs</h2> | |
| <div style='width:70px; height:70px; border-radius:10px; background:linear-gradient(45deg, #ff6b6b, #4ecdc4); display:flex; align-items:center; justify-content:center; font-size:30px;'> | |
| <img src="{sticker}" style="width:60px; height:60px; border-radius:8px;" alt="β¨" onerror="this.style.display='none'; this.nextSibling.style.display='block';"> | |
| <span style="display:none; color:white;">β¨</span> | |
| </div> | |
| </div> | |
| {image_html} | |
| {html_output} | |
| </div> | |
| """ | |
| return final_html | |
| # Handle button press | |
| if submit: | |
| with st.spinner("Generating advice..."): | |
| result = skincare_advice(name, gender, age, skin_concern, description, duration, sensitivity, routine, image) | |
| if result.startswith("<span style='color:red;'>"): | |
| st.markdown(result, unsafe_allow_html=True) | |
| else: | |
| st.markdown(result, unsafe_allow_html=True) |