From b97ad5eb2b181328971224c54b1890a1b7c85dd2 Mon Sep 17 00:00:00 2001 From: ajaysi Date: Sun, 18 Aug 2024 17:13:00 +0530 Subject: [PATCH] Use system instructions to steer the behavior of a model --- lib/ai_writers/blog_from_google_serp.py | 20 +--- lib/ai_writers/twitter_ai_writer.py | 91 ++++++++++++------- .../text_generation/gemini_pro_text.py | 8 +- .../text_generation/main_text_generation.py | 18 +++- .../text_generation/openai_text_gen.py | 5 +- lib/utils/alwrity_utils.py | 7 +- .../alwrity_system_instruction.prompts | 2 + 7 files changed, 90 insertions(+), 61 deletions(-) create mode 100644 lib/workspace/alwrity_prompts/alwrity_system_instruction.prompts diff --git a/lib/ai_writers/blog_from_google_serp.py b/lib/ai_writers/blog_from_google_serp.py index 019a84a3..df9249e3 100644 --- a/lib/ai_writers/blog_from_google_serp.py +++ b/lib/ai_writers/blog_from_google_serp.py @@ -15,26 +15,9 @@ from ..gpt_providers.text_generation.main_text_generation import llm_text_gen def write_blog_google_serp(search_keyword, search_results): """Combine the given online research and GPT blog content""" - try: - config_path = Path(os.environ["ALWRITY_CONFIG"]) - with open(config_path, 'r', encoding='utf-8') as file: - config = json.load(file) - except Exception as err: - logger.error(f"Error: Failed to read values from config: {err}") - exit(1) - - blog_characteristics = config['Blog Content Characteristics'] - prompt = f""" As expert Creative Content writer, - I want you to write {blog_characteristics['Blog Type']} blog post, - that explores {search_keyword} and also include 5 FAQs. - - Below are the guidelines to follow: - 1). You must respond in {blog_characteristics['Blog Language']} language. - 2). Tone and Brand Alignment: Adjust your tone, voice, personality for {blog_characteristics['Blog Tone']} audience. - 3). Make sure your response content length is of {blog_characteristics['Blog Length']} words. - 4). Include FAQs from 'People also Ask' section of provided context 'google search result'. + I want you to write blog post, that explores {search_keyword} and also include 5 FAQs. I want the post to offer unique insights, relatable examples, and a fresh perspective on the topic. Here are some Google search results to spark your creativity on {search_keyword}: @@ -51,6 +34,7 @@ def write_blog_google_serp(search_keyword, search_results): logger.error(f"Exit: Failed to get response from LLM: {err}") exit(1) + def improve_blog_intro(blog_content, blog_intro): """Combine the given online research and gpt blog content""" prompt = f""" diff --git a/lib/ai_writers/twitter_ai_writer.py b/lib/ai_writers/twitter_ai_writer.py index 63f55c2d..719fd0e6 100644 --- a/lib/ai_writers/twitter_ai_writer.py +++ b/lib/ai_writers/twitter_ai_writer.py @@ -13,59 +13,84 @@ def tweet_writer(): 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." + 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", + label="**Target Audience**", placeholder="e.g., technology enthusiasts, travel lovers", help="Describe the audience you want to target with this tweet." ) + col3, col4 = st.columns([5, 5]) + with col3: + tweet_tone = st.selectbox( + label="**Tweet Tone**", + options=["Humorous", "Informative", "Inspirational", "Serious", "Casual"], + help="Choose the tone you'd like the tweet to have." + ) + + with col4: + cta = st.text_input( + label="**Call to Action (Optional)**", + placeholder="e.g., Retweet this if you agree! (Leave blank if not applicable)", + help="Provide a call to action if you'd like to include one." + ) + + col5, col6 = st.columns([5, 5]) + with col5: + keywords_hashtags = st.text_input( + label="**Keywords/Hashtags**", + placeholder="e.g., #AI #Innovation", + help="Provide 2-3 relevant keywords or hashtags." + ) + + with col6: + tweet_length = st.selectbox( + "Tweet Length (Optional)", + options=["Short (under 100 characters)", "Medium (100-200 characters)", "Long (200+ characters)"], + help="Choose the desired tweet length.", + ) + if st.button('**Write Tweets**'): if not target_audience or not hook: st.error("🚫 Please provide all required inputs.") else: - with st.status("Assigning AI professional to write your Google Ads copy..", expanded=True) as status: - response = tweet_generator(target_audience, hook) + with st.status("Assigning AI professional to write your tweets...", expanded=True) as status: + response = tweet_generator(target_audience, hook, tweet_tone, cta, keywords_hashtags, tweet_length) if response: st.subheader(f'**πŸ§•πŸ‘©: Your Tweets!**') st.markdown(response) else: - st.error("πŸ’₯**Failed to write Letter. Please try again!**") + st.error("πŸ’₯**Failed to generate tweets. Please try again!**") -def tweet_generator(target_audience, hook): - """ Email project_update_writer """ +def tweet_generator(target_audience, hook, tone_style, cta, keywords_hashtags, tweet_length): + """ Tweet Generator """ 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. - """ + 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 input: "{hook}" + 2. Include the following call to action: "{cta}" + 3. Use 2-3 relevant keywords/hashtags, including: "{keywords_hashtags}" + 4. Adopt the following tone/style: "{tone_style}" + 5. Adhere to the following length requirement: {tweet_length} + + Make sure to keep the tone consistent with the selected style and platform context. + + Here are some examples of call-to-actions to include (if no specific CTA was provided): + - Retweet this if you agree! + - Share your thoughts in the comments! + - Learn more at [link] + - Follow for more {target_audience} content. + + Output each tweet separated by a newline. + """ try: response = llm_text_gen(prompt) diff --git a/lib/gpt_providers/text_generation/gemini_pro_text.py b/lib/gpt_providers/text_generation/gemini_pro_text.py index 347227d9..5a999dd3 100644 --- a/lib/gpt_providers/text_generation/gemini_pro_text.py +++ b/lib/gpt_providers/text_generation/gemini_pro_text.py @@ -2,7 +2,6 @@ import os import sys from pathlib import Path -import streamlit as st import google.generativeai as genai from dotenv import load_dotenv @@ -21,7 +20,7 @@ from tenacity import ( @retry(wait=wait_random_exponential(min=1, max=60), stop=stop_after_attempt(6)) -def gemini_text_response(prompt, temperature, top_p, n, max_tokens): +def gemini_text_response(prompt, temperature, top_p, n, max_tokens, system_prompt): """ Common functiont to get response from gemini pro Text. """ #FIXME: Include : https://github.com/google-gemini/cookbook/blob/main/quickstarts/rest/System_instructions_REST.ipynb try: @@ -37,7 +36,9 @@ def gemini_text_response(prompt, temperature, top_p, n, max_tokens): "max_output_tokens": max_tokens, } # FIXME: Expose model_name in main_config - model = genai.GenerativeModel(model_name="gemini-1.5-pro-latest", generation_config=generation_config) + model = genai.GenerativeModel(model_name="gemini-1.5-pro-latest", + generation_config=generation_config, + system_instruction=system_prompt) try: # text_response = [] response = model.generate_content(prompt, stream=True) @@ -45,7 +46,6 @@ def gemini_text_response(prompt, temperature, top_p, n, max_tokens): for chunk in response: # text_response.append(chunk.text) print(chunk.text) - #st.write(chunk.text) else: print(response) logger.info(f"Number of Token in Prompt Sent: {model.count_tokens(prompt)}") diff --git a/lib/gpt_providers/text_generation/main_text_generation.py b/lib/gpt_providers/text_generation/main_text_generation.py index 7395730a..75246f2a 100644 --- a/lib/gpt_providers/text_generation/main_text_generation.py +++ b/lib/gpt_providers/text_generation/main_text_generation.py @@ -27,7 +27,21 @@ def llm_text_gen(prompt): str: Generated text based on the prompt. """ try: + # Read the config param to create system instruction for the LLM. gpt_provider, model, temperature, max_tokens, top_p, n, fp = read_return_config_section('llm_config') + blog_tone, blog_demographic, blog_type, blog_language, \ + blog_output_format, blog_length = read_return_config_section('blog_characteristics') + + # Construct the system prompt with the sidebar config params. + system_instructions = f""" + Below are the guidelines to follow: + 1). You must respond in {blog_language} language. + 2). Tone and Brand Alignment: Adjust your tone, voice, personality for {blog_tone} audience. + 3). Make sure your response content length is of {blog_length} words. + 4). The type of blog is {blog_type}, write accordingly. + 5). The demographic for this content is {blog_demographic}. + 6). Your response should be in {blog_output_format} format. + """ #gpt_provider = check_gpt_provider(gpt_provider) # Check if API key is provided for the given gpt_provider @@ -37,7 +51,7 @@ def llm_text_gen(prompt): if 'google' in gpt_provider.lower(): try: logger.info("Using Google Gemini Pro text generation model.") - response = gemini_text_response(prompt, temperature, top_p, n, max_tokens) + response = gemini_text_response(prompt, temperature, top_p, n, max_tokens, system_instructions) return response except Exception as err: logger.error(f"Failed to get response from gemini: {err}") @@ -45,7 +59,7 @@ def llm_text_gen(prompt): elif 'openai' in gpt_provider.lower(): try: logger.info(f"Using OpenAI Model: {model} for text Generation.") - response = openai_chatgpt(prompt, model, temperature, max_tokens, top_p, n, fp) + response = openai_chatgpt(prompt, model, temperature, max_tokens, top_p, n, fp, system_instructions) return response except Exception as err: logger.error(f"Failed to get response from Openai: {err}") diff --git a/lib/gpt_providers/text_generation/openai_text_gen.py b/lib/gpt_providers/text_generation/openai_text_gen.py index 9b2788fe..857873c6 100644 --- a/lib/gpt_providers/text_generation/openai_text_gen.py +++ b/lib/gpt_providers/text_generation/openai_text_gen.py @@ -14,7 +14,7 @@ from tenacity import ( @retry(wait=wait_random_exponential(min=1, max=60), stop=stop_after_attempt(6)) -def openai_chatgpt(prompt, model, temperature, max_tokens, top_p, n, fp): +def openai_chatgpt(prompt, model, temperature, max_tokens, top_p, n, fp, system_prompt): """ Wrapper function for OpenAI's ChatGPT completion. @@ -45,7 +45,8 @@ def openai_chatgpt(prompt, model, temperature, max_tokens, top_p, n, fp): client = openai.OpenAI(api_key=os.getenv('OPENAI_API_KEY')) response = client.chat.completions.create( model=model, - messages=[{"role": "user", "content": prompt}], + messages=[{"role": "system", "content": system_prompt}, + {"role": "user", "content": prompt}], max_tokens=max_tokens, n=n, top_p=top_p, diff --git a/lib/utils/alwrity_utils.py b/lib/utils/alwrity_utils.py index 231e74d0..c4e48e4f 100644 --- a/lib/utils/alwrity_utils.py +++ b/lib/utils/alwrity_utils.py @@ -131,8 +131,11 @@ def ai_seo_tools(): "Generate OpenGraph Tags", "Optimize/Resize Image" ] - choice = st.selectbox("**πŸ‘‡Select AI SEO Tool:**", options, index=0, format_func=lambda x: f"πŸ“ {x}") - + + # Using st.radio instead of st.selectbox + choice = st.radio("**πŸ‘‡ Select AI SEO Tool:**", options, index=0, format_func=lambda x: f"πŸ“ {x}") + + # Handle choices based on the selected option if choice == "Generate Structured Data - Rich Snippet": ai_structured_data() elif choice == "Generate Meta Description for SEO": diff --git a/lib/workspace/alwrity_prompts/alwrity_system_instruction.prompts b/lib/workspace/alwrity_prompts/alwrity_system_instruction.prompts new file mode 100644 index 00000000..b3dba8f0 --- /dev/null +++ b/lib/workspace/alwrity_prompts/alwrity_system_instruction.prompts @@ -0,0 +1,2 @@ +alwrity_system_instruction: | +