Auto blogging/article writing tool including image generation from Midjourney and publishing to Wordpress (Gutenberg ready).
import os
import sys
import time
import requests
import openai
from serpapi import GoogleSearch
from dotenv import load_dotenv
from termcolor import colored
from tqdm import tqdm
import colorama
colorama.init(autoreset=True)
from config import Config
import json
import re

load_dotenv()

cfg = Config()

# Configure OpenAI API key
try:
    openai.api_key = cfg.openai_api_key
    browserless_api_key = cfg.browserless_api_key
    llm_model = cfg.llm_model
except KeyError:
    sys.stderr.write("OpenAI key configuration failed.")
    exit(1)


def convert_to_gutenberg_blocks(text):
    # Split the text into lines
    lines = text.split('\n')

    # Initialize an empty list to hold the blocks
    blocks = []

    # Initialize an empty string to hold the current paragraph
    paragraph = ""

    # Iterate over each line
    for line in lines:
        # Check if the line is a headline
        if re.match(r"^# ", line):
            # If there's a current paragraph, add it as a block
            if paragraph:
                blocks.append(create_paragraph_block(paragraph))
                paragraph = ""

            # Add the headline as a block
            blocks.append(create_heading_block(line))

        # Check if the line is a list item
        elif re.match(r"^- ", line):
            # If there's a current paragraph, add it as a block
            if paragraph:
                blocks.append(create_paragraph_block(paragraph))
                paragraph = ""

            # Add the list as a block
            blocks.append(create_list_block(line))

        # Check if the line is an image
        elif re.match(r"^!\[.*\]\(.*\)", line):
            # If there's a current paragraph, add it as a block
            if paragraph:
                blocks.append(create_paragraph_block(paragraph))
                paragraph = ""

            # Add the image as a block
            blocks.append(create_image_block(line))

        # Check if the line is a quote
        elif re.match(r"^> ", line):
            # If there's a current paragraph, add it as a block
            if paragraph:
                blocks.append(create_paragraph_block(paragraph))
                paragraph = ""

            # Add the quote as a block
            blocks.append(create_quote_block(line))

        # Otherwise, add the line to the current paragraph
        else:
            paragraph += line

    # If there's a current paragraph, add it as a block
    if paragraph:
        blocks.append(create_paragraph_block(paragraph))

    # Return the blocks as a JSON string
    return json.dumps({"blocks": blocks}, ensure_ascii=False)

def create_paragraph_block(text):
    # Replace **text** with <strong>text</strong>
    text = re.sub(r"\*\*(.*?)\*\*", r"<strong>\1</strong>", text)
    return {
        "blockName": "core/paragraph",
        "attrs": {},
        "innerBlocks": [],
        "innerHTML": text
    }

def create_heading_block(text):
    return {
        "blockName": "core/heading",
        "attrs": {"level": text.count('#')},
        "innerBlocks": [],
        "innerHTML": text.replace('#', '').strip()
    }

def create_list_block(text):
    return {
        "blockName": "core/list",
        "attrs": {},
        "innerBlocks": [],
        "innerHTML": f"<li>{text.replace('-', '').strip()}</li>"
    }

def create_image_block(text):
    alt_text, url = re.match(r"^!\[(.*)\]\((.*)\)", text).groups()
    return {
        "blockName": "core/image",
        "attrs": {"url": url, "alt": alt_text},
        "innerBlocks": [],
        "innerHTML": ""
    }

def create_quote_block(text):
    return {
        "blockName": "core/quote",
        "attrs": {},
        "innerBlocks": [],
        "innerHTML": text.replace('> ', '').strip()
    }


def init(article, research):
    prompt = f"""The following article has been written by AI with user input. Review, if the user input is incorporated correctly.
    Rewrite the article if no. If yes, return NO CHANGE only.
    User input {research}\n\n
    Article: {article}"""

    chunked_output = ""
    for chunk in openai.ChatCompletion.create(
            model=cfg.llm_model,
            temperature=1,
            stream=True,
            messages=[
                {'role': 'system', 'content': 'You are a helpful assistant.'},
                {'role': 'system', 'content': "You're an expert in blogging, research and SEO."},
                {'role': 'system', 'content': 'Your name is BloggingGPT.'},
                {'role': 'system', 'content': 'Content you write is well SEO Optimised.'},
                {'role': 'system', 'content': 'You use engaging tone of voice.'},
                {"role": "user", "content": prompt}
            ]
    ):
        content = chunk["choices"][0].get("delta", {}).get("content")
        if content is not None:
            #print(content, end='')
            chunked_output += content
    return chunked_output

if __name__ == "__main__":
    # Open the file in read mode ('r')
    with open('your_file.txt', 'r') as file:
        # Read the file content and store it in the 'chunk' variable
        chunk = file.read()

    # Now you can use the 'chunk' variable in the convert_to_gutenberg_blocks function
    gutenberg_blocks = convert_to_gutenberg_blocks(chunk)
articles/review.py
seedgularity/AIBlogPilotGPT
import os
import sys
import time
import requests
import openai
from serpapi import GoogleSearch
from dotenv import load_dotenv
from termcolor import colored
from tqdm import tqdm
import colorama
colorama.init(autoreset=True)
from config import Config

load_dotenv()

cfg = Config()

# Configure OpenAI API key
try:
    openai.api_key = cfg.openai_api_key
    browserless_api_key = cfg.browserless_api_key
    llm_model = cfg.llm_model
    fast_llm_model = cfg.fast_llm_model
except KeyError:
    sys.stderr.write("OpenAI key configuration failed.")
    exit(1)

def optimise_article(article):
    # Split the article into chunks of approximately 1000 words each
    article_chunks = [article[i:i+1000] for i in range(0, len(article), 1000)]

    optimised_article = ""

    for chunk in article_chunks:
        prompt = f"""You are an expert in SEO and blogging. A blogger wrote the following article.
        Your task is the review the article and optimise it for SEO. You don't return tips, you update the article by yourself.
        You can add, remove or change the text. Focus on long tail keywords and readability. 
        Article:{chunk}"""

        chunked_output = ""
        for response in openai.ChatCompletion.create(
                model=cfg.llm_model,
                temperature=0.9,
                stream=True,
                messages=[
                    {'role': 'system', 'content': 'You are a helpful assistant.'},
                    {'role': 'system', 'content': "You're an expert in blogging, research and SEO."},
                    {'role': 'system', 'content': 'Your name is BloggingGPT.'},
                    {'role': 'system', 'content': 'Content you write is well SEO Optimised.'},
                    {'role': 'system', 'content': 'You use engaging tone of voice.'},
                    {"role": "user", "content": prompt}
                ]
        ):
            content = response["choices"][0].get("delta", {}).get("content")
            if content is not None:
                chunked_output += content

        # Add the optimised chunk to the final article
        optimised_article += chunked_output

    return optimised_article
articles/seo.py
seedgularity/AIBlogPilotGPT
import sys
import openai
from dotenv import load_dotenv
import colorama
colorama.init(autoreset=True)
from config import Config

load_dotenv()

cfg = Config()

# Configure OpenAI API key
try:
    openai.api_key = cfg.openai_api_key
    browserless_api_key = cfg.browserless_api_key
    llm_model = cfg.llm_model
except KeyError:
    sys.stderr.write("OpenAI key configuration failed.")
    exit(1)

