witcheverly
commited on
Commit
·
3b27d22
1
Parent(s):
e442f69
first commit
Browse files- CaptionGenerator.py +138 -0
- app_utils.py +80 -0
- images/.DS_Store +0 -0
- images/insta.png +0 -0
- images/insta_post.png +0 -0
- pages/📸_InstaMuse.py +125 -0
- test_app.py +16 -0
- user_data/user_data.csv +5 -0
- ✨_Home.py +86 -0
CaptionGenerator.py
ADDED
@@ -0,0 +1,138 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
'''
|
2 |
+
This script contains the CaptionGenerator class,
|
3 |
+
which is used to generate Instagram captions for images
|
4 |
+
using BLIP and Gemini models.
|
5 |
+
'''
|
6 |
+
import google.generativeai as genai
|
7 |
+
import streamlit as st
|
8 |
+
import app_utils as utils
|
9 |
+
from transformers import AutoProcessor, Blip2ForConditionalGeneration
|
10 |
+
|
11 |
+
genai.configure(api_key=utils.get_gemini_api_key())
|
12 |
+
|
13 |
+
class CaptionGenerator:
|
14 |
+
"""
|
15 |
+
Class for generating Instagram captions for images using BLIP and Gemini models.
|
16 |
+
The model from Hugging Face is used to generate the initial caption for the image,
|
17 |
+
which is then used as a prompt for the Gemini model to generate five distinct and
|
18 |
+
engaging captions for the image.
|
19 |
+
|
20 |
+
Attributes:
|
21 |
+
- google_api_key (str): Google API key for accessing the Generative AI API.
|
22 |
+
- gemini_model (GenerativeModel): Gemini model for generating Instagram captions.
|
23 |
+
- blip_processor (AutoProcessor): BLIP model processor for image captioning.
|
24 |
+
- blip_model (BlipForConditionalGeneration): BLIP model for image captioning.
|
25 |
+
|
26 |
+
Methods:
|
27 |
+
- process_image(image_data): Resize and prepare the image for caption generation.
|
28 |
+
- predict(image_data): Generate five Instagram captions for the provided image.
|
29 |
+
"""
|
30 |
+
def __init__(self):
|
31 |
+
self.gemini = genai.GenerativeModel('gemini-pro')
|
32 |
+
self.processor = None
|
33 |
+
self.model = None
|
34 |
+
|
35 |
+
def image_2_text(self, image_data):
|
36 |
+
"""
|
37 |
+
Generate a caption for the provided image using the BLIP-2 model.
|
38 |
+
:param image_data: PIL.Image - The image for which the caption is to be generated.
|
39 |
+
:return: description - The description generated for the image.
|
40 |
+
"""
|
41 |
+
try:
|
42 |
+
self.processor, self.model, _ = utils.init_model(init_model_required=True)
|
43 |
+
inputs = self.processor(images=image_data, return_tensors="pt")
|
44 |
+
generated_ids = self.model.generate(**inputs, max_length=100)
|
45 |
+
description = self.processor.batch_decode(generated_ids, skip_special_tokens=True)[0].strip()
|
46 |
+
return description
|
47 |
+
|
48 |
+
except Exception as e:
|
49 |
+
st.error(f"Error occurred during image captioning: {e}")
|
50 |
+
|
51 |
+
|
52 |
+
def text_2_caption(self, image_description):
|
53 |
+
"""
|
54 |
+
Generate five Instagram captions for the provided image.
|
55 |
+
The image is first processed before generating captions.
|
56 |
+
|
57 |
+
:param image_description: str - The description of the image for which captions are to be generated.
|
58 |
+
:return: str - Five Instagram captions formatted as specified.
|
59 |
+
"""
|
60 |
+
prompt = (
|
61 |
+
f"This caption was generated with a deep learning model."
|
62 |
+
f"Your task is to enhance the caption to make it more engaging:"
|
63 |
+
f"Given this provided photo description, generate five distinct "
|
64 |
+
f"fun and engaging Instagram captions. Each caption must include "
|
65 |
+
f"at least one emoji and one hashtag. The captions should be "
|
66 |
+
f"formatted with a preceding 'Caption #', followed by the "
|
67 |
+
f"caption text. Ensure each caption is separated by a blank "
|
68 |
+
f"line for readability."
|
69 |
+
f"Original Caption: {image_description}"
|
70 |
+
f"Please format your response as follows: \n"
|
71 |
+
f"**Caption 1**: [caption text]\n"
|
72 |
+
f"**Caption 2**: [caption text]\n"
|
73 |
+
f"**Caption 3**: [caption text]\n"
|
74 |
+
f"**Caption 4**: [caption text]\n"
|
75 |
+
f"**Caption 5**: [caption text]\n"
|
76 |
+
)
|
77 |
+
|
78 |
+
try:
|
79 |
+
response = self.gemini.generate_content(prompt)
|
80 |
+
caption = response.parts[0].text
|
81 |
+
caption_list = response.parts[0].text.split("\n")
|
82 |
+
return caption, caption_list, image_description
|
83 |
+
|
84 |
+
except Exception as e:
|
85 |
+
st.error(f"Unable to connect to Gemini API: {e}")
|
86 |
+
|
87 |
+
|
88 |
+
# try:
|
89 |
+
# response = gemini_model.generate_content(prompt)
|
90 |
+
# caption = response.parts[0].text
|
91 |
+
# caption_list = response.parts[0].text.split("\n")
|
92 |
+
# return caption, caption_list, image_description
|
93 |
+
#
|
94 |
+
# except Exception as e:
|
95 |
+
# st.error(f"Unable to generate captions from description: {e}")
|
96 |
+
|
97 |
+
def caption_2_hashtag(self, caption):
|
98 |
+
"""
|
99 |
+
Generate additional hashtags based on the content of the caption.
|
100 |
+
|
101 |
+
:param caption: str - The caption for which hashtags are to be generated.
|
102 |
+
:return: str - Additional hashtags based on the content of the caption.
|
103 |
+
"""
|
104 |
+
# Generate hashtags based on the content of the caption
|
105 |
+
prompt = (f"Given the provided caption, generate relevant hashtags to increase engagement,"
|
106 |
+
f"and are related to the caption content. Original Image Description: {caption},"
|
107 |
+
f"Please format your response as follows:\n"
|
108 |
+
f'[hashtags separated by commas]'
|
109 |
+
f" \n")
|
110 |
+
|
111 |
+
try:
|
112 |
+
response = self.gemini.generate_content(prompt)
|
113 |
+
hashtags = response.parts[0].text
|
114 |
+
return hashtags
|
115 |
+
|
116 |
+
except Exception as e:
|
117 |
+
st.error(f"Error occurred with Gemini API: {e}")
|
118 |
+
|
119 |
+
|
120 |
+
@st.cache_resource()
|
121 |
+
def load_model():
|
122 |
+
"""
|
123 |
+
Loads the BLIP-2 model for image captioning. This function is cached to avoid
|
124 |
+
re-loading the model on every call.
|
125 |
+
:param CaptionGenerator: The class for generating captions for images.
|
126 |
+
:return: Instance of the CaptionGenerator class.
|
127 |
+
"""
|
128 |
+
return CaptionGenerator()
|
129 |
+
|
130 |
+
|
131 |
+
# Example usage of the CaptionGenerator class
|
132 |
+
# caption_generator = load_model()
|
133 |
+
# image = Image.open("example.jpg")
|
134 |
+
# desc = caption_generator.image_2_text(image)
|
135 |
+
# captions, caption_list, img_description = caption_generator.text_2_caption(desc)
|
136 |
+
# hashtags = caption_generator.caption_2_hashtag(img_description)
|
137 |
+
# print(captions)
|
138 |
+
# print(hashtags)
|
app_utils.py
ADDED
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Utility functions for the Instagram Caption Generator app.
|
3 |
+
"""
|
4 |
+
import streamlit as st
|
5 |
+
from dotenv import load_dotenv
|
6 |
+
from transformers import AutoProcessor, Blip2ForConditionalGeneration
|
7 |
+
import os
|
8 |
+
from pathlib import Path
|
9 |
+
import pandas as pd
|
10 |
+
|
11 |
+
|
12 |
+
def get_gemini_api_key():
|
13 |
+
"""
|
14 |
+
Retrieves the Google API key for accessing the Generative AI API.
|
15 |
+
:return: str - The Google API key.
|
16 |
+
"""
|
17 |
+
load_dotenv()
|
18 |
+
google_api_key = os.getenv("GOOGLE_API_KEY")
|
19 |
+
return google_api_key
|
20 |
+
|
21 |
+
|
22 |
+
@st.cache_resource()
|
23 |
+
def init_model(init_model_required):
|
24 |
+
"""
|
25 |
+
Initializes the BLIP-2 model and processor for image captioning.
|
26 |
+
This helper function allows for lazy loading of the model and processor.
|
27 |
+
The streamlit app can call this function to load the model and processor
|
28 |
+
only when needed.
|
29 |
+
:param init_model_required: bo
|
30 |
+
ol - Flag to indicate if the model needs to be initialized.
|
31 |
+
:returns: AutoProcessor, Blip2ForConditionalGeneration, bool - Model processor, BLIP-2 model, and flag.
|
32 |
+
"""
|
33 |
+
if init_model_required:
|
34 |
+
try:
|
35 |
+
processor = AutoProcessor.from_pretrained('./data/pretrained/blip2-opt-2.7b')
|
36 |
+
blip2_model = Blip2ForConditionalGeneration.from_pretrained('./data/pretrained/blip2-opt-2.7b')
|
37 |
+
init_model_required = False
|
38 |
+
return processor, blip2_model, init_model_required
|
39 |
+
except Exception as e:
|
40 |
+
st.error(f"Error occurred during model initialization: {e}")
|
41 |
+
|
42 |
+
|
43 |
+
# Function to store the user data to a CSV file
|
44 |
+
def save_user_data(first_name, last_name, email, phone):
|
45 |
+
"""
|
46 |
+
Function to store the user data to a CSV file
|
47 |
+
|
48 |
+
:param first_name: str - First name of the user
|
49 |
+
:param last_name: str - Last name of the user
|
50 |
+
:param email: str - Email of the user
|
51 |
+
:param phone: str - Phone number of the user
|
52 |
+
:return: None
|
53 |
+
"""
|
54 |
+
csv_file = Path("./user_data/user_data.csv")
|
55 |
+
# Check if the file exists and create a DataFrame accordingly
|
56 |
+
if csv_file.exists():
|
57 |
+
df = pd.read_csv(csv_file)
|
58 |
+
else:
|
59 |
+
df = pd.DataFrame(columns=["First Name", "Last Name", "Email", "Phone Number"])
|
60 |
+
|
61 |
+
# Add and save new user data (not for production).
|
62 |
+
new_data = pd.DataFrame({"First Name": [first_name],
|
63 |
+
"Last Name": [last_name],
|
64 |
+
"Email": [email],
|
65 |
+
"Phone Number": [phone]})
|
66 |
+
df = pd.concat([df, new_data], ignore_index=True)
|
67 |
+
df.to_csv(csv_file, index=False)
|
68 |
+
return None
|
69 |
+
|
70 |
+
|
71 |
+
def get_gif(path):
|
72 |
+
"""Function to get the GIF image"""
|
73 |
+
with open(path, "rb") as file:
|
74 |
+
gif = file.read()
|
75 |
+
return gif
|
76 |
+
|
77 |
+
|
78 |
+
# Blip-2 does most of the standard image processing needed for image captioning.
|
79 |
+
def process_image(image_data, processor):
|
80 |
+
pass
|
images/.DS_Store
ADDED
Binary file (6.15 kB). View file
|
|
images/insta.png
ADDED
![]() |
images/insta_post.png
ADDED
![]() |
pages/📸_InstaMuse.py
ADDED
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import streamlit as st
|
3 |
+
from PIL import Image
|
4 |
+
import pyperclip
|
5 |
+
import app_utils as utils
|
6 |
+
from CaptionGenerator import CaptionGenerator, load_model
|
7 |
+
|
8 |
+
# Define Streamlit configurations
|
9 |
+
st.set_page_config(
|
10 |
+
page_title="Instamuse",
|
11 |
+
page_icon=":camera:",
|
12 |
+
layout='wide',
|
13 |
+
menu_items={
|
14 |
+
'Get Help': 'https://www.streamlit.io',
|
15 |
+
'Report a bug': "https://github.com/aditya-67/Instagram_Caption_Generator/issues",
|
16 |
+
'About': "# This is a Streamlit app that uses AI to generate captions for images."
|
17 |
+
}
|
18 |
+
)
|
19 |
+
|
20 |
+
# Initialize the caption generator
|
21 |
+
caption_generator = load_model()
|
22 |
+
|
23 |
+
# Define aesthetic enhancements, including CSS for the spinner
|
24 |
+
st.markdown(
|
25 |
+
"""
|
26 |
+
<style>
|
27 |
+
.big-font {
|
28 |
+
font-size:30px !important;
|
29 |
+
font-weight: bold;
|
30 |
+
}
|
31 |
+
.image-shadow {
|
32 |
+
box-shadow: 8px 8px 20px grey;
|
33 |
+
}
|
34 |
+
/* Centering the spinner */
|
35 |
+
.st-bq {
|
36 |
+
position: fixed;
|
37 |
+
top: 50%;
|
38 |
+
left: 50%;
|
39 |
+
transform: translate(-50%, -50%);
|
40 |
+
font-size: 20px; /* Make text larger */
|
41 |
+
}
|
42 |
+
</style>
|
43 |
+
""",
|
44 |
+
unsafe_allow_html=True
|
45 |
+
)
|
46 |
+
|
47 |
+
# Sidebar configuration
|
48 |
+
with st.sidebar:
|
49 |
+
st.image(os.path.join('images', 'insta.png'), width=300)
|
50 |
+
st.title("Welcome to InstaMuse!")
|
51 |
+
st.subheader("Turn your snapshots into social media sensations.")
|
52 |
+
st.write("Start turning heads with your posts. Use InstaMuse now and watch your likes soar!")
|
53 |
+
|
54 |
+
# Main page content
|
55 |
+
st.markdown('<p class="big-font">InstaMuse Photo Caption Generator</p>', unsafe_allow_html=True)
|
56 |
+
st.write("### Upload your photo below and spark some caption magic! ଘ(੭ˊᵕˋ)੭* ੈ✩‧₊")
|
57 |
+
|
58 |
+
# Upload image file and process image
|
59 |
+
file = st.file_uploader(
|
60 |
+
"Upload your image here:",
|
61 |
+
type=["jpg", "png"],
|
62 |
+
help="Only jpg and png images are supported"
|
63 |
+
)
|
64 |
+
|
65 |
+
if file:
|
66 |
+
image = Image.open(file)
|
67 |
+
image.thumbnail((600, 600), Image.Resampling.LANCZOS)
|
68 |
+
|
69 |
+
try:
|
70 |
+
desc = caption_generator.image_2_text(image)
|
71 |
+
captions, caption_list, img_description = caption_generator.text_2_caption(desc)
|
72 |
+
st.session_state['captions'] = captions
|
73 |
+
st.session_state['caption_list'] = caption_list
|
74 |
+
st.session_state['img_description'] = img_description
|
75 |
+
except Exception as e:
|
76 |
+
st.error(f"Error generating captions: {e}")
|
77 |
+
captions = None
|
78 |
+
|
79 |
+
with st.spinner(r'#### :sparkles: :sparkles: Generating... please wait :hourglass_flowing_sand:'):
|
80 |
+
st.session_state['file'] = file
|
81 |
+
|
82 |
+
with st.container():
|
83 |
+
col1, col2 = st.columns(2)
|
84 |
+
|
85 |
+
with col1:
|
86 |
+
st.markdown("## 📸 Your Image:")
|
87 |
+
st.image(image, caption='Uploaded Image', use_column_width=True)
|
88 |
+
|
89 |
+
with col2:
|
90 |
+
if captions:
|
91 |
+
st.markdown("## 📝 Generated Captions:")
|
92 |
+
for caption in caption_list:
|
93 |
+
if caption.strip():
|
94 |
+
st.info(f"##### {caption}")
|
95 |
+
|
96 |
+
# Action buttons with functionality
|
97 |
+
if 'captions' in st.session_state and st.session_state['captions']:
|
98 |
+
col1, col2, col3, col4 = st.columns(4)
|
99 |
+
if col1.button("📋 Copy"):
|
100 |
+
pyperclip.copy(st.session_state['captions'])
|
101 |
+
st.success("Caption copied to clipboard!")
|
102 |
+
|
103 |
+
if col2.button("🔄 Regenerate"):
|
104 |
+
with st.spinner('Regenerating captions...'):
|
105 |
+
st.rerun()
|
106 |
+
|
107 |
+
if col3.button("✨ More Hashtags"):
|
108 |
+
with st.spinner('Generating hashtags...'):
|
109 |
+
try:
|
110 |
+
hashtags = caption_generator.caption_2_hashtag(st.session_state['img_description'])
|
111 |
+
except Exception as e:
|
112 |
+
st.error(f"Error generating hashtags: {e}")
|
113 |
+
hashtags = None
|
114 |
+
st.write("### Generated Hashtags:")
|
115 |
+
st.write(f"**{hashtags}**")
|
116 |
+
|
117 |
+
if col4.button(":window: Clear Screen"):
|
118 |
+
st.rerun()
|
119 |
+
|
120 |
+
with st.expander("Need help?"):
|
121 |
+
st.write("Please contact us at [email](mailto:jess@llmjessica.com)")
|
122 |
+
|
123 |
+
# Footer
|
124 |
+
st.markdown("---")
|
125 |
+
st.caption("Thank you for using InstaMuse! Feel free to contact us for any suggestions or issues.")
|
test_app.py
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import unittest
|
2 |
+
from PIL import Image
|
3 |
+
from app import import_and_predict
|
4 |
+
|
5 |
+
|
6 |
+
class TestApp(unittest.TestCase):
|
7 |
+
|
8 |
+
def test_import_and_predict(self):
|
9 |
+
image_data = Image.new('RGB', (100, 100)) # Mock image data
|
10 |
+
caption = import_and_predict(image_data) # Call the function
|
11 |
+
self.assertIsInstance(caption, str) # Check if caption is a string
|
12 |
+
self.assertTrue(len(caption) > 0) # Check if caption is not empty
|
13 |
+
|
14 |
+
|
15 |
+
if __name__ == '__main__':
|
16 |
+
unittest.main()
|
user_data/user_data.csv
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
First Name,Last Name,Email,Phone Number
|
2 |
+
Jane,Doe,jd@gmail.com,99999999
|
3 |
+
j`,as,22,22
|
4 |
+
z,asds,4,3
|
5 |
+
test,test,test,test
|
✨_Home.py
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import streamlit as st
|
3 |
+
from app_utils import get_gif, save_user_data
|
4 |
+
|
5 |
+
|
6 |
+
def main():
|
7 |
+
# Define Streamlit configurations
|
8 |
+
st.set_page_config(page_title="Instamuse", page_icon=":camera:", initial_sidebar_state='auto')
|
9 |
+
|
10 |
+
# Sidebar configuration
|
11 |
+
with st.sidebar:
|
12 |
+
st.image(os.path.abspath('images/insta.png'))
|
13 |
+
st.title("InstaMuse")
|
14 |
+
st.subheader(
|
15 |
+
"Welcome to InstaMuse, the ultimate tool for turning your snapshots "
|
16 |
+
"into social media sensations!"
|
17 |
+
)
|
18 |
+
st.write("Start turning heads with your posts. Use InstaMuse now and watch your likes soar!")
|
19 |
+
|
20 |
+
# Title and Style
|
21 |
+
st.markdown("""
|
22 |
+
<style>
|
23 |
+
.title-font {
|
24 |
+
font-size: 50px;
|
25 |
+
font-weight: bold;
|
26 |
+
font-family: 'Helvetica', sans-serif;
|
27 |
+
color: #FF573D;
|
28 |
+
}
|
29 |
+
</style>
|
30 |
+
""", unsafe_allow_html=True)
|
31 |
+
st.markdown('<h1 class="title-font">The Worlds Best Instagram Caption Generator</h1>', unsafe_allow_html=True)
|
32 |
+
|
33 |
+
# Subheader
|
34 |
+
st.write(
|
35 |
+
"### Transform your online presence—join InstaMuse to create "
|
36 |
+
"innovative captions that increase likes and enhance your visibility."
|
37 |
+
)
|
38 |
+
|
39 |
+
# Gif display
|
40 |
+
st.image(get_gif(os.path.abspath('images/insta.png')))
|
41 |
+
|
42 |
+
# Why us?
|
43 |
+
st.subheader('Why InstaMuse?')
|
44 |
+
st.write("""
|
45 |
+
- 🎨 **Creativity at your fingertips:** Generate unique captions that stand out.
|
46 |
+
- ⏳ **Save time:** Stop spending hours trying to write the perfect caption.
|
47 |
+
- 🚀 **Boost engagement:** Captions crafted to keep your audience engaged.
|
48 |
+
- 💸 **Free to use:** Get access to our technology preview at no cost.
|
49 |
+
""")
|
50 |
+
|
51 |
+
# Success Stories
|
52 |
+
st.subheader('Success Stories')
|
53 |
+
cols = st.columns(2)
|
54 |
+
with cols[0]:
|
55 |
+
st.image(os.path.abspath('images/insta_post.png'))
|
56 |
+
with cols[1]:
|
57 |
+
st.write("")
|
58 |
+
st.write('"InstaMuse helped us reach a wider audience. Our engagement rates have never been higher!" - CR')
|
59 |
+
st.write('"Thanks to InstaMuse, our posts now resonate better with our audience, bringing more likes and comments than ever before." - LJ')
|
60 |
+
st.write('"The creative captions we developed with InstaMuse have not only increased likes but also built lasting connections with our followers." - MK')
|
61 |
+
|
62 |
+
# Sign up section
|
63 |
+
st.subheader('Sign up here for priority access')
|
64 |
+
st.write('Enter your details below to get early access to our innovative caption generator.')
|
65 |
+
|
66 |
+
# Form to collect user details
|
67 |
+
with st.form(key='user_details_form', clear_on_submit=True):
|
68 |
+
cols = st.columns(2)
|
69 |
+
with cols[0]:
|
70 |
+
first_name = st.text_input("First Name")
|
71 |
+
email = st.text_input("Email", help="We'll never share your email with anyone else.")
|
72 |
+
with cols[1]:
|
73 |
+
last_name = st.text_input("Last Name")
|
74 |
+
phone = st.text_input("Phone Number", help="We'll never share your number with anyone else.")
|
75 |
+
submit_button = st.form_submit_button("Start Using InstaMuse")
|
76 |
+
|
77 |
+
if submit_button:
|
78 |
+
if first_name and last_name and email and phone:
|
79 |
+
save_user_data(first_name, last_name, email, phone)
|
80 |
+
st.success("Thank you for signing up! We will be in touch soon.")
|
81 |
+
else:
|
82 |
+
st.error("Please fill in all the fields.")
|
83 |
+
|
84 |
+
|
85 |
+
if __name__ == "__main__":
|
86 |
+
main()
|