WIP - UI, Audio, firecrawl, long-form - V0.5

This commit is contained in:
ajaysi
2024-06-20 22:48:52 +05:30
parent 899abad1ba
commit 074ddf6210
12 changed files with 206 additions and 131 deletions

View File

@@ -20,20 +20,20 @@ If you have 💻 Laptop + 🛜 Internet + 10 minutes, you will be generating blo
--- ---
### [Getting started for Developers](https://github.com/AJaySi/AI-Writer/wiki/Alwrity--%E2%80%90-Get-started) ### [Getting started for Developers](https://github.com/AJaySi/AI-Writer/wiki/Alwrity--%E2%80%90-Get-started)
` ```
Step1: git clone https://github.com/AJaySi/AI-Writer.git Step1: git clone https://github.com/AJaySi/AI-Writer.git
Step2: pip install -r requirements.txt Step2: pip install -r requirements.txt
Step3: streamlit run alwrity.py Step3: streamlit run alwrity.py
Step4: Visit Alwrity UI in Browser & Start generation AI personalized content. Step4: Visit Alwrity UI in Browser & Start generation AI personalized content.
` ```
--- ---
### Updating to latest Code: (Existing users) ### Updating to latest Code: (Existing users)
` ```
1). Git pull 1). Git pull
2). streamlit run alwrity.py 2). streamlit run alwrity.py
3). pip install -r requirements.txt 3). pip install -r requirements.txt
` ```
--- ---
**Still stuck, [Open issue here](https://github.com/AJaySi/AI-Writer/issues) & Someone will bail you out. **Still stuck, [Open issue here](https://github.com/AJaySi/AI-Writer/issues) & Someone will bail you out.
@@ -92,6 +92,7 @@ Use the [main_config](https://github.com/AJaySi/AI-Writer/blob/main/main_config)
- [Gemini API](https://gemini.google.com/app): Google powered LLM for natural language processing tasks. - [Gemini API](https://gemini.google.com/app): Google powered LLM for natural language processing tasks.
- [Ollama](https://ollama.com/) : Local, Privacy focused, LLM provider for research and content generation capabilities. - [Ollama](https://ollama.com/) : Local, Privacy focused, LLM provider for research and content generation capabilities.
- [CrewAI](https://www.crewai.com/): Collaborative AI agents framework. - [CrewAI](https://www.crewai.com/): Collaborative AI agents framework.
- [firecrawl](https://www.firecrawl.dev/): Turn websites into LLM-ready data
--- ---
## Features ## Features

View File

@@ -33,7 +33,7 @@ def check_api_keys():
missing_keys.append((key, description)) missing_keys.append((key, description))
if missing_keys: if missing_keys:
st.warning("🚨 Some API keys are missing! Please provide them below: 🚨") st.error("🚨 Some API keys are missing! Please provide them below: 🚨")
new_keys = [] new_keys = []
for key, description in missing_keys: for key, description in missing_keys:
@@ -321,45 +321,43 @@ def main():
if api_keys_valid and llm_environs_valid: if api_keys_valid and llm_environs_valid:
# Clear previous messages and display the sidebar configuration # Clear previous messages and display the sidebar configuration
sidebar_configuration() sidebar_configuration()
else:
st.error("Error loading Environment variables.")
# Define the tabs # Define the tabs
tab1, tab2, tab3, tab4, tab5 = st.tabs( tab1, tab2, tab3, tab4, tab5 = st.tabs(
["AI Writers", "Content Planning", "Agents Content Teams", "Alwrity Brain", "Ask Alwrity"]) ["AI Writers", "Content Planning", "Agents Content Teams", "Alwrity Brain", "Ask Alwrity"])
with tab1: with tab1:
write_blog() write_blog()
with tab2: with tab2:
content_planning_tools() content_planning_tools()
with tab3: with tab3:
ai_agents_team() ai_agents_team()
with tab4: with tab4:
alwrity_brain() alwrity_brain()
with tab5: with tab5:
st.info("Chatbot") st.info("Chatbot")
st.markdown("Create a collection by uploading files (PDF, MD, CSV, etc), or crawl a data source (Websites, more sources coming soon.") st.markdown("Create a collection by uploading files (PDF, MD, CSV, etc), or crawl a data source (Websites, more sources coming soon.")
st.markdown("One can ask/chat, summarize and do semantic search over the uploaded data") st.markdown("One can ask/chat, summarize and do semantic search over the uploaded data")
#alwrity_chat_docqa() #alwrity_chat_docqa()
# Sidebar for prompt modification # Sidebar for prompt modification
st.sidebar.title("📝 Modify Prompts") st.sidebar.title("📝 Modify Prompts")
prompts = read_prompts() prompts = read_prompts()
if prompts: if prompts:
edited_prompts = [] edited_prompts = []
for i, prompt in enumerate(prompts): for i, prompt in enumerate(prompts):
edited_prompt = st.sidebar.text_area(f"Prompt {i+1}", prompt) edited_prompt = st.sidebar.text_area(f"Prompt {i+1}", prompt)
edited_prompts.append(edited_prompt) edited_prompts.append(edited_prompt)
if st.sidebar.button("Save Prompts"): if st.sidebar.button("Save Prompts"):
write_prompts(edited_prompts) write_prompts(edited_prompts)
st.sidebar.success("Prompts saved successfully!") st.sidebar.success("Prompts saved successfully!")
else: else:
st.sidebar.warning("No prompts found in the file.") st.sidebar.warning("No prompts found in the file.")
# Functions for the main options # Functions for the main options

View File

@@ -1,21 +1,27 @@
import sys import sys
import os import os
import asyncio
from textwrap import dedent from textwrap import dedent
from pathlib import Path from pathlib import Path
from datetime import datetime from datetime import datetime
import streamlit as st import streamlit as st
from gtts import gTTS
import base64
from dotenv import load_dotenv from dotenv import load_dotenv
# Load environment variables
load_dotenv(Path('../../.env')) load_dotenv(Path('../../.env'))
# Logger setup
from loguru import logger from loguru import logger
logger.remove() logger.remove()
logger.add(sys.stdout, logger.add(sys.stdout,
colorize=True, colorize=True,
format="<level>{level}</level>|<green>{file}:{line}:{function}</green>| {message}" format="<level>{level}</level>|<green>{file}:{line}:{function}</green>| {message}")
)
from ..ai_web_researcher.gpt_online_researcher import do_google_serp_search,\ # Import other necessary modules
do_tavily_ai_search, do_metaphor_ai_research, do_google_pytrends_analysis 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 .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 ..ai_web_researcher.you_web_reseacher import get_rag_results, search_ydc_index
from ..blog_metadata.get_blog_metadata import blog_metadata from ..blog_metadata.get_blog_metadata import blog_metadata
@@ -23,6 +29,21 @@ from ..blog_postprocessing.save_blog_to_file import save_blog_to_file
from ..gpt_providers.text_to_image_generation.main_generate_image_from_prompt import generate_image from ..gpt_providers.text_to_image_generation.main_generate_image_from_prompt import generate_image
# Function to convert text to speech and save as an audio file
def text_to_speech(text, lang='en'):
tts = gTTS(text=text, lang=lang)
tts.save("output.mp3")
return "output.mp3"
# Function to get audio file as a downloadable link
def get_audio_file(audio_file):
with open(audio_file, "rb") as file:
data = file.read()
b64_data = base64.b64encode(data).decode()
return f'<a href="data:audio/mp3;base64,{b64_data}" download="output.mp3">Download audio file</a>'
def write_blog_from_keywords(search_keywords, url=None): def write_blog_from_keywords(search_keywords, url=None):
""" """
This function will take a blog Topic to first generate sections for it This function will take a blog Topic to first generate sections for it
@@ -45,8 +66,8 @@ def write_blog_from_keywords(search_keywords, url=None):
status.update(label=f"🛀 Starting Tavily AI research: {search_keywords}") status.update(label=f"🛀 Starting Tavily AI research: {search_keywords}")
tavily_search_result, t_titles, t_answer = do_tavily_ai_search(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}", status.update(label=f"🙆 Finished Google Search & Tavily AI Search on: {search_keywords}",
state="complete", expanded=False) state="complete", expanded=False)
except Exception as err: except Exception as err:
st.error(f"Failed in web research: {err}") st.error(f"Failed in web research: {err}")
@@ -66,21 +87,21 @@ def write_blog_from_keywords(search_keywords, url=None):
# logger.info/check the final blog content. # logger.info/check the final blog content.
logger.info("######### Draft1: Finished Blog from Google web search: ###########") logger.info("######### Draft1: Finished Blog from Google web search: ###########")
with st.status("Started Writing blog from Tavily Web search..", expanded=True) as status: with st.status("Started Writing blog from Tavily Web search..", expanded=True) as status:
# Do Tavily AI research to augument the above blog. # Do Tavily AI research to augment the above blog.
try: try:
#example_blog_titles.append(t_titles) # example_blog_titles.append(t_titles)
if blog_markdown_str and tavily_search_result: if blog_markdown_str and tavily_search_result:
logger.info(f"\n\n######### Blog content after Tavily AI research: ######### \n\n") 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) blog_markdown_str = write_blog_google_serp(search_keywords, tavily_search_result)
status.update(label="Finished Writing Blog From Tavily Results:{blog_markdown_str}", expanded=True) status.update(label=f"Finished Writing Blog From Tavily Results:{blog_markdown_str}", expanded=True)
except Exception as err: except Exception as err:
logger.error(f"Failed to do Tavily AI research: {err}") logger.error(f"Failed to do Tavily AI research: {err}")
status.update(label="🙎 Generating - Title, Meta Description, Tags, Categories for the content.", expanded=True) status.update(label="🙎 Generating - Title, Meta Description, Tags, Categories for the content.", expanded=True)
try: try:
blog_title, blog_meta_desc, blog_tags, blog_categories = blog_metadata(blog_markdown_str) blog_title, blog_meta_desc, blog_tags, blog_categories = asyncio.run(blog_metadata(blog_markdown_str))
except Exception as err: except Exception as err:
st.error(f"Failed to get blog metadata: {err}") st.error(f"Failed to get blog metadata: {err}")
@@ -94,38 +115,21 @@ def write_blog_from_keywords(search_keywords, url=None):
except Exception as err: except Exception as err:
st.warning(f"Failed in Image generation: {err}") st.warning(f"Failed in Image generation: {err}")
saved_blog_to_file = save_blog_to_file(blog_markdown_str, blog_title, blog_meta_desc, saved_blog_to_file = save_blog_to_file(blog_markdown_str, blog_title, blog_meta_desc,
blog_tags, blog_categories, generated_image_filepath) blog_tags, blog_categories, generated_image_filepath)
status.update(label=f"Saved the content in this file: {saved_blog_to_file}") status.update(label=f"Saved the content in this file: {saved_blog_to_file}")
logger.info(f"\n\n --------- Finished writing Blog for : {search_keywords} -------------- \n") logger.info(f"\n\n --------- Finished writing Blog for : {search_keywords} -------------- \n")
# Render the result on streamlit UI
st.image(generated_image_filepath)
st.markdown(f"{blog_markdown_str}")
status.update(label=f"Finished, Review & Use your Original Content Below: {saved_blog_to_file}", state="complete")
# Display options below the content # Render the result on streamlit UI
col1, col2, col3, col4, col5 = st.columns(5) if generated_image_filepath:
if col1.button('Copy'): st.image(generated_image_filepath)
pyperclip.copy(blog_markdown_str) st.markdown(f"{blog_markdown_str}")
st.success("Text copied to clipboard!") status.update(label=f"Finished, Review & Use your Original Content Below: {saved_blog_to_file}",
state="complete")
if col2.button('Rephrase'):
rephrased_text = rephrase_text(blog_markdown_str) # Passing the text and language to the engine, here we have marked slow=False. Which tells
st.markdown(rephrased_text) # the module that the converted audio should have a high speed
tts = gTTS(text=blog_markdown_str, lang='en', slow=False)
if col3.button('Change Tone'): # Saving the converted audio in a mp3 file
tone = st.selectbox("Select Tone", ["Formal", "Casual", "Professional"]) tts.save("delete_me.mp3")
if st.button("Apply Tone"): st.audio("delete_me.mp3")
toned_text = change_tone(blog_markdown_str, tone)
st.markdown(toned_text)
if col4.button('Make Shorter'):
shorter_text = make_shorter(blog_markdown_str)
st.markdown(shorter_text)
if col5.button('Translate'):
language = st.selectbox("Select Language", ["Spanish", "French", "German"])
if st.button("Translate"):
translated_text = translate_text(blog_markdown_str, language)
st.markdown(translated_text)

View File

@@ -124,15 +124,15 @@ def long_form_generator(content_keywords):
# Configure generative AI # Configure generative AI
load_dotenv(Path('../.env')) load_dotenv(Path('../.env'))
generation_config = { generation_config = {
"temperature": 0.6, "temperature": 0.7,
"top_p": 1, "top_p": 1,
"max_output_tokens": 8096, "max_output_tokens": 8096,
} }
genai.configure(api_key=os.getenv('GEMINI_API_KEY')) genai.configure(api_key=os.getenv('GEMINI_API_KEY'))
# Initialize the generative model # Initialize the generative model
#model = genai.GenerativeModel('gemini-pro', generation_config=generation_config) model = genai.GenerativeModel('gemini-1.5-flash', generation_config=generation_config)
model_pro = genai.GenerativeModel('gemini-1.5-flash', generation_config=generation_config) model_pro = genai.GenerativeModel('gemini-pro', generation_config=generation_config)
# Do SERP web research for given keywords to generate title and outline. # Do SERP web research for given keywords to generate title and outline.
web_research_result, g_titles = do_google_serp_search(content_keywords) web_research_result, g_titles = do_google_serp_search(content_keywords)
@@ -203,14 +203,14 @@ def long_form_generator(content_keywords):
logger.info(f"Writing in progress... Current draft length: {len(draft)} characters") 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") status.update(label=f"Writing in progress... Current draft length: {len(draft)} characters")
search_terms = f""" search_terms = f"""
I will provide you with blog outline, your task is to read the outline & return 8 google search keywords. I will provide you with content outline below, your task is to read the outline & return 8 google search keywords.
Your response will be used to do web research for writing on the given outline. Your response will be used to do web research for writing on the given outline.
Do not explain your response, provide 8 google search sentences encompassing the given content outline. Do not explain your response, provide 8 google search sentences encompassing the given content outline.
Provide the search term results as comma separated values.\n\n Important: Provide the search term results as comma separated values.\n\n
Content Outline:\n Content Outline:\n
'{content_outline}' '{content_outline}'
""" """
search_words = generate_with_retry(model_pro, search_terms).text search_words = generate_with_retry(model, search_terms).text
status.update(label=f"Search terms from written draft: {search_words}") status.update(label=f"Search terms from written draft: {search_words}")
while 'IAMDONE' not in continuation: while 'IAMDONE' not in continuation:
@@ -218,6 +218,7 @@ def long_form_generator(content_keywords):
str_list = re.split(r',\s*', search_words) str_list = re.split(r',\s*', search_words)
# Strip quotes from each element # Strip quotes from each element
str_list = [s.strip('\'"') for s in str_list] str_list = [s.strip('\'"') for s in str_list]
for search_term 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) web_research_result, m_titles, t_titles = do_tavily_ai_search(search_term, max_results=5)
try: try:

View File

@@ -17,7 +17,7 @@ logger.add(sys.stdout,
) )
from ..ai_web_researcher.firecrawl_web_crawler import scrape_url from ..ai_web_researcher.firecrawl_web_crawler import scrape_url
from ..blog_metadata.get_blog_metadata import blog_metadata from ..blog_metadata.get_blog_metadata import blog_metadata, run_async
from ..blog_postprocessing.save_blog_to_file import save_blog_to_file from ..blog_postprocessing.save_blog_to_file import save_blog_to_file
from ..gpt_providers.text_to_image_generation.main_generate_image_from_prompt import generate_image from ..gpt_providers.text_to_image_generation.main_generate_image_from_prompt import generate_image
from ..gpt_providers.text_generation.main_text_generation import llm_text_gen from ..gpt_providers.text_generation.main_text_generation import llm_text_gen
@@ -31,7 +31,11 @@ def blog_from_url(weburl):
# Use to store the blog in a string, to save in a *.md file. # Use to store the blog in a string, to save in a *.md file.
blog_markdown_str = None blog_markdown_str = None
tavily_search_result = None tavily_search_result = None
example_blog_titles = [] # Initializing the variables
blog_title = None
blog_meta_desc = None
blog_tags = None
blog_categories = None
logger.info(f"Researching and Writing Blog on: {weburl}") logger.info(f"Researching and Writing Blog on: {weburl}")
with st.status("Started Writing..", expanded=True) as status: with st.status("Started Writing..", expanded=True) as status:
@@ -39,12 +43,12 @@ def blog_from_url(weburl):
status.update(label=f"Researching and Writing Blog on: {weburl}") status.update(label=f"Researching and Writing Blog on: {weburl}")
try: try:
scraped_text = scrape_url(weburl) scraped_text = scrape_url(weburl)
logger.info(scraped_text) #logger.info(scraped_text)
except Exception as err: except Exception as err:
st.error(f"Failed to scrape web page from url-{weburl} - Error: {err}") st.error(f"Failed to scrape web page from url-{weburl} - Error: {err}")
logger.error(f"Failed in web research: {err}") logger.error(f"Failed in web research: {err}")
st.stop() st.stop()
status.update(label="Successfully Scraped/Fetched url: {weburl}", expanded=False, state="complete") status.update(label=f"Successfully Scraped/Fetched url: {weburl}", expanded=False, state="complete")
with st.status(f"Started Writing blog from {weburl}..", expanded=True) as status: with st.status(f"Started Writing blog from {weburl}..", expanded=True) as status:
# Do Tavily AI research to augument the above blog. # Do Tavily AI research to augument the above blog.
@@ -58,7 +62,7 @@ def blog_from_url(weburl):
try: try:
status.update(label="🙎 Generating - Title, Meta Description, Tags, Categories for the content.") 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) blog_title, blog_meta_desc, blog_tags, blog_categories = run_async(blog_metadata(blog_markdown_str))
except Exception as err: except Exception as err:
st.error(f"Failed to get blog metadata: {err}") st.error(f"Failed to get blog metadata: {err}")
@@ -71,8 +75,11 @@ def blog_from_url(weburl):
saved_blog_to_file = save_blog_to_file(blog_markdown_str, blog_title, blog_meta_desc, saved_blog_to_file = save_blog_to_file(blog_markdown_str, blog_title, blog_meta_desc,
blog_tags, blog_categories, generated_image_filepath) blog_tags, blog_categories, generated_image_filepath)
status.update(label=f"Saved the content in this file: {saved_blog_to_file}") status.update(label=f"Saved the content in this file: {saved_blog_to_file}")
logger.info(f"\n\n --------- Finished writing Blog for : {weburl} -------------- \n") logger.info(f"\n\n --------- Finished writing Blog for : {weburl} -------------- \n")
st.image(generated_image_filepath) if generated_image_filepath:
st.image(generated_image_filepath)
st.markdown(f"{blog_markdown_str}") st.markdown(f"{blog_markdown_str}")
status.update(label=f"Finished, Review & Use your Original Content Below: {saved_blog_to_file}", state="complete") status.update(label=f"Finished, Review & Use your Original Content Below: {saved_blog_to_file}", state="complete")