def write_skeleton_product_review(title):
    prompt = """Write a product review for """+title+"""". Use the following information:
    
    Have you been looking for the best [keyword] recipe? I've got you covered!
>write an [tone] introduction about [keyword] including [experience], [expertise], authority and trustworthiness talking to [audience] who are [pain point].
Optional add ons to the intro prompt to keep it on track :
Describe the flavors of the dish as [flavors].
The ingredients in this dish are [x].
The dish is made with [type of cooking method]
[highlight an affiliate related to this post]
What is [keyword]?
>write a high-level overview of [keyword] to [audience] explaining [feature(s)]
[Keyword] Ingredients
>write a paragraph of the ingredients needed to make [keyword]. This ingredients are [list ingredients]. Include [note and specific features/health benefits or allergen notices]
How to Make [keyword]
>write a list of # steps explaining how to [keyword] to [audience]
You will take this list and put them into h3s. You can skip this if you have particular steps already.
Step 1: [step here]
>write a paragraph explaining [step] in [how to do X] in simple terms. Explain why this is necessary and how it helps
Step 2: [step here]
>write a paragraph explaining [step] in [how to do X] in simple terms. Explain why this is necessary and how it helps
[highlight an affiliate related to this post. Duplicate this or move this to areas where you can promote a certain cooking tool or an ingredient from Amazon]
Substitutes/Alternatives/Variations for [Keyword]
>write a paragraph about alternative/substitute/variations for [keyword] replacing [ingredient/cooking method] with [replacement]
You can rerun this command if there are multiple substitutes or variations.
[highlight an affiliate related to this post]
Any Other Headings Go Here
>write a paragraph about [header] for [audience] including [x]
This is a great place to answer questions about the best brands for ingredients, where to buy things, if they can replace x with y, and varied cooking methods.
[highlight an affiliate related to this post]
[keyword] Recipe
[insert the recipe block from either WP recipe maker or Create by Mediavine. I recommend filling this in manually. Include an image in the recipe template]
FAQs
>write a list of FAQs that [audience] would ask about [keyword] and answer them
Alternatively, find questions then ask Jasper to:
>write a concise answer to this question: "question" including [x]
[highlight an affiliate related to this post]
Conclusion/Final Thoughts: How to [keyword]
>write an engaging conclusion for a blog post about [keyword] talking to [audience]. Include a call to action for readers to [action. i.e. read next post titled “x”, leave a comment, buy a course titled “x” that does “y”]
Read More:
[insert relevant read more block here]

Strictly follow the example structure of JSON:
    
    {
    "Title": "The Role of Energy Efficiency in Home Design",
    "Description": "This article focuses on the importance and incorporation of energy efficiency in home design and its resulting benefits",
    "Sections": [
        {
            "Heading_H2": "Incorporating Energy Efficiency in Home Design",
            "Description": "A detailed guide on how energy efficiency can be embedded into home design, with sub-sections including",
            "SubSections": [
                {
                "Heading_H3": "Passive Design Strategies",
                "Description": "Explanation of passive design strategies to optimize energy efficiency."
                },
                {
                "Heading_H3": "Selecting Efficient Appliances",
                "Description": "Guide on choosing energy-efficient appliances for the home."
                },
                {
                "Heading_H3": "Material Selection for Energy Efficiency",
                "Description": "Discussion on how material selection impacts energy efficiency and the best materials to choose.",
                  "SubSections": [
                      {
                      "Heading_H4": "Insulation Materials",
                      "Description": "Analysis on the role of insulation materials in enhancing energy efficiency."
                      },
                      {
                      "Heading_H4": "Window Materials",
                      "Description": "Guide to choosing energy-efficient window materials."
                      }
                  ]
                }
            ]
        }
    ]
}
"""

    chunked_output = ""
    for chunk in openai.ChatCompletion.create(
            model=llm_model,
            stream=True,
            messages=[
                {'role': 'system', 'content': 'You are a helpful assistant.'},
                {'role': 'system', 'content': "You're an expert in blogging and SEO."},
                {'role': 'system', 'content': 'Your name is BloggingGPT.'},
                {'role': 'system', 'content': 'Return the output as JSON.'},
                {"role": "user", "content": prompt}
            ]
    ):
        content = chunk["choices"][0].get("delta", {}).get("content")
        if content is not None:
            #print(content, end='')
            chunked_output += content

    return chunked_output

def write_skeleton(title):
    prompt = """Propose a structure for an article with title """+title+"""". 
    Make sure you include headings - H2, H3, H4.
    Please ensure to include actual names in the structure.
    Include description for each section.
    Add FAQ section if relevant. Strictly follow the example structure of JSON below. Make sure the JSON is valid.
    
    {
    "Title": "The Role of Energy Efficiency in Home Design",
    "Description": "This article focuses on the importance and incorporation of energy efficiency in home design and its resulting benefits",
    "Sections": [
        {
            "Heading_H2": "Incorporating Energy Efficiency in Home Design",
            "Description": "A detailed guide on how energy efficiency can be embedded into home design, with sub-sections including",
            "SubSections": [
                {
                "Heading_H3": "Passive Design Strategies",
                "Description": "Explanation of passive design strategies to optimize energy efficiency."
                },
                {
                "Heading_H3": "Selecting Efficient Appliances",
                "Description": "Guide on choosing energy-efficient appliances for the home."
                },
                {
                "Heading_H3": "Material Selection for Energy Efficiency",
                "Description": "Discussion on how material selection impacts energy efficiency and the best materials to choose.",
                  "SubSections": [
                      {
                      "Heading_H4": "Insulation Materials",
                      "Description": "Analysis on the role of insulation materials in enhancing energy efficiency."
                      },
                      {
                      "Heading_H4": "Window Materials",
                      "Description": "Guide to choosing energy-efficient window materials."
                      }
                  ]
                }
            ]
        }
    ]
}"""

    chunked_output = ""
    for chunk in openai.ChatCompletion.create(
            model=llm_model,
            stream=True,
            messages=[
                {'role': 'system', 'content': 'You are a helpful assistant.'},
                {'role': 'system', 'content': "You're an expert in blogging and SEO."},
                {'role': 'system', 'content': 'Your name is BloggingGPT.'},
                {'role': 'system', 'content': 'Return the output as JSON.'},
                {"role": "user", "content": prompt}
            ]
    ):
        content = chunk["choices"][0].get("delta", {}).get("content")
        if content is not None:
            #print(content, end='')
            chunked_output += content

    return chunked_output

if __name__ == "__main__":
    write_skeleton_product_review("Review of Acure Ultra Hydrating Shampoo")
articles/skeleton.py
seedgularity/AIBlogPilotGPT
import os
import sys
import time
import requests
import openai
from serpapi import GoogleSearch
from dotenv import load_dotenv
from termcolor import colored
from tqdm import tqdm
import colorama
colorama.init(autoreset=True)
from config import Config

load_dotenv()

cfg = Config()

# Configure OpenAI API key
try:
    openai.api_key = cfg.openai_api_key
    browserless_api_key = cfg.browserless_api_key
    llm_model = cfg.llm_model
except KeyError:
    sys.stderr.write("OpenAI key configuration failed.")
    exit(1)


def find_conclusion(text, function_to_call):
    if "In conclusion," in text:
        print("Found In conclusion text. Removing...")
        return function_to_call(text)
    return text
def in_conclusion_killer(text):
    ###THIS BLOODY THING###
    prompt = f"""Remove in conclusion text. Don't add anything.: {text}"""
    chunked_output = ""
    for chunk in openai.ChatCompletion.create(
            model=cfg.llm_model,
            temperature=1,
            stream=True,
            messages=[
                {'role': 'system', 'content': 'You are a helpful assistant.'},
                {'role': 'system', 'content': "You're an expert in blogging, research and SEO."},
                {'role': 'system', 'content': 'Your name is BloggingGPT.'},
                {'role': 'system', 'content': 'Content you write is well SEO Optimised.'},
                {'role': 'system', 'content': 'You use engaging tone of voice.'},
                {'role': 'system', 'content': 'You strictly follow user request.'},
                {'role': 'system', 'content': 'You strictly return content user asked for only.'},
                {'role': 'system', 'content': "You don't say or add anything, just return the content."},
                {"role": "user", "content": prompt}
            ]
    ):
        content = chunk["choices"][0].get("delta", {}).get("content")
        if content is not None:
            # print(content, end='')
            chunked_output += content

    return chunked_output
