WIP- Try AI-Writer and Web research; working. Working on usuability aspects.
This commit is contained in:
23
.env.bk
Normal file
23
.env.bk
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Required should be minimum.
|
||||||
|
|
||||||
|
# Model to use, presently supporting Openai, Gemini, ollama(wip), minstral(wip)
|
||||||
|
GPT_PROVIDER="google"
|
||||||
|
MODEL_TO_USE="gemini"
|
||||||
|
|
||||||
|
|
||||||
|
# Provide the key for MODEL_TO_USE
|
||||||
|
OPENAI_API_KEY=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
|
||||||
|
GEMINI_API_KEY=AIzaSyDM3SfGw9SeBpB39-PWpY8qQjt9OZAeZdM
|
||||||
|
MISTRAL_API_KEY=zaObt2UMIjKKx3Vwmt6G8ccIsrVZI4PT
|
||||||
|
|
||||||
|
|
||||||
|
#--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
SERPER_API_KEY=281b6a882ae28164c08d0bee7113d63ed9f5e547
|
||||||
|
TAVILY_API_KEY=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
|
||||||
|
METAPHOR_API_KEY=94105da2-2954-4b49-933c-1920c7a1a2b3
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Tools and utilities APIs.
|
||||||
|
TINIFY_API_KEY=crJLXQL3DMdXYHz1LvZy60Rd1vYH8mvZ
|
||||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,6 +1,6 @@
|
|||||||
*.pyc
|
*.pyc
|
||||||
__pycache__
|
__pycache__
|
||||||
pseo-experiemnts/
|
pseo-experiments/
|
||||||
*.swp
|
*.swp
|
||||||
venv/
|
venv/
|
||||||
*.pyc
|
*.pyc
|
||||||
@@ -19,4 +19,6 @@ blogs/
|
|||||||
.env
|
.env
|
||||||
papers_already_written_on.txt
|
papers_already_written_on.txt
|
||||||
lib/papers_to_write_on
|
lib/papers_to_write_on
|
||||||
workspace/
|
workspace/web_research_reports/
|
||||||
|
workspace/logs/
|
||||||
|
workspace/personal/
|
||||||
|
|||||||
20
README.md
20
README.md
@@ -6,9 +6,19 @@ This toolkit automates and enhances the process of blog creation, optimization,
|
|||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
To use this tool, follow one of the Options below:
|
To use this tool, follow one of the Options below:
|
||||||
|
---
|
||||||
|
|
||||||
|
### Option 1: Cloud install: (I just want to write blogs..)
|
||||||
|
|
||||||
|
Step 1). Make efforts to fork this present repo into your own account.
|
||||||
|
|
||||||
|
Step 2). Follow this guide: <br>
|
||||||
|
https://docs.replit.com/programming-ide/using-git-on-replit/running-github-repositories-replit
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
### Option 1: Local laptop Install: (I know what I am doing..)
|
|
||||||
|
### Option 2: Local laptop Install: (I know what I am doing..)
|
||||||
|
|
||||||
Step 1. Clone this repository to your local machine.
|
Step 1. Clone this repository to your local machine.
|
||||||
|
|
||||||
@@ -24,14 +34,6 @@ Step 4. Once the tools is running it will guide/ask for your APIs. It will provi
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Option 2: Cloud install: (I just want to write blogs..)
|
|
||||||
|
|
||||||
Step 1). Make efforts to fork this present repo into your own account.
|
|
||||||
|
|
||||||
Step 2). Follow this guide: <br>
|
|
||||||
https://docs.replit.com/programming-ide/using-git-on-replit/running-github-repositories-replit
|
|
||||||
|
|
||||||
|
|
||||||
### Option 3: Web URL: (Clickty Clickty Website, Free..)
|
### Option 3: Web URL: (Clickty Clickty Website, Free..)
|
||||||
|
|
||||||
Step 1). Error 404: Page not found.
|
Step 1). Error 404: Page not found.
|
||||||
|
|||||||
476
alwrity.py
476
alwrity.py
@@ -1,13 +1,18 @@
|
|||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import requests
|
|
||||||
import typer
|
import typer
|
||||||
from PyInquirer import prompt
|
from prompt_toolkit.shortcuts import checkboxlist_dialog, message_dialog, input_dialog
|
||||||
|
from prompt_toolkit import prompt
|
||||||
|
from prompt_toolkit.styles import Style
|
||||||
|
from prompt_toolkit.shortcuts import radiolist_dialog
|
||||||
|
from prompt_toolkit.clipboard.pyperclip import PyperclipClipboard
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
import requests
|
||||||
from rich import print
|
from rich import print
|
||||||
|
from rich.console import Console
|
||||||
from rich.text import Text
|
from rich.text import Text
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
load_dotenv(Path('.env'))
|
load_dotenv(Path('.env'))
|
||||||
|
|
||||||
app = typer.Typer()
|
app = typer.Typer()
|
||||||
@@ -19,105 +24,71 @@ from lib.ai_writers.keywords_to_blog import write_blog_from_keywords
|
|||||||
|
|
||||||
def prompt_for_time_range():
|
def prompt_for_time_range():
|
||||||
os.system("clear" if os.name == "posix" else "cls")
|
os.system("clear" if os.name == "posix" else "cls")
|
||||||
print("\n🙋 If you researching keywords that are recent than use accordingly, Default is Anytime.\n")
|
print("\n🙋 If you're researching keywords that are recent, use accordingly. Default is Anytime.\n")
|
||||||
questions = [
|
choices = [("anytime", "Anytime"), ("past year", "Past Year"), ("past month", "Past Month"),
|
||||||
{
|
("past week", "Past Week"), ("past day", "Past Day")]
|
||||||
'type': 'list',
|
selected_time_range = radiolist_dialog(title="Select Search result time range:", values=choices).run()
|
||||||
'name': 'time_range',
|
return selected_time_range[0] if selected_time_range else None
|
||||||
'message': '👋 Select Search result time range:',
|
|
||||||
'choices': ["anytime", "past year", "past month", "past week", "past day"],
|
|
||||||
'default': 'anytime'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
answers = prompt(questions)
|
|
||||||
return answers['time_range']
|
|
||||||
|
|
||||||
def write_blog_options():
|
def write_blog_options():
|
||||||
questions = [
|
choices = [
|
||||||
{
|
("Keywords", "Keywords"),
|
||||||
'type': 'list',
|
("Audio YouTube", "Audio YouTube"),
|
||||||
'name': 'blog_type',
|
("Programming", "Programming"),
|
||||||
'message': '📝 Choose a blog type:',
|
("Scholar", "Scholar"),
|
||||||
'choices': ['Keywords', 'Audio YouTube', 'Programming',
|
("News/TBD", "News/TBD"),
|
||||||
'Scholar', 'News/TBD','Finance/TBD', 'Quit'],
|
("Finance/TBD", "Finance/TBD"),
|
||||||
}
|
("Quit", "Quit")
|
||||||
]
|
]
|
||||||
answers = prompt(questions)
|
selected_blog_type = radiolist_dialog(title="Choose a blog type:", values=choices).run()
|
||||||
return answers['blog_type']
|
return selected_blog_type if selected_blog_type else None
|
||||||
|
|
||||||
|
|
||||||
@app.command()
|
@app.command()
|
||||||
def start_interactive_mode():
|
def start_interactive_mode():
|
||||||
"""
|
|
||||||
This function is executed when no command is provided.
|
|
||||||
It prompts the user to choose between "Write Blog" and "Do Web Research."
|
|
||||||
"""
|
|
||||||
os.system("clear" if os.name == "posix" else "cls")
|
os.system("clear" if os.name == "posix" else "cls")
|
||||||
text = Text()
|
text = "_______________________________________________________________________\n"
|
||||||
text.append("_______________________________________________________________________")
|
text += "\n⚠️ Alert! 💥❓💥\n"
|
||||||
text.append("\n⚠️ Alert! 💥❓💥\n", style="bold red")
|
text += "If you know what to write, choose 'Write Blog'\n"
|
||||||
text.append("If you know what to write, choose 'Write Blog'\n", style="bold blue")
|
text += "If unsure, let's 'do web research' to write on\n"
|
||||||
text.append("If unsure, lets 'do web research' to write on\n", style="bold red")
|
text += "If Testing-it-out/getting-started, choose 'Blog Tools\n"
|
||||||
text.append("If Testing-it-out/getting-started, choose 'Blog Tools\n", style="bold green")
|
text += "_______________________________________________________________________\n"
|
||||||
text.append("_______________________________________________________________________\n")
|
|
||||||
|
|
||||||
print(text)
|
print(text)
|
||||||
|
|
||||||
questions = [
|
choices = [
|
||||||
{
|
("Write Blog", "Write Blog"),
|
||||||
'type': 'list',
|
("Do keyword Research", "Do keyword Research"),
|
||||||
'name': 'mode',
|
("Create Blog Images", "Create Blog Images"),
|
||||||
'message': 'Choose an option:',
|
("Competitor Analysis", "Competitor Analysis"),
|
||||||
'choices': ['Write Blog', 'Do keyword Research', 'Create Blog Images',
|
("Blog Tools", "Blog Tools"),
|
||||||
'Competitor Analysis', 'Blog Tools', 'Social Media', 'Quit'],
|
("Social Media", "Social Media"),
|
||||||
}
|
("Quit", "Quit")
|
||||||
]
|
]
|
||||||
answers = prompt(questions)
|
mode = radiolist_dialog(title="Choose an option:", values=choices).run()
|
||||||
mode = answers['mode']
|
if mode:
|
||||||
if mode == 'Write Blog':
|
if mode == 'Write Blog':
|
||||||
write_blog()
|
write_blog()
|
||||||
elif mode == 'Do keyword Research':
|
elif mode == 'Do keyword Research':
|
||||||
do_web_research()
|
do_web_research()
|
||||||
elif mode == 'Create Blog Images':
|
elif mode == 'Create Blog Images':
|
||||||
faq_generator()
|
faq_generator()
|
||||||
elif mode == 'Competitor Analysis':
|
elif mode == 'Competitor Analysis':
|
||||||
# Metaphor similar search
|
competitor_analysis()
|
||||||
competitor_analysis()
|
elif mode == 'Blog Tools':
|
||||||
elif mode == 'Recent News Summarizer':
|
blog_tools()
|
||||||
print("""TBD: 1. Get tavily News.
|
elif mode == 'Social Media':
|
||||||
2. Get metaphor news.
|
print("""
|
||||||
3. Get from NewsApi
|
#whatsapp
|
||||||
4. Get YOU.com News.""")
|
#instagram
|
||||||
recent_news_summarizer()
|
#youtube
|
||||||
elif mode == 'Blog Tools':
|
#twitter/X
|
||||||
blog_tools()
|
#Linked-in posts
|
||||||
elif mode == 'Social Media':
|
""")
|
||||||
print("""
|
raise typer.Exit()
|
||||||
#whatsapp
|
elif mode == 'Quit':
|
||||||
#instagram
|
typer.echo("Exiting, Getting Lost!")
|
||||||
#youtube
|
raise typer.Exit()
|
||||||
#twitter/X
|
|
||||||
#Linked-in posts
|
|
||||||
""")
|
|
||||||
raise typer.Exit()
|
|
||||||
elif mode == 'Quit':
|
|
||||||
typer.echo("Exiting, F*** Off!")
|
|
||||||
raise typer.Exit()
|
|
||||||
|
|
||||||
|
|
||||||
def get_api_key(api_key: str, api_description: str):
|
|
||||||
"""
|
|
||||||
Ask the user to input the missing API key and add it to the .env file.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
api_key (str): The name of the API key variable.
|
|
||||||
api_description (str): The description of the API key.
|
|
||||||
"""
|
|
||||||
user_input = typer.prompt(f"{api_description} is missing. Please enter {api_key} API Key:")
|
|
||||||
with open(".env", "a") as env_file:
|
|
||||||
env_file.write(f"{api_key}={user_input}\n")
|
|
||||||
print(f"✅ {api_description} API Key added to .env file.")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def check_search_apis():
|
def check_search_apis():
|
||||||
@@ -125,6 +96,10 @@ def check_search_apis():
|
|||||||
Check if necessary environment variables are present.
|
Check if necessary environment variables are present.
|
||||||
Display messages with links on how to get them if not present.
|
Display messages with links on how to get them if not present.
|
||||||
"""
|
"""
|
||||||
|
# Create a Rich console
|
||||||
|
console = Console()
|
||||||
|
|
||||||
|
# Use rich.print for styling and hyperlinking
|
||||||
print("\n\n🙋♂️ 🙋♂️ Before doing web research, ensure the following API keys are available:")
|
print("\n\n🙋♂️ 🙋♂️ Before doing web research, ensure the following API keys are available:")
|
||||||
print("Blogen uses Basic, Semantic, Neural web search using above APIs for contextual blog generation.\n")
|
print("Blogen uses Basic, Semantic, Neural web search using above APIs for contextual blog generation.\n")
|
||||||
|
|
||||||
@@ -139,46 +114,33 @@ def check_search_apis():
|
|||||||
with typer.progressbar(api_keys.items(), label="Checking API keys", length=len(api_keys)) as progress:
|
with typer.progressbar(api_keys.items(), label="Checking API keys", length=len(api_keys)) as progress:
|
||||||
for key, description in progress:
|
for key, description in progress:
|
||||||
if os.getenv(key) is None:
|
if os.getenv(key) is None:
|
||||||
print(f"[bold red]✖ 🚫 {key} is missing:[/bold red] [link={key}]Get {key} API Key[/link]")
|
# Use rich.print for styling and hyperlinking
|
||||||
|
print(f"[bold red]✖ 🚫 {key} is missing:[/bold red] [blue underline]Get {key} API Key[/blue underline]")
|
||||||
|
typer.echo(f"[bold red]✖ 🚫 {key} is missing:[/bold red] [link={key}]Get {key} API Key[/link]")
|
||||||
missing_keys.append((key, description))
|
missing_keys.append((key, description))
|
||||||
|
|
||||||
if missing_keys:
|
if missing_keys:
|
||||||
print("\nMost are Free APIs and really worth your while signing up for them.")
|
print("\nMost are Free APIs and really worth your while signing up for them.")
|
||||||
print(":pile_of_poo: :pile_of_poo: GO GET THEM, on above urls. [bold red]")
|
print("💩💩💩: GO GET THEM, on above urls. [bold red]")
|
||||||
print("Note: They offer free/limited api calls, so we use most of them to have a lot of free api calls.")
|
#print("Note: They offer free/limited api calls, so we use most of them to have a lot of free api calls.")
|
||||||
print("\n[bold red]TBD: Provide option to use user defined search engines.\n")
|
|
||||||
for key, description in missing_keys:
|
for key, description in missing_keys:
|
||||||
get_api_key(key, description)
|
get_api_key(key, description)
|
||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def check_llm_environs():
|
def get_api_key(api_key: str, api_description: str):
|
||||||
""" Function to check which LLM api is given. """
|
"""
|
||||||
gpt_provider = os.getenv("GPT_PROVIDER")
|
Ask the user to input the missing API key and add it to the .env file.
|
||||||
|
|
||||||
if gpt_provider == "google":
|
|
||||||
api_key_var = "GEMINI_API_KEY"
|
|
||||||
missing_api_msg = f"To get your {api_key_var}, please visit: https://aistudio.google.com/app/apikey"
|
|
||||||
elif gpt_provider == "openai":
|
|
||||||
api_key_var = "OPENAI_API_KEY"
|
|
||||||
missing_api_msg = "To get your OpenAI API key, please visit: https://openai.com/blog/openai-api"
|
|
||||||
else:
|
|
||||||
typer.echo("Unsupported GPT provider specified in GPT_PROVIDER environment variable.")
|
|
||||||
return
|
|
||||||
|
|
||||||
if os.getenv(api_key_var) is None:
|
Args:
|
||||||
typer.echo(f"The {api_key_var} environment variable is missing.")
|
api_key (str): The name of the API key variable.
|
||||||
typer.echo(missing_api_msg)
|
api_description (str): The description of the API key.
|
||||||
api_key = typer.prompt(f"Please enter your {api_key_var} API Key:")
|
"""
|
||||||
# Update .env file
|
user_input = typer.prompt(f"\n🙆🙆Please enter {api_key} API Key:")
|
||||||
with open(".env", "a") as env_file:
|
with open(".env", "a") as env_file:
|
||||||
env_file.write(f"{api_key_var}={api_key}\n")
|
env_file.write(f"{api_key}={user_input}\n")
|
||||||
typer.echo(f"{api_key_var} API Key added to .env file.")
|
print(f"✅ {api_description} API Key added to .env file.")
|
||||||
return
|
|
||||||
|
|
||||||
if gpt_provider == "openai" and os.getenv("OPENAI_API_KEY") is None:
|
|
||||||
typer.echo("To get your OpenAI API key, please visit: https://openai.com/blog/openai-api")
|
|
||||||
|
|
||||||
|
|
||||||
def faq_generator():
|
def faq_generator():
|
||||||
@@ -186,46 +148,45 @@ def faq_generator():
|
|||||||
|
|
||||||
|
|
||||||
def blog_tools():
|
def blog_tools():
|
||||||
""" Blogging Aid Tools """
|
|
||||||
os.system("clear" if os.name == "posix" else "cls")
|
os.system("clear" if os.name == "posix" else "cls")
|
||||||
text = Text()
|
text = "_______________________________________________________________________\n"
|
||||||
text.append("_______________________________________________________________________")
|
text += "\n⚠️ Alert! 💥❓💥\n"
|
||||||
text.append("\n⚠️ Alert! 💥❓💥\n", style="bold red")
|
text += "Collection of Helpful Blogging Tools, powered by LLMs.\n"
|
||||||
text.append("Collection of Helpful Blogging Tools, powered by LLMs.\n", style="bold green")
|
text += "_______________________________________________________________________\n"
|
||||||
text.append("_______________________________________________________________________\n")
|
|
||||||
|
|
||||||
print(text)
|
print(text)
|
||||||
|
|
||||||
# https://developers.google.com/speed/docs/insights/v5/get-started
|
choices = [
|
||||||
questions = [
|
("Write Blog Title", "Write Blog Title"),
|
||||||
{
|
("Write Blog Meta Description", "Write Blog Meta Description"),
|
||||||
'type': 'list',
|
("Write Blog Introduction", "Write Blog Introduction"),
|
||||||
'name': 'mode',
|
("Write Blog conclusion", "Write Blog conclusion"),
|
||||||
'message': 'Choose a Blogging Tool:',
|
("Write Blog Outline", "Write Blog Outline"),
|
||||||
'choices': ['Write Blog Title', 'Write Blog Meta Description', 'Write Blog Introduction',
|
("Generate Blog FAQs", "Generate Blog FAQs"),
|
||||||
'Write Blog conclusion', 'Write Blog Outline', 'Generate Blog FAQs', 'Research blog referances',
|
("Research blog references", "Research blog references"),
|
||||||
'Convert Blog To HTML', 'Convert Blog To Markdown', 'Blog Proof Reader',
|
("Convert Blog To HTML", "Convert Blog To HTML"),
|
||||||
'Get Blog Tags', 'Get blog categories', 'Get Blog Code Examples', 'Check WebPage Performance',
|
("Convert Blog To Markdown", "Convert Blog To Markdown"),
|
||||||
'Quit/Exit',],
|
("Blog Proof Reader", "Blog Proof Reader"),
|
||||||
}
|
("Get Blog Tags", "Get Blog Tags"),
|
||||||
|
("Get blog categories", "Get blog categories"),
|
||||||
|
("Get Blog Code Examples", "Get Blog Code Examples"),
|
||||||
|
("Check WebPage Performance", "Check WebPage Performance"),
|
||||||
|
("Quit/Exit", "Quit/Exit")
|
||||||
]
|
]
|
||||||
answers = prompt(questions)
|
selected_tool = radiolist_dialog(title="Choose a Blogging Tool:", values=choices).run()
|
||||||
mode = answers['mode']
|
if selected_tool:
|
||||||
if mode == 'Write Blog Title':
|
tool = selected_tool[0]
|
||||||
return
|
if tool == 'Write Blog Title':
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def competitor_analysis():
|
def competitor_analysis():
|
||||||
""" Do metaphor similar search """
|
text = "_______________________________________________________________________\n"
|
||||||
text = Text()
|
text += "\n⚠️ Alert! 💥❓💥\n"
|
||||||
text.append("_______________________________________________________________________")
|
text += "Provide competitor's URL, get details of similar/alternative companies.\n"
|
||||||
text.append("\n⚠️ Alert! 💥❓💥\n", style="bold red")
|
text += "Usecases: Know similar companies and alternatives, to given URL\n"
|
||||||
text.append("Provide competitor's URL, get details of similar/alternative companies.\n", style="bold red")
|
text += "_______________________________________________________________________\n"
|
||||||
text.append("Usecases: Know similar companies and alternatives, to given URL\n", style="bold blue")
|
|
||||||
text.append("_______________________________________________________________________\n")
|
|
||||||
print(text)
|
print(text)
|
||||||
similar_url = typer.prompt(f"Enter Valid URL to get web analysis")
|
similar_url = prompt("Enter Valid URL to get web analysis")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
metaphor_find_similar(similar_url)
|
metaphor_find_similar(similar_url)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
@@ -234,96 +195,148 @@ def competitor_analysis():
|
|||||||
|
|
||||||
|
|
||||||
def write_blog():
|
def write_blog():
|
||||||
"""
|
|
||||||
Write Blog option with sub-options like Keywords, Audio YouTube, GitHub, and Scholar.
|
|
||||||
"""
|
|
||||||
blog_type = write_blog_options()
|
blog_type = write_blog_options()
|
||||||
|
if blog_type:
|
||||||
if blog_type == 'Keywords':
|
if blog_type == 'Keywords':
|
||||||
blog_from_keyword()
|
blog_from_keyword()
|
||||||
elif blog_type == 'Audio YouTube':
|
elif blog_type == 'Audio YouTube':
|
||||||
audio_youtube = typer.prompt("Enter YouTube URL for audio blog generation:")
|
audio_youtube = prompt("Enter YouTube URL for audio blog generation:")
|
||||||
print(f"Write audio blog based on YouTube URL: {audio_youtube}")
|
print(f"Write audio blog based on YouTube URL: {audio_youtube}")
|
||||||
elif blog_type == 'GitHub':
|
elif blog_type == 'GitHub':
|
||||||
github = typer.prompt("Enter GitHub URL, CSV file, or topic:")
|
github = prompt("Enter GitHub URL, CSV file, or topic:")
|
||||||
print(f"Write blog based on GitHub: {github}")
|
print(f"Write blog based on GitHub: {github}")
|
||||||
elif blog_type == 'Scholar':
|
elif blog_type == 'Scholar':
|
||||||
scholar = typer.prompt("Enter research papers keywords:")
|
scholar = prompt("Enter research papers keywords:")
|
||||||
print(f"Write blog based on scholar: {scholar}")
|
print(f"Write blog based on scholar: {scholar}")
|
||||||
elif blog_type == 'Quit':
|
elif blog_type == 'Quit':
|
||||||
typer.echo("Exiting, F*** Off!")
|
typer.echo("Exiting, Getting Lost..")
|
||||||
raise typer.Exit()
|
raise typer.Exit()
|
||||||
|
|
||||||
|
|
||||||
def blog_from_keyword():
|
def blog_from_keyword():
|
||||||
""" Write blog from given keyword. """
|
""" Input blog keywords, research and write a factual blog."""
|
||||||
print("Write blog based on keywords.")
|
while True:
|
||||||
check_llm_environs()
|
print("________________________________________________________________")
|
||||||
keywords = typer.prompt("Enter 'keywords/Blog Title' for blog generation:")
|
blog_keywords = input_dialog(
|
||||||
final_blog = write_blog_from_keywords(keywords)
|
title='Enter Keywords/Blog Title',
|
||||||
|
text='Shit in, Shit Out; Better keywords, better research, hence better content.\n👋 Enter keywords/Blog Title for blog generation:',
|
||||||
|
).run()
|
||||||
|
|
||||||
|
# If the user cancels, exit the loop
|
||||||
|
if blog_keywords is None:
|
||||||
|
break
|
||||||
|
if blog_keywords and len(blog_keywords.split()) >= 2:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
message_dialog(
|
||||||
|
title='Warning',
|
||||||
|
text='🚫 Blog keywords should be at least two words long. Please try again.'
|
||||||
|
).run()
|
||||||
|
if blog_keywords:
|
||||||
|
try:
|
||||||
|
write_blog_from_keywords(blog_keywords)
|
||||||
|
except Exception as err:
|
||||||
|
print(f"Failed to write blog on {blog_keywords}, Error: {err}\n")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
def do_web_research():
|
def do_web_research():
|
||||||
"""
|
""" Input keywords and do web research and present a report."""
|
||||||
Do Web Research option with time_range, search_keywords, and include_urls sub-options.
|
|
||||||
"""
|
|
||||||
if check_search_apis():
|
if check_search_apis():
|
||||||
while True:
|
while True:
|
||||||
print("________________________________________________________________")
|
print("________________________________________________________________")
|
||||||
search_keywords = typer.prompt("👋 Enter keywords for web research:")
|
search_keywords = input_dialog(
|
||||||
# Giving a single keywords, yields bad results.
|
title='Enter Search Keywords below:',
|
||||||
|
text='👋 Enter keywords for web research (Or keywords from your blog):',
|
||||||
|
).run()
|
||||||
if search_keywords and len(search_keywords.split()) >= 2:
|
if search_keywords and len(search_keywords.split()) >= 2:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
print("🚫 Search keywords should be at least three words long. Please try again.")
|
message_dialog(
|
||||||
|
title='Warning',
|
||||||
|
text='🚫 Search keywords should be at least three words long. Please try again.'
|
||||||
|
).run()
|
||||||
|
selected_time_range = prompt_for_time_range()
|
||||||
|
|
||||||
# Display available choices
|
# Display input dialog for similar search URL (optional)
|
||||||
# print("Choose from the following options:")
|
similar_url = input_dialog(
|
||||||
# search_keyword_choices = ["choice1", "choice2", "choice3"]
|
title="Enter a similar search URL",
|
||||||
# for i, choice in enumerate(search_keyword_choices, start=1):
|
text="👋 Enter a similar search URL (Optional: Enter to skip):\n🙋Usecases: Competitor Analysis Tool. 📡Discover similar companies, startups and technologies.",
|
||||||
# print(f"{i}. '{choice}'")
|
default="",
|
||||||
#
|
).run()
|
||||||
# choice_index = typer.prompt("Enter the NUMBER to choose which keywords to use:")
|
|
||||||
#
|
|
||||||
# try:
|
|
||||||
# choice_index = int(choice_index)
|
|
||||||
# if 1 <= choice_index <= len(search_keyword_choices):
|
|
||||||
# search_keywords = search_keyword_choices[choice_index - 1]
|
|
||||||
# break
|
|
||||||
# else:
|
|
||||||
# print("🚫 Invalid choice. Please try again.")
|
|
||||||
# except ValueError:
|
|
||||||
# print("🚫 Invalid input. Please enter a valid number.")
|
|
||||||
|
|
||||||
|
# Display input dialog for included URLs (optional)
|
||||||
print("________________________________________________________________")
|
include_urls = input_dialog(
|
||||||
time_range = prompt_for_time_range()
|
title="Enter URLs to include in the web search:",
|
||||||
|
text="👋 Enter comma-separated URLs to include in web research (press Enter to skip):\n🙋 If you wish to [bold]confine search[/bold] to certain domains like wikipedia etc.",
|
||||||
|
default="",
|
||||||
|
).run()
|
||||||
|
|
||||||
os.system("clear" if os.name == "posix" else "cls")
|
|
||||||
print("\n________________________________________________________________")
|
|
||||||
print("\n🙋 Include a [green]URL[/green] to get [bold]similar/semantic[/bold]. For example, competitor's url.")
|
|
||||||
print("📡 Usecases: Competitor Analysis Tool. Discover similar companies, startups and technologies.\n")
|
|
||||||
similar_url = typer.prompt("👋 Enter a similar search URL (press Enter to continue):", default="")
|
|
||||||
|
|
||||||
os.system("clear" if os.name == "posix" else "cls")
|
try:
|
||||||
print("\n________________________________________________________________")
|
print(f"🚀🎬🚀 [bold green]Starting web research on given keywords: {search_keywords}..")
|
||||||
print("\n🙋 If you wish to [bold]confine search[/bold] to certain domains like wikipedia etc.\n")
|
#print(f"Web Research: Time Range - {time_range}, Search Keywords - {search_keywords}, Include URLs - {include_urls}")
|
||||||
include_urls = typer.prompt("👋 Enter comma-separated URLs to include in web research (press Enter if none):", default="")
|
web_research_result = gpt_web_researcher(search_keywords,
|
||||||
|
time_range=selected_time_range,
|
||||||
try:
|
include_domains=include_urls,
|
||||||
print(f"🚀🚀 [bold green]Starting web research on given keywords: {search_keywords}..")
|
similar_url=similar_url)
|
||||||
#print(f"Web Research: Time Range - {time_range}, Search Keywords - {search_keywords}, Include URLs - {include_urls}")
|
except Exception as err:
|
||||||
web_research_result = gpt_web_researcher(search_keywords,
|
print(f"\n💥🤯 [bold red]ERROR 🤯 : Failed to do web research: {err}\n")
|
||||||
time_range=time_range,
|
|
||||||
include_domains=include_urls,
|
|
||||||
similar_url=similar_url)
|
def check_llm_environs():
|
||||||
except Exception as err:
|
""" Function to check which LLM api is given. """
|
||||||
print(f"\n💥🤯 [bold red]ERROR 🤯 : Failed to do web research: {err}\n")
|
# Check if GPT_PROVIDER is defined in .env file
|
||||||
|
gpt_provider = os.getenv("GPT_PROVIDER")
|
||||||
|
|
||||||
|
# Load .env file
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
# Disable unsupported GPT providers
|
||||||
|
supported_providers = ['google', 'openai', 'mistralai']
|
||||||
|
if gpt_provider is None or gpt_provider.lower() not in supported_providers:
|
||||||
|
#message_dialog(
|
||||||
|
# title="Unsupported GPT Provider",
|
||||||
|
# text="GPT_PROVIDER is not set or has an unsupported value."
|
||||||
|
#).run()
|
||||||
|
|
||||||
|
# Prompt user to select a provider
|
||||||
|
selected_provider = radiolist_dialog(
|
||||||
|
title='Select your preferred GPT provider:',
|
||||||
|
text="Please choose GPT provider Below:\n👺Google Gemini recommended, its 🆓.",
|
||||||
|
values=[
|
||||||
|
("Google", "google"),
|
||||||
|
("Openai", "openai"),
|
||||||
|
("MistralAI/WIP", "mistralai/WIP"),
|
||||||
|
("Ollama", "Ollama (TBD)")
|
||||||
|
]
|
||||||
|
).run()
|
||||||
|
if selected_provider:
|
||||||
|
gpt_provider = selected_provider
|
||||||
|
|
||||||
|
if gpt_provider.lower() == "google":
|
||||||
|
api_key_var = "GEMINI_API_KEY"
|
||||||
|
missing_api_msg = f"To get your {api_key_var}, please visit: https://aistudio.google.com/app/apikey"
|
||||||
|
elif gpt_provider.lower() == "openai":
|
||||||
|
api_key_var = "OPENAI_API_KEY"
|
||||||
|
missing_api_msg = "To get your OpenAI API key, please visit: https://openai.com/blog/openai-api"
|
||||||
|
elif gpt_provider.lower() == "mistralai":
|
||||||
|
api_key_var = "MISTRAL_API_KEY"
|
||||||
|
missing_api_msg = "To get your MistralAI API key, please visit: https://mistralai.com/api"
|
||||||
|
|
||||||
|
if os.getenv(api_key_var) is None:
|
||||||
|
# Ask for the API key
|
||||||
|
print(f"🚫The {api_key_var} is missing. {missing_api_msg}")
|
||||||
|
api_key = typer.prompt(f"\n🙆🙆Please enter {api_key_var} API Key:")
|
||||||
|
|
||||||
|
# Update .env file
|
||||||
|
with open(".env", "a") as env_file:
|
||||||
|
env_file.write(f"GPT_PROVIDER={gpt_provider.lower()}\n")
|
||||||
|
env_file.write(f"{api_key_var}={api_key}\n")
|
||||||
|
|
||||||
|
|
||||||
def check_internet():
|
def check_internet():
|
||||||
try:
|
try:
|
||||||
# Attempt to send a GET request to a well-known website
|
|
||||||
response = requests.get("http://www.google.com", timeout=20)
|
response = requests.get("http://www.google.com", timeout=20)
|
||||||
if not response.status_code == 200:
|
if not response.status_code == 200:
|
||||||
print("💥🤯 WTFish, Internet is NOT available. Enjoy the wilderness..")
|
print("💥🤯 WTFish, Internet is NOT available. Enjoy the wilderness..")
|
||||||
@@ -340,8 +353,25 @@ def check_internet():
|
|||||||
print("Internet: An error occurred:", e)
|
print("Internet: An error occurred:", e)
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def create_env_file():
|
||||||
|
env_file = Path('.env')
|
||||||
|
if not env_file.is_file():
|
||||||
|
try:
|
||||||
|
with open('.env', 'w') as f:
|
||||||
|
f.write('# Alwrity will add your environment variables here\n')
|
||||||
|
except Exception as e:
|
||||||
|
print(f"💥🤯Error occurred while creating .env file: {e}")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
print("Checking Internet, lets get the basics right.")
|
||||||
check_internet()
|
check_internet()
|
||||||
|
print("Create .env file, if not Present working directory")
|
||||||
|
create_env_file()
|
||||||
|
print("Check Metaphor, Tavily, YOU.com Search API keys.")
|
||||||
check_search_apis()
|
check_search_apis()
|
||||||
|
print("Check LLM details & AI Model to use.")
|
||||||
check_llm_environs()
|
check_llm_environs()
|
||||||
|
load_dotenv(Path('.env'))
|
||||||
app()
|
app()
|
||||||
|
|||||||
@@ -66,23 +66,23 @@ def google_search(query):
|
|||||||
Returns:
|
Returns:
|
||||||
list: List of search results based on the specified flag.
|
list: List of search results based on the specified flag.
|
||||||
"""
|
"""
|
||||||
try:
|
#try:
|
||||||
perform_serpapi_google_search(query)
|
# perform_serpapi_google_search(query)
|
||||||
logger.info(f"FIXME: Google serapi: {query}")
|
# logger.info(f"FIXME: Google serapi: {query}")
|
||||||
#return process_search_results(search_result)
|
# #return process_search_results(search_result)
|
||||||
except Exception as err:
|
#except Exception as err:
|
||||||
logger.error(f"ERROR: Check Here: https://serpapi.com/. Your requests may be over. {err}")
|
# logger.error(f"ERROR: Check Here: https://serpapi.com/. Your requests may be over. {err}")
|
||||||
|
|
||||||
# Retry with serper.dev
|
# Retry with serper.dev
|
||||||
try:
|
try:
|
||||||
logger.info("Trying Google search with Serper.dev: https://serper.dev/api-key")
|
logger.info("Trying Google search with Serper.dev: https://serper.dev/api-key")
|
||||||
search_result = perform_serperdev_google_search(query)
|
search_result = perform_serperdev_google_search(query)
|
||||||
process_search_results(search_result)
|
process_search_results(search_result)
|
||||||
|
return(search_result)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"Failed to do Google search with serper.dev: {err}")
|
logger.error(f"Failed to do Google search with serper.dev: {err}")
|
||||||
|
|
||||||
return(search_result)
|
|
||||||
|
|
||||||
# # Retry with BROWSERLESS API
|
# # Retry with BROWSERLESS API
|
||||||
# try:
|
# try:
|
||||||
# search_result = perform_browserless_google_search(query)
|
# search_result = perform_browserless_google_search(query)
|
||||||
@@ -118,7 +118,10 @@ def perform_serpapi_google_search(query, location="in"):
|
|||||||
try:
|
try:
|
||||||
# Check if API key is provided
|
# Check if API key is provided
|
||||||
if not os.getenv("SERPAPI_KEY"):
|
if not os.getenv("SERPAPI_KEY"):
|
||||||
raise ValueError("SERPAPI_KEY key is required for SerpApi")
|
#raise ValueError("SERPAPI_KEY key is required for SerpApi")
|
||||||
|
logger.error("SERPAPI_KEY key is required for SerpApi")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
# Create a GoogleSearch instance
|
# Create a GoogleSearch instance
|
||||||
search = GoogleSearch({
|
search = GoogleSearch({
|
||||||
@@ -164,7 +167,7 @@ def perform_serperdev_google_search(query):
|
|||||||
"q": query,
|
"q": query,
|
||||||
"gl": "in",
|
"gl": "in",
|
||||||
"hl": "en",
|
"hl": "en",
|
||||||
"num": 5,
|
"num": 10,
|
||||||
"autocorrect": True,
|
"autocorrect": True,
|
||||||
"page": 1,
|
"page": 1,
|
||||||
"type": "search",
|
"type": "search",
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ Note: Ensure that the required libraries are installed using 'pip install pytren
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import time # I wish
|
||||||
|
import random
|
||||||
import requests
|
import requests
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import sys
|
import sys
|
||||||
@@ -186,6 +188,7 @@ def get_related_topics_and_save_csv(search_keywords):
|
|||||||
data = pytrends.related_topics()
|
data = pytrends.related_topics()
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"Failed to get pytrends realted topics: {err}")
|
logger.error(f"Failed to get pytrends realted topics: {err}")
|
||||||
|
return
|
||||||
# Extract data from the result
|
# Extract data from the result
|
||||||
top_topics = list(data.values())[0]['top']
|
top_topics = list(data.values())[0]['top']
|
||||||
rising_topics = list(data.values())[0]['rising']
|
rising_topics = list(data.values())[0]['rising']
|
||||||
@@ -238,6 +241,8 @@ def get_results(query):
|
|||||||
try:
|
try:
|
||||||
query = urllib.parse.quote_plus(query)
|
query = urllib.parse.quote_plus(query)
|
||||||
response = get_source(f"https://suggestqueries.google.com/complete/search?output=chrome&hl=en&q={query}")
|
response = get_source(f"https://suggestqueries.google.com/complete/search?output=chrome&hl=en&q={query}")
|
||||||
|
time.sleep(random.uniform(0.1, 0.6))
|
||||||
|
|
||||||
if response:
|
if response:
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
results = json.loads(response.text)
|
results = json.loads(response.text)
|
||||||
@@ -501,6 +506,8 @@ def do_google_trends_analysis(search_term):
|
|||||||
else:
|
else:
|
||||||
all_the_keywords.append(suggestions_df['Keywords'].tolist())
|
all_the_keywords.append(suggestions_df['Keywords'].tolist())
|
||||||
all_the_keywords = ','.join([', '.join(filter(None, map(str, sublist))) for sublist in all_the_keywords])
|
all_the_keywords = ','.join([', '.join(filter(None, map(str, sublist))) for sublist in all_the_keywords])
|
||||||
|
# Generate a random sleep time between 2 and 3 seconds
|
||||||
|
time.sleep(random.uniform(2, 3))
|
||||||
|
|
||||||
#
|
#
|
||||||
# # FIXME: Get result from vision GPT. Fetch and visualize Google Trends data
|
# # FIXME: Get result from vision GPT. Fetch and visualize Google Trends data
|
||||||
@@ -510,12 +517,16 @@ def do_google_trends_analysis(search_term):
|
|||||||
# result_df = plot_interest_by_region(search_term)
|
# result_df = plot_interest_by_region(search_term)
|
||||||
#
|
#
|
||||||
# Display additional information
|
# Display additional information
|
||||||
result_df = get_related_topics_and_save_csv(search_term)
|
try:
|
||||||
# Extract 'Top' topic_title
|
result_df = get_related_topics_and_save_csv(search_term)
|
||||||
top_topic_title = result_df['topic_title'].values.tolist()
|
# Extract 'Top' topic_title
|
||||||
# Join each sublist into one string separated by comma
|
if result_df:
|
||||||
#top_topic_title = [','.join(filter(None, map(str, sublist))) for sublist in top_topic_title]
|
top_topic_title = result_df['topic_title'].values.tolist()
|
||||||
top_topic_title = ','.join([', '.join(filter(None, map(str, sublist))) for sublist in top_topic_title])
|
# Join each sublist into one string separated by comma
|
||||||
|
#top_topic_title = [','.join(filter(None, map(str, sublist))) for sublist in top_topic_title]
|
||||||
|
top_topic_title = ','.join([', '.join(filter(None, map(str, sublist))) for sublist in top_topic_title])
|
||||||
|
except Exception as err:
|
||||||
|
logger.error(f"Failed to get results from google trends related topics: {err}")
|
||||||
|
|
||||||
# TBD: Not getting great results OR unable to understand them.
|
# TBD: Not getting great results OR unable to understand them.
|
||||||
#all_the_keywords += top_topic_title
|
#all_the_keywords += top_topic_title
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import json
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import sys
|
import sys
|
||||||
from typing import List, NamedTuple
|
from typing import List, NamedTuple
|
||||||
from loguru import logger
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from ..gpt_providers.gemini_pro_text import gemini_text_response
|
from ..gpt_providers.gemini_pro_text import gemini_text_response
|
||||||
@@ -17,8 +16,9 @@ from .tavily_ai_search import get_tavilyai_results
|
|||||||
from .metaphor_basic_neural_web_search import metaphor_find_similar, metaphor_search_articles
|
from .metaphor_basic_neural_web_search import metaphor_find_similar, metaphor_search_articles
|
||||||
from .google_serp_search import google_search
|
from .google_serp_search import google_search
|
||||||
from .google_trends_researcher import do_google_trends_analysis
|
from .google_trends_researcher import do_google_trends_analysis
|
||||||
from .web_research_report import write_web_research_report
|
#from .web_research_report import write_web_research_report
|
||||||
|
|
||||||
|
from loguru import logger
|
||||||
# Configure logger
|
# Configure logger
|
||||||
logger.remove()
|
logger.remove()
|
||||||
logger.add(sys.stdout,
|
logger.add(sys.stdout,
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ def get_tavilyai_results(keywords, include_urls, search_depth="advanced"):
|
|||||||
# Retrieve API keys
|
# Retrieve API keys
|
||||||
api_key = os.getenv('TAVILY_API_KEY')
|
api_key = os.getenv('TAVILY_API_KEY')
|
||||||
if not api_key:
|
if not api_key:
|
||||||
raise ValueError("API keys for Tavily or OpenAI are not set.")
|
raise ValueError("API keys for Tavily is Not set.")
|
||||||
|
|
||||||
# Initialize Tavily client
|
# Initialize Tavily client
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
from langchain.adapters.openai import convert_openai_messages
|
import os
|
||||||
from langchain.chat_models import ChatOpenAI
|
|
||||||
|
|
||||||
from ..gpt_providers.gemini_pro_text import gemini_text_response
|
from ..gpt_providers.gemini_pro_text import gemini_text_response
|
||||||
|
|
||||||
|
|
||||||
def write_web_research_report(web_research, faq_questions, gpt_provider="gemini"):
|
def write_web_research_report(web_research, faq_questions):
|
||||||
""" """
|
""" """
|
||||||
|
gpt_provider = os.environ["GPT_PROVIDER"]
|
||||||
if "gemini" in gpt_provider:
|
if "gemini" in gpt_provider:
|
||||||
prompt = ["You are an SEO and marketing expert, who writes unique, factual and comprehensive research reports."
|
prompt = ["You are an SEO and marketing expert, who writes unique, factual and comprehensive research reports."
|
||||||
"I will provide you web research report as json data and a list of related FAQ questions."
|
"I will provide you web research report as json data and a list of related FAQ questions."
|
||||||
|
|||||||
@@ -34,14 +34,14 @@ def write_blog_google_serp(search_keyword, search_results):
|
|||||||
Google search Result: "{search_results}"
|
Google search Result: "{search_results}"
|
||||||
"""
|
"""
|
||||||
logger.info("Generating blog and FAQs from web search result.")
|
logger.info("Generating blog and FAQs from web search result.")
|
||||||
if 'google' in gpt_providers:
|
if 'google' in gpt_providers.lower():
|
||||||
try:
|
try:
|
||||||
response = gemini_text_response(prompt)
|
response = gemini_text_response(prompt)
|
||||||
return response
|
return response
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"Failed to get response from gemini: {err}")
|
logger.error(f"Failed to get response from gemini: {err}")
|
||||||
raise err
|
raise err
|
||||||
elif 'openai' in gpt_providers:
|
elif 'openai' in gpt_providers.lower():
|
||||||
try:
|
try:
|
||||||
logger.info("Calling OpenAI LLM.")
|
logger.info("Calling OpenAI LLM.")
|
||||||
response = openai_chatgpt(prompt)
|
response = openai_chatgpt(prompt)
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ def blog_with_keywords(blog, keywords):
|
|||||||
list of keywords: '{keywords}'
|
list of keywords: '{keywords}'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if 'google' in gpt_providers:
|
if 'google' in gpt_providers.lower():
|
||||||
prompt = f"""You are an expert copywriter specializing in content optimization for SEO.
|
prompt = f"""You are an expert copywriter specializing in content optimization for SEO.
|
||||||
I will provide you with my 'blog content' and 'list of keywords' on the same topic.
|
I will provide you with my 'blog content' and 'list of keywords' on the same topic.
|
||||||
Your task is to write an original blog, using the given keywords and blog content.
|
Your task is to write an original blog, using the given keywords and blog content.
|
||||||
@@ -39,7 +39,6 @@ def blog_with_keywords(blog, keywords):
|
|||||||
Always, include figures, data, results from given content.
|
Always, include figures, data, results from given content.
|
||||||
It is important that your blog is original and unique. It should be highly readable and SEO optimized.
|
It is important that your blog is original and unique. It should be highly readable and SEO optimized.
|
||||||
|
|
||||||
|
|
||||||
Blog content: '{blog}'
|
Blog content: '{blog}'
|
||||||
list of keywords: '{keywords}'
|
list of keywords: '{keywords}'
|
||||||
"""
|
"""
|
||||||
@@ -49,7 +48,7 @@ def blog_with_keywords(blog, keywords):
|
|||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"Failed to get response from gemini: {err}")
|
logger.error(f"Failed to get response from gemini: {err}")
|
||||||
raise err
|
raise err
|
||||||
elif 'openai' in gpt_providers:
|
elif 'openai' in gpt_providers.lower():
|
||||||
try:
|
try:
|
||||||
logger.info("Calling OpenAI LLM.")
|
logger.info("Calling OpenAI LLM.")
|
||||||
response = openai_chatgpt(prompt)
|
response = openai_chatgpt(prompt)
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ def blog_with_research(report, blog):
|
|||||||
"""Combine the given online research and gpt blog content"""
|
"""Combine the given online research and gpt blog content"""
|
||||||
gpt_providers = os.environ["GPT_PROVIDER"]
|
gpt_providers = os.environ["GPT_PROVIDER"]
|
||||||
prompt = f"""
|
prompt = f"""
|
||||||
You are an expert copywriter specializing in content optimization for SEO.
|
You are an expert copywriter specializing in SEO content optimization for blogs.
|
||||||
I will provide you with a 'research report' and a 'blog content' on the same topic.
|
I will provide you with a 'research report' and a 'blog content' on the same topic.
|
||||||
Your task is to transform and combine the given research and blog content into a well-structured markdown, unique
|
Your task is to transform and combine the given 'research report' and 'blog content' into a well-structured, unique
|
||||||
and engaging blog article.
|
and original blog article.
|
||||||
|
|
||||||
Your objectives include:
|
Your objectives include:
|
||||||
1. Master the report and blog content: Understand main ideas, key points, and the core message.
|
1. Master the report and blog content: Understand main ideas, key points, and the core message.
|
||||||
@@ -47,11 +47,11 @@ def blog_with_research(report, blog):
|
|||||||
that will rank well in search engine results and engage readers effectively.
|
that will rank well in search engine results and engage readers effectively.
|
||||||
|
|
||||||
Create a blog post, in markdown, from the given research report and blog content below.
|
Create a blog post, in markdown, from the given research report and blog content below.
|
||||||
Research report: {report}
|
Research report: '{report}'
|
||||||
Blog content: {blog}
|
Blog content: '{blog}'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if 'google' in gpt_providers:
|
if 'google' in gpt_providers.lower():
|
||||||
prompt = f"""You are an expert copywriter specializing in content optimization for SEO.
|
prompt = f"""You are an expert copywriter specializing in content optimization for SEO.
|
||||||
I will provide you with my 'research report' and 'blog content' on the same topic.
|
I will provide you with my 'research report' and 'blog content' on the same topic.
|
||||||
Your task is to transform and combine the given research and blog content into a blog article.
|
Your task is to transform and combine the given research and blog content into a blog article.
|
||||||
@@ -70,7 +70,7 @@ def blog_with_research(report, blog):
|
|||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"Failed to get response from gemini: {err}")
|
logger.error(f"Failed to get response from gemini: {err}")
|
||||||
raise err
|
raise err
|
||||||
elif 'openai' in gpt_providers:
|
elif 'openai' in gpt_providers.lower():
|
||||||
try:
|
try:
|
||||||
logger.info("Calling OpenAI LLM.")
|
logger.info("Calling OpenAI LLM.")
|
||||||
response = openai_chatgpt(prompt)
|
response = openai_chatgpt(prompt)
|
||||||
@@ -78,3 +78,6 @@ def blog_with_research(report, blog):
|
|||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"failed to get response from Openai: {err}")
|
logger.error(f"failed to get response from Openai: {err}")
|
||||||
raise err
|
raise err
|
||||||
|
else:
|
||||||
|
logger.error(f"Unrecognised/Un-Supoorted GPT_PROVIDER: {gpt_providers}\n")
|
||||||
|
return
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import sys
|
import sys
|
||||||
|
import os
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from ..gpt_providers.openai_chat_completion import openai_chatgpt
|
from ..gpt_providers.openai_chat_completion import openai_chatgpt
|
||||||
@@ -13,9 +14,9 @@ logger.add(sys.stdout,
|
|||||||
|
|
||||||
|
|
||||||
# FIXME: Provide num_blogs, num_faqs as inputs.
|
# FIXME: Provide num_blogs, num_faqs as inputs.
|
||||||
def get_blog_sections_from_websearch(search_keyword, search_results, gpt_providers="gemini"):
|
def get_blog_sections_from_websearch(search_keyword, search_results):
|
||||||
"""Combine the given online research and gpt blog content"""
|
"""Combine the given online research and gpt blog content"""
|
||||||
|
gpt_providers = os.environ["GPT_PROVIDER"]
|
||||||
prompt = f"""
|
prompt = f"""
|
||||||
As a SEO expert and content writer, I will provide you with a search keyword and its google search result.
|
As a SEO expert and content writer, I will provide you with a search keyword and its google search result.
|
||||||
Your task is to write a blog title and 5 blog sub titles, from the given google search result.
|
Your task is to write a blog title and 5 blog sub titles, from the given google search result.
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
from textwrap import dedent
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
@@ -32,41 +33,42 @@ def write_blog_from_keywords(search_keywords, url=None):
|
|||||||
# TBD: Keeping the results directory as fixed, for now.
|
# TBD: Keeping the results directory as fixed, for now.
|
||||||
os.environ["SEARCH_SAVE_FILE"] = os.path.join(os.getcwd(), "workspace", "web_research_reports",
|
os.environ["SEARCH_SAVE_FILE"] = os.path.join(os.getcwd(), "workspace", "web_research_reports",
|
||||||
search_keywords.replace(" ", "_") + "_" + datetime.now().strftime("%Y-%m-%d_%H-%M-%S"))
|
search_keywords.replace(" ", "_") + "_" + datetime.now().strftime("%Y-%m-%d_%H-%M-%S"))
|
||||||
logger.info(f"Researching and Writing Blog on keywords: {search_keywords}")
|
|
||||||
# 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 = ""
|
blog_markdown_str = ""
|
||||||
example_blog_titles = []
|
example_blog_titles = []
|
||||||
|
|
||||||
|
logger.info(f"Researching and Writing Blog on keywords: {search_keywords}")
|
||||||
# Call on the got-researcher, tavily apis for this. Do google search for organic competition.
|
# Call on the got-researcher, tavily apis for this. Do google search for organic competition.
|
||||||
google_search_result, g_titles = do_google_serp_search(search_keywords)
|
google_search_result, g_titles = do_google_serp_search(search_keywords)
|
||||||
example_blog_titles.append(g_titles)
|
example_blog_titles.append(g_titles)
|
||||||
blog_markdown_str = write_blog_google_serp(search_keywords, google_search_result)
|
blog_markdown_str = write_blog_google_serp(search_keywords, google_search_result)
|
||||||
# logger.info/check the final blog content.
|
# logger.info/check the final blog content.
|
||||||
logger.info(f"Final blog content: {blog_markdown_str}")
|
logger.info(f"######### Blog content Google SERP research: ###########\n\n{blog_markdown_str}\n\n")
|
||||||
|
|
||||||
# Do Tavily AI research to augument the above blog.
|
# Do Tavily AI research to augument the above blog.
|
||||||
tavily_search_result, t_titles = do_tavily_ai_search(search_keywords)
|
tavily_search_result, t_titles = do_tavily_ai_search(search_keywords)
|
||||||
example_blog_titles.append(t_titles)
|
example_blog_titles.append(t_titles)
|
||||||
blog_markdown_str = blog_with_research(blog_markdown_str, tavily_search_result)
|
if tavily_search_result:
|
||||||
logger.info(f"Final blog content: {blog_markdown_str}")
|
blog_markdown_str = blog_with_research(blog_markdown_str, tavily_search_result)
|
||||||
|
logger.info(f"######### Blog content after Tavily AI research: ######### \n\n{blog_markdown_str}\n\n")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Do Metaphor/Exa AI search.
|
# Do Metaphor/Exa AI search.
|
||||||
metaphor_search_result, m_titles = do_metaphor_ai_research(search_keywords)
|
metaphor_search_result, m_titles = do_metaphor_ai_research(search_keywords)
|
||||||
example_blog_titles.append(m_titles)
|
example_blog_titles.append(m_titles)
|
||||||
blog_markdown_str = blog_with_research(blog_markdown_str, metaphor_search_result)
|
blog_markdown_str = blog_with_research(blog_markdown_str, metaphor_search_result)
|
||||||
logger.info(f"Final blog content: {blog_markdown_str}")
|
logger.info(f"######## Blog content after EXA AI research: ########## \n\n{blog_markdown_str}\n\n")
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"Failed to do Metaphor AI search: {err}")
|
logger.error(f"Failed to do Metaphor AI search: {err}")
|
||||||
|
|
||||||
# Do Google trends analysis and combine with latest blog.
|
# Do Google trends analysis and combine with latest blog.
|
||||||
try:
|
try:
|
||||||
pytrends_search_result = do_google_pytrends_analysis(search_keywords)
|
pytrends_search_result = do_google_pytrends_analysis(search_keywords)
|
||||||
|
logger.info(f"Google Trends keywords to use in the blog: {pytrends_search_result}\n")
|
||||||
blog_markdown_str = blog_with_keywords(blog_markdown_str, pytrends_search_result)
|
blog_markdown_str = blog_with_keywords(blog_markdown_str, pytrends_search_result)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"Failed to do Google Trends Analysis:{err}")
|
logger.error(f"Failed to do Google Trends Analysis:{err}")
|
||||||
|
logger.info(f"########### Blog Content After Google Trends Analysis:######### \n {blog_markdown_str}\n\n")
|
||||||
blog_markdown_str = blog_proof_editor(blog_markdown_str, search_keywords)
|
|
||||||
logger.info(f"Final blog content: {blog_markdown_str}")
|
|
||||||
|
|
||||||
# Combine YOU.com RAG search with the latest blog content.
|
# Combine YOU.com RAG search with the latest blog content.
|
||||||
#you_rag_result = get_rag_results(search_keywords)
|
#you_rag_result = get_rag_results(search_keywords)
|
||||||
@@ -74,6 +76,8 @@ def write_blog_from_keywords(search_keywords, url=None):
|
|||||||
#blog_markdown_str = blog_with_research(blog_markdown_str, you_search_result)
|
#blog_markdown_str = blog_with_research(blog_markdown_str, you_search_result)
|
||||||
#logger.info(f"Final blog content: {blog_markdown_str}")
|
#logger.info(f"Final blog content: {blog_markdown_str}")
|
||||||
|
|
||||||
|
blog_markdown_str = blog_proof_editor(blog_markdown_str, search_keywords)
|
||||||
|
|
||||||
blog_title, blog_meta_desc, blog_tags, blog_categories = blog_metadata(blog_markdown_str,
|
blog_title, blog_meta_desc, blog_tags, blog_categories = blog_metadata(blog_markdown_str,
|
||||||
search_keywords, example_blog_titles)
|
search_keywords, example_blog_titles)
|
||||||
|
|
||||||
@@ -92,4 +96,12 @@ def write_blog_from_keywords(search_keywords, url=None):
|
|||||||
# TBD: Save the blog content as a .md file. Markdown or HTML ?
|
# TBD: Save the blog content as a .md file. Markdown or HTML ?
|
||||||
save_blog_to_file(blog_markdown_str, blog_title, blog_meta_desc, blog_tags, blog_categories, generated_image_filepath)
|
save_blog_to_file(blog_markdown_str, blog_title, blog_meta_desc, blog_tags, blog_categories, generated_image_filepath)
|
||||||
|
|
||||||
|
blog_frontmatter = dedent(f"""\n\n\n\
|
||||||
|
---
|
||||||
|
title: {blog_title}
|
||||||
|
categories: [{blog_categories}]
|
||||||
|
tags: [{blog_tags}]
|
||||||
|
Meta description: {blog_meta_desc.replace(":", "-")}
|
||||||
|
---\n\n""")
|
||||||
|
logger.info(f"{blog_frontmatter}{blog_markdown_str}")
|
||||||
logger.info(f"\n\n ################ Finished writing Blog for : {search_keywords} #################### \n")
|
logger.info(f"\n\n ################ Finished writing Blog for : {search_keywords} #################### \n")
|
||||||
|
|||||||
@@ -27,13 +27,13 @@ def get_blog_categories(blog_article):
|
|||||||
The blog content is: '{blog_article}'"
|
The blog content is: '{blog_article}'"
|
||||||
"""
|
"""
|
||||||
logger.info("Generating blog categories for the given blog.")
|
logger.info("Generating blog categories for the given blog.")
|
||||||
if 'google' in gpt_providers:
|
if 'google' in gpt_providers.lower():
|
||||||
try:
|
try:
|
||||||
response = gemini_text_response(prompt)
|
response = gemini_text_response(prompt)
|
||||||
return response
|
return response
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"Failed to get response from gemini: {err}")
|
logger.error(f"Failed to get response from gemini: {err}")
|
||||||
elif 'openai' in gpt_providers:
|
elif 'openai' in gpt_providers.lower():
|
||||||
try:
|
try:
|
||||||
response = openai_chatgpt(prompt)
|
response = openai_chatgpt(prompt)
|
||||||
return response
|
return response
|
||||||
|
|||||||
@@ -27,13 +27,13 @@ def generate_blog_description(blog_content):
|
|||||||
Respond with only one of your best effort and do not include your explanations.
|
Respond with only one of your best effort and do not include your explanations.
|
||||||
Blog Content: '{blog_content}'"""
|
Blog Content: '{blog_content}'"""
|
||||||
|
|
||||||
if 'google' in gpt_providers:
|
if 'google' in gpt_providers.lower():
|
||||||
try:
|
try:
|
||||||
response = gemini_text_response(prompt)
|
response = gemini_text_response(prompt)
|
||||||
return response
|
return response
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error("Failed to get response from gemini.")
|
logger.error("Failed to get response from gemini.")
|
||||||
elif 'openai' in gpt_providers:
|
elif 'openai' in gpt_providers.lower():
|
||||||
try:
|
try:
|
||||||
response = openai_chatgpt(prompt)
|
response = openai_chatgpt(prompt)
|
||||||
return response
|
return response
|
||||||
|
|||||||
@@ -42,13 +42,22 @@ def generate_blog_title(blog_article, keywords=None, example_titles=None, num_ti
|
|||||||
Blog Keywords: '{keywords}'
|
Blog Keywords: '{keywords}'
|
||||||
Example Titles: '{example_titles}'
|
Example Titles: '{example_titles}'
|
||||||
"""
|
"""
|
||||||
if 'google' in gpt_providers:
|
elif not example_titles:
|
||||||
|
prompt = prompt = f"""As a SEO expert, I will provide you with my blog article.
|
||||||
|
Your task is to write {num_titles} blog title.
|
||||||
|
Follow SEO best practises to suggest the blog title.
|
||||||
|
Please keep the titles concise, not exceeding 60 words.
|
||||||
|
Respond with only {num_titles} title and no explanations.
|
||||||
|
Negative Keywords: Unvieling, unleash, power of. Dont use such words in your title.
|
||||||
|
Blog Article: '{keywords}'
|
||||||
|
"""
|
||||||
|
if 'google' in gpt_providers.lower():
|
||||||
try:
|
try:
|
||||||
response = gemini_text_response(prompt)
|
response = gemini_text_response(prompt)
|
||||||
return response
|
return response
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error(f"Failed to get response from gemini: {err}")
|
logger.error(f"Failed to get response from gemini: {err}")
|
||||||
elif 'openai' in gpt_providers:
|
elif 'openai' in gpt_providers.lower():
|
||||||
try:
|
try:
|
||||||
logger.info("Calling OpenAI LLM.")
|
logger.info("Calling OpenAI LLM.")
|
||||||
response = openai_chatgpt(prompt)
|
response = openai_chatgpt(prompt)
|
||||||
|
|||||||
@@ -25,13 +25,13 @@ def get_blog_tags(blog_article):
|
|||||||
for the given blog content. Only reply with comma separated values.
|
for the given blog content. Only reply with comma separated values.
|
||||||
Blog content: {blog_article}."""
|
Blog content: {blog_article}."""
|
||||||
logger.info("Generating Blog tags for the given blog post.")
|
logger.info("Generating Blog tags for the given blog post.")
|
||||||
if 'google' in gpt_providers:
|
if 'google' in gpt_providers.lower():
|
||||||
try:
|
try:
|
||||||
response = gemini_text_response(prompt)
|
response = gemini_text_response(prompt)
|
||||||
return response
|
return response
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.error("Failed to get response from gemini.")
|
logger.error("Failed to get response from gemini.")
|
||||||
elif 'openai' in gpt_providers:
|
elif 'openai' in gpt_providers.lower():
|
||||||
try:
|
try:
|
||||||
response = openai_chatgpt(prompt)
|
response = openai_chatgpt(prompt)
|
||||||
return response
|
return response
|
||||||
|
|||||||
@@ -26,19 +26,19 @@ def blog_proof_editor(blog_content, blog_keywords):
|
|||||||
4). Tone and Brand Alignment: Adjust the tone, voice, personality of given content to make it unique.
|
4). Tone and Brand Alignment: Adjust the tone, voice, personality of given content to make it unique.
|
||||||
5). Optimize Content Structure: Reorganize the content for a more impactful presentation,
|
5). Optimize Content Structure: Reorganize the content for a more impactful presentation,
|
||||||
including better paragraphing and transitions.
|
including better paragraphing and transitions.
|
||||||
6). Simplify given content: Simplify concepts and replace overly complex jargons and words.
|
6). Simplify content: Simplify concepts and replace overly complex words. Use simple english words.
|
||||||
7). Refine Overall Structure: Make structural changes to improve the overall impact of the content.
|
7). Refine Overall Structure: Make structural changes to improve the overall impact of the content.
|
||||||
|
|
||||||
\n\nMain keywords: '{blog_keywords}'
|
\n\nMain keywords: '{blog_keywords}'
|
||||||
My Blog: '{blog_content}'. """
|
My Blog: '{blog_content}'. """
|
||||||
|
|
||||||
if 'openai' in gpt_provider:
|
if 'openai' in gpt_provider.lower():
|
||||||
try:
|
try:
|
||||||
response = openai_chatgpt(prompt)
|
response = openai_chatgpt(prompt)
|
||||||
return response
|
return response
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
SystemError(f"Openai Error Blog Proof Reading: {err}")
|
SystemError(f"Openai Error Blog Proof Reading: {err}")
|
||||||
elif 'google' in gpt_provider:
|
elif 'google' in gpt_provider.lower():
|
||||||
try:
|
try:
|
||||||
response = gemini_text_response(prompt)
|
response = gemini_text_response(prompt)
|
||||||
return response
|
return response
|
||||||
|
|||||||
@@ -57,13 +57,13 @@ def convert_tomarkdown_format(blog_content, gpt_provider="openai"):
|
|||||||
|
|
||||||
Blog Post: '{blog_content}'"""
|
Blog Post: '{blog_content}'"""
|
||||||
|
|
||||||
if 'openai' in gpt_provider:
|
if 'openai' in gpt_provider.lower():
|
||||||
try:
|
try:
|
||||||
response = openai_chatgpt(prompt)
|
response = openai_chatgpt(prompt)
|
||||||
return response
|
return response
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
SystemError(f"Openai Error in converting to Markdown format.")
|
SystemError(f"Openai Error in converting to Markdown format.")
|
||||||
elif 'gemini' in gpt_provider:
|
elif 'gemini' in gpt_provider.lower():
|
||||||
|
|
||||||
prompt = f""" Convert the given blog post into well structured MARKDOWN content.
|
prompt = f""" Convert the given blog post into well structured MARKDOWN content.
|
||||||
Do not alter the given blog post.
|
Do not alter the given blog post.
|
||||||
|
|||||||
@@ -17,14 +17,8 @@ import openai
|
|||||||
from openai import OpenAI
|
from openai import OpenAI
|
||||||
from pytube import YouTube
|
from pytube import YouTube
|
||||||
import tempfile
|
import tempfile
|
||||||
from html2image import Html2Image
|
|
||||||
import datetime
|
import datetime
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
import moviepy.editor as mp
|
|
||||||
import requests
|
|
||||||
from moviepy.editor import AudioFileClip
|
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
|
||||||
|
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
logger.remove()
|
logger.remove()
|
||||||
|
|||||||
147
requirements.txt
147
requirements.txt
@@ -1,146 +1,25 @@
|
|||||||
openai
|
requests
|
||||||
PyInquirer
|
typer[all]
|
||||||
rich
|
rich
|
||||||
|
python-dotenv
|
||||||
|
loguru
|
||||||
|
openai
|
||||||
google.generativeai
|
google.generativeai
|
||||||
mistralai
|
mistralai
|
||||||
|
tenacity
|
||||||
|
tavily-python
|
||||||
tabulate
|
tabulate
|
||||||
metaphor_python
|
metaphor_python
|
||||||
exa_py
|
exa_py
|
||||||
GoogleNews
|
GoogleNews
|
||||||
sklearn
|
clint
|
||||||
|
scikit-learn
|
||||||
matplotlib
|
matplotlib
|
||||||
plotly
|
plotly
|
||||||
requests_html
|
requests_html
|
||||||
pytrends
|
pytrends
|
||||||
wordcloud
|
|
||||||
rich
|
|
||||||
aiofiles
|
|
||||||
typer[all]
|
|
||||||
aiohttp
|
|
||||||
aiosignal
|
|
||||||
annotated-types
|
|
||||||
anyio
|
|
||||||
args
|
|
||||||
async-timeout
|
|
||||||
asyncio
|
|
||||||
attrs
|
|
||||||
beautifulsoup4
|
|
||||||
blinker
|
|
||||||
blis
|
|
||||||
Brotli
|
|
||||||
catalogue
|
|
||||||
certifi
|
|
||||||
cffi
|
|
||||||
charset-normalizer
|
|
||||||
chromedriver-autoinstaller
|
|
||||||
click
|
|
||||||
clint
|
|
||||||
cloudpathlib
|
|
||||||
colorama
|
|
||||||
confection
|
|
||||||
cssselect2
|
|
||||||
cymem
|
|
||||||
dataclasses-json
|
|
||||||
decorator
|
|
||||||
distro
|
|
||||||
docopt
|
|
||||||
duckduckgo-search
|
|
||||||
exceptiongroup
|
|
||||||
fonttools
|
|
||||||
frozenlist
|
|
||||||
greenlet
|
|
||||||
grpcio
|
|
||||||
grpcio-tools
|
|
||||||
h11
|
|
||||||
h2
|
|
||||||
hpack
|
|
||||||
html2image
|
|
||||||
html5lib
|
|
||||||
httpcore
|
|
||||||
httpx
|
|
||||||
hyperframe
|
|
||||||
idna
|
|
||||||
imageio
|
|
||||||
imageio-ffmpeg
|
|
||||||
itsdangerous
|
|
||||||
Jinja2
|
|
||||||
joblib
|
|
||||||
jsonpatch
|
|
||||||
jsonpointer
|
|
||||||
langchain
|
|
||||||
langchain-core
|
|
||||||
langcodes
|
|
||||||
langsmith
|
|
||||||
loguru
|
|
||||||
lxml
|
|
||||||
Markdown
|
|
||||||
markdown2
|
|
||||||
MarkupSafe
|
|
||||||
marshmallow
|
|
||||||
md2pdf
|
|
||||||
moviepy
|
|
||||||
multidict
|
|
||||||
murmurhash
|
|
||||||
mypy-extensions
|
|
||||||
nltk
|
|
||||||
numpy
|
|
||||||
openai
|
|
||||||
outcome
|
|
||||||
packaging
|
|
||||||
param
|
|
||||||
permchain
|
|
||||||
Pillow
|
|
||||||
playwright
|
|
||||||
preshed
|
|
||||||
proglog
|
|
||||||
protobuf
|
|
||||||
pycparser
|
|
||||||
pydub
|
|
||||||
pydyf
|
|
||||||
pyee
|
|
||||||
pyphen
|
|
||||||
PySocks
|
|
||||||
python-dotenv
|
|
||||||
python-multipart
|
|
||||||
pytube
|
pytube
|
||||||
PyYAML
|
wordcloud
|
||||||
regex
|
nltk
|
||||||
requests
|
prompt_toolkit
|
||||||
selenium
|
ipython
|
||||||
serpapi
|
|
||||||
six
|
|
||||||
smart-open
|
|
||||||
sniffio
|
|
||||||
socksio
|
|
||||||
sortedcontainers
|
|
||||||
soupsieve
|
|
||||||
spacy-legacy
|
|
||||||
spacy-loggers
|
|
||||||
SQLAlchemy
|
|
||||||
srsly
|
|
||||||
stability-sdk
|
|
||||||
starlette
|
|
||||||
tavily-python
|
|
||||||
tenacity
|
|
||||||
thinc
|
|
||||||
tiktoken
|
|
||||||
tinycss2
|
|
||||||
tqdm
|
|
||||||
trio
|
|
||||||
trio-websocket
|
|
||||||
typer
|
|
||||||
typing-inspect
|
|
||||||
typing_extensions
|
|
||||||
urllib3
|
|
||||||
uvicorn
|
|
||||||
wasabi
|
|
||||||
weasel
|
|
||||||
weasyprint
|
|
||||||
webdriver-manager
|
|
||||||
webencodings
|
|
||||||
websocket-client
|
|
||||||
Werkzeug
|
|
||||||
wsproto
|
|
||||||
yarl
|
|
||||||
youtube-transcript-api
|
|
||||||
zopfli
|
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
Company,URL,Focus Areas,keyword
|
|
||||||
Codiga,https://www.codiga.io/,Coding,Code Snippets and Code Analysis
|
|
||||||
Mutable AI,https://mutable.ai/,Coding,Build fast with production quality using AI
|
|
||||||
Replit Ghostwriter,https://replit.com/,Coding,Accelerate your coding with AI assistance and mobile app
|
|
||||||
Stenography,https://stenography.dev/,Coding,Finally. Automatic Documentation.
|
|
||||||
|
@@ -1,20 +0,0 @@
|
|||||||
https://arxiv.org/abs/1910.10683
|
|
||||||
https://arxiv.org/abs/2306.03438
|
|
||||||
https://arxiv.org/pdf/2302.06144.pdf
|
|
||||||
https://arxiv.org/pdf/2303.03004v3.pdf
|
|
||||||
https://arxiv.org/abs/2001.00059
|
|
||||||
https://arxiv.org/abs/2012.07023
|
|
||||||
https://arxiv.org/abs/2105.08645
|
|
||||||
https://arxiv.org/abs/2105.04297
|
|
||||||
https://arxiv.org/abs/2010.03150
|
|
||||||
https://arxiv.org/abs/2105.12485
|
|
||||||
https://arxiv.org/abs/2010.07987
|
|
||||||
https://arxiv.org/pdf/2306.13549.pdf
|
|
||||||
https://arxiv.org/pdf/2312.16602.pdf
|
|
||||||
https://arxiv.org/pdf/2310.03744.pdf
|
|
||||||
https://arxiv.org/abs/2312.06647
|
|
||||||
https://arxiv.org/pdf/2312.03700.pdf
|
|
||||||
https://arxiv.org/abs/2312.09237
|
|
||||||
https://arxiv.org/abs/2312.13286
|
|
||||||
https://arxiv.org/pdf/2310.20550.pdf
|
|
||||||
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
image-generation,txt2img,img2img,image2image,text2image,diffusion,generative-art,stability-ai,stable-diffusion,ai,ai-tools,ai-assistant,ai-agents-framework,llm,multi-agent,agent,llama2,mistral,fine-tuning,rag,generative,prompt-engineering,prompt-tuning,generative-ai,text-to-image-generation,llm-ops,retrieval-augmented-generation,langchain,gemini-api,vertex-ai,huggingface,semantic-search,auto-gpt,llmops,ai-toolkit,chatbot,chatgpt,chat-gpt,multimodal,code-assistant,text-to-video,llms,gpt-4
|
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
https://github.com/Significant-Gravitas/AutoGPT
|
|
||||||
https://github.com/gpt-engineer-org/gpt-engineer
|
|
||||||
https://github.com/reworkd/AgentGPT
|
|
||||||
https://github.com/geekan/MetaGPT
|
|
||||||
https://github.com/Josh-XT/AGiXT
|
|
||||||
https://github.com/litanlitudan/skyagi
|
|
||||||
https://github.com/joonspk-research/generative_agents
|
|
||||||
https://github.com/smol-ai/developer
|
|
||||||
https://github.com/Forethought-Technologies/AutoChain
|
|
||||||
https://github.com/TransformerOptimus/SuperAGI
|
|
||||||
https://github.com/homanp/superagent
|
|
||||||
https://github.com/a16z-infra/ai-town
|
|
||||||
https://github.com/AI-Engineer-Foundation/agent-protocol
|
|
||||||
https://github.com/microsoft/autogen
|
|
||||||
https://github.com/cpacker/MemGPT
|
|
||||||
https://github.com/shroominic/codeinterpreter-api
|
|
||||||
https://github.com/aiwaves-cn/agents
|
|
||||||
https://github.com/dataelement/bisheng
|
|
||||||
https://github.com/Maplemx/Agently
|
|
||||||
https://github.com/zilliztech/GPTCache
|
|
||||||
http://github.com//Significant-Gravitas/AutoGPT
|
|
||||||
http://github.com//AUTOMATIC1111/stable-diffusion-webui
|
|
||||||
http://github.com//gpt-engineer-org/gpt-engineer
|
|
||||||
http://github.com//lencx/ChatGPT
|
|
||||||
http://github.com//hpcaitech/ColossalAI
|
|
||||||
http://github.com//LAION-AI/Open-Assistant
|
|
||||||
http://github.com//xitu/gold-miner
|
|
||||||
http://github.com//babysor/MockingBird
|
|
||||||
http://github.com//google-research/google-research
|
|
||||||
http://github.com//photoprism/photoprism
|
|
||||||
http://github.com//explosion/spaCy
|
|
||||||
http://github.com//AMAI-GmbH/AI-Expert-Roadmap
|
|
||||||
http://github.com//StanGirard/quivr
|
|
||||||
http://github.com//microsoft/AI-For-Beginners
|
|
||||||
http://github.com//GitHubDaily/GitHubDaily
|
|
||||||
http://github.com//Lightning-AI/pytorch-lightning
|
|
||||||
http://github.com//lutzroeder/netron
|
|
||||||
http://github.com//JushBJJ/Mr.-Ranedeer-AI-Tutor
|
|
||||||
http://github.com//s0md3v/roop
|
|
||||||
http://github.com//microsoft/generative-ai-for-beginners
|
|
||||||
http://github.com//leon-ai/leon
|
|
||||||
http://github.com//geekan/MetaGPT
|
|
||||||
http://github.com//jmorganca/ollama
|
|
||||||
http://github.com//run-llama/llama_index
|
|
||||||
http://github.com//milvus-io/milvus
|
|
||||||
http://github.com//chatchat-space/Langchain-Chatchat
|
|
||||||
http://github.com//zhayujie/chatgpt-on-wechat
|
|
||||||
http://github.com//mindsdb/mindsdb
|
|
||||||
http://github.com//FlowiseAI/Flowise
|
|
||||||
http://github.com//microsoft/unilm
|
|
||||||
http://github.com//mlabonne/llm-course
|
|
||||||
http://github.com//microsoft/semantic-kernel
|
|
||||||
http://github.com//ymcui/Chinese-LLaMA-Alpaca
|
|
||||||
http://github.com//mudler/LocalAI
|
|
||||||
http://github.com//mlc-ai/mlc-llm
|
|
||||||
http://github.com//THUDM/ChatGLM2-6B
|
|
||||||
http://github.com//langgenius/dify
|
|
||||||
http://github.com//vllm-project/vllm
|
|
||||||
http://github.com//TransformerOptimus/SuperAGI
|
|
||||||
http://github.com//ludwig-ai/ludwig
|
|
||||||
http://github.com//hiyouga/LLaMA-Factory
|
|
||||||
http://github.com//bentoml/OpenLLM
|
|
||||||
http://github.com//cloneofsimo/lora
|
|
||||||
http://github.com//eosphoros-ai/DB-GPT
|
|
||||||
http://github.com//labring/FastGPT
|
|
||||||
http://github.com//Mintplex-Labs/anything-llm
|
|
||||||
http://github.com//danswer-ai/danswer
|
|
||||||
http://github.com//neuml/txtai
|
|
||||||
http://github.com//run-llama/rags
|
|
||||||
http://github.com//postgresml/postgresml
|
|
||||||
http://github.com//h2oai/h2ogpt
|
|
||||||
http://github.com//css-doodle/css-doodle
|
|
||||||
http://github.com//williamngan/pts
|
|
||||||
http://github.com//dair-ai/Prompt-Engineering-Guide
|
|
||||||
http://github.com//AI4Finance-Foundation/FinGPT
|
|
||||||
http://github.com//yzfly/awesome-chatgpt-zh
|
|
||||||
http://github.com//microsoft/promptflow
|
|
||||||
http://github.com//jina-ai/jina
|
|
||||||
http://github.com//deepset-ai/haystack
|
|
||||||
http://github.com//open-mmlab/mmagic
|
|
||||||
http://github.com//bentoml/BentoML
|
|
||||||
http://github.com//openvinotoolkit/openvino
|
|
||||||
http://github.com//reworkd/AgentGPT
|
|
||||||
http://github.com//logspace-ai/langflow
|
|
||||||
http://github.com//mayooear/gpt4-pdf-chatbot-langchain
|
|
||||||
http://github.com//botpress/botpress
|
|
||||||
http://github.com//activeloopai/deeplake
|
|
||||||
http://github.com//danny-avila/LibreChat
|
|
||||||
http://github.com//liaokongVFX/LangChain-Chinese-Getting-Started-Guide
|
|
||||||
http://github.com//kyrolabs/awesome-langchain
|
|
||||||
http://github.com//zilliztech/GPTCache
|
|
||||||
http://github.com//speechbrain/speechbrain
|
|
||||||
http://github.com//vercel/ai
|
|
||||||
http://github.com//skorch-dev/skorch
|
|
||||||
http://github.com//baichuan-inc/Baichuan-7B
|
|
||||||
http://github.com//microsoft/autogen
|
|
||||||
http://github.com//f/awesome-chatgpt-prompts
|
|
||||||
http://github.com//xtekky/gpt4free
|
|
||||||
http://github.com//python-telegram-bot/python-telegram-bot
|
|
||||||
http://github.com//wechaty/wechaty
|
|
||||||
http://github.com//RasaHQ/rasa
|
|
||||||
http://github.com//lobehub/lobe-chat
|
|
||||||
http://github.com//transitive-bullshit/chatgpt-api
|
|
||||||
http://github.com//GaiZhenbiao/ChuanhuChatGPT
|
|
||||||
http://github.com//gunthercox/ChatterBot
|
|
||||||
http://github.com//mamoe/mirai
|
|
||||||
http://github.com//haotian-liu/LLaVA
|
|
||||||
http://github.com//howdyai/botkit
|
|
||||||
http://github.com//databrickslabs/dolly
|
|
||||||
http://github.com//chiphuyen/stanford-tensorflow-tutorials
|
|
||||||
http://github.com//ChatGPTNextWeb/ChatGPT-Next-Web
|
|
||||||
http://github.com//openai/openai-cookbook
|
|
||||||
http://github.com//binary-husky/gpt_academic
|
|
||||||
http://github.com//PlexPt/awesome-chatgpt-prompts-zh
|
|
||||||
http://github.com//KillianLucas/open-interpreter
|
|
||||||
http://github.com//acheong08/ChatGPT
|
|
||||||
http://github.com//tw93/Pake
|
|
||||||
http://github.com//LC044/WeChatMsg
|
|
||||||
http://github.com//openai/chatgpt-retrieval-plugin
|
|
||||||
http://github.com//openai-translator/openai-translator
|
|
||||||
http://github.com//sweepai/sweep
|
|
||||||
http://github.com//lucidrains/imagen-pytorch
|
|
||||||
http://github.com//GokuMohandas/Made-With-ML
|
|
||||||
http://github.com//TabbyML/tabby
|
|
||||||
http://github.com//chroma-core/chroma
|
|
||||||
http://github.com//eugeneyan/open-llms
|
|
||||||
http://github.com//cleanlab/cleanlab
|
|
||||||
http://github.com//RUCAIBox/LLMSurvey
|
|
||||||
http://github.com//OpenNMT/OpenNMT-py
|
|
||||||
http://github.com//joaomdmoura/crewAI
|
|
||||||
http://github.com//Pythagora-io/gpt-pilot
|
|
||||||
http://github.com//mouredev/Hello-Python
|
|
||||||
http://github.com//Bin-Huang/chatbox
|
|
||||||
http://github.com//getumbrel/llama-gpt
|
|
||||||
http://github.com//gventuri/pandas-ai
|
|
||||||
|
@@ -1,9 +0,0 @@
|
|||||||
https://github.com/louisfb01/best_AI_papers_2023
|
|
||||||
https://github.com/Giskard-AI/awesome-ai-safety
|
|
||||||
https://github.com/mahseema/awesome-ai-tools
|
|
||||||
https://github.com/Hyraze/ai-collective-tools#image-generator
|
|
||||||
https://github.com/Horhorist/Awesome-ai
|
|
||||||
https://github.com/youraibot/AI-Toolkit
|
|
||||||
https://github.com/hades217/awesome-ai
|
|
||||||
https://github.com/WooooDyy/LLM-Agent-Paper-List
|
|
||||||
https://github.com/e2b-dev/awesome-ai-agents
|
|
||||||
BIN
workspace/keyword_blog.gif
Normal file
BIN
workspace/keyword_blog.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
BIN
workspace/keyword_blog.png
Normal file
BIN
workspace/keyword_blog.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 57 KiB |
Reference in New Issue
Block a user