Streamlit UI, Porting CLI - WIP
This commit is contained in:
77
lib/ai_writers/facebook_ai_writer.py
Normal file
77
lib/ai_writers/facebook_ai_writer.py
Normal file
@@ -0,0 +1,77 @@
|
||||
import time #Iwish
|
||||
import os
|
||||
import json
|
||||
import requests
|
||||
import streamlit as st
|
||||
|
||||
|
||||
def generate_facebook_post(business_type, target_audience, post_goal, post_tone, include, avoid):
|
||||
"""
|
||||
Generates a Facebook post prompt for an LLM based on user input.
|
||||
|
||||
Args:
|
||||
business_type: The type of business, e.g., fashion retailer, fitness coach.
|
||||
target_audience: A description of the target audience.
|
||||
post_goal: The goal of the Facebook post.
|
||||
post_tone: The desired tone of the post.
|
||||
include: Elements to include in the post (e.g., images, videos, links).
|
||||
avoid: Elements to avoid in the post (e.g., long paragraphs, technical jargon).
|
||||
|
||||
Returns:
|
||||
A string containing the LLM prompt.
|
||||
"""
|
||||
prompt = f"""I am a {business_type}.
|
||||
|
||||
Please help me write a detailed Facebook post that will engage my target audience, {target_audience}.
|
||||
|
||||
Here are some additional details to consider:
|
||||
|
||||
* **Post Goal:** {post_goal}
|
||||
* **Post Tone:** {post_tone}
|
||||
* **Include:** {include}
|
||||
* **Avoid:** {avoid}
|
||||
|
||||
**Example Post Structure:**
|
||||
|
||||
1. **Attention-Grabbing Opening:** Start with a question or a bold statement to capture attention.
|
||||
2. **Engaging Content:** Briefly describe the main message or offer, highlighting key benefits or features.
|
||||
3. **Call-to-Action (CTA):** Encourage the audience to take a specific action (e.g., visit a link, comment, share).
|
||||
4. **Multimedia:** Mention the types of multimedia elements to include (e.g., images, videos).
|
||||
5. **Hashtags:** Include relevant hashtags to increase post visibility.
|
||||
|
||||
"""
|
||||
try:
|
||||
response = generate_text_with_exception_handling(prompt)
|
||||
return response
|
||||
except Exception as err:
|
||||
st.error(f"An error occurred while generating the prompt: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def facebook_post_writer():
|
||||
st.title("Alwrity - Facebook Post Generator")
|
||||
st.markdown("This app will help you create a Facebook post prompt for an LLM.")
|
||||
|
||||
try:
|
||||
# Collect user inputs with default values
|
||||
business_type = st.text_input("**What is your business type?**", placeholder="fitness coach")
|
||||
target_audience = st.text_input("**Describe your target audience:**", placeholder="fitness enthusiasts")
|
||||
post_goal = st.selectbox("**What is the goal of your post?**", ["Promote a new product", "Share valuable content", "Increase engagement", "Other"], index=2)
|
||||
post_tone = st.selectbox("**What tone do you want to use?**", ["Informative", "Humorous", "Inspirational", "Upbeat", "Casual"], index=3)
|
||||
include = st.text_input("**What elements do you want to include?** (e.g., images, videos, links, hashtags, questions)", placeholder="short video with a sneak peek of the challenge")
|
||||
avoid = st.text_input("**What elements do you want to avoid?** (e.g., long paragraphs, technical jargon)", placeholder="long paragraphs")
|
||||
|
||||
if st.button("Write FaceBook Post"):
|
||||
if not business_type or not target_audience:
|
||||
st.error("🚫 Provide required inputs. Least, you can do..")
|
||||
|
||||
generated_post = generate_facebook_post(business_type, target_audience, post_goal, post_tone, include, avoid)
|
||||
if generated_post:
|
||||
st.subheader(f'**🧕 Verify: Alwrity can make mistakes.**')
|
||||
st.write("## Generated Facebook Post:")
|
||||
st.write(generated_post)
|
||||
st.write("\n\n\n\n\n")
|
||||
else:
|
||||
st.error("Error: Failed to generate Facebook Post.")
|
||||
except Exception as e:
|
||||
st.error(f"An error occurred: {e}")
|
||||
73
lib/ai_writers/insta_ai_writer.py
Normal file
73
lib/ai_writers/insta_ai_writer.py
Normal file
@@ -0,0 +1,73 @@
|
||||
import time #Iwish
|
||||
import os
|
||||
import json
|
||||
import requests
|
||||
import streamlit as st
|
||||
|
||||
|
||||
def insta_writer():
|
||||
# Title and description
|
||||
st.title("✍️ Instagram Caption Writer")
|
||||
|
||||
# Input section
|
||||
with st.expander("**PRO-TIP** - Read the instructions below.", expanded=True):
|
||||
input_insta_keywords = st.text_input('**Enter main keywords of Your instagram caption!**')
|
||||
col1, col2, space, col3, col4 = st.columns([5, 5, 0.5, 5, 5])
|
||||
with col1:
|
||||
input_insta_type = st.selectbox('Voice Tone', ('Neutral', 'Formal', 'Casual', 'Funny',
|
||||
'Optimistic', 'Assertive', 'Friendly', 'Encouraging', 'Sarcastic'), index=0)
|
||||
with col2:
|
||||
input_insta_cta = st.selectbox('CTA (Call To Action)', ('Shop Now',
|
||||
'Learn More', 'Swipe Up', 'Sign Up', 'Link in Bio', 'Sense of urgency'), index=0)
|
||||
with col3:
|
||||
input_insta_audience = st.selectbox('Choose Target Audience', ('For All',
|
||||
'Age:18-24 (Gen Z)', 'Age:25-34 (Millennials)'), index=0)
|
||||
with col4:
|
||||
input_insta_language = st.selectbox('Choose Language', ('English', 'Hindustani',
|
||||
'Chinese', 'Hindi', 'Spanish'), index=0)
|
||||
|
||||
|
||||
# Generate Blog Title button
|
||||
if st.button('**Get Instagram Captions**'):
|
||||
with st.spinner():
|
||||
# Clicking without providing data, really ?
|
||||
if not input_insta_keywords:
|
||||
st.error('** 🫣 P🫣 Provide Inputs to generate Blog Tescription. Keywords, are required!**')
|
||||
elif input_insta_keywords:
|
||||
insta_captions = generate_insta_captions(input_insta_keywords,
|
||||
input_insta_type,
|
||||
input_insta_cta,
|
||||
input_insta_audience,
|
||||
input_insta_language
|
||||
)
|
||||
if insta_captions:
|
||||
st.subheader('**👩👩🔬Go Viral, with these Instagram captions!🎆🎇 🎇**')
|
||||
st.code(insta_captions)
|
||||
else:
|
||||
st.error("💥**Failed to generate instagram Captions. Please try again!**")
|
||||
|
||||
|
||||
# Function to generate blog metadesc
|
||||
def generate_insta_captions(input_insta_keywords, input_insta_type, input_insta_cta, input_insta_audience, input_insta_language):
|
||||
""" Function to call upon LLM to get the work done. """
|
||||
|
||||
# If keywords and content both are given.
|
||||
if input_insta_keywords:
|
||||
prompt = f"""As an instagram expert and experienced content writer,
|
||||
I will provide you with my 'instagram caption keywords', along with CTA, Target Audience & voice tone.
|
||||
Your task is to write 3 instagram captions.
|
||||
|
||||
Follow below guidelines to generate instagram captions:
|
||||
1). Front-Loading: Capture attention by placing key info at the beginning of your captions.
|
||||
2). Optimise your captions for {input_insta_cta} Call-to-Action (CTA).
|
||||
3). Hashtag Usage: Limit yourself to four relevant hashtags per caption.
|
||||
4). Brand Voice and Tone: Use and convey {input_insta_type} voice tone in your captions.
|
||||
5). Optimise your captions for {input_insta_audience} target audience.
|
||||
6). Emojis: Inject personality and emotion into your captions with emojis.
|
||||
7). Brevity: Keep your captions concise and to the point.
|
||||
8). Important: Your response should be in {input_insta_language} language.
|
||||
|
||||
\nInstagram caption keywords: '{input_insta_keywords}'\n
|
||||
"""
|
||||
insta_captions = generate_text_with_exception_handling(prompt)
|
||||
return insta_captions
|
||||
102
lib/ai_writers/keywords_to_blog_streamlit.py
Normal file
102
lib/ai_writers/keywords_to_blog_streamlit.py
Normal file
@@ -0,0 +1,102 @@
|
||||
import sys
|
||||
import os
|
||||
from textwrap import dedent
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
import streamlit as st
|
||||
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv(Path('../../.env'))
|
||||
from loguru import logger
|
||||
logger.remove()
|
||||
logger.add(sys.stdout,
|
||||
colorize=True,
|
||||
format="<level>{level}</level>|<green>{file}:{line}:{function}</green>| {message}"
|
||||
)
|
||||
|
||||
from ..ai_web_researcher.gpt_online_researcher import do_google_serp_search,\
|
||||
do_tavily_ai_search, do_metaphor_ai_research, do_google_pytrends_analysis
|
||||
from .blog_from_google_serp import write_blog_google_serp, blog_with_research
|
||||
from ..ai_web_researcher.you_web_reseacher import get_rag_results, search_ydc_index
|
||||
from ..blog_metadata.get_blog_metadata import blog_metadata
|
||||
from ..blog_postprocessing.save_blog_to_file import save_blog_to_file
|
||||
|
||||
|
||||
def write_blog_from_keywords(search_keywords, url=None):
|
||||
"""
|
||||
This function will take a blog Topic to first generate sections for it
|
||||
and then generate content for each section.
|
||||
"""
|
||||
# Use to store the blog in a string, to save in a *.md file.
|
||||
blog_markdown_str = None
|
||||
tavily_search_result = None
|
||||
example_blog_titles = []
|
||||
|
||||
logger.info(f"Researching and Writing Blog on keywords: {search_keywords}")
|
||||
with st.status("Started Writing..", expanded=True) as status:
|
||||
st.empty()
|
||||
status.update(label="Researching and Writing Blog on keywords.")
|
||||
# Call on the got-researcher, tavily apis for this. Do google search for organic competition.
|
||||
try:
|
||||
google_search_result, g_titles = do_google_serp_search(search_keywords)
|
||||
status.update(label=f"🙎 Finished with Google web for Search: {search_keywords}")
|
||||
example_blog_titles.append(g_titles)
|
||||
|
||||
status.update(label=f"🛀 Starting Tavily AI research: {search_keywords}")
|
||||
tavily_search_result, t_titles, t_answer = do_tavily_ai_search(search_keywords)
|
||||
status.update(label=f"🙆 Finished Google Search & Tavily AI Search on: {search_keywords}", expanded=False)
|
||||
|
||||
except Exception as err:
|
||||
logger.error(f"Failed in web research: {err}")
|
||||
|
||||
with st.status("Started Writing blog from google search..", expanded=True) as status:
|
||||
status.update(label="Researching and Writing Blog on keywords.")
|
||||
# Call on the got-researcher, tavily apis for this. Do google search for organic competition.
|
||||
try:
|
||||
status.update(label=f"🛀 Writing blog from Google Search on: {search_keywords}")
|
||||
blog_markdown_str = write_blog_google_serp(search_keywords, google_search_result)
|
||||
st.markdown(blog_markdown_str)
|
||||
|
||||
# Hate the robotic introductions.
|
||||
#blog_markdown_str = improve_blog_intro(blog_markdown_str, t_answer)
|
||||
#st.markdown(blog_markdown_str)
|
||||
status.update(label="🙎 Draft 1: Your Content from Google search result.", expanded=False)
|
||||
except Exception as err:
|
||||
logger.error(f"Failed in Google web research: {err}")
|
||||
|
||||
# logger.info/check the final blog content.
|
||||
logger.info("######### Draft1: Finished Blog from Google web search: ###########")
|
||||
|
||||
with st.status("Started Writing blog from Tavily Web search..", expanded=True) as status:
|
||||
# Do Tavily AI research to augument the above blog.
|
||||
try:
|
||||
#example_blog_titles.append(t_titles)
|
||||
if blog_markdown_str and tavily_search_result:
|
||||
logger.info(f"\n\n######### Blog content after Tavily AI research: ######### \n\n")
|
||||
blog_markdown_str = write_blog_google_serp(search_keywords, tavily_search_result)
|
||||
status.update(label="Finished Writing Blog From Tavily Results:{blog_markdown_str}")
|
||||
else:
|
||||
print("Not Writing with TAVILY..\n\n")
|
||||
except Exception as err:
|
||||
logger.error(f"Failed to do Tavily AI research: {err}")
|
||||
|
||||
status.update(label="🙎 Generating - Title, Meta Description, Tags, Categories for the content.")
|
||||
blog_title, blog_meta_desc, blog_tags, blog_categories = blog_metadata(blog_markdown_str,
|
||||
search_keywords, example_blog_titles)
|
||||
|
||||
generated_image_filepath = None
|
||||
|
||||
saved_blog_to_file = save_blog_to_file(blog_markdown_str, blog_title, blog_meta_desc,
|
||||
blog_tags, blog_categories, generated_image_filepath)
|
||||
status.update(label=f"Saved the content in this file: {saved_blog_to_file}")
|
||||
blog_frontmatter = dedent(f"""
|
||||
\n---------------------------------------------------------------------
|
||||
title: {blog_title.strip()}\n
|
||||
categories: [{blog_categories.strip()}]\n
|
||||
tags: [{blog_tags.strip()}]\n
|
||||
Meta description: {blog_meta_desc.replace(":", "-").strip()}\n
|
||||
---------------------------------------------------------------------\n
|
||||
""")
|
||||
logger.info(f"\n\n --------- Finished writing Blog for : {search_keywords} -------------- \n")
|
||||
st.markdown(f"{blog_frontmatter}\n\n{blog_markdown_str}")
|
||||
status.update(label=f"Finished, Review & Use your Original Content Below: {saved_blog_to_file}")
|
||||
67
lib/ai_writers/linkedin_ai_writer.py
Normal file
67
lib/ai_writers/linkedin_ai_writer.py
Normal file
@@ -0,0 +1,67 @@
|
||||
import time #Iwish
|
||||
import os
|
||||
import json
|
||||
import requests
|
||||
import streamlit as st
|
||||
|
||||
|
||||
def linked_post_writer():
|
||||
# Title and description
|
||||
st.title("✍️ Alwrity - AI Linkedin Blog Post Generator")
|
||||
|
||||
# Input section
|
||||
with st.expander("**PRO-TIP** - Read the instructions below.", expanded=True):
|
||||
input_blog_keywords = st.text_input('**Enter main keywords of your Post!** (2-3 words that defines your blog)')
|
||||
col1, col2, space, col3 = st.columns([5, 5, 0.5, 5])
|
||||
with col1:
|
||||
input_linkedin_type = st.selectbox('Post Type', ('General', 'How-to Guides', 'Polls', 'Listicles',
|
||||
'Reality check posts', 'Job Posts', 'FAQs', 'Checklists/Cheat Sheets'), index=0)
|
||||
with col2:
|
||||
input_linkedin_length = st.selectbox('Post Length', ('1000 words', 'Long Form', 'Short form'), index=0)
|
||||
with col3:
|
||||
input_linkedin_language = st.selectbox('Choose Language', ('English', 'Vietnamese',
|
||||
'Chinese', 'Hindi', 'Spanish'), index=0)
|
||||
# Generate Blog FAQ button
|
||||
if st.button('**Get LinkedIn Post**'):
|
||||
with st.spinner():
|
||||
# Clicking without providing data, really ?
|
||||
if not input_blog_keywords:
|
||||
st.error('** 🫣Provide Inputs to generate Blinkedin Post. Keywords, required!**')
|
||||
elif input_blog_keywords:
|
||||
linkedin_post = generate_linkedin_post(input_blog_keywords, input_linkedin_type,
|
||||
input_linkedin_length, input_linkedin_language)
|
||||
if linkedin_post:
|
||||
st.subheader('**🧕🔬👩 Go Rule LinkedIn with this Blog Post!**')
|
||||
st.write(linkedin_post)
|
||||
st.write("\n\n\n")
|
||||
else:
|
||||
st.error("💥**Failed to generate linkedin Post. Please try again!**")
|
||||
|
||||
|
||||
# Function to generate blog metadesc
|
||||
def generate_linkedin_post(input_blog_keywords, input_linkedin_type, input_linkedin_length, input_linkedin_language):
|
||||
""" Function to call upon LLM to get the work done. """
|
||||
|
||||
# Fetch SERP results & PAA questions for FAQ.
|
||||
serp_results, people_also_ask = get_serp_results(input_blog_keywords)
|
||||
|
||||
# If keywords and content both are given.
|
||||
if serp_results:
|
||||
prompt = f"""As a SEO expert and experienced linkedin content writer,
|
||||
I will provide you with my 'blog keywords' and 'google serp results'.
|
||||
Your task is to write a detailed linkedin post, using given keywords and search results.
|
||||
|
||||
Follow below guidelines for generating the linkedin post:
|
||||
1). Write a title, introduction, sections, faqs and a conclusion for the post.
|
||||
2). Your FAQ should be based on 'People also ask' and 'Related Queries' from given serp results.
|
||||
3). Maintain consistent voice of tone, keep the sentence short and simple.
|
||||
4). Make sure to include important results from the given google serp results.
|
||||
5). Optimise your response for blog type of {input_linkedin_type}.
|
||||
6). Important to provide your response in {input_linkedin_language} language.\n
|
||||
|
||||
blog keywords: '{input_blog_keywords}'\n
|
||||
google serp results: '{serp_results}'
|
||||
people_also_ask: '{people_also_ask}'
|
||||
"""
|
||||
linkedin_post = generate_text_with_exception_handling(prompt)
|
||||
return linkedin_post
|
||||
@@ -13,6 +13,7 @@ import yaml
|
||||
from pathlib import Path
|
||||
from dotenv import load_dotenv
|
||||
from configparser import ConfigParser
|
||||
import streamlit as st
|
||||
|
||||
from google.api_core import retry
|
||||
import google.generativeai as genai
|
||||
@@ -57,190 +58,195 @@ def long_form_generator(content_keywords):
|
||||
Write long form content using prompt chaining and iterative generation.
|
||||
Parameters:
|
||||
"""
|
||||
# Read the main_config to define tone, character, personality of the content to be generated.
|
||||
try:
|
||||
logger.info(f"Starting to write content on {content_keywords}.")
|
||||
# Define persona and writing guidelines
|
||||
content_tone, target_audience, content_type, content_language, output_format = read_return_config_section('blog_characteristics')
|
||||
except Exception as err:
|
||||
logger.error(f"Failed to Read config params from main_config: {err}")
|
||||
return
|
||||
|
||||
try:
|
||||
filepath = os.path.join(os.environ["PROMPTS_DIR"], "long_form_ai_writer.prompts")
|
||||
# Check if file exists
|
||||
if not os.path.exists(filepath):
|
||||
raise FileNotFoundError(f"File {filepath} does not exist")
|
||||
with open(filepath, 'r') as file:
|
||||
prompts = yaml.safe_load(file)
|
||||
except Exception as err:
|
||||
logger.error(f"Exit: Failed to read prompts from {filepath}: {err}")
|
||||
exit(1)
|
||||
|
||||
writing_guidelines = prompts.get('writing_guidelines').format(
|
||||
content_language=content_language,
|
||||
content_tone=content_tone,
|
||||
content_type=content_type,
|
||||
output_format=output_format,
|
||||
content_keywords=content_keywords,
|
||||
target_audience=target_audience
|
||||
)
|
||||
|
||||
content_title = prompts.get('content_title').format(
|
||||
content_language=content_language,
|
||||
content_keywords=content_keywords,
|
||||
target_audience=target_audience
|
||||
)
|
||||
with st.status("Start Writing Long Form Article, Hold my Beer..", expanded=True) as status:
|
||||
# Read the main_config to define tone, character, personality of the content to be generated.
|
||||
try:
|
||||
logger.info(f"Starting to write content on {content_keywords}.")
|
||||
# Define persona and writing guidelines
|
||||
content_tone, target_audience, content_type, content_language, output_format = read_return_config_section('blog_characteristics')
|
||||
except Exception as err:
|
||||
logger.error(f"Failed to Read config params from main_config: {err}")
|
||||
return
|
||||
|
||||
content_outline = prompts.get('content_outline').format(
|
||||
content_language=content_language,
|
||||
content_title='{content_title}',
|
||||
content_type=content_type,
|
||||
target_audience=target_audience
|
||||
)
|
||||
|
||||
starting_prompt = prompts.get('starting_prompt').format(
|
||||
content_language=content_language,
|
||||
content_title='{content_title}',
|
||||
content_outline='{content_outline}',
|
||||
writing_guidelines=writing_guidelines
|
||||
)
|
||||
|
||||
continuation_prompt = prompts.get('continuation_prompt').format(
|
||||
content_language=content_language,
|
||||
content_title='{content_title}',
|
||||
content_outline='{content_outline}',
|
||||
content_text='{content_text}',
|
||||
web_research_result='{web_research_result}',
|
||||
writing_guidelines=writing_guidelines
|
||||
)
|
||||
|
||||
# Configure generative AI
|
||||
load_dotenv(Path('../.env'))
|
||||
generation_config = {
|
||||
"temperature": 0.8,
|
||||
"top_p": 0.95,
|
||||
"max_output_tokens": 8192,
|
||||
}
|
||||
|
||||
genai.configure(api_key=os.getenv('GEMINI_API_KEY'))
|
||||
# Initialize the generative model
|
||||
model = genai.GenerativeModel('gemini-pro', generation_config=generation_config)
|
||||
model_pro = genai.GenerativeModel('gemini-1.5-flash-latest', generation_config=generation_config)
|
||||
|
||||
# Do SERP web research for given keywords to generate title and outline.
|
||||
web_research_result, g_titles = do_google_serp_search(content_keywords)
|
||||
|
||||
# Generate prompts
|
||||
try:
|
||||
content_title = generate_with_retry(model_pro, content_title.format(web_research_result=web_research_result)).text
|
||||
logger.info(f"The title of the content is: {content_title}")
|
||||
except Exception as err:
|
||||
logger.error(f"Content title Generation Error: {err}")
|
||||
return
|
||||
|
||||
try:
|
||||
content_outline = generate_with_retry(model_pro, content_outline.format(
|
||||
content_title=content_title,
|
||||
web_research_result=web_research_result)).text
|
||||
logger.info(f"The content Outline is: {content_outline}\n\n")
|
||||
except Exception as err:
|
||||
logger.error(f"Failed to generate content outline: {err}")
|
||||
|
||||
try:
|
||||
logger.info("Do web research with Tavily to provide context for content creation.")
|
||||
# Do Metaphor/Exa AI search.
|
||||
table_data = []
|
||||
web_research_result, m_titles, t_titles = do_tavily_ai_search(content_keywords, max_results=5)
|
||||
for item in web_research_result.get("results"):
|
||||
title = item.get("title", "")
|
||||
snippet = item.get("content", "")
|
||||
table_data.append([title, snippet])
|
||||
web_research_result = table_data
|
||||
except Exception as err:
|
||||
logger.error(f"Failed to do Tavily AI search: {err}")
|
||||
return
|
||||
|
||||
try:
|
||||
starting_draft = generate_with_retry(model_pro, starting_prompt.format(
|
||||
content_title=content_title,
|
||||
content_outline=content_outline,
|
||||
web_research_result=web_research_result,
|
||||
writing_guidelines=writing_guidelines)).text
|
||||
except Exception as err:
|
||||
logger.error(f"Failed to Generate Starting draft: {err}")
|
||||
return
|
||||
|
||||
try:
|
||||
logger.info(f"Starting to write on the outline introduction.")
|
||||
draft = starting_draft
|
||||
continuation = generate_with_retry(model, continuation_prompt.format(
|
||||
content_title=content_title,
|
||||
content_outline=content_outline,
|
||||
content_text=draft,
|
||||
web_research_result=web_research_result,
|
||||
writing_guidelines=writing_guidelines)).text
|
||||
except Exception as err:
|
||||
logger.error(f"Failed to write the initial draft: {err}")
|
||||
|
||||
# Add the continuation to the initial draft, keep building the story until we see 'IAMDONE'
|
||||
try:
|
||||
draft += '\n\n' + continuation
|
||||
except Exception as err:
|
||||
logger.error(f"Failed as: {err} and {continuation}")
|
||||
|
||||
logger.info(f"Writing in progress... Current draft length: {len(draft)} characters")
|
||||
search_terms = f"""
|
||||
I will provide you with blog outline, your task is to read the outline & return 3 google search keywords.
|
||||
Your response will be used to do web research for writing on the given outline.
|
||||
Do not explain your response, provide 3 google search sentences encompassing the given content outline.
|
||||
|
||||
Content Outline:\n\n
|
||||
{content_outline}
|
||||
"""
|
||||
search_words = generate_with_retry(model_pro, search_terms).text
|
||||
|
||||
while 'IAMDONE' not in continuation:
|
||||
try:
|
||||
#web_research_result, m_titles = do_metaphor_ai_research(content_keywords)
|
||||
str_list = re.split(r',\s*', search_words)
|
||||
# Strip quotes from each element
|
||||
str_list = [s.strip('\'"') for s in str_list]
|
||||
for search_term in str_list:
|
||||
web_research_result, m_titles, t_titles = do_tavily_ai_search(search_term, max_results=5)
|
||||
|
||||
filepath = os.path.join(os.environ["PROMPTS_DIR"], "long_form_ai_writer.prompts")
|
||||
# Check if file exists
|
||||
if not os.path.exists(filepath):
|
||||
raise FileNotFoundError(f"File {filepath} does not exist")
|
||||
with open(filepath, 'r') as file:
|
||||
prompts = yaml.safe_load(file)
|
||||
except Exception as err:
|
||||
logger.error(f"Exit: Failed to read prompts from {filepath}: {err}")
|
||||
exit(1)
|
||||
|
||||
writing_guidelines = prompts.get('writing_guidelines').format(
|
||||
content_language=content_language,
|
||||
content_tone=content_tone,
|
||||
content_type=content_type,
|
||||
output_format=output_format,
|
||||
content_keywords=content_keywords,
|
||||
target_audience=target_audience
|
||||
)
|
||||
|
||||
content_title = prompts.get('content_title').format(
|
||||
content_language=content_language,
|
||||
content_keywords=content_keywords,
|
||||
target_audience=target_audience
|
||||
)
|
||||
|
||||
content_outline = prompts.get('content_outline').format(
|
||||
content_language=content_language,
|
||||
content_title='{content_title}',
|
||||
content_type=content_type,
|
||||
target_audience=target_audience
|
||||
)
|
||||
|
||||
starting_prompt = prompts.get('starting_prompt').format(
|
||||
content_language=content_language,
|
||||
content_title='{content_title}',
|
||||
content_outline='{content_outline}',
|
||||
writing_guidelines=writing_guidelines
|
||||
)
|
||||
|
||||
continuation_prompt = prompts.get('continuation_prompt').format(
|
||||
content_language=content_language,
|
||||
content_title='{content_title}',
|
||||
content_outline='{content_outline}',
|
||||
content_text='{content_text}',
|
||||
web_research_result='{web_research_result}',
|
||||
writing_guidelines=writing_guidelines
|
||||
)
|
||||
|
||||
# Configure generative AI
|
||||
load_dotenv(Path('../.env'))
|
||||
generation_config = {
|
||||
"temperature": 0.6,
|
||||
"top_p": 1,
|
||||
"max_output_tokens": 4096,
|
||||
}
|
||||
|
||||
genai.configure(api_key=os.getenv('GEMINI_API_KEY'))
|
||||
# Initialize the generative model
|
||||
model = genai.GenerativeModel('gemini-pro', generation_config=generation_config)
|
||||
model_pro = genai.GenerativeModel('gemini-1.5-flash-latest', generation_config=generation_config)
|
||||
|
||||
# Do SERP web research for given keywords to generate title and outline.
|
||||
web_research_result, g_titles = do_google_serp_search(content_keywords)
|
||||
|
||||
# Generate prompts
|
||||
try:
|
||||
content_title = generate_with_retry(model_pro, content_title.format(web_research_result=web_research_result)).text
|
||||
logger.info(f"The title of the content is: {content_title}")
|
||||
status.update(label=f"The title of the content is: {content_title}")
|
||||
except Exception as err:
|
||||
logger.error(f"Content title Generation Error: {err}")
|
||||
return
|
||||
|
||||
try:
|
||||
content_outline = generate_with_retry(model_pro, content_outline.format(
|
||||
content_title=content_title,
|
||||
web_research_result=web_research_result)).text
|
||||
logger.info(f"The content Outline is: {content_outline}\n\n")
|
||||
status.update(label="Generated the content outline.")
|
||||
except Exception as err:
|
||||
logger.error(f"Failed to generate content outline: {err}")
|
||||
|
||||
try:
|
||||
logger.info("Do web research with Tavily to provide context for content creation.")
|
||||
# Do Metaphor/Exa AI search.
|
||||
table_data = []
|
||||
web_research_result, m_titles, t_titles = do_tavily_ai_search(content_keywords, max_results=5)
|
||||
for item in web_research_result.get("results"):
|
||||
title = item.get("title", "")
|
||||
snippet = item.get("content", "")
|
||||
table_data.append([title, snippet])
|
||||
web_research_result = table_data
|
||||
except Exception as err:
|
||||
logger.error(f"Failed to do Tavily AI search: {err}")
|
||||
return
|
||||
|
||||
try:
|
||||
starting_draft = generate_with_retry(model_pro, starting_prompt.format(
|
||||
content_title=content_title,
|
||||
content_outline=content_outline,
|
||||
web_research_result=web_research_result,
|
||||
writing_guidelines=writing_guidelines)).text
|
||||
except Exception as err:
|
||||
logger.error(f"Failed to Generate Starting draft: {err}")
|
||||
return
|
||||
|
||||
try:
|
||||
logger.info(f"Starting to write on the outline introduction.")
|
||||
draft = starting_draft
|
||||
continuation = generate_with_retry(model, continuation_prompt.format(
|
||||
content_title=content_title,
|
||||
content_title=content_title,
|
||||
content_outline=content_outline,
|
||||
content_text=draft,
|
||||
web_research_result=web_research_result,
|
||||
writing_guidelines=writing_guidelines)).text
|
||||
|
||||
draft += '\n\n' + continuation
|
||||
logger.info(f"Writing in progress... Current draft length: {len(draft)} characters")
|
||||
|
||||
# At this point, the context is little stale. We should more web research on
|
||||
# related queries as per the content outline, to augment the LLM context.
|
||||
except Exception as err:
|
||||
logger.error(f"Failed to continually write the Essay: {err}")
|
||||
return
|
||||
logger.error(f"Failed to write the initial draft: {err}")
|
||||
|
||||
# Remove 'IAMDONE' and print the final story
|
||||
final = draft.replace('IAMDONE', '').strip()
|
||||
|
||||
blog_title, blog_meta_desc, blog_tags, blog_categories = blog_metadata(final,
|
||||
content_keywords, m_titles)
|
||||
|
||||
generated_image_filepath = None
|
||||
# TBD: Save the blog content as a .md file. Markdown or HTML ?
|
||||
save_blog_to_file(final, blog_title, blog_meta_desc, blog_tags, blog_categories, generated_image_filepath)
|
||||
|
||||
blog_frontmatter = f"""
|
||||
---
|
||||
title: {blog_title}
|
||||
categories: [{blog_categories}]
|
||||
tags: [{blog_tags}]
|
||||
Meta description: {blog_meta_desc.replace(":", "-")}
|
||||
---"""
|
||||
logger.info(f"\n{blog_frontmatter}{final}\n\n")
|
||||
logger.info(f"\n\n ################ Finished writing Blog for : {content_keywords} #################### \n")
|
||||
# Add the continuation to the initial draft, keep building the story until we see 'IAMDONE'
|
||||
try:
|
||||
draft += '\n\n' + continuation
|
||||
except Exception as err:
|
||||
logger.error(f"Failed as: {err} and {continuation}")
|
||||
|
||||
logger.info(f"Writing in progress... Current draft length: {len(draft)} characters")
|
||||
search_terms = f"""
|
||||
I will provide you with blog outline, your task is to read the outline & return 3 google search keywords.
|
||||
Your response will be used to do web research for writing on the given outline.
|
||||
Do not explain your response, provide 3 google search sentences encompassing the given content outline.
|
||||
Provide the search term results as comma separated values.\n\n
|
||||
Content Outline:\n
|
||||
'{content_outline}'
|
||||
"""
|
||||
search_words = generate_with_retry(model_pro, search_terms).text
|
||||
status.update(label=f"Search terms from written draft: {search_words}")
|
||||
|
||||
while 'IAMDONE' not in continuation:
|
||||
try:
|
||||
#web_research_result, m_titles = do_metaphor_ai_research(content_keywords)
|
||||
str_list = re.split(r',\s*', search_words)
|
||||
# Strip quotes from each element
|
||||
str_list = [s.strip('\'"') for s in str_list]
|
||||
for search_term in str_list:
|
||||
web_research_result, m_titles, t_titles = do_tavily_ai_search(search_term, max_results=5)
|
||||
|
||||
continuation = generate_with_retry(model, continuation_prompt.format(
|
||||
content_title=content_title,
|
||||
content_outline=content_outline,
|
||||
content_text=draft,
|
||||
web_research_result=web_research_result,
|
||||
writing_guidelines=writing_guidelines)).text
|
||||
|
||||
draft += '\n\n' + continuation
|
||||
logger.info(f"Writing in progress... Current draft length: {len(draft)} characters")
|
||||
status.update(label=f"Writing in progress... Current draft length: {len(draft)} characters")
|
||||
# At this point, the context is little stale. We should more web research on
|
||||
# related queries as per the content outline, to augment the LLM context.
|
||||
except Exception as err:
|
||||
logger.error(f"Failed to continually write the Essay: {err}")
|
||||
return
|
||||
|
||||
# Remove 'IAMDONE' and print the final story
|
||||
final = draft.replace('IAMDONE', '').strip()
|
||||
|
||||
blog_title, blog_meta_desc, blog_tags, blog_categories = blog_metadata(final,
|
||||
content_keywords, m_titles)
|
||||
|
||||
generated_image_filepath = None
|
||||
# TBD: Save the blog content as a .md file. Markdown or HTML ?
|
||||
save_blog_to_file(final, blog_title, blog_meta_desc, blog_tags, blog_categories, generated_image_filepath)
|
||||
|
||||
blog_frontmatter = f"""
|
||||
---
|
||||
title: {blog_title}
|
||||
categories: [{blog_categories}]
|
||||
tags: [{blog_tags}]
|
||||
Meta description: {blog_meta_desc.replace(":", "-")}
|
||||
---"""
|
||||
logger.info(f"\n{blog_frontmatter}{final}\n\n")
|
||||
st.write(f"\n{blog_frontmatter}{final}\n\n")
|
||||
logger.info(f"\n\n ################ Finished writing Blog for : {content_keywords} #################### \n")
|
||||
|
||||
74
lib/ai_writers/twitter_ai_writer.py
Normal file
74
lib/ai_writers/twitter_ai_writer.py
Normal file
@@ -0,0 +1,74 @@
|
||||
import time #Iwish
|
||||
import os
|
||||
import json
|
||||
import requests
|
||||
import streamlit as st
|
||||
|
||||
|
||||
def tweet_writer():
|
||||
""" AI Tweet Generator """
|
||||
with st.expander("**PRO-TIP** - Read the instructions below.", expanded=True):
|
||||
col1, col2 = st.columns([5, 5])
|
||||
with col1:
|
||||
hook = st.text_input(
|
||||
label="What's the tweet about:(Hook)",
|
||||
placeholder="e.g., Discover the future of tech today!",
|
||||
help="Provide a compelling opening statement or question to grab attention."
|
||||
)
|
||||
|
||||
with col2:
|
||||
# Collect user inputs with placeholders and help text
|
||||
target_audience = st.text_input(
|
||||
label="Target Audience",
|
||||
placeholder="e.g., technology enthusiasts, travel lovers",
|
||||
help="Describe the audience you want to target with this tweet."
|
||||
)
|
||||
|
||||
if st.button('**Write Tweets**'):
|
||||
with st.status("Assigning AI professional to write your Google Ads copy..", expanded=True) as status:
|
||||
if not target_audience or not hook:
|
||||
st.error("🚫 Please provide all required inputs.")
|
||||
else:
|
||||
response = tweet_generator(target_audience, hook)
|
||||
if response:
|
||||
st.subheader(f'**🧕👩: Your Final Tweets!**')
|
||||
st.write(response)
|
||||
st.write("\n\n\n\n\n\n")
|
||||
else:
|
||||
st.error("💥**Failed to write Letter. Please try again!**")
|
||||
|
||||
|
||||
def tweet_generator(target_audience, hook):
|
||||
""" Email project_update_writer """
|
||||
|
||||
prompt = f"""
|
||||
You are a social media expert creating tweets for an audience interested in {target_audience}.
|
||||
Write 5 engaging, concise, and visually appealing tweets that each:
|
||||
|
||||
1. Start with a compelling hook based on the following keywords: "{hook}"
|
||||
2. Include a compelling call to action.
|
||||
3. Use 2-3 relevant hashtags.
|
||||
4. Adopt a tone that matches the following options:
|
||||
- Humorous
|
||||
- Informative
|
||||
- Inspirational
|
||||
- Serious
|
||||
- Casual
|
||||
5. Be under 100 characters (including spaces and punctuation).
|
||||
|
||||
Here are some examples of call-to-actions to include:
|
||||
- Retweet this if you agree!
|
||||
- Share your thoughts in the comments!
|
||||
- Learn more at [link]
|
||||
- Follow for more [topic] content
|
||||
- Like if you're excited about [topic]
|
||||
|
||||
Output each tweet separated by a newline.
|
||||
"""
|
||||
|
||||
try:
|
||||
response = generate_text_with_exception_handling(prompt)
|
||||
return response
|
||||
except Exception as err:
|
||||
st.error(f"Exit: Failed to get response from LLM: {err}")
|
||||
exit(1)
|
||||
257
lib/ai_writers/youtube_ai_writer.py
Normal file
257
lib/ai_writers/youtube_ai_writer.py
Normal file
@@ -0,0 +1,257 @@
|
||||
import time #Iwish
|
||||
import os
|
||||
import json
|
||||
import streamlit as st
|
||||
|
||||
|
||||
def write_yt_description():
|
||||
st.title("📽️ YT Description Writer")
|
||||
col1, col2 = st.columns([1, 1])
|
||||
with col1:
|
||||
keywords = st.text_input('**Describe Your YT video Keywords (comma-separated)**',
|
||||
help="Enter keywords separated by commas.").split(',')
|
||||
target_audience = st.multiselect('**Select Your Target Audience**',
|
||||
['Beginners', 'Marketers', 'Gamers', 'Foodies', 'Entrepreneurs', 'Students', 'Parents',
|
||||
'Tech Enthusiasts', 'General Audience', 'News Readers', 'Finance Enthusiasts'],
|
||||
help="Select the target audience for your video.")
|
||||
|
||||
with col2:
|
||||
tone_style = st.selectbox('**Select Tone and Style of YT Description**',
|
||||
['Casual', 'Professional', 'Humorous', 'Formal', 'Informal', 'Inspirational'],
|
||||
help="Select the tone and style of your video.")
|
||||
language = st.selectbox('**Select YT description Language**',
|
||||
['English', 'Spanish', 'Chinese', 'Hindi', 'Arabic'],
|
||||
help="Select the language for the video description.")
|
||||
|
||||
if st.button('**Generate YT Description**'):
|
||||
with st.spinner():
|
||||
if not keywords:
|
||||
st.error("🚫 Please provide all required inputs.")
|
||||
else:
|
||||
response = generate_youtube_description(keywords, target_audience, tone_style, language)
|
||||
if response:
|
||||
st.subheader(f'**🧕👩: Your Final youtube Description !**')
|
||||
st.write(response)
|
||||
st.write("\n\n\n\n\n\n")
|
||||
else:
|
||||
st.error("💥**Failed to write YT Description. Please try again!**")
|
||||
|
||||
|
||||
def generate_youtube_description(keywords, target_audience, tone_style, language):
|
||||
""" Generate youtube script generator """
|
||||
|
||||
prompt = f"""
|
||||
Please write a descriptive YouTube description in {language} for a video about {keywords} based on the following information:
|
||||
|
||||
Keywords: {', '.join(keywords)}
|
||||
|
||||
Target Audience: {', '.join(target_audience)}
|
||||
|
||||
Language for description: {', '.join(language)}
|
||||
|
||||
Tone and Style: {tone_style}
|
||||
|
||||
Specific Instructions:
|
||||
|
||||
- Include Primary Keywords Early: Place the most important keywords at the beginning to enhance SEO.
|
||||
- Write a Compelling Hook: Start with an engaging sentence to grab attention and entice viewers to watch the video.
|
||||
- Provide a Brief Overview: Summarize the video's content and what viewers can expect to learn or experience.
|
||||
- Use Relevant Keywords: Integrate additional keywords naturally to improve searchability.
|
||||
- Add Timestamps: Include timestamps for different sections of the video, if applicable.
|
||||
- Include Links: Add links to related videos, playlists, or external resources.
|
||||
- Encourage Engagement: Ask viewers to like, comment, and subscribe, and include a clear call to action.
|
||||
- Provide Contact Information: Include relevant social media handles, website links, or contact information.
|
||||
- Use Clear and Concise Language: Avoid jargon and keep sentences straightforward and easy to understand.
|
||||
- Include Hashtags: Use relevant hashtags to increase discoverability, placing them at the end of the description.
|
||||
- Tailor the Language and Tone: Adjust to suit the target audience.
|
||||
- Engage and Describe: Use descriptive language to make the video sound interesting.
|
||||
- Be Concise but Informative: Provide enough context about the video.
|
||||
- Highlight Unique Details: Mention any important details or highlights that make the video unique.
|
||||
- Ensure Proper Grammar and Spelling: Maintain a high standard of writing.
|
||||
|
||||
Generate a detailed YouTube description that adheres to the above guidelines and includes a compelling hook, a brief overview, relevant keywords, a call to action, hashtags, and any other relevant information. Ensure proper formatting and a clear structure.
|
||||
"""
|
||||
|
||||
try:
|
||||
response = generate_text_with_exception_handling(prompt)
|
||||
return response
|
||||
except Exception as err:
|
||||
st.error(f"Exit: Failed to get response from LLM: {err}")
|
||||
exit(1)
|
||||
|
||||
def write_yt_title():
|
||||
""" Generat YT Titles UI """
|
||||
st.title("🎬 Write YT Video Titles")
|
||||
with st.expander("**PRO-TIP** - Read the instructions below.", expanded=True):
|
||||
col1, col2 = st.columns([5, 5])
|
||||
with col1:
|
||||
main_points = st.text_area('**What is your video about ?**',
|
||||
placeholder='Write few words on your video for title ? (e.g., "New trek, Latest in news, Finance, Tech...")')
|
||||
tone_style = st.selectbox('**Select Tone & Style**', ['Casual', 'Professional', 'Humorous', 'Formal', 'Informal', 'Inspirational'])
|
||||
with col2:
|
||||
target_audience = st.multiselect('**Select Video Target Audience(One Or Multiple)**', [
|
||||
'Beginners',
|
||||
'Marketers',
|
||||
'Gamers',
|
||||
'Foodies',
|
||||
'Entrepreneurs',
|
||||
'Students',
|
||||
'Parents',
|
||||
'Tech Enthusiasts',
|
||||
'General Audience',
|
||||
'News article',
|
||||
'Finance Article'])
|
||||
|
||||
use_case = st.selectbox('**Youtube Title Use Case**', [
|
||||
'Tutorials',
|
||||
'Product Reviews',
|
||||
'Explainer Videos',
|
||||
'Vlogs',
|
||||
'Motivational Speeches',
|
||||
'Comedy Skits',
|
||||
'Educational Content'
|
||||
])
|
||||
if st.button('**Write YT Titles**'):
|
||||
with st.status("Assigning AI professional to write your YT Titles..", expanded=True) as status:
|
||||
if not main_points:
|
||||
st.error("🚫 Please provide all required inputs.")
|
||||
else:
|
||||
response = generate_youtube_title(target_audience, main_points, tone_style, use_case)
|
||||
if response:
|
||||
st.subheader(f'**🧕👩: Your Final youtube Titles !**')
|
||||
st.markdown(response)
|
||||
st.write("\n\n\n")
|
||||
else:
|
||||
st.error("💥**Failed to write Letter. Please try again!**")
|
||||
|
||||
|
||||
def generate_youtube_title(target_audience, main_points, tone_style, use_case):
|
||||
""" Generate youtube script generator """
|
||||
|
||||
prompt = f"""
|
||||
**Instructions:**
|
||||
|
||||
Please generate 5 YouTube title options for a video about **{main_points}** based on the following information:
|
||||
|
||||
|
||||
**Target Audience:** {target_audience}
|
||||
|
||||
**Tone and Style:** {tone_style}
|
||||
|
||||
**Use Case:** {use_case}
|
||||
|
||||
**Specific Instructions:**
|
||||
|
||||
* Make the titles catchy and attention-grabbing.
|
||||
* Use relevant keywords to improve SEO.
|
||||
* Tailor the language and tone to the target audience.
|
||||
* Ensure the title reflects the content and use case of the video.
|
||||
"""
|
||||
|
||||
try:
|
||||
response = generate_text_with_exception_handling(prompt)
|
||||
return response
|
||||
except Exception as err:
|
||||
st.error(f"Exit: Failed to get response from LLM: {err}")
|
||||
exit(1)
|
||||
|
||||
|
||||
def write_yt_script():
|
||||
""" Generate youtube scripts """
|
||||
with st.expander("**PRO-TIP** - Read the instructions below.", expanded=True):
|
||||
col1, col2 = st.columns([5, 5])
|
||||
with col1:
|
||||
main_points = st.text_area('**What is your video about ?**',
|
||||
placeholder='Write few lines on Video idea for transcript ? (e.g., "New trek, Latest in news, Finance, Tech...")')
|
||||
tone_style = st.selectbox('**Select Tone & Style**', ['Casual', 'Professional', 'Humorous', 'Formal', 'Informal', 'Inspirational'])
|
||||
target_audience = st.multiselect('**Select Video Target Audience(One Or Multiple)**', [
|
||||
'Beginners',
|
||||
'Marketers',
|
||||
'Gamers',
|
||||
'Foodies',
|
||||
'Entrepreneurs',
|
||||
'Students',
|
||||
'Parents',
|
||||
'Tech Enthusiasts',
|
||||
'General Audience',
|
||||
'News article',
|
||||
'Finance Article'
|
||||
])
|
||||
with col2:
|
||||
# Selectbox for Video Length
|
||||
video_length = st.selectbox('**Select Video Length**', [
|
||||
'Short (1-3 minutes)',
|
||||
'Medium (3-5 minutes)',
|
||||
'Long (5-10 minutes)',
|
||||
'Very Long (10+ minutes)'
|
||||
])
|
||||
|
||||
# Selectbox for Script Structure
|
||||
script_structure = st.selectbox('**Script Structure**', [
|
||||
'Linear',
|
||||
'Storytelling',
|
||||
'Q&A'
|
||||
])
|
||||
|
||||
use_case = st.selectbox('**Youtube Script Use Case**', [
|
||||
'Tutorials',
|
||||
'Product Reviews',
|
||||
'Explainer Videos',
|
||||
'Vlogs',
|
||||
'Motivational Speeches',
|
||||
'Comedy Skits',
|
||||
'Educational Content'
|
||||
])
|
||||
if st.button('**Write YT Script**'):
|
||||
with st.status("Assigning AI professional to write your YT script..", expanded=True) as status:
|
||||
if not main_points:
|
||||
st.error("🚫 Please provide all required inputs.")
|
||||
else:
|
||||
response = generate_youtube_script(target_audience, main_points, tone_style, video_length, use_case, script_structure)
|
||||
if response:
|
||||
st.subheader(f'**🧕👩: Your Final youtube script!**')
|
||||
st.write(response)
|
||||
st.write("\n\n\n\n\n\n")
|
||||
else:
|
||||
st.error("💥**Failed to write Letter. Please try again!**")
|
||||
|
||||
|
||||
def generate_youtube_script(target_audience, main_points, tone_style, video_length, use_case, script_structure):
|
||||
""" Generate youtube script generator """
|
||||
prompt = f"""
|
||||
Please write a YouTube script for a video about {main_points} based on the following information:
|
||||
|
||||
Target Audience: {', '.join(target_audience)}
|
||||
|
||||
Main Points: {', '.join(main_points)}
|
||||
|
||||
Tone and Style: {tone_style}
|
||||
|
||||
Video Length: {video_length}
|
||||
|
||||
Script Structure: {script_structure}
|
||||
|
||||
Specific Instructions:
|
||||
* Include a strong hook to grab attention at the start.
|
||||
* Structure the script with clear sections and headings.
|
||||
* Provide engaging introductions and conclusions for each section.
|
||||
* Use clear and concise language, avoiding jargon or overly technical terms.
|
||||
* Tailor the language and tone to the target audience.
|
||||
* Include relevant examples, anecdotes, and stories to make the video more engaging.
|
||||
* Add questions to encourage viewer interaction and participation.
|
||||
* End the script with a strong call to action, encouraging viewers to subscribe, like the video, or visit your website.
|
||||
|
||||
Use Case: {use_case}
|
||||
|
||||
Output Format:
|
||||
|
||||
Please provide the script in a clear and easy-to-read format.
|
||||
Include clear headings for each section and ensure that all instructions are followed.
|
||||
"""
|
||||
|
||||
try:
|
||||
response = generate_text_with_exception_handling(prompt)
|
||||
return response
|
||||
except Exception as err:
|
||||
st.error(f"Exit: Failed to get response from LLM: {err}")
|
||||
exit(1)
|
||||
Reference in New Issue
Block a user