def write_intro(title, toneofvoice):

    prompt = f"""
As an AI blog post writer, your task is to craft an engaging and professional introduction paragraph for an article. Here are the details you need to consider:

The article's title is {title}. However, do not include the title in the introduction.
Write in the style of a professional blogger crafting a long-form article.
The article will have following tone of voice: {toneofvoice}.
Do not include any form of concluding statements like 'in conclusion'.
Remember, your goal is to create an introduction that hooks the reader and sets the stage for the rest of the article."""

    chunked_output = ""
    for chunk in openai.ChatCompletion.create(
            model=cfg.llm_model,
            temperature=1,
            stream=True,
            messages=[
                {'role': 'system', 'content': 'You are a helpful assistant.'},
                {'role': 'system', 'content': "You're an expert in blogging, research and SEO."},
                {'role': 'system', 'content': 'Your name is BloggingGPT.'},
                {'role': 'system', 'content': 'Content you write is well SEO Optimised.'},
                {'role': 'system', 'content': 'You use engaging tone of voice.'},
                {"role": "user", "content": prompt}
            ]
    ):
        content = chunk["choices"][0].get("delta", {}).get("content")
        if content is not None:
            #print(content, end='')
            chunked_output += content
    chunked_output = find_conclusion(chunked_output, in_conclusion_killer)
    return chunked_output


def write_section(title, article_description, heading, heading_description, toneofvoice):
    if article_description == "":
        article_description = "Not available, use the title"
    if heading_description == "":
        heading_description = "Not available, use the heading"

    prompt = f"""
As an AI blog post section writer, your task is to generate unique, compelling, and SEO-optimized content for various blog post sections. Here are the details you need to consider:
You will not include any concluding summaries.
You will not include section headings.
The article will have following tone of voice: {toneofvoice}.
You will be provided with an article title {title}, an article description {article_description}, a section heading {heading}, and a section description {heading_description}.
Using these inputs, generate captivating, grammatically correct, and easy-to-read content that is suitable for the respective section.
Make important parts of the text bold - but focus on keywords the article is targeting. You can also use quotes and citations.
The content should engage readers and facilitate their understanding of the blog post's content. Maintain an engaging tone of voice throughout.
The content should be ready to be copied and pasted directly into Wordpress with Gutenberg formatting, without the need for any additional formatting.
Remember, your goal is to create a section body that aligns with the provided inputs and is optimized for search engines."""

    chunked_output = ""
    for chunk in openai.ChatCompletion.create(
            model=cfg.llm_model,
            temperature=1,
            stream=True,
            messages=[
                {'role': 'system', 'content': 'Your name is BloggingGPT.'},
                {'role': 'system', 'content': "You're an expert in blogging, research and SEO."},
                {'role': 'system', 'content': 'Content produced is well SEO Optimised.'},
                {'role': 'system', 'content': 'You strictly return content user asked for only.'},
                {"role": "user", "content": prompt}
            ]
    ):
        content = chunk["choices"][0].get("delta", {}).get("content")
        if content is not None:
            #print(content, end='')
            chunked_output += content

    chunked_output = in_conclusion_killer(chunked_output)
    return chunked_output

def write_subsection(title, article_description, heading, heading_description, subheading, subheading_description, toneofvoice):
    if article_description == "":
        article_description = "Not available, use the title"
    if heading_description == "":
        heading_description = "Not available, use the heading"
    if subheading_description == "":
        subheading_description = "Not available, use the subheading"

    prompt = f"""As an AI blog post section writer, your task is to generate unique, compelling, and SEO-optimized content for various blog post sections and subsections. Here are the details you need to consider:

You will not include any concluding summaries.
You will not include section or subsections headings.
The article will have following tone of voice: {toneofvoice}.
You will be provided with an article title {title}, an article description {article_description}, a section heading {heading}, a section description {heading_description}, a subsection heading {subheading}, and a subsection description {subheading_description}.
Using these inputs, generate captivating, grammatically correct, and easy-to-read content that is suitable for the respective section and subsection.
Make important parts of the text bold. You can also use quotes and citations. Add bulleted lists.
When relevant, add pros and cons comparisons.
The content should engage readers and facilitate their understanding of the blog post's content. Maintain an engaging tone of voice throughout.
The content should be ready to be copied and pasted directly into Wordpress with Gutenberg formatting, without the need for any additional formatting.
Remember, your goal is to create a section body and subsection body that align with the provided inputs and are optimized for search engines."""

    chunked_output = ""
    for chunk in openai.ChatCompletion.create(
            model=cfg.llm_model,
            temperature=1,
            stream=True,
            messages=[
                {'role': 'system', 'content': 'You are a helpful assistant.'},
                {'role': 'system', 'content': "You're an expert in blogging, research and SEO."},
                {'role': 'system', 'content': 'Your name is BloggingGPT.'},
                {'role': 'system', 'content': 'Content produced is well SEO Optimised.'},
                {'role': 'system', 'content': 'You use engaging tone of voice.'},
                {'role': 'system', 'content': 'You strictly return content user asked for only.'},
                {"role": "user", "content": prompt}
            ]
    ):
        content = chunk["choices"][0].get("delta", {}).get("content")
        if content is not None:
            #print(content, end='')
            chunked_output += content

    chunked_output = find_conclusion(chunked_output, in_conclusion_killer)
    return chunked_output

if __name__ == "__main__":
    write_section()
articles/writing.py
seedgularity/AIBlogPilotGPT
# Importing necessary libraries
import os
import openai
from dotenv import load_dotenv

# Loading environment variables from .env file
load_dotenv()

# Singleton class to ensure only one instance of a class exists
class Singleton(type):
    # Dictionary to store instances of classes
    _instances = {}

    # Overriding the __call__ method to control class instantiation
    def __call__(cls, *args, **kwargs):
        # If an instance of the class does not exist, create one
        if cls not in cls._instances:
            cls._instances[cls] = super(
                Singleton, cls).__call__(
                *args, **kwargs)
        # Return the instance of the class
        return cls._instances[cls]

# Config class to manage configuration settings
class Config(metaclass=Singleton):
    # Initialization method
    def __init__(self):
        # Fetching environment variables and setting them as class attributes
        self.llm_model = os.getenv("LLM_MODEL")
        self.fast_llm_model = os.getenv("FAST_LLM_MODEL")
        self.openai_api_key = os.getenv("OPENAI_API_KEY")
        self.openai_api_key_fast = os.getenv("OPENAI_API_KEY_FAST")
        openai.api_key = self.openai_api_key
        self.serpapi_api_key = os.getenv("SERPAPI_API_KEY")
        self.browserless_api_key = os.getenv("BROWSERLESS_API_KEY")
        self.brave_search_api_key = os.getenv("BRAVE_SEARCH_API_KEY")
        self.wolfram_alpha_appid = os.getenv("WOLFRAM_ALPHA_APPID")
        self.site_url = os.getenv("SITE_URL")
        self.wp_admin_username = os.getenv("WP_ADMIN_USERNAME")
        self.wp_admin_password = os.getenv("WP_ADMIN_PASSWORD")

    # Method to set the llm_model attribute
    def set_llm_model(self, value: str):
        self.llm_model = value

    # Method to set the llm_model attribute
    def set_fast_llm_model(self, value: str):
        self.fast_llm_model = value

    # Method to set the openai_api_key attribute
    def set_openai_api_key(self, value: str):
        self.openai_api_key = value

    def set_openai_api_key_fast(self, value: str):
        self.openai_api_key_fast = value

    # Method to set the serp_api_key attribute
    def set_serpapi_api_key(self, value: str):
        self.serpapi_api_key = value

    # Method to set the browserless_api_key attribute
    def set_browserless_api_key(self, value: str):
        self.browserless_api_key = value

    # Method to set the brave_search_api_key attribute
    def set_brave_search_api_key(self, value: str):
        self.brave_search_api_key = value

    def set_site_url(self, value: str):
        self.site_url = value

    def set_wp_admin_username(self, value: str):
        self.wp_admin_username = value

    def set_wp_admin_password(self, value: str):
        self.wp_admin_password = value
