Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import google.generativeai as genai | |
| import os | |
| from dotenv import load_dotenv | |
| from styles import get_custom_css | |
| from formulas import offer_formulas | |
| import PyPDF2 | |
| import docx | |
| from PIL import Image | |
| import io | |
| # Set page to wide mode to use full width | |
| st.set_page_config(layout="wide") | |
| # Load environment variables | |
| load_dotenv() | |
| # Configure Google Gemini API | |
| genai.configure(api_key=os.getenv('GOOGLE_API_KEY')) | |
| model = genai.GenerativeModel('gemini-1.5-flash') # Updated to model that supports images | |
| # Initialize session state variables if they don't exist | |
| if 'submitted' not in st.session_state: | |
| st.session_state.submitted = False | |
| if 'offer_result' not in st.session_state: | |
| st.session_state.offer_result = "" | |
| # Hide Streamlit menu and footer | |
| st.markdown(""" | |
| <style> | |
| #MainMenu {visibility: hidden;} | |
| footer {visibility: hidden;} | |
| header {visibility: hidden;} | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # Custom CSS | |
| st.markdown(get_custom_css(), unsafe_allow_html=True) | |
| # App title and description - centered and without emoji | |
| st.markdown('<h1 style="text-align: center;">Great Offer Generator</h1>', unsafe_allow_html=True) | |
| st.markdown('<h3 style="text-align: center;">Transform your skills into compelling offers!</h3>', unsafe_allow_html=True) | |
| # Create two columns for layout - left column 40%, right column 60% | |
| col1, col2 = st.columns([4, 6]) | |
| # Main input section in left column | |
| with col1: | |
| # Add tabs for different input methods | |
| input_tab1, input_tab2, input_tab3 = st.tabs(["Entrada Manual", "Subir Archivo", "Subir Imagen"]) | |
| with input_tab1: | |
| skills = st.text_area('💪 Tus Habilidades', height=70, | |
| help='Lista tus habilidades y experiencia clave') | |
| product_service = st.text_area('🎯 Producto/Servicio', height=70, | |
| help='Describe tu producto o servicio') | |
| with input_tab2: | |
| uploaded_file = st.file_uploader("Sube un archivo con tu información", type=['txt', 'pdf', 'docx']) | |
| if uploaded_file is not None: | |
| # Handle different file types | |
| file_type = uploaded_file.name.split('.')[-1].lower() | |
| if file_type == 'txt': | |
| # Read text file | |
| file_content = uploaded_file.read().decode('utf-8') | |
| st.success(f"Archivo cargado correctamente: {uploaded_file.name}") | |
| elif file_type == 'pdf': | |
| try: | |
| import PyPDF2 | |
| pdf_reader = PyPDF2.PdfReader(uploaded_file) | |
| file_content = "" | |
| for page in pdf_reader.pages: | |
| file_content += page.extract_text() + "\n" | |
| st.success(f"Archivo PDF cargado correctamente: {uploaded_file.name}") | |
| except Exception as e: | |
| st.error(f"Error al leer el archivo PDF: {str(e)}") | |
| file_content = "" | |
| elif file_type == 'docx': | |
| try: | |
| import docx | |
| doc = docx.Document(uploaded_file) | |
| file_content = "\n".join([para.text for para in doc.paragraphs]) | |
| st.success(f"Archivo DOCX cargado correctamente: {uploaded_file.name}") | |
| except Exception as e: | |
| st.error(f"Error al leer el archivo DOCX: {str(e)}") | |
| file_content = "" | |
| # Display preview of file content | |
| with st.expander("Vista previa del contenido"): | |
| st.write(file_content[:500] + "..." if len(file_content) > 500 else file_content) | |
| with input_tab3: | |
| uploaded_image = st.file_uploader("Sube una imagen de tu producto o servicio", type=['jpg', 'jpeg', 'png']) | |
| if uploaded_image is not None: | |
| # Display the uploaded image | |
| image = Image.open(uploaded_image) | |
| st.image(image, caption="Imagen cargada", use_container_width=True) | |
| # Convert to format for Gemini | |
| image_bytes = uploaded_image.getvalue() | |
| image_parts = [ | |
| { | |
| "mime_type": uploaded_image.type, | |
| "data": image_bytes | |
| } | |
| ] | |
| st.success(f"Imagen cargada correctamente: {uploaded_image.name}") | |
| # Accordion for additional settings | |
| with st.expander('⚙️ Configuración Avanzada'): | |
| target_audience = st.text_area('👥 Público Objetivo', height=70, | |
| help='Describe tu cliente o público ideal') | |
| # Selector de fórmula | |
| formula_type = st.selectbox( | |
| '📋 Tipo de Fórmula', | |
| options=list(offer_formulas.keys()), | |
| help='Selecciona el tipo de fórmula para tu oferta' | |
| ) | |
| # Removed the "Ver detalles de la fórmula" expander section | |
| temperature = st.slider('🌡️ Nivel de Creatividad', min_value=0.0, max_value=2.0, value=0.7, | |
| help='Valores más altos hacen que el resultado sea más creativo pero menos enfocado') | |
| # Generate button with callback | |
| def generate_offer(): | |
| has_manual_input = bool(skills and product_service) | |
| has_file_input = bool('uploaded_file' in locals() and uploaded_file is not None) | |
| has_image_input = bool('uploaded_image' in locals() and uploaded_image is not None) | |
| # Handle all scenarios | |
| if not (has_manual_input or has_file_input or has_image_input): | |
| st.error('Por favor ingresa texto, sube un archivo o una imagen') | |
| return | |
| st.session_state.submitted = True | |
| # Store inputs based on what's available | |
| if has_manual_input: | |
| st.session_state.skills = skills | |
| st.session_state.product_service = product_service | |
| if has_file_input: | |
| st.session_state.file_content = file_content | |
| if has_image_input: | |
| st.session_state.image_parts = image_parts | |
| # Set input type | |
| if has_image_input: | |
| if has_manual_input and has_file_input: | |
| st.session_state.input_type = "all" | |
| elif has_manual_input: | |
| st.session_state.input_type = "manual_image" | |
| elif has_file_input: | |
| st.session_state.input_type = "file_image" | |
| else: | |
| st.session_state.input_type = "image" | |
| else: | |
| if has_manual_input and has_file_input: | |
| st.session_state.input_type = "both" | |
| elif has_manual_input: | |
| st.session_state.input_type = "manual" | |
| else: | |
| st.session_state.input_type = "file" | |
| # Store common settings | |
| st.session_state.target_audience = target_audience | |
| st.session_state.temperature = temperature | |
| st.session_state.formula_type = formula_type | |
| st.button('Generar Oferta 🎉', on_click=generate_offer) | |
| # Results column | |
| with col2: | |
| # Check if form has been submitted | |
| if st.session_state.submitted: | |
| with st.spinner('Creando tu oferta perfecta...'): | |
| # Determine which input source to use and create appropriate prompt | |
| base_prompt = f"""You are a professional copywriter specializing in creating irresistible offers. | |
| Create a compelling and persuasive offer using the {st.session_state.formula_type} formula. | |
| Target Audience: {st.session_state.target_audience if hasattr(st.session_state, 'target_audience') and st.session_state.target_audience else 'General audience'} | |
| """ | |
| if st.session_state.input_type == "manual": | |
| prompt = base_prompt + f""" | |
| Based on the following information: | |
| Skills: {st.session_state.skills} | |
| Product/Service: {st.session_state.product_service} | |
| """ | |
| elif st.session_state.input_type == "file": | |
| prompt = base_prompt + f""" | |
| Based on the following information from the uploaded file: | |
| File Content: {st.session_state.file_content} | |
| """ | |
| elif st.session_state.input_type == "image": | |
| prompt = base_prompt + f""" | |
| Based on the image provided, create an offer that highlights the visual elements and appeals to the target audience. | |
| """ | |
| elif st.session_state.input_type == "both": | |
| prompt = base_prompt + f""" | |
| Based on the following combined information: | |
| Skills: {st.session_state.skills} | |
| Product/Service: {st.session_state.product_service} | |
| Additional Information from File: {st.session_state.file_content} | |
| Please consider both the manual input and file content to create a comprehensive offer. | |
| """ | |
| elif st.session_state.input_type == "manual_image": | |
| prompt = base_prompt + f""" | |
| Based on the following information and the image provided: | |
| Skills: {st.session_state.skills} | |
| Product/Service: {st.session_state.product_service} | |
| Please analyze both the text information and the visual elements in the image to create a comprehensive offer. | |
| """ | |
| elif st.session_state.input_type == "file_image": | |
| prompt = base_prompt + f""" | |
| Based on the following information from the uploaded file and the image provided: | |
| File Content: {st.session_state.file_content} | |
| Please analyze both the file content and the visual elements in the image to create a comprehensive offer. | |
| """ | |
| else: # all inputs | |
| prompt = base_prompt + f""" | |
| Based on all the following information: | |
| Skills: {st.session_state.skills} | |
| Product/Service: {st.session_state.product_service} | |
| Additional Information from File: {st.session_state.file_content} | |
| Please analyze the text information, file content, and the visual elements in the image to create the most comprehensive offer. | |
| """ | |
| prompt += f""" | |
| Formula Description: | |
| {offer_formulas[st.session_state.formula_type]["description"]} | |
| Please create a professional, engaging, and irresistible offer that highlights the value proposition and creates urgency. | |
| IMPORTANT: Provide ONLY the final offer text. Do not include any explanations, labels, formatting instructions, brackets, or call to action at the end.""" | |
| try: | |
| # Create generation config with temperature | |
| generation_config = genai.GenerationConfig(temperature=st.session_state.temperature) | |
| # Pass the generation config to generate_content | |
| if "image" in st.session_state.input_type: | |
| response = model.generate_content([prompt, st.session_state.image_parts[0]], generation_config=generation_config) | |
| else: | |
| response = model.generate_content(prompt, generation_config=generation_config) | |
| st.session_state.offer_result = response.text | |
| # Display result - without emoji | |
| st.markdown('### Oferta Generada') | |
| st.markdown(st.session_state.offer_result) | |
| # Add download button below the result with 80% width | |
| col_download, col_empty = st.columns([8, 2]) | |
| with col_download: | |
| st.download_button( | |
| label="Descargar Oferta", | |
| data=st.session_state.offer_result, | |
| file_name="oferta_generada.txt", | |
| mime="text/plain" | |
| ) | |
| except Exception as e: | |
| st.error(f'Ocurrió un error: {str(e)}') | |
| st.session_state.submitted = False | |
| # Footer | |
| st.markdown('---') | |
| st.markdown('Made with ❤️ by Jesús Cabrera') |