Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -12,6 +12,7 @@ import psutil
|
|
12 |
|
13 |
st.set_page_config(layout="wide")
|
14 |
|
|
|
15 |
st.markdown("""
|
16 |
<style>
|
17 |
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap');
|
@@ -58,7 +59,6 @@ st.markdown("""
|
|
58 |
padding: 10px 15px;
|
59 |
transition: text-shadow 0.3s ease-in-out;
|
60 |
text-shadow: 5px 5px 12px rgba(0, 0, 0, 0.5);
|
61 |
-
|
62 |
}
|
63 |
.navbar li a:hover {
|
64 |
color: #ff6f61;
|
@@ -107,11 +107,10 @@ st.markdown("""
|
|
107 |
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.25);
|
108 |
transition: all 0.3s ease;
|
109 |
border: 1px solid rgba(0, 0, 0, 0.1);
|
110 |
-
background-color: #fff;
|
111 |
filter: brightness(1.05);
|
112 |
z-index: 10;
|
113 |
}
|
114 |
-
|
115 |
.feature i {
|
116 |
font-size: 1.5rem;
|
117 |
color: #2196f3;
|
@@ -138,12 +137,10 @@ st.markdown("""
|
|
138 |
text-align: center;
|
139 |
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
|
140 |
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
141 |
-
|
142 |
height: 290px;
|
143 |
padding-top: 10px;
|
144 |
}
|
145 |
-
|
146 |
-
}
|
147 |
.plan:hover {
|
148 |
transform: translateY(-5px);
|
149 |
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.15);
|
@@ -152,7 +149,6 @@ st.markdown("""
|
|
152 |
font-size: 1.5rem;
|
153 |
margin-bottom: 0.5rem;
|
154 |
}
|
155 |
-
|
156 |
.plan.free { border-top: 4px solid #28a745; }
|
157 |
.plan.premium { border-top: 4px solid #ff6f61; }
|
158 |
.plan.business { border-top: 4px solid #2196f3; }
|
@@ -194,6 +190,17 @@ st.markdown("""
|
|
194 |
font-family: 'Poppins', sans-serif;
|
195 |
}
|
196 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
197 |
/* Footer */
|
198 |
footer {
|
199 |
background: #1a1a1a;
|
@@ -255,6 +262,7 @@ footer {
|
|
255 |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
256 |
""", unsafe_allow_html=True)
|
257 |
|
|
|
258 |
def format_time(seconds):
|
259 |
minutes = int(seconds // 60)
|
260 |
secs = int(seconds % 60)
|
@@ -285,8 +293,8 @@ class TranscriptionProgress:
|
|
285 |
def load_model(language='en', summarizer_type='bart'):
|
286 |
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
287 |
if language == 'ur':
|
288 |
-
processor = AutoProcessor.from_pretrained("GogetaBlueMUI/whisper-medium-ur-fleurs")
|
289 |
-
model = AutoModelForSpeechSeq2Seq.from_pretrained("GogetaBlueMUI/whisper-medium-ur-fleurs").to(device)
|
290 |
else:
|
291 |
processor = AutoProcessor.from_pretrained("openai/whisper-small")
|
292 |
model = AutoModelForSpeechSeq2Seq.from_pretrained("openai/whisper-small").to(device)
|
@@ -449,6 +457,7 @@ def generate_srt(transcript, include_timeframe=True):
|
|
449 |
srt_content += f"{text}\n\n"
|
450 |
return srt_content
|
451 |
|
|
|
452 |
def main():
|
453 |
st.markdown("""
|
454 |
<div class="header">
|
@@ -471,33 +480,7 @@ def main():
|
|
471 |
</div>
|
472 |
""", unsafe_allow_html=True)
|
473 |
|
474 |
-
|
475 |
-
<style>
|
476 |
-
/* Video player styling */
|
477 |
-
.stVideo > div {
|
478 |
-
max-width: 600px !important;
|
479 |
-
max-height: 450px !important;
|
480 |
-
margin: 0 auto;
|
481 |
-
border: 3px solid #2196f3;
|
482 |
-
border-radius: 8px;
|
483 |
-
overflow: hidden;
|
484 |
-
}
|
485 |
-
|
486 |
-
/* Footer column styling */
|
487 |
-
.footer-container {
|
488 |
-
display: flex;
|
489 |
-
justify-content: space-between;
|
490 |
-
}
|
491 |
-
.footer-section:first-child {
|
492 |
-
margin-left: 10px;
|
493 |
-
}
|
494 |
-
.footer-section:last-child {
|
495 |
-
margin-right: 10px;
|
496 |
-
}
|
497 |
-
</style>
|
498 |
-
""", unsafe_allow_html=True)
|
499 |
-
|
500 |
-
|
501 |
if 'app_state' not in st.session_state:
|
502 |
st.session_state['app_state'] = 'upload'
|
503 |
if 'video_path' not in st.session_state:
|
@@ -539,8 +522,6 @@ def main():
|
|
539 |
st.session_state['app_state'] = 'processing'
|
540 |
st.write(f"Uploaded file: {uploaded_file.name}")
|
541 |
st.rerun()
|
542 |
-
|
543 |
-
|
544 |
|
545 |
if st.session_state['app_state'] == 'processing':
|
546 |
with st.form(key="processing_form"):
|
@@ -601,28 +582,50 @@ def main():
|
|
601 |
os.remove(temp_file)
|
602 |
|
603 |
if st.session_state['app_state'] == 'results':
|
|
|
604 |
st.video(st.session_state['video_path'], start_time=st.session_state['current_time'])
|
|
|
|
|
605 |
st.session_state['show_timeframe'] = st.checkbox("Show timeframe in transcript", value=st.session_state['show_timeframe'])
|
606 |
st.markdown("### Search Subtitles")
|
607 |
-
|
608 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
609 |
st.markdown(f"### {st.session_state['language']} Transcript")
|
|
|
610 |
for text, start, end in st.session_state['primary_transcript']:
|
611 |
-
display_text = text.lower()
|
612 |
-
if not search_query or search_query in display_text:
|
|
|
613 |
label = f"[{format_time(start)} - {format_time(end)}] {text}" if st.session_state['show_timeframe'] else text
|
614 |
if st.button(label, key=f"primary_{start}"):
|
615 |
st.session_state['current_time'] = start
|
616 |
st.rerun()
|
|
|
|
|
|
|
|
|
617 |
if st.session_state['english_transcript']:
|
618 |
st.markdown("### English Translation")
|
|
|
619 |
for text, start, end in st.session_state['english_transcript']:
|
620 |
-
display_text = text.lower()
|
621 |
-
if not search_query or search_query in display_text:
|
|
|
622 |
label = f"[{format_time(start)} - {format_time(end)}] {text}" if st.session_state['show_timeframe'] else text
|
623 |
if st.button(label, key=f"english_{start}"):
|
624 |
st.session_state['current_time'] = start
|
625 |
st.rerun()
|
|
|
|
|
|
|
|
|
626 |
if (st.session_state['language_code'] == 'en' or st.session_state['translate_to_english']) and not st.session_state['summary_generated']:
|
627 |
if st.button("Generate Summary"):
|
628 |
with st.spinner("Generating summary..."):
|
@@ -637,12 +640,16 @@ def main():
|
|
637 |
if st.session_state['english_summary'] and st.session_state['summary_generated']:
|
638 |
st.markdown("### Summary")
|
639 |
st.write(st.session_state['english_summary'])
|
|
|
|
|
640 |
st.markdown("### Download Subtitles")
|
641 |
include_timeframe = st.checkbox("Include timeframe in subtitles", value=True)
|
642 |
transcript_to_download = st.session_state['primary_transcript'] or st.session_state['english_transcript']
|
643 |
if transcript_to_download:
|
644 |
srt_content = generate_srt(transcript_to_download, include_timeframe)
|
645 |
st.download_button(label="Download Subtitles (SRT)", data=srt_content, file_name="subtitles.srt", mime="text/plain")
|
|
|
|
|
646 |
st.markdown("### Edit Subtitles")
|
647 |
transcript_to_edit = st.session_state['primary_transcript'] or st.session_state['english_transcript']
|
648 |
if transcript_to_edit and st.button("Delete Subtitles"):
|
@@ -678,7 +685,9 @@ def main():
|
|
678 |
|
679 |
if st.session_state['app_state'] == 'results' and st.session_state['edited_video_path']:
|
680 |
st.markdown("### Edited Video")
|
|
|
681 |
st.video(st.session_state['edited_video_path'])
|
|
|
682 |
with open(st.session_state['edited_video_path'], "rb") as file:
|
683 |
st.download_button(label="Download Edited Video", data=file, file_name="edited_video.mp4", mime="video/mp4")
|
684 |
|
@@ -703,29 +712,29 @@ def main():
|
|
703 |
""", unsafe_allow_html=True)
|
704 |
|
705 |
st.markdown("""
|
706 |
-
|
707 |
-
|
708 |
-
|
709 |
-
|
710 |
-
|
711 |
-
|
712 |
-
|
713 |
-
|
714 |
-
|
715 |
-
|
716 |
-
|
717 |
-
|
718 |
-
|
719 |
-
|
720 |
-
|
721 |
-
|
722 |
-
|
723 |
-
|
724 |
-
|
725 |
-
</div>
|
726 |
</div>
|
727 |
</div>
|
728 |
-
|
|
|
729 |
|
730 |
st.markdown("""
|
731 |
<div id="contact" class="contact-section" style="padding: 3rem 2rem; background: #f1f4f8; border-radius: 1rem; margin: 2rem 0;">
|
@@ -733,11 +742,11 @@ def main():
|
|
733 |
<div style="max-width: 600px; margin: 0 auto;">
|
734 |
<div style="margin-bottom: 1rem;">
|
735 |
<label for="email" style="display: block; margin-bottom: 0.5rem; font-weight: 500;">Email</label>
|
736 |
-
<input type="email" id="email" placeholder="Your email address" style="width: 100%; padding: 0.75rem;
|
737 |
</div>
|
738 |
<div style="margin-bottom: 1rem;">
|
739 |
<label for="message" style="display: block; margin-bottom: 0.5rem; font-weight: 500;">Message</label>
|
740 |
-
<textarea id="message" rows="5" placeholder="Your message" style="width: 100%; padding: 0.75rem; border-radius: 0.5rem;
|
741 |
</div>
|
742 |
<button onclick="alert('Message sent successfully!')" style="background: linear-gradient(135deg, #ff6f61, #ff8a65); color: white; font-weight: 600; padding: 0.75rem 1.5rem; border-radius: 0.5rem; border: none; cursor: pointer; width: 100%;">Send Message</button>
|
743 |
</div>
|
@@ -746,11 +755,9 @@ def main():
|
|
746 |
|
747 |
st.markdown("""
|
748 |
<div class="plans">
|
749 |
-
<h2 style="text-align: center; margin-bottom: 2rem;color: black;">Choose Your Plan</h2>
|
750 |
<div class="plan-box">
|
751 |
-
<div class="plan free"
|
752 |
-
style="background: linear-gradient(135deg, #299f45, #185726);
|
753 |
-
padding-bottom: 0px">
|
754 |
<h3 style="color: white;">Free</h3>
|
755 |
<p><strong>$0</strong> / month</p>
|
756 |
<p>Basic video transcription</p>
|
@@ -758,7 +765,7 @@ def main():
|
|
758 |
<p>Max 5 minutes video</p>
|
759 |
<p>No summarization</p>
|
760 |
</div>
|
761 |
-
<div class="plan premium"
|
762 |
<h3 style="color: white;">Premium</h3>
|
763 |
<p><strong>$19</strong> / month</p>
|
764 |
<p>Advanced transcription</p>
|
@@ -766,7 +773,7 @@ def main():
|
|
766 |
<p>Max 30 minutes video</p>
|
767 |
<p>AI summarization</p>
|
768 |
</div>
|
769 |
-
<div class="plan business"
|
770 |
<h3 style="color: white;">Business</h3>
|
771 |
<p><strong>$49</strong> / month</p>
|
772 |
<p>Enterprise-grade transcription</p>
|
@@ -827,5 +834,6 @@ def main():
|
|
827 |
});
|
828 |
</script>
|
829 |
""", unsafe_allow_html=True)
|
|
|
830 |
if __name__ == "__main__":
|
831 |
main()
|
|
|
12 |
|
13 |
st.set_page_config(layout="wide")
|
14 |
|
15 |
+
# CSS Styling
|
16 |
st.markdown("""
|
17 |
<style>
|
18 |
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap');
|
|
|
59 |
padding: 10px 15px;
|
60 |
transition: text-shadow 0.3s ease-in-out;
|
61 |
text-shadow: 5px 5px 12px rgba(0, 0, 0, 0.5);
|
|
|
62 |
}
|
63 |
.navbar li a:hover {
|
64 |
color: #ff6f61;
|
|
|
107 |
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.25);
|
108 |
transition: all 0.3s ease;
|
109 |
border: 1px solid rgba(0, 0, 0, 0.1);
|
110 |
+
background-color: #fff;
|
111 |
filter: brightness(1.05);
|
112 |
z-index: 10;
|
113 |
}
|
|
|
114 |
.feature i {
|
115 |
font-size: 1.5rem;
|
116 |
color: #2196f3;
|
|
|
137 |
text-align: center;
|
138 |
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
|
139 |
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
140 |
+
border-top: 4px solid #28a745;
|
141 |
height: 290px;
|
142 |
padding-top: 10px;
|
143 |
}
|
|
|
|
|
144 |
.plan:hover {
|
145 |
transform: translateY(-5px);
|
146 |
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.15);
|
|
|
149 |
font-size: 1.5rem;
|
150 |
margin-bottom: 0.5rem;
|
151 |
}
|
|
|
152 |
.plan.free { border-top: 4px solid #28a745; }
|
153 |
.plan.premium { border-top: 4px solid #ff6f61; }
|
154 |
.plan.business { border-top: 4px solid #2196f3; }
|
|
|
190 |
font-family: 'Poppins', sans-serif;
|
191 |
}
|
192 |
|
193 |
+
/* Video player styling */
|
194 |
+
video {
|
195 |
+
display: block;
|
196 |
+
width: 350px !important;
|
197 |
+
height: 500px !important;
|
198 |
+
object-fit: contain;
|
199 |
+
margin: 0 auto;
|
200 |
+
border: 3px solid #2196f3;
|
201 |
+
border-radius: 8px;
|
202 |
+
}
|
203 |
+
|
204 |
/* Footer */
|
205 |
footer {
|
206 |
background: #1a1a1a;
|
|
|
262 |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
|
263 |
""", unsafe_allow_html=True)
|
264 |
|
265 |
+
# Function Definitions
|
266 |
def format_time(seconds):
|
267 |
minutes = int(seconds // 60)
|
268 |
secs = int(seconds % 60)
|
|
|
293 |
def load_model(language='en', summarizer_type='bart'):
|
294 |
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
295 |
if language == 'ur':
|
296 |
+
processor = AutoProcessor.from_pretrained("GogetaBlueMUI/whisper-medium-ur-fleurs-v2")
|
297 |
+
model = AutoModelForSpeechSeq2Seq.from_pretrained("GogetaBlueMUI/whisper-medium-ur-fleurs-v2").to(device)
|
298 |
else:
|
299 |
processor = AutoProcessor.from_pretrained("openai/whisper-small")
|
300 |
model = AutoModelForSpeechSeq2Seq.from_pretrained("openai/whisper-small").to(device)
|
|
|
457 |
srt_content += f"{text}\n\n"
|
458 |
return srt_content
|
459 |
|
460 |
+
# Main Function
|
461 |
def main():
|
462 |
st.markdown("""
|
463 |
<div class="header">
|
|
|
480 |
</div>
|
481 |
""", unsafe_allow_html=True)
|
482 |
|
483 |
+
# Initialize session state
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
484 |
if 'app_state' not in st.session_state:
|
485 |
st.session_state['app_state'] = 'upload'
|
486 |
if 'video_path' not in st.session_state:
|
|
|
522 |
st.session_state['app_state'] = 'processing'
|
523 |
st.write(f"Uploaded file: {uploaded_file.name}")
|
524 |
st.rerun()
|
|
|
|
|
525 |
|
526 |
if st.session_state['app_state'] == 'processing':
|
527 |
with st.form(key="processing_form"):
|
|
|
582 |
os.remove(temp_file)
|
583 |
|
584 |
if st.session_state['app_state'] == 'results':
|
585 |
+
st.markdown('<div style="display: flex; justify-content: center;">', unsafe_allow_html=True)
|
586 |
st.video(st.session_state['video_path'], start_time=st.session_state['current_time'])
|
587 |
+
st.markdown('</div>', unsafe_allow_html=True)
|
588 |
+
|
589 |
st.session_state['show_timeframe'] = st.checkbox("Show timeframe in transcript", value=st.session_state['show_timeframe'])
|
590 |
st.markdown("### Search Subtitles")
|
591 |
+
|
592 |
+
# Callback to handle search query updates
|
593 |
+
def update_search_query():
|
594 |
+
st.session_state['search_query'] = st.session_state.get('search_input', '').lower().strip()
|
595 |
+
|
596 |
+
# Text input with on_change callback
|
597 |
+
st.text_input("Search subtitles...", value=st.session_state['search_query'], key="search_input", on_change=update_search_query)
|
598 |
+
|
599 |
+
# Primary Transcript
|
600 |
st.markdown(f"### {st.session_state['language']} Transcript")
|
601 |
+
primary_matches = 0
|
602 |
for text, start, end in st.session_state['primary_transcript']:
|
603 |
+
display_text = text.lower() # Case-insensitive comparison
|
604 |
+
if not st.session_state['search_query'] or st.session_state['search_query'] in display_text:
|
605 |
+
primary_matches += 1
|
606 |
label = f"[{format_time(start)} - {format_time(end)}] {text}" if st.session_state['show_timeframe'] else text
|
607 |
if st.button(label, key=f"primary_{start}"):
|
608 |
st.session_state['current_time'] = start
|
609 |
st.rerun()
|
610 |
+
if primary_matches == 0 and st.session_state['search_query']:
|
611 |
+
st.info("No matches found in primary transcript for the search query.")
|
612 |
+
|
613 |
+
# English Transcript
|
614 |
if st.session_state['english_transcript']:
|
615 |
st.markdown("### English Translation")
|
616 |
+
english_matches = 0
|
617 |
for text, start, end in st.session_state['english_transcript']:
|
618 |
+
display_text = text.lower() # Case-insensitive comparison
|
619 |
+
if not st.session_state['search_query'] or st.session_state['search_query'] in display_text:
|
620 |
+
english_matches += 1
|
621 |
label = f"[{format_time(start)} - {format_time(end)}] {text}" if st.session_state['show_timeframe'] else text
|
622 |
if st.button(label, key=f"english_{start}"):
|
623 |
st.session_state['current_time'] = start
|
624 |
st.rerun()
|
625 |
+
if english_matches == 0 and st.session_state['search_query']:
|
626 |
+
st.info("No matches found in English transcript for the search query.")
|
627 |
+
|
628 |
+
# Summary Generation
|
629 |
if (st.session_state['language_code'] == 'en' or st.session_state['translate_to_english']) and not st.session_state['summary_generated']:
|
630 |
if st.button("Generate Summary"):
|
631 |
with st.spinner("Generating summary..."):
|
|
|
640 |
if st.session_state['english_summary'] and st.session_state['summary_generated']:
|
641 |
st.markdown("### Summary")
|
642 |
st.write(st.session_state['english_summary'])
|
643 |
+
|
644 |
+
# Download Subtitles
|
645 |
st.markdown("### Download Subtitles")
|
646 |
include_timeframe = st.checkbox("Include timeframe in subtitles", value=True)
|
647 |
transcript_to_download = st.session_state['primary_transcript'] or st.session_state['english_transcript']
|
648 |
if transcript_to_download:
|
649 |
srt_content = generate_srt(transcript_to_download, include_timeframe)
|
650 |
st.download_button(label="Download Subtitles (SRT)", data=srt_content, file_name="subtitles.srt", mime="text/plain")
|
651 |
+
|
652 |
+
# Edit Subtitles
|
653 |
st.markdown("### Edit Subtitles")
|
654 |
transcript_to_edit = st.session_state['primary_transcript'] or st.session_state['english_transcript']
|
655 |
if transcript_to_edit and st.button("Delete Subtitles"):
|
|
|
685 |
|
686 |
if st.session_state['app_state'] == 'results' and st.session_state['edited_video_path']:
|
687 |
st.markdown("### Edited Video")
|
688 |
+
st.markdown('<div style="display: flex; justify-content: center;">', unsafe_allow_html=True)
|
689 |
st.video(st.session_state['edited_video_path'])
|
690 |
+
st.markdown('</div>', unsafe_allow_html=True)
|
691 |
with open(st.session_state['edited_video_path'], "rb") as file:
|
692 |
st.download_button(label="Download Edited Video", data=file, file_name="edited_video.mp4", mime="video/mp4")
|
693 |
|
|
|
712 |
""", unsafe_allow_html=True)
|
713 |
|
714 |
st.markdown("""
|
715 |
+
<div id="about" class="about-section" style="padding: 3rem 2rem; background: #f8f9fa; border-radius: 1rem; margin: 2rem 0;">
|
716 |
+
<h2 style="text-align: center; color: black; margin-bottom: 2rem;">About VidEp</h2>
|
717 |
+
<div style="display: flex; align-items: center; gap: 2rem; flex-wrap: wrap;">
|
718 |
+
<div style="flex: 1; min-width: 300px;">
|
719 |
+
<img src="https://i.postimg.cc/g0z3WVgT/about.jpg" style="width: 100%; height: auto; border-radius: 1rem;" alt="About VidEp">
|
720 |
+
</div>
|
721 |
+
<div style="flex: 2; min-width: 300px;">
|
722 |
+
<h3 style="color:grey;">Our Mission</h3>
|
723 |
+
<p>VidEp aims to revolutionize how creators and professionals work with video content by providing state-of-the-art AI-powered tools for transcription, translation, and summarization.</p>
|
724 |
+
<h3 style="color:grey;">What We Do</h3>
|
725 |
+
<p>Our platform combines the latest advancements in speech recognition and natural language processing to automatically transcribe videos in multiple languages, generate accurate translations, and create concise summaries of content.</p>
|
726 |
+
<h3 style="color:grey;">Why Choose Us</h3>
|
727 |
+
<ul>
|
728 |
+
<li>Advanced AI models for superior accuracy</li>
|
729 |
+
<li>Multi-language support including English and Urdu</li>
|
730 |
+
<li>Easy-to-use interface for editing and managing subtitles</li>
|
731 |
+
<li>Smart search functionality to quickly find content</li>
|
732 |
+
<li>Seamless video editing based on transcripts</li>
|
733 |
+
</ul>
|
|
|
734 |
</div>
|
735 |
</div>
|
736 |
+
</div>
|
737 |
+
""", unsafe_allow_html=True)
|
738 |
|
739 |
st.markdown("""
|
740 |
<div id="contact" class="contact-section" style="padding: 3rem 2rem; background: #f1f4f8; border-radius: 1rem; margin: 2rem 0;">
|
|
|
742 |
<div style="max-width: 600px; margin: 0 auto;">
|
743 |
<div style="margin-bottom: 1rem;">
|
744 |
<label for="email" style="display: block; margin-bottom: 0.5rem; font-weight: 500;">Email</label>
|
745 |
+
<input type="email" id="email" placeholder="Your email address" style="width: 100%; padding: 0.75rem; border-radius: 0.5rem; border: 1px solid #e0e0e0;">
|
746 |
</div>
|
747 |
<div style="margin-bottom: 1rem;">
|
748 |
<label for="message" style="display: block; margin-bottom: 0.5rem; font-weight: 500;">Message</label>
|
749 |
+
<textarea id="message" rows="5" placeholder="Your message" style="width: 100%; padding: 0.75rem; border-radius: 0.5rem; border: 1px solid #e0e0e0;"></textarea>
|
750 |
</div>
|
751 |
<button onclick="alert('Message sent successfully!')" style="background: linear-gradient(135deg, #ff6f61, #ff8a65); color: white; font-weight: 600; padding: 0.75rem 1.5rem; border-radius: 0.5rem; border: none; cursor: pointer; width: 100%;">Send Message</button>
|
752 |
</div>
|
|
|
755 |
|
756 |
st.markdown("""
|
757 |
<div class="plans">
|
758 |
+
<h2 style="text-align: center; margin-bottom: 2rem; color: black;">Choose Your Plan</h2>
|
759 |
<div class="plan-box">
|
760 |
+
<div class="plan free" style="background: linear-gradient(135deg, #299f45, #185726); padding-bottom: 0px">
|
|
|
|
|
761 |
<h3 style="color: white;">Free</h3>
|
762 |
<p><strong>$0</strong> / month</p>
|
763 |
<p>Basic video transcription</p>
|
|
|
765 |
<p>Max 5 minutes video</p>
|
766 |
<p>No summarization</p>
|
767 |
</div>
|
768 |
+
<div class="plan premium" style="background-color:#a32b2d">
|
769 |
<h3 style="color: white;">Premium</h3>
|
770 |
<p><strong>$19</strong> / month</p>
|
771 |
<p>Advanced transcription</p>
|
|
|
773 |
<p>Max 30 minutes video</p>
|
774 |
<p>AI summarization</p>
|
775 |
</div>
|
776 |
+
<div class="plan business" style="background-color:#396ca3">
|
777 |
<h3 style="color: white;">Business</h3>
|
778 |
<p><strong>$49</strong> / month</p>
|
779 |
<p>Enterprise-grade transcription</p>
|
|
|
834 |
});
|
835 |
</script>
|
836 |
""", unsafe_allow_html=True)
|
837 |
+
|
838 |
if __name__ == "__main__":
|
839 |
main()
|