config.py
seedgularity/AIBlogPilotGPT
import requests
import json
from PIL import Image
from io import BytesIO

url = "https://api.thenextleg.io/getImage"

payload = json.dumps({
    "imgUrl": "https://cdn.midjourney.com/0109b6ae-a6b0-4bbd-a89c-fd6071cc1763/0_2.png"
})
headers = {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer dffc660d-8ad0-4a13-bc91-119e27b8e4a3'
}

response = requests.request("POST", url, headers=headers, data=payload)

# Assuming the response is in bytes
image = Image.open(BytesIO(response.content))
image.save('output.png')



enhancer/down.py
seedgularity/AIBlogPilotGPT
import os
import sys
import time
import requests
import openai
from serpapi import GoogleSearch
from dotenv import load_dotenv
from termcolor import colored
from tqdm import tqdm
import colorama
colorama.init(autoreset=True)
from config import Config

load_dotenv()

cfg = Config()

# Configure OpenAI API key
try:
    openai.api_key = cfg.openai_api_key
    browserless_api_key = cfg.browserless_api_key
    llm_model = cfg.llm_model
    fast_llm_model = cfg.fast_llm_model
except KeyError:
    sys.stderr.write("OpenAI key configuration failed.")
    exit(1)

def add_links(article):
    # Split the article into chunks of approximately 100 words each
    word_list = article.split()
    chunks = [' '.join(word_list[i:i + 100]) for i in range(0, len(word_list), 100)]

    chunked_output = ""
    for chunk in chunks:
        prompt = f"""You are an expert in SEO and blogging. A blogger wrote the following article.
            Your task is the review the article and add links to relevant sources. Add 5 links maximum.
            Article:{chunk}"""

        for output in openai.ChatCompletion.create(
                model=llm_model,
                stream=True,
                messages=[
                    {'role': 'system', 'content': 'You are a helpful assistant.'},
                    {'role': 'system', 'content': "You're an expert in blogging, research and SEO."},
                    {'role': 'system', 'content': 'Your name is BloggingGPT.'},
                    {'role': 'system', 'content': 'Content you write is well SEO Optimised.'},
                    {'role': 'system', 'content': 'You use engaging tone of voice.'},
                    {"role": "user", "content": prompt}
                ]
        ):
            content = output["choices"][0].get("delta", {}).get("content")
            if content is not None:
                #print(content, end='')
                chunked_output += content

    return chunked_output
enhancer/linker.py
seedgularity/AIBlogPilotGPT
# Import necessary libraries
from midjourney_api import TNL
import requests
import json
import time
import os
from tqdm import tqdm
from PIL import Image
from io import BytesIO
from dotenv import load_dotenv

# Load the .env file
load_dotenv()

# Define API key and initialize TNL
TNL_API_KEY = os.getenv("TNL_API_KEY")
tnl = TNL(TNL_API_KEY)


def generate_image(title):
    """
    Function to generate image using TNL API
    """
    # Define the prompt for the image
    prompt = f"""Header image for an article '{title}',extra sharp, 8k, photorealistic, shot on Kodak gold --ar 16:9"""

    # Get the response from the API
    response = tnl.imagine(prompt)

    # Keep checking until message_id is not None
    while "messageId" not in response:
        print("Waiting for message id...")
        time.sleep(5)  # wait for 5 seconds before checking again

    print("Message id: ", response["messageId"])

    # Call check_progress function to wait for the image generation to complete
    check_progress(response["messageId"])

    return response["messageId"]


def check_progress(id):
    """
    Function to check the progress of the image generation and download the image
    """
    # Define the URL and headers for the request
    url = f"https://api.thenextleg.io/v2/message/{id}?expireMins=12"
    headers = {'Authorization': f'Bearer {TNL_API_KEY}'}

    # Initialize progress bar
    progress_bar = tqdm(total=100)

    # Keep checking the progress until it reaches 100
    while True:
        response = requests.get(url, headers=headers)
        response_json = response.json()

        # Convert response_json['progress'] to an integer before subtracting progress_bar.n
        progress_bar.update(int(response_json['progress']) - progress_bar.n)  # Update progress bar

        if int(response_json['progress']) == 100:
            progress_bar.close()  # Close progress bar
            break
        else:
            time.sleep(5)

    # Get the URL of the third image
    third_image_url = response_json['response']['imageUrls'][2]

    print(third_image_url)

    # Download the image
    download_image(third_image_url, id)


def download_image(image_url, id):
    """
    Function to download the image and save it in different formats
    """
    url = "https://api.thenextleg.io/getImage"
    payload = json.dumps({"imgUrl": image_url})
    headers = {
        'Content-Type': 'application/json',
        'Authorization': f'Bearer {TNL_API_KEY}'
    }

    response = requests.post(url, headers=headers, data=payload)

    # Assuming the response is in bytes
    image = Image.open(BytesIO(response.content))

    # Define the directory to save the images
    directory = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'temp', 'imgs')

    # Create the directory if it doesn't exist
    os.makedirs(directory, exist_ok=True)

    # Save the images in the defined directory
    image.save(os.path.join(directory, f'{id}.png'))

    original_image = Image.open(os.path.join(directory, f'{id}.png'))
    rgb_image = original_image.convert('RGB')
    small_image_name = f'{id}_small.jpg'
    rgb_image.save(os.path.join(directory, small_image_name), "JPEG", quality=70)

    return small_image_name


def generate_and_check(title):
    """
    Main function to generate the image and check its progress
    """
    message_id = generate_image(title)
    check_progress(message_id)


if __name__ == "__main__":
    generate_and_check("Top 5 Renewable Energy Sources for 2023")
enhancer/midjourney_ai.py
seedgularity/AIBlogPilotGPT
import requests
import json

def get_post_by_title(site_url, title):
    response = requests.get(f'{site_url}/wp-json/wp/v2/posts?search={title}')
    posts = json.loads(response.text)

    if len(posts) == 0:
        print("No posts found with that title.")
    else:
        for post in posts:
            print(post['title']['rendered'])
            print(post['content']['rendered'])

# Example usage:
site_url = 'https://iminsweden.com/'
title = 'A Comprehensive Overview of the Swedish Education System'
get_post_by_title(site_url, title)

enhancer/post_enhancer.py
seedgularity/AIBlogPilotGPT
import os
import sys
import time
import requests
import openai
from serpapi import GoogleSearch
from dotenv import load_dotenv
from termcolor import colored
from tqdm import tqdm
import colorama
colorama.init(autoreset=True)
from config import Config

load_dotenv()

cfg = Config()

# Configure OpenAI API key
try:
    openai.api_key = cfg.openai_api_key
    browserless_api_key = cfg.browserless_api_key
    llm_model = cfg.llm_model
    fast_llm_model = cfg.fast_llm_model
except KeyError:
    sys.stderr.write("OpenAI key configuration failed.")
    exit(1)



def translate_content(article, language):
    prompt = f"""Please translate the following English article into the specified language. 
            Make sure it's SEO optimised and grammatically correct.
            Language: {language}
            English Article: {article}"""

    chunked_output = ""
    for chunk in openai.ChatCompletion.create(
            model=cfg.llm_model,
            temperature=1,
            stream=True,
            messages=[
                {'role': 'system', 'content': 'You are a helpful assistant.'},
                {'role': 'system', 'content': "You're an expert translating from English to any language."},
                {'role': 'system', 'content': 'You use engaging tone of voice.'},
                {"role": "user", "content": prompt}
            ]
    ):
        content = chunk["choices"][0].get("delta", {}).get("content")
        if content is not None:
            # print(content, end='')
            chunked_output += content

    return chunked_output
enhancer/translate.py
seedgularity/AIBlogPilotGPT
import os
import sys
import time
import requests
import openai
from serpapi import GoogleSearch
from dotenv import load_dotenv
from termcolor import colored
from tqdm import tqdm
import colorama
colorama.init(autoreset=True)
from config import Config

load_dotenv()

cfg = Config()

# Configure OpenAI API key
try:
    openai.api_key = cfg.openai_api_key
    browserless_api_key = cfg.browserless_api_key
    llm_model = cfg.llm_model
except KeyError:
    sys.stderr.write("OpenAI key configuration failed.")
    exit(1)

def propose_niche(user_search):
    input_text = f"""Your task is to propose a niche that will grow fastest in organic 
    results and once the user agrees to the niche, your goal is to propose a name, 
    domain name and then topics and write articles. User has also found the following on Google:
    '{user_search}'.
    Start with proposing the niche."""

    chunked_output = ""
    for chunk in openai.ChatCompletion.create(
            model=cfg.llm_model,
            stream=True,
            messages=[
                {'role': 'system', 'content': 'You are a helpful assistant.'},
                {'role': 'system', 'content': "You're an expert in blogging and SEO."},
                {'role': 'system', 'content': 'Your name is BloggingGPT.'},
                {"role": "user", "content": input_text}
            ]
    ):
        content = chunk["choices"][0].get("delta", {}).get("content")
        if content is not None:
            print(content, end='')
            chunked_output += content

    return chunked_output

initiation/kickoff.py
seedgularity/AIBlogPilotGPT
## DOESN'T WORK YET

from orchestrar import wp
from langchain.llms import OpenAI
from langchain.document_loaders import TextLoader
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.text_splitter import CharacterTextSplitter, RecursiveCharacterTextSplitter
from langchain.vectorstores import FAISS
from langchain.agents import Tool
from langchain.agents import AgentType
from langchain.memory import ConversationBufferMemory
from langchain import OpenAI
from langchain.utilities import SerpAPIWrapper
from langchain.agents import initialize_agent
from langchain import PromptTemplate
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.document_loaders import WebBaseLoader
from langchain.document_loaders import TextLoader
from langchain.retrievers import SVMRetriever
from langchain.chat_models import ChatOpenAI
from langchain.retrievers.multi_query import MultiQueryRetriever
from langchain.chains import RetrievalQA
from langchain.chat_models import ChatOpenAI
import logging
from dotenv import load_dotenv
from config import Config
import openai
import sys

# Load the .env file
load_dotenv()

# Configure OpenAI API key
cfg = Config()
try:
    openai.api_key = cfg.openai_api_key
except KeyError:
    sys.stderr.write("OpenAI key configuration failed.")
    exit(1)

text = wp.get_all_articles('https://iminsweden.com/')

def analyse_text():
    # Your analysis logic goes here
    pass

def save_file(text):
    with open('output.txt', 'w', encoding='utf-8') as f:
        f.write(text)

def load_file(filename='output.txt'):
    with open(filename, 'r', encoding='utf-8') as f:
        return f.read()

def load_AI():
    loader = TextLoader("./output.txt")
    loader.load()

if __name__ == "__main__":
    #text = wp.get_all_articles('https://iminsweden.com/')
    #save_file(text)

    #loader = WebBaseLoader("https://lilianweng.github.io/posts/2023-06-23-agent/")
    loader = TextLoader("output.txt")
    data = loader.load()

    text_splitter = RecursiveCharacterTextSplitter(chunk_size=2500, chunk_overlap=0)
    all_splits = text_splitter.split_documents(data)
    #print(all_splits)

    vectorstore = Chroma.from_documents(documents=all_splits, embedding=OpenAIEmbeddings())
    question = ("What is the Article Title of article with Article ID: 252?")
    docs = vectorstore.similarity_search(question)

    logging.basicConfig()
    logging.getLogger('langchain.retrievers.multi_query').setLevel(logging.INFO)

    retriever_from_llm = MultiQueryRetriever.from_llm(retriever=vectorstore.as_retriever(),
                                                      llm=ChatOpenAI(temperature=0))
    unique_docs = retriever_from_llm.get_relevant_documents(query=question)
    len(unique_docs)

    #llm = ChatOpenAI(model_name="gpt-4-0613", temperature=0)
    #qa_chain = RetrievalQA.from_chain_type(llm, retriever=vectorstore.as_retriever())
    #result = qa_chain({"query": question})
    #print(result["result"])

    template = """Use the following pieces of context to answer the question at the end. 
    If you don't know the answer, just say that you don't know, don't try to make up an answer. 
    Use three sentences maximum and keep the answer as concise as possible. 
    Always say "thanks for asking!" at the end of the answer. 
    {context}
    Question: {question}
    Helpful Answer:"""
    QA_CHAIN_PROMPT = PromptTemplate.from_template(template)

    llm = ChatOpenAI(model_name="gpt-4-0613", temperature=0)
    qa_chain = RetrievalQA.from_chain_type(
        llm,
        retriever=vectorstore.as_retriever(),
        chain_type_kwargs={"prompt": QA_CHAIN_PROMPT}
    )
    result = qa_chain({"query": question})
    print(result["result"])

# Save text to file
# save_file(text)

# Load text from file as a string
#loaded_text = load_file()

# You can now use 'loaded_text' as a string in your script
#print(loaded_text)
interlinker/linker.py
seedgularity/AIBlogPilotGPT
import os
import sys
import json
from dotenv import load_dotenv
import openai
import toml
from halo import Halo
import colorama
from termcolor import colored
import time
from colorama import Fore, Style
colorama.init(autoreset=True)
from pyfiglet import Figlet

from config import Config

from initiation import kickoff
import articles.writing
from articles import skeleton
from articles import writing
from researcher import search
from orchestrar import gutenberg
from orchestrar import wp
from orchestrar import blogs
from enhancer import midjourney_ai

import ssl
ssl._create_default_https_context = ssl._create_unverified_context

# Initialize colorama
colorama.init(autoreset=True)

# Load the .env file
load_dotenv()

# Configure OpenAI API key
cfg = Config()
try:
    openai.api_key = cfg.openai_api_key
except KeyError:
    sys.stderr.write("OpenAI key configuration failed.")
    exit(1)

# Global variables for article content
article_content = ""
article_title = ""
article_description = ""
findings = ""
wp_admin = ""
wp_pass = ""
wp_url = ""
published_articles = ""
tone = ""
keywords = ""

def process_section(section, level=2, max_depth=5):
    """
    Process a section or subsection of the article.
    """
    section_type = 'section' if level == 2 else 'subsection'
    section_content = ""
    spinner = Halo(text=f'Processing {section_type}: {section[f"Heading_H{level}"]}', spinner='dots')
    spinner.start()

    # Write section or subsection
    section_content = articles.writing.write_section(article_title,
                                                     article_description,
                                                     section[f'Heading_H{level}'],
                                                     section['Description'],
                                                     tone)

    spinner.succeed(f"Finished processing {section_type}: {section[f'Heading_H{level}']}")

    # Process subsections if they exist and the maximum depth has not been reached
    if 'SubSections' in section and level < max_depth:
        for sub_section in section['SubSections']:
            section_content += process_section(sub_section, level + 1)

    return "\n\n" + f"<h{level}>" + section[f'Heading_H{level}'] + f"</h{level}>" + "\n\n" + section_content


def process_json(json_string):
    """
    Process the JSON string to generate the article content.
    """
    global article_content
    global article_title  # Declare article_title as global
    spinner = Halo(text='Parsing JSON', spinner='dots')
    spinner.start()

    data = json.loads(json_string)
    article_title = data['Title']  # This now refers to the global variable
    if findings.strip():
        article_description = data['Description'] + " " +f"""{findings}"""
        #print("\n\n\n\nArticle_description: ", article_description)
        #print("\n\n\n\n")
    else:
        article_description = data['Description']

    spinner.succeed('Finished parsing JSON')

    # Add the intro to the article content
    article_content += writing.write_intro(article_title, tone) + "\n\n"

    for section in data['Sections']:
        article_content += process_section(section)

    return article_content

def is_json(json_string):
    """
    Check if a string is valid JSON.
    """
    try:
        json.loads(json_string)
    except ValueError:
        return False
    return True

def wait_for_image(image_name):
    """
    Function to wait for the image file to appear in the specified directory
    """
    # Define the base directory
    base_dir = "./temp/imgs/"

    # Use os.path.join to create the full path
    image_path = os.path.join(base_dir, image_name)
    print(f"Looking for image at: {image_path}")

    # Keep checking for the image file until it appears
    while True:
        try:
            if os.path.isfile(image_path):
                print("Image file found.")
                break
            else:
                print("Image file not found. Waiting...")
                time.sleep(5)  # wait for 5 seconds before checking again
        except Exception as e:
            print(f"Error while checking for image: {e}")
            break


def article(title=None, category=None):
    """
    Main function to generate the article.
    """
    global findings
    global article_content
    global article_title

    # Reset article_content
    article_content = ""

    if title is None:
        title = input("Please enter the article title: ")
    else:
        print(f"Article Title: {title}")
    if category is None:
        category = input("Please enter the article category: ")
    else:
        print(f"Article Category: {category}")

    # RESEARCH
    if title is not None and category is not None:
        research = 'y'
    else:
        research = input("Do you want me to research the internet? (y/n): ")
    if research == 'y':
        search_results = search.go(title)
        findings = f"""This is additional info from user you need to incorporate: {search_results}"""
        print(colored("\n" + "################### RESEARCH FINISHED ###################\n", "green", attrs=["bold"]))

    # ARTICLE TYPE
    if title is not None and category is not None:
        article_type = 'a'
    else:
        article_type = input("Do you want Article or Product Review? (a/p): ")
    spinner = Halo(text='Preparing Structure of Article', spinner='dots')
    spinner.start()

    article_skeleton = ""
    while not is_json(article_skeleton):
        try:
            if article_type == 'a':
                article_skeleton = skeleton.write_skeleton(title)
            elif article_type == 'p':
                article_skeleton = skeleton.write_skeleton_product_review(title)
        except Exception as e:
            spinner.fail(str(e))
        else:
            spinner.succeed("Finished writing the article skeleton")

    # PROCESS SECTIONS
    try:
        article_content += process_json(article_skeleton)
    except Exception as e:
        spinner.fail(str(e))
    else:
        spinner.succeed("Finished processing JSON")

    print(colored("\n" + "################### ARTICLE GENERATED ###################", "green",
                  attrs=["bold"]))

    # SAVE TO TXT FILE
    if title is not None and category is not None:
        save_to_txt = 'y'
    else:
        save_to_txt = input("Do you want to save this article to a txt file? (y/n): ")
    if save_to_txt == 'y':
        with open(f"./temp/articles/{title}.txt", "w") as file:
            file.write(article_content)
        print(colored("\nArticle saved to txt file.", "green", attrs=["bold"]))

    # GENERATE IMAGES
    featured_image_name = midjourney_ai.generate_image(title)

    # Wait for the image file to appear
    wait_for_image(featured_image_name + "_small.jpg")

    # Define the base directory
    base_dir = "/temp/imgs"

    # Use os.path.join to create the full path
    featured_image_path = os.path.join(base_dir, featured_image_name + "_small.jpg")
    featured_image_path = "." + featured_image_path

    # WORDPRESS IMPORT
    if title is not None and category is not None:
        wp_import = 'y'
    else:
        wp_import = input("Do you want to import this article to WordPress? (y/n): ")
    if wp_import == 'y':
        print(colored("\n" + "################### WORDPRESS IMPORT ###################", "green",
                      attrs=["bold"]))

        spinner = Halo(text='Preparing article for WordPress import', spinner='dots')
        spinner.start()
        try:
            to_wordpress = gutenberg.convert_to_gutenberg_blocks(article_content)
            tags = [category]
            wp.post_to_wordpress(article_title, to_wordpress, category, tags, featured_image_path, wp_admin, wp_pass, wp_url)
        except Exception as e:
            spinner.fail(str(e))
        else:
            spinner.succeed("Article imported to WordPress\n\n")

def parse_blog_articles():
    data = json.loads(get_blog_details())

    for item in data:
        #print(f'Category: {item["Category"]}, Title: {item["Title"]}')
        article(item["Title"], item["Category"])

def get_blog_details():
    global wp_admin
    global wp_pass
    global wp_url
    global tone
    global keywords

    data = toml.load("blogs/blogs.toml")

    # print all the blogs and ask user to choose one
    print("List of blogs:")
    for i, blog in enumerate(data["blog"], start=1):
        print(f"{i}. {blog['name']}")

    # ask user for blog number
    blog_number = int(input("\nEnter the number of the blog: "))
    # get the chosen blog
    chosen_blog = data["blog"][blog_number - 1]

    # get the WP admin username and password from the .env file
    wp_admin = os.getenv(f"WP_ADMIN_USERNAME_{chosen_blog['id']}")
    wp_pass = os.getenv(f"WP_ADMIN_PASSWORD_{chosen_blog['id']}")
    wp_url = os.getenv(f"WP_URL_{chosen_blog['id']}")

    print(f"\nBlog Name: {chosen_blog['name']}")
    print(f"Description: {chosen_blog['description']}")
    print(f"URL: {chosen_blog['url']}")
    print(f"Tone: {chosen_blog['tone']}")
    print(f"Keywords: {chosen_blog['keywords']}")
    #print(f"WordPress Admin: {wp_admin}")
    #print(f"WordPress Password: {wp_pass}")

    print("\n")

    tone = chosen_blog['tone']
    keywords = chosen_blog['keywords']

    # get the published articles from the blog
    spinner = Halo(text='Loading existing articles...', spinner='dots')
    spinner.start()
    try:
        published_articles = wp.get_all_posts_titles(chosen_blog['url'])
    except Exception as e:
        spinner.fail(str(e))
    else:
        spinner.succeed("Articles loaded")

    # generate the JSON for the articles
    spinner = Halo(text='Generating articles JSON', spinner='dots')
    spinner.start()
    try:
        json_articles = blogs.init_blog(chosen_blog['description'],published_articles, tone, keywords)
    except Exception as e:
        spinner.fail(str(e))
    else:
        spinner.succeed("JSON Generated")

    print(json_articles)
    return json_articles

if __name__ == "__main__":
    f = Figlet(font='big', width=300)
    print(Fore.CYAN + Style.BRIGHT + f.renderText('AI BLOG PILOT'))
    #article()
    parse_blog_articles()
main.py
seedgularity/AIBlogPilotGPT
import os
import sys
import json
from dotenv import load_dotenv
import openai
import toml
from halo import Halo
import colorama
from termcolor import colored

from config import Config

# Load the .env file
load_dotenv()

# Configure OpenAI API key
cfg = Config()
try:
    openai.api_key = cfg.openai_api_key
except KeyError:
    sys.stderr.write("OpenAI key configuration failed.")
    exit(1)


def init_blog(description, published_articles, toneofvoice, keywords):
    if keywords is None:
        prompt = """I have the following blog with the following description: """ + description + """.
        The blog has published articles with titles: """ + str(published_articles) + """.
        The blog has following tone of voice: """ + str(toneofvoice) + """.
        I want you to propose next 15 article titles with categories but be creative. Rotate categories randomly.
        Focus on articles with long-tail keywords, have high potential to rank in top positions on Google 
        and titles will have high click through rate. Read the categories from description in random order.
        The titles will have maximum of 9 words.
        If you want to use year, it should be 2023 but make sure it makes sense to use year!
        Output all in JSON format. Strictly follow the following JSON format:
        
        {
            "Category": "Category name",
            "Title": "Article title"
        }
        """
    else:
        prompt = """I have the following blog with the following description: """ + description + """.
                The blog has following articles with titles: """ + str(published_articles) + """.
                The blog has following tone of voice: """ + str(toneofvoice) + """.
                I want you to propose next 3 article titles with categories but be creative. Rotate categories randomly.
                Focus on articles with following keywords: """ +str(keywords)+""". You can create and use long-tail version of them. 
                Titles will have high click through rate. Read the categories from description in random order.
                The titles will have maximum of 9 words.
                If you want to use year, it should be 2023 but make sure it makes sense to use year!
                Output all in JSON format. Strictly follow the following JSON format:

                {
                    "Category": "Category name",
                    "Title": "Article title"
                }
                """

    chunked_output = ""
    for chunk in openai.ChatCompletion.create(
            model=cfg.llm_model,
            temperature=0.7,
            stream=True,
            messages=[
                {'role': 'system', 'content': 'Your name is BloggingGPT.'},
                {'role': 'system', 'content': "You're an expert in blogging, research and SEO."},
                {'role': 'system', 'content': 'You strictly return content user asked for only.'},
                {"role": "user", "content": prompt}
            ]
    ):
        content = chunk["choices"][0].get("delta", {}).get("content")
        if content is not None:
            #print(content, end='')
            chunked_output += content

    return chunked_output
orchestrar/blogs.py
seedgularity/AIBlogPilotGPT
import sys
import openai
from dotenv import load_dotenv
import colorama
colorama.init(autoreset=True)
from config import Config
import re

from wordpress_xmlrpc import Client, WordPressPost
from wordpress_xmlrpc.methods.posts import NewPost

import ssl
ssl._create_default_https_context = ssl._create_unverified_context

load_dotenv()

cfg = Config()

# Configure OpenAI API key
try:
    openai.api_key = cfg.openai_api_key
    browserless_api_key = cfg.browserless_api_key
    llm_model = cfg.llm_model
except KeyError:
    sys.stderr.write("OpenAI key configuration failed.")
    exit(1)


def convert_to_gutenberg_blocks(text):
    # Split the text into paragraphs
    paragraphs = text.split('\n\n')

    # Initialize an empty list to hold the blocks
    blocks = []

    # Iterate over each paragraph
    for paragraph in paragraphs:
        # Split the paragraph into lines
        lines = paragraph.split('\n')

        # Initialize an empty string to hold the current paragraph
        current_paragraph = ""

        # Iterate over each line
        for line in lines:
            # Check if the line is a headline
            if re.match(r"^<h[1-6]>", line):
                # If there's a current paragraph, add it as a block
                if current_paragraph:
                    blocks.append(create_paragraph_block(current_paragraph))
                    current_paragraph = ""

                # Add the headline as a block
                blocks.append(create_heading_block(line))

            # Check if the line is a link
            elif re.search(r"\[(.*?)\]\((.*?)\)", line):
                # If there's a current paragraph, add it as a block
                if current_paragraph:
                    blocks.append(create_paragraph_block(current_paragraph))
                    current_paragraph = ""

                # Add the link as a block
                blocks.append(create_link_block(line))

            # Otherwise, add the line to the current paragraph
            else:
                current_paragraph += line

        # If there's a current paragraph, add it as a block
        if current_paragraph:
            blocks.append(create_paragraph_block(current_paragraph))

    # Return the blocks as a HTML string
    return '\n'.join(blocks)

def create_paragraph_block(text):
    # Replace **text** with <strong>text</strong>
    text = re.sub(r"\*\*(.*?)\*\*", r"<strong>\1</strong>", text)
    return '<!-- wp:paragraph --><p>{}</p><!-- /wp:paragraph -->'.format(text)

def create_link_block(text):
    # Replace [text](url) with <a href="url">text</a>
    text = re.sub(r"\[(.*?)\]\((.*?)\)", r'<a href="\2">\1</a>', text)
    return '<!-- wp:paragraph --><p>{}</p><!-- /wp:paragraph -->'.format(text)

def create_heading_block(text):
    level = re.search(r"<h([1-6])>", text).group(1)
    text = re.sub(r"<\/?h[1-6]>", "", text)
    return '<!-- wp:heading {{"level": {}}} --><h{}>{}</h{}><!-- /wp:heading -->'.format(level, level, text.strip(), level)

def create_list_block(text):
    return '<!-- wp:list --><ul><li>{}</li></ul><!-- /wp:list -->'.format(text.replace("-", "").strip())

def create_image_block(text):
    alt_text, url = re.match(r"^!\[(.*)\]\((.*)\)", text).groups()
    return '<!-- wp:image {{"url": "{}", "alt": "{}"}} --><figure class="wp-block-image"><img src="{}" alt="{}"/></figure><!-- /wp:image -->'.format(url, alt_text, url, alt_text)

def create_quote_block(text):
    return '<!-- wp:quote --><blockquote>{}</blockquote><!-- /wp:quote -->'.format(text.replace("> ", "").strip())


##################### ONLY FOR TESTING #####################
def post_to_wordpress(title, content, category, tags):
    wp_url = cfg.site_url
    wp_username = cfg.wp_admin_username
    wp_password = cfg.wp_admin_password
    wp_blogid = ""

    wp = Client(wp_url, wp_username, wp_password)

    post = WordPressPost()
    post.title = title
    post.content = content
    post.terms_names = {
        'category': [category],
        'post_tag': tags
    }
    post.post_status = 'draft'  # Set the status of the new post.

    wp.call(NewPost(post))

def main():
    # Open the file in read mode ('r')
    with open('../How to Make Your Own Eco-Friendly Shopping Bags.txt', 'r') as file:
        # Read the file content and store it in the 'chunk' variable
        chunk = file.read()

    # Now you can use the 'chunk' variable in the convert_to_gutenberg_blocks function
    gutenberg_blocks = convert_to_gutenberg_blocks(chunk)
    post_to_wordpress("How to Make Your Own Eco-Friendly Shopping Bags", gutenberg_blocks, "Climate Change", ["Climate Change"])

if __name__ == "__main__":
    main()
orchestrar/gutenberg.py
seedgularity/AIBlogPilotGPT
import xmlrpc.client as xmlrpc_client
from wordpress_xmlrpc import Client, WordPressPost
from wordpress_xmlrpc.methods.posts import NewPost
from wordpress_xmlrpc.methods.media import UploadFile
from dotenv import load_dotenv
from config import Config
import requests
import json

import ssl
ssl._create_default_https_context = ssl._create_unverified_context

# Load the .env file
load_dotenv()

# Configure OpenAI API key
cfg = Config()


def get_all_articles(site_url):
    page = 1
    published_articles = ""
    while True:
        response = requests.get(f'{site_url}/wp-json/wp/v2/posts?page={page}')
        posts = json.loads(response.text)

        # Check if posts is a list
        if not isinstance(posts, list):
            break

        if len(posts) == 0:
            break

        for post in posts:
            # Check if the post is a dictionary
            if not isinstance(post, dict):
                continue

            #published_articles += post['title']['rendered'] + '\n' + post['content']['rendered'] + ', \n\n'
            published_articles += 'Article ID: ' + str(post['id']) + '\nwith Article Title: ' + post['title']['rendered'] + '\nand Article Content: ' + post['content']['rendered'] + ', \n\n'
            #print(post['title']['rendered'])

        page += 1

    return published_articles



def get_all_posts_titles(site_url):
    page = 1
    published_articles = ""
    while True:
        response = requests.get(f'{site_url}/wp-json/wp/v2/posts?page={page}')
        posts = json.loads(response.text)

        # Check if posts is a list
        if not isinstance(posts, list):
            break

        if len(posts) == 0:
            break

        for post in posts:
            # Check if the post is a dictionary
            if not isinstance(post, dict):
                continue

            published_articles += post['title']['rendered'] + ', '
            #print(post['title']['rendered'])

        page += 1

    return published_articles

# Example usage:
#site_url = 'https://iminsweden.com/'
#get_all_posts_titles(site_url)

def post_to_wordpress(title, content, category, tags, image_path=None, wp_admin=None, wp_password=None, wp_url=None):
    wp_url = wp_url if wp_url is not None else cfg.site_url
    wp_username = wp_admin if wp_admin is not None else cfg.wp_admin_username
    wp_password = wp_password if wp_password is not None else cfg.wp_admin_password

    wp = Client(wp_url, wp_username, wp_password)

    post = WordPressPost()
    post.title = title
    post.content = content
    post.terms_names = {
        'category': [category],
        'post_tag': tags
    }
    post.post_status = 'publish'  # Set the status of the new post.

    # If an image path is provided, upload the image and set it as the featured image
    if image_path is not None:
        data = {
            'name': 'picture.jpg',
            'type': 'image/jpeg',  # mimetype
        }

        # read the binary file and let the XMLRPC library encode it into base64
        with open(image_path, 'rb') as img:
            data['bits'] = xmlrpc_client.Binary(img.read())

        response = wp.call(UploadFile(data))
        attachment_id = response['id']

        post.thumbnail = attachment_id

    wp.call(NewPost(post))

def load_post_from_wp():
    return 0


if __name__ == "__main__":
    post_to_wordpress("aaaa", "Uncategorized", "Uncategorized", "", "../temp/imgs/C1CH8g2L7m102KkTG8tI_small.jpg")
orchestrar/wp.py
seedgularity/AIBlogPilotGPT
#https://github.com/mayooear/gpt4-pdf-chatbot-langchain
researcher/pdf.py
seedgularity/AIBlogPilotGPT
import os
import sys
import time
import requests
import openai
from serpapi import GoogleSearch
from dotenv import load_dotenv
from termcolor import colored
from tqdm import tqdm
import concurrent.futures
import colorama
colorama.init(autoreset=True)
from config import Config

load_dotenv()

cfg = Config()

# Configure OpenAI API key
try:
    #openai.api_key = cfg.openai_api_key
    openai.api_key = cfg.openai_api_key_fast
    browserless_api_key = cfg.browserless_api_key
    openai_model = cfg.llm_model
    serpapi_api_key = cfg.serpapi_api_key
except KeyError:
    sys.stderr.write("OpenAI key configuration failed.")
    exit(1)

headers = {'Cache-Control': 'no-cache', 'Content-Type': 'application/json'}
params = {'token': browserless_api_key}

def scrape(link):
    """Scrape the content of a webpage."""
    json_data = {
        'url': link,
        'elements': [{'selector': 'body'}],
    }
    response = requests.post('https://chrome.browserless.io/scrape', params=params, headers=headers, json=json_data)

    if response.status_code == 200:
        webpage_text = response.json()['data'][0]['results'][0]['text']
        return webpage_text
    else:
        return ""

def summarize(question, webpage_text):
    """Summarize the relevant information from a body of text related to a question."""
    prompt = f"""You are an intelligent summarization engine. Extract and summarize the
  most relevant information from a body of text related to a question.

  Question: {question}

  Body of text to extract and summarize information from:
  {webpage_text[0:2500]}

  Relevant information:"""

    while True:
        try:
            response = openai.ChatCompletion.create(
                model=openai_model,
                messages=[
                    {"role": "system", "content": "You are a helpful assistant."},
                    {"role": "user", "content": prompt},
                ]
            )
            return response.choices[0].message.content
        except openai.error.RateLimitError:
            print("Rate limit exceeded. Sleeping for 3 seconds.")
            time.sleep(3)
        except openai.error.ServiceUnavailableError:
            print("Service unavailable. Retrying in 5 seconds.")
            time.sleep(5)

def final_summary(question, summaries):
    """Construct a final summary from a list of summaries."""
    num_summaries = len(summaries)
    prompt = f"You are an intelligent summarization engine. Extract and summarize relevant information from the {num_summaries} points below to construct an answer to a question.\n\nQuestion: {question}\n\nRelevant Information:"

    for i, summary in enumerate(summaries):
        prompt += f"\n{i + 1}. {summary}"

    while True:
        try:
            response = openai.ChatCompletion.create(
                model=openai_model,
                messages=[
                    {"role": "system", "content": "You are a helpful assistant."},
                    {"role": "user", "content": prompt},
                ]
            )
            return response.choices[0].message.content
        except openai.error.RateLimitError:
            print("Rate limit exceeded. Sleeping for 3 seconds.")
            time.sleep(3)
        except openai.error.ServiceUnavailableError:
            print("Service unavailable. Retrying in 5 seconds.")
            time.sleep(5)

def link(r):
    """Extract the link from a search result."""
    return r['link']

def search_results(question):
    """Get search results for a question."""
    search = GoogleSearch({
        "q": question,
        "api_key": serpapi_api_key,
        "logging": False
    })

    result = search.get_dict()
    return list(map(link, result['organic_results']))

def print_citations(links, summaries):
    """Print citations for the summaries."""
    print("CITATIONS")
    num_citations = min(len(links), len(summaries))
    for i in range(num_citations):
        print(f"[{i + 1}] {links[i]}\n{summaries[i]}\n")

def scrape_and_summarize(link, question):
    """Scrape the content of a webpage and summarize it."""
    webpage_text = scrape(link)
    summary = summarize(question, webpage_text)
    return summary

def go(keyphrase=None):
    if keyphrase is None:
        keyphrase = input("What would you like me to search?")
    links = search_results(keyphrase)[:7]  # Limit the number of search results
    summaries = []

    with concurrent.futures.ThreadPoolExecutor() as executor:
        future_to_summary = {executor.submit(scrape_and_summarize, link, keyphrase): link for link in links}
        for i, future in enumerate(concurrent.futures.as_completed(future_to_summary)):
            summaries.append(future.result())
            print(f"Step {i+1}: Scraping and summarizing link {i+1}")

    print("Step 9: Generating final summary")
    answer = final_summary(keyphrase, summaries)

    #print("HERE IS THE ANSWER")
    #print(answer)
    #print_citations(links, summaries)
    return answer

if __name__ == "__main__":
    go()
researcher/search.py
seedgularity/AIBlogPilotGPT