View File

@@ -2,7 +2,7 @@ import sys
import streamlit as st import streamlit as st
from loguru import logger from loguru import logger
import random import random
import time import asyncio
logger.remove() logger.remove()
logger.add(sys.stdout, logger.add(sys.stdout,
@@ -12,7 +12,7 @@ logger.add(sys.stdout,
from ..gpt_providers.text_generation.main_text_generation import llm_text_gen from ..gpt_providers.text_generation.main_text_generation import llm_text_gen
def blog_metadata(blog_article): async def blog_metadata(blog_article):
""" Common function to get blog metadata """ """ Common function to get blog metadata """
logger.info(f"Generating Content MetaData\n") logger.info(f"Generating Content MetaData\n")
@@ -20,22 +20,22 @@ def blog_metadata(blog_article):
total_steps = 4 total_steps = 4
# Step 1: Generate blog title # Step 1: Generate blog title
time.sleep(random.uniform(1, 3)) await asyncio.sleep(random.uniform(1, 3))
blog_title = generate_blog_title(blog_article) blog_title = generate_blog_title(blog_article)
progress_bar.progress(1 / total_steps) progress_bar.progress(1 / total_steps)
# Step 2: Generate blog meta description # Step 2: Generate blog meta description
time.sleep(random.uniform(1, 3)) await asyncio.sleep(random.uniform(1, 3))
blog_meta_desc = generate_blog_description(blog_article) blog_meta_desc = generate_blog_description(blog_article)
progress_bar.progress(2 / total_steps) progress_bar.progress(2 / total_steps)
# Step 3: Generate blog tags # Step 3: Generate blog tags
time.sleep(random.uniform(1, 3)) await asyncio.sleep(random.uniform(1, 3))
blog_tags = get_blog_tags(blog_article) blog_tags = get_blog_tags(blog_article)
progress_bar.progress(3 / total_steps) progress_bar.progress(3 / total_steps)
# Step 4: Generate blog categories # Step 4: Generate blog categories
time.sleep(random.uniform(1, 3)) await asyncio.sleep(random.uniform(1, 3))
blog_categories = get_blog_categories(blog_article) blog_categories = get_blog_categories(blog_article)
progress_bar.progress(4 / total_steps) progress_bar.progress(4 / total_steps)
@@ -117,3 +117,10 @@ def get_blog_tags(blog_article):
logger.error(f"Failed to get response from LLM: {err}") logger.error(f"Failed to get response from LLM: {err}")
raise err raise err
# Helper function to run the asyncio event loop within Streamlit
def run_async(coro):
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
result = loop.run_until_complete(coro)
loop.close()
return result

View File

@@ -2,6 +2,8 @@ import os
import re import re
import sys import sys
import streamlit as st import streamlit as st
from streamlit_mic_recorder import speech_to_text
import tempfile import tempfile
from pathlib import Path from pathlib import Path
import configparser import configparser
@@ -10,7 +12,6 @@ import uuid
from PIL import Image from PIL import Image
from PyPDF2 import PdfReader from PyPDF2 import PdfReader
from docx import Document from docx import Document
from loguru import logger from loguru import logger
logger.remove() logger.remove()
logger.add(sys.stdout, logger.add(sys.stdout,
@@ -19,7 +20,6 @@ logger.add(sys.stdout,
) )
from rich import print
from lib.ai_web_researcher.gpt_online_researcher import gpt_web_researcher from lib.ai_web_researcher.gpt_online_researcher import gpt_web_researcher
from lib.ai_web_researcher.metaphor_basic_neural_web_search import metaphor_find_similar from lib.ai_web_researcher.metaphor_basic_neural_web_search import metaphor_find_similar
from lib.ai_writers.keywords_to_blog_streamlit import write_blog_from_keywords from lib.ai_writers.keywords_to_blog_streamlit import write_blog_from_keywords
@@ -41,11 +41,40 @@ from lib.gpt_providers.text_to_image_generation.main_generate_image_from_prompt
from lib.content_planning_calender.content_planning_agents_alwrity_crew import ai_agents_planner from lib.content_planning_calender.content_planning_agents_alwrity_crew import ai_agents_planner
def record_voice(language="en"):
# https://github.com/B4PT0R/streamlit-mic-recorder?tab=readme-ov-file#example
state = st.session_state
if "text_received" not in state:
state.text_received = []
text = speech_to_text(
start_prompt="🎙Record🔊",
stop_prompt="🔇Stop Recording🚨",
language=language,
use_container_width=True,
just_once=False,
)
if text:
state.text_received.append(text)
result = ""
for text in state.text_received:
result += text
state.text_received = []
return result if result else None
def is_youtube_link(text): def is_youtube_link(text):
if text is not None: if text is not None:
youtube_regex = re.compile(r'(https?://)?(www\.)?(youtube|youtu|youtube-nocookie)\.(com|be)/(watch\?v=|embed/|v/|.+\?v=)?([^&=%\?]{11})') youtube_regex = re.compile(r'(https?://)?(www\.)?(youtube|youtu|youtube-nocookie)\.(com|be)/(watch\?v=|embed/|v/|.+\?v=)?([^&=%\?]{11})')
return youtube_regex.match(text) return youtube_regex.match(text)
def is_web_link(text): def is_web_link(text):
if text is not None: if text is not None:
web_regex = re.compile(r'(https?://)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)') web_regex = re.compile(r'(https?://)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)')
@@ -87,10 +116,11 @@ def process_input(input_text, uploaded_file):
return "video_file" return "video_file"
return None return None
def blog_from_keyword(): def blog_from_keyword():
""" Input blog keywords, research and write a factual blog.""" """ Input blog keywords, research and write a factual blog."""
st.title("Blog Content Writer") st.title("Blog Content Writer")
col1, col2 = st.columns([2, 1.5]) col1, col2, col3 = st.columns([2, 1.5, 0.5])
with col1: with col1:
user_input = st.text_area('**👇Enter Keywords/Title/YouTube Link/Web URLs**', user_input = st.text_area('**👇Enter Keywords/Title/YouTube Link/Web URLs**',
help='Provide keywords, titles, YouTube links, or web URLs to generate content.', help='Provide keywords, titles, YouTube links, or web URLs to generate content.',
@@ -104,6 +134,10 @@ def blog_from_keyword():
uploaded_file = st.file_uploader("**👇Attach files (Audio, Video, Image, Document)**", uploaded_file = st.file_uploader("**👇Attach files (Audio, Video, Image, Document)**",
type=["txt", "pdf", "docx", "jpg", "jpeg", "png", "mp3", "wav", "mp4", "mkv", "avi"], type=["txt", "pdf", "docx", "jpg", "jpeg", "png", "mp3", "wav", "mp4", "mkv", "avi"],
help='Attach files such as audio, video, images, or documents.') help='Attach files such as audio, video, images, or documents.')
with col3:
user_input = record_voice()
if user_input:
st.info(user_input)
temp_file_path = None temp_file_path = None
if uploaded_file is not None: if uploaded_file is not None:

View File

@@ -1,6 +1,14 @@
import os import os
import sys
import json import json
from pathlib import Path from pathlib import Path
from loguru import logger
logger.remove()
logger.add(sys.stdout,
colorize=True,
format="<level>{level}</level>|<green>{file}:{line}:{function}</green>| {message}"
)
def read_return_config_section(config_section): def read_return_config_section(config_section):
""" read_return_config_section """ read_return_config_section

Binary file not shown.

Before

Width:  |  Height:  |  Size: 162 KiB

After

Width:  |  Height:  |  Size: 270 KiB

View File

@@ -1,13 +1,27 @@
writing_guidelines: | writing_guidelines: |
As an expert content writer and web researcher, write highly detailed long form, {content_type} content on {content_keywords}.
Follow these writing guidelines: Writing Guidelines:
1. You must Write in {content_language} language. As an expert {content_type} content writer and web researcher on {content_keywords}, follow these writing guidelines:
2. Ensure your content appeals to the target audience of {target_audience}.
3. Maintain a consistent tone of {content_tone} throughout. Language: Write in the {content_language} language.
4. Use simple {content_language} words to appeal to all readers. Audience: Ensure your content appeals to the target audience of {target_audience}.
5. Format your content using {output_format}. Tone: Maintain a consistent tone of {content_tone} throughout.
6. Avoid words like: Unleash, ultimate, uncover, discover, elevate, revolutionizing, unveiling, harnessing, dive, delve into, embrace. Simplicity: Use simple {content_language} words to appeal to all readers.
Remember, your main goal is to write as much as you can. If you get through the story too fast, that is bad. Expand, never summarize. Formatting: Format your content using {output_format}.
Word Choice: Avoid words like: unleash, ultimate, uncover, discover, elevate, revolutionizing, unveiling, harnessing, dive, delve into, embrace.
Immerse yourself fully in the topic you're exploring. Use vivid descriptions to captivate your readers and bring your subject to life.
Develop your ideas thoroughly—let their nuances, challenges, and intricacies unfold naturally.
Follow the structure of your outline, but don't feel constrained by it. Allow your blog post to evolve as you write.
Incorporate rich imagery, sensory details, and evocative language to make your content engaging and relatable.
Introduce elements subtly that can grow into deeper discussions, related topics, or additional insights later in the post.
Keep your readers intrigued by not resolving everything too quickly.
Plant the seeds of subtopics or potential shifts in perspective that can be expanded upon in future posts.
Remember, your main goal is to provide valuable, in-depth content. If you rush through your topic, it will leave readers wanting more.
Expand your ideas, never summarize. Write as much as you can, ensuring that your content is thorough and comprehensive.
content_title: | content_title: |
@@ -51,7 +65,7 @@ starting_prompt: |
First, silently review the content outline and title. Consider how to begin writing your content. Take your time. First, silently review the content outline and title. Consider how to begin writing your content. Take your time.
Start by writing the very beginning of the outline. You are not expected to finish the entire content now. Start by writing the very beginning of the outline. You are not expected to finish the entire content now.
Your writing should be detailed, only scratching the surface of the first bullet of your outline. Your writing should be detailed, only scratching the surface of the first bullet of your outline.
Try to write AT MINIMUM 1000 WORDS and MAXIMUM 2000 WORDS. Try to write AT MINIMUM 500 WORDS.
"""{{writing_guidelines}}""" """{{writing_guidelines}}"""
@@ -60,30 +74,29 @@ starting_prompt: |
continuation_prompt: | continuation_prompt: |
As an expert {content_language} content writer and web researcher specializing in SEO-optimized content, continue writing the content for the given title and outline. As an expert {content_language} content writer and web researcher specializing in SEO-optimized content, continue writing the content for the given title and outline.
The Title of the content is: Title of the Content:
"""{{content_title}}""" {{content_title}}
The content Outline is: Content Outline:
"""{{content_outline}}""" {{content_outline}}
Relevant web research results to use: Relevant Web Research Results to Use:
"""{{web_research_result}}""" {{web_research_result}}
You've begun to immerse yourself in this world, and the words are flowing. You've begun to immerse yourself in this subject, and the words are flowing. Here's what you've written so far:
Here's what you've written so far: {{content_text}}
"""{{content_text}}"""
=====
=========== First, silently review the content outline and what you've written so far.
Take your time to understand the flow and context.
Identify the next section of your outline to write about.
It is important to continue from where you left off.
First, silently review the content outline and what you've written so far. Take your time. Your task is to continue writing from where you left off and cover the next part of the outline.
Identify what the single next part of your outline you should write. You are not expected to finish the entire content now.
Important to Continue from where you left off. Your writing should be detailed enough to thoroughly explore the next part of your outline.
Aim to write at least 500 words. However, only once the entire content is completely finished, write IAMDONE.
Remember, do not write the whole outline sections right now.
Your task is to continue where you left off and write the next part of the outline. {writing_guidelines}
You are not expected to finish the whole content now. Your writing should be
detailed enough that you are only scratching the surface of the next part of
your outline. Try to write AT MINIMUM 1000 WORDS. However, only once the whole outline content
is COMPLETELY finished, write IAMDONE. Remember, do NOT write a whole outline sections right now.
"""{{writing_guidelines}}"""

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 5.8 MiB

View File

@@ -33,3 +33,5 @@ streamlit
yfinance yfinance
pandas_ta pandas_ta
firecrawl-py firecrawl-py
gTTS
streamlit-mic-recorder