AI Article Generator
Overview of the AI-Driven Content Generation and Management System
This software system is an advanced, AI-powered platform designed for automated content creation and digital publishing. Utilizing Python and various APIs, it integrates artificial intelligence, image processing, and web services to automate the generation, editing, and distribution of digital content, especially articles.
Click Here to View my AI Article Generating Website
This is an example of the AI articles generated
from flask import Flask, request, jsonify, make_response
from flask_cors import CORS
from contentgenerator import GenerateArticle
app = Flask(__name__)
# Enable CORS for all domains on all routes
CORS(app, resources={r"/*": {"origins": "*"}}, supports_credentials=True)
@app.route('/generate_article', methods=['POST', 'OPTIONS'])
def generate_article():
if request.method == 'OPTIONS':
response = make_response()
response.headers.set('Access-Control-Allow-Origin', '*')
response.headers.set('Access-Control-Allow-Headers', 'Content-Type')
response.headers.set('Access-Control-Allow-Methods', 'POST')
print('OPTIONS Response Headers:', response.headers)
return response
else:
try:
data = request.json
generator = GenerateArticle()
article, post_id, post_url = generator.generate_article(data['topic'])
# If article is None or ValueError is raised
if article is None or post_id is None:
return jsonify({'error': 'Article generation failed'}), 400
return jsonify({'post_id': post_id, 'post_url': post_url})
except ValueError as e:
return jsonify({'error': str(e)}), 400
if __name__ == '__main__':
app.run(debug=True, port=5000)
main.py
- Flask Application Setup:
- Initializes a Flask app instance, setting up the web server backend.
- Enables Cross-Origin Resource Sharing (CORS) across all routes for unrestricted access from different domains, crucial for API accessibility.
- Article Generation Endpoint (
/generate_article
):- Defines a POST route to handle article generation requests.
- Uses an
OPTIONS
method to respond to preflight requests in CORS contexts, ensuring compatibility with browsers’ same-origin policy. - Extracts the article topic from the incoming JSON request.
- Creates an instance of
GenerateArticle
fromcontentgenerator.py
to generate the article, post ID, and URL based on the provided topic. - Handles potential errors with appropriate JSON responses, indicating robust error handling.
- Response Handling:
- Returns a JSON response containing the post ID and URL if the article generation is successful.
- Sends an error response if the article generation fails or encounters exceptions, ensuring the client receives meaningful feedback.
- Server Execution:
- Configures the Flask app to run with debug mode enabled on port 5000, facilitating development and testing.
from email.mime import image
from nntplib import ArticleInfo
from pydoc_data.topics import topics
from urllib import request
from wordpress import wordPress
from config import UNSPLASH_API_KEY, WORDPRESS_PASSWORD, WORDPRESS_USERNAME,WORDPRESS_SITE_URL, GOOGLE_API_KEY, GOOGLE_CX, OPENAI_API_KEY
import requests
import json
import random
import re
import pandas as pd
from aiassistant import OpenAIAssistant
class Images:
def __init__(self,openai_assistant):
self.currentarticle = OpenAIAssistant()
self.WpArticle = wordPress()
self.offset = 0
#self.google_api_key = google_api_key
#self.google_cx = google_cx
#self.unsplash_api_key = unsplash_api_key
def search_google_images(query):
url = "https://www.googleapis.com/customsearch/v1"
params = {
'key': GOOGLE_API_KEY,
'cx': GOOGLE_CX,
'q': query,
'searchType': 'image',
'imgSize': 'large', # Set image size to large for higher quality images
'num': 10,
} # Number of results per request }
response = requests.get(url, params=params)
if response.status_code == 200:
results = json.loads(response.content)['items']
if results:
return random.choice(results)['link']
return None # Define a function to search for images on Unsplash based on the topic
def search_unsplash_images(self,topics):
headers = {
'Authorization': f'Client-ID {UNSPLASH_API_KEY}',
'Accept-Version': 'v1'
}
# Initialize empty lists to store featured image URLs and content image URLs
featured_image_urls = []
content_image_urls = []
for topic in topics:
# Search for an image for the featured image
query = topic
url = f'https://api.unsplash.com/search/photos?query={query}&orientation=landscape'
response = requests.get(url, headers=headers)
if response.status_code == 200:
results = json.loads(response.content)['results']
if results:
# Select a random image from the results
featured_image_url = random.choice(results)['urls']['regular']
featured_image_urls.append(featured_image_url)
else:
featured_image_urls.append(None)
# Search for an image to add to the content
query = f'{topic}'
url = f'https://api.unsplash.com/search/photos?query={query}&orientation=landscape'
response = requests.get(url, headers=headers)
if response.status_code == 200:
results = json.loads(response.content)['results']
if results:
# Select a random image from the results
content_image_url = random.choice(results)['urls']['regular']
content_image_urls.append(content_image_url)
else:
content_image_urls.append(None)
else:
content_image_urls.append(None)
return random.choice(featured_image_urls), random.choice(content_image_urls)
def image_info_dictionary(self, article):
image_positions = {}
# Adjusted regex pattern to match your image placeholders and descriptions
image_pattern = r'\["?image\s*(\d+)"?\]\s*\["?([^"]+)"?\]'
matches = list(re.finditer(image_pattern, article))
print("Number of matches found:", len(matches)) # Debug print
for match in matches:
image_placeholder = match.group(1)
image_description = match.group(2)
position = match.start()
image_positions[image_placeholder] = {
"pos": position,
"image_description": image_description,
"matched_string": match.group(0)
}
print(f"Match: {match.group(0)}, Position: {position}, Description: {image_description}") # Debug print
return image_positions, article
def insert_content_images(self, article, topic):
print("Article before processing:", article) # Debug print
image_dictionary, updated_article = self.image_info_dictionary(article)
print("Image Dictionary:", image_dictionary) # Debug print
for image_info in image_dictionary.values():
pos = image_info["pos"] + self.offset
matched_string = image_info["matched_string"]
description = image_info["image_description"]
# Debug prints
print("Position:", pos)
print("Description:", description)
# Generate the image using the description
image_url = self.currentarticle.generate_image(description)
print("Generated Image URL:", image_url)
# Insert the image URL into the article text at the specified position
content_media_id, wp_content_image_url = self.WpArticle.upload_media_to_wordpress(image_url, topic)
updated_article = updated_article[:pos] + f'<img src="{wp_content_image_url}">' + updated_article[pos + len(matched_string):]
self.offset += len(f'<img src="{wp_content_image_url}">') - len(matched_string)
print("Updated Article Segment:", updated_article[pos:pos+100]) # Print a segment of the updated article for verification
return updated_article
def insert_featured_images(self,img_keywords,topic):
featured_image_url = self.currentarticle.generate_image(img_keywords)
#featured_image_url, content_image_url_notused = self.search_unsplash_images(img_keywords)
#image_description = self.generate_image_description(article)
#content_image_url=self.article.generate_image(image_description)
featured_media_id, featured_image_url = self.WpArticle.upload_media_to_wordpress(featured_image_url, topic)
return featured_media_id, featured_image_url
Image_handling.py
Key Functionalities:
- Image Searching:
- Implements functions to search for images using Google’s Custom Search API (
search_google_images
) and Unsplash API (search_unsplash_images
). This showcases the script’s capability to integrate with external APIs and retrieve relevant images based on given topics or queries.
- Implements functions to search for images using Google’s Custom Search API (
- Image Information Processing:
- The
image_info_dictionary
method processes articles to identify placeholders for images and their descriptions. It uses regex patterns to match and extract image-related information, demonstrating proficiency in text processing and pattern matching.
- The
- Image Integration into Articles:
- The
insert_content_images
method incorporates images into articles at specified positions. It generates images using descriptions through theOpenAIAssistant
, uploads them to WordPress, and updates the article content with image URLs. This process highlights the script’s ability to manage content dynamically and integrate AI-generated images into textual content.
- The
- Featured Image Handling:
- The
insert_featured_images
method handles the generation and uploading of featured images for articles, further integrating with WordPress functionalities. This method signifies the script’s role in enhancing the visual appeal and completeness of generated articles.
- The
Complexities:
- API Integration and Usage: The script demonstrates complex interactions with external APIs (Google, Unsplash, WordPress) for image searching and uploading. Handling API responses, especially in the context of image data, requires careful parsing and error handling.
- Regular Expressions: Utilizing regex for parsing image placeholders and descriptions in articles indicates an advanced understanding of text processing, crucial for dynamic content manipulation.
- Dynamic Content Modification: The ability to dynamically insert images into articles based on AI-generated descriptions and user-defined placeholders shows a sophisticated approach to content management.
- Error Handling and Debugging: The script includes error handling mechanisms and debugging prints, essential for ensuring robustness and easing maintenance and troubleshooting.
import pandas as pd
from wordpress import wordPress
from aiassistant import OpenAIAssistant
from image_handling import Images
from gui import CustomDialog, show_article_dialog
import openpyxl
import json
import utils
from config import DATABASE_LOCATION, ARTICLE_DATABASE, ARTICLES
class GenerateArticle:
def __init__(self):
self.article = OpenAIAssistant()
self.images = Images(self.article)
self.wpArticle = wordPress()
def generate_image_description(self, article_text):
prompt = f"Based on the following article, provide a short description for a relevant image:\n\n{article_text}"
return self.article.ask_gpt(prompt)
def generate_topics(self, n_topics=1):
topics = []
for _ in range(n_topics):
response = self.article.ask_gpt(self._topic_prompt())
response_dict, error = utils.parse_json_string(utils.clean_response_string(response))
if error:
# Handle the error appropriately, e.g., log the error or raise an exception
continue
utils.append_data_to_excel(pd.DataFrame(response_dict), ARTICLES)
topics.append(response_dict)
return topics
def generate_initial_article(self, topic):
article = self.article.ask_gpt(self._article_prompt(topic))
article = self._clean_article(article)
title = self._generate_title(topic)
return article, title
def generate_improved_article(self, topic):
prompt = f"Improve journal article on {topic}"
improved_article = self.article.ask_gpt(prompt)
title = self._generate_title(improved_article)
return improved_article, title
def edit_article(self, user_input, article):
return self.article.ask_gpt(f"{user_input}\n{article}")
""" def generate_article(self, img_keywords, topic, category):
article, title = self.generate_initial_article(topic)
user_decision, article = self._article_dialog_loop(article)
if user_decision == "Upload Article":
article = self.images.insert_content_images(article, topic)
featured_media_id, _ = self.images.insert_featured_images(img_keywords, topic)
category_id = self.wpArticle.get_category_id(category)
if category_id:
PostID = self.wpArticle.create_post(title, article, category_id, featured_media_id)
return article, PostID
elif user_decision == "Do Not Upload":
# Skip to the next topic or handle as needed
return None, None
# If user decides to edit the output, no action is needed here
return article, None"""
def generate_image_keywords(self, topic):
prompt = f"""Provide an image description for Dalle to generate an interesting image on the topic '{topic}' in a python list format like: ["Keyword1","Keyword2","Keyword3"] """
response = self.article.ask_gpt(prompt)
try:
# Parsing the string response into a Python list
image_keywords_list = eval(response) # Use eval() cautiously
print(image_keywords_list)
# Joining the list into a comma-separated string
image_keywords = ', '.join(image_keywords_list)
print(image_keywords)
return image_keywords
except Exception as e:
print(f"Could not generate image keywords: {e}")
# Handle the error appropriately
return []
""" def generate_image_keywords(self, topic):
prompt = "Provide an image description for Dalle to generate an interesting image on the topic '{topic}' in a python list format like: ["Keyword1","Keyword2","Keyword3"]
response = self.article.ask_gpt(prompt)
try:
# Parsing the string response into a Python list
image_keywords_list = eval(response) # Use eval() cautiously
print(image_keywords_list)
# Joining the list into a comma-separated string
image_keywords = ', '.join(image_keywords_list)
print(image_keywords)
return image_keywords
except Exception as e:
print(f"Could not generate image keywords: {e}")
# Handle the error appropriately
return []"""
def generate_image_keywords(self, topic):
prompt = f"""Provide an a short one sentence image description for Dalle to generate an interesting image on the topic '{topic}' in a python list format like: ["an intersting desciription for featured image of article"] """
response = self.article.ask_gpt(prompt)
try:
# Parsing the string response into a Python list
image_keywords_list = eval(response) # Use eval() cautiously
print(image_keywords_list)
# Joining the list into a comma-separated string
image_keywords = ', '.join(image_keywords_list)
print(image_keywords)
return image_keywords
except Exception as e:
print(f"Could not generate image keywords: {e}")
# Handle the error appropriately
return []
def generate_category(self, topic):
prompt = f"Provide one word for an appropriate category for a website post on the topic: '{topic}' in python list format such as: [category]"
response = self.article.ask_gpt(prompt)
print(response)
# Attempt to parse the response
try:
# Removing brackets and quotes, and trimming whitespace
cleaned_response = response.replace('[', '').replace(']', '').replace("'", "").replace('"', '').strip()
# Splitting the string into a list based on commas
category_list = cleaned_response.split(',')
# Get the first item in the list as the category, or default to "Uncategorized"
category = category_list[0].strip() if category_list else "Uncategorized"
return category
except Exception as e:
print(f"An error occurred: {e}")
# Handle the error appropriately
return "Uncategorized"
def generate_article(self, topic):
image_keywords = self.generate_image_keywords(topic)
category = self.generate_category(topic)
article, title = self.generate_initial_article(topic)
# Check if the article is less than 50 words
word_count = len(article.split())
if word_count < 50:
raise ValueError("Generated article is too short.")
# Insert images into the article
article = self.images.insert_content_images(article, topic)
featured_media_id, _ = self.images.insert_featured_images(image_keywords, topic)
# Create the WordPress post
category_id = self.wpArticle.get_category_id(category)
if category_id:
post_id, post_url = self.wpArticle.create_post(title, article, category_id, featured_media_id)
return article, post_id, post_url
else:
return None, None
def _article_dialog_loop(self, article):
user_decision = None
user_input = None
while True:
button_clicked, user_input = show_article_dialog(self.root, article)
if button_clicked == "Upload Article":
user_decision = "Upload Article"
break
elif button_clicked == "Do Not Upload":
user_decision = "Do Not Upload"
break
elif button_clicked == "Edit Output":
article = self.article.ask_gpt(user_input + "\n" + article)
# Continue the loop for further actions
return user_decision, article
def _topic_prompt(self):
topic = """
create a nested dictionary of interesting topics for articles,
keywords for images to represent that article, and a
category for that article in the format shown below:
topic_dict = {
"topic1": {
"Topic": "interesting topic",
"Image Search": [keyword1, keyword2, keyword3],
"Category": "website category"
},
"topic2": {
"Topic": "interesting topic",
"Image Search": [keyword1, keyword2, keyword3],
"Category": "website category"
},
"topic3": {
"Topic": "interesting topic",
"Image Search": [keyword1, keyword2, keyword3],
"Category": "website category"
}
}
please don't write anything else but the dictionary
"""
return topic
def _article_prompt(self,articleprompt):
prompt = f"""Generate an interesting and informative article between 200 and
500 words on the topic: '{articleprompt}'. Make sure the article does not
have a title, does not have an abstract, and does not have a heading
for the introduction. Enclose subheadings with HTML: <h5> tag. Include paragraph tags: <p> tag. Create 2 image positions
and descriptions after the closing paragraph tags (</p>) in the article .
The positions should be in the form "image1","image2" etc. followed by image description as shown: ["image1"][image 1 description].
The images should be relevant to the paragraph they are inserted into. The description should be a short sentence that describes the image.
The description will be used with an AI like DALLE to generate an image relevant
to the corresponding paragraph."""
return prompt
def _generate_title(self, topic):
prompt = f"""Write me an interesting title for the {topic} in the form: ["title"]"""
response = self.article.ask_gpt(prompt)
try:
# Removing brackets and quotes, and trimming whitespace
cleaned_response = response.replace('[', '').replace(']', '').replace("'", "").replace('"', '').strip()
# Splitting the string into a list based on commas
title_list = cleaned_response.split(',')
# Get the first item in the list as the category, or default to "Uncategorized"
title = title_list[0].strip() if title_list else "No Title"
return title
except Exception as e:
print(f"An error occurred: {e}")
# Handle the error appropriately
return "No Title"
def _clean_article(self, article):
# Add your cleaning logic here
cleaned_article = article # Replace this with actual cleaning operations
return cleaned_article
class GenerateArticleTopics:
def __init__(self, root):
self.root = root
self.topic_ai = OpenAIAssistant()
def generate_topics(self, n_topics=1):
topics = []
for _ in range(n_topics):
response = self.topic_ai.ask_gpt(self._topic_prompt())
response_dict, error = utils.parse_json_string(utils.clean_response_string(response))
if error:
# Handle the error appropriately
continue
topics.append(response_dict)
utils.append_data_to_excel(pd.DataFrame(response_dict), "ArticleTypes.xlsx")
return topics
def process_topics(self):
workbook, worksheet = utils.load_or_initialize_workbook(DATABASE_LOCATION + ARTICLES, ["Image Search", "Topic", "Category"])
database_workbook, database_worksheet = utils.load_or_initialize_workbook(DATABASE_LOCATION + ARTICLE_DATABASE, ["Image Search", "Topic", "Category"])
topics = utils.read_worksheet(worksheet)
database_topics = utils.read_worksheet(database_worksheet)
matching_topics = set(topics).intersection(database_topics)
utils.delete_matching_rows(worksheet, matching_topics)
utils.save_workbook(workbook, DATABASE_LOCATION + ARTICLES)
for topic_data in utils.iterate_rows(worksheet, ["Image Search", "Topic", "Category"]):
image_search, topic, category = topic_data
print(topic_data["Image Search"])
if topic_data["Topic"] not in matching_topics:
self._generate_and_process_article(topic_data["Image Search"],topic_data["Topic"],topic_data["Category"], database_worksheet)
utils.save_workbook(database_workbook, DATABASE_LOCATION + ARTICLE_DATABASE)
utils.save_workbook(database_workbook, "ArticleTypes_Database.xlsx")
def _topic_prompt(self):
return("""
create a nested dictionary of interesting topics for articles,
keywords for images to represent that article, and a
category for that article in the format shown below:
topic_dict = {
"topic1": {
"Topic": "interesting topic",
"Image Search": [keyword1, keyword2, keyword3],
"Category": "website category"
},
"topic2": {
"Topic": "interesting topic",
"Image Search": [keyword1, keyword2, keyword3],
"Category": "website category"
},
"topic3": {
"Topic": "interesting topic",
"Image Search": [keyword1, keyword2, keyword3],
"Category": "website category"
}
}
please don't write anything else but the dictionary
""")
def _generate_and_process_article(self, image_keywords, topic, category, database_worksheet):
article_generator = GenerateArticle(self.root)
article, PostID = article_generator.generate_article(image_keywords, topic, category)
if PostID:
database_worksheet.append([', '.join(image_keywords), topic, category])
print(f"Article for topic '{topic}' has been generated and posted with ID {PostID}.")
contentgenerator.py
Key Functionalities:
- AI-Driven Content Generation:
- Initial Article Generation: Uses OpenAI’s GPT model to generate a draft of the article based on a given topic, demonstrating the integration of AI for initial content creation.
- Improved Article Generation: Enhances the quality of the initial draft by generating a refined version, showcasing advanced use of AI for content improvement.
- Image Description and Keyword Generation:
- Generates image descriptions and keywords relevant to the article’s topic using AI, which are essential for sourcing and creating appropriate images for the articles.
- Category Generation:
- Automatically generates a category for the article using AI, aiding in the organized classification of the content on WordPress.
- Image Integration:
- Integrates the
Images
class fromimage_handling.py
to insert AI-generated or sourced images into the article at appropriate positions, enhancing the article’s visual appeal.
- Integrates the
- WordPress Article Creation:
- Creates and uploads the final article to WordPress, complete with AI-generated content, images, and category, using the
wordPress
class fromwordpress.py
.
- Creates and uploads the final article to WordPress, complete with AI-generated content, images, and category, using the
- Interactive Article Editing (
_article_dialog_loop
):- Provides an option for manual editing of the article through a GUI, allowing for user intervention and customization before finalizing the content.
- Topic and Article Data Management:
- Manages topics and article data using Excel workbooks, storing and processing information necessary for article generation and tracking.
Complexities:
- AI Integration and Text Processing: The script exhibits complex integration with OpenAI’s GPT model, processing and utilizing AI-generated text for various aspects of article creation.
- Modular Design and External Class Integration: Demonstrates a modular approach by integrating functionalities from
image_handling.py
andwordpress.py
, indicating a well-structured and maintainable codebase. - GUI for User Interaction: Incorporates user interfaces for article editing, showcasing the ability to blend automated processes with manual interventions.
- Data Management: Manages data effectively using Excel workbooks, displaying proficiency in handling and organizing large sets of data.
import tkinter as tk
from tkinter import simpledialog
class CustomDialog(simpledialog.Dialog):
def __init__(self, parent, title, message, buttons, article):
self._buttons = buttons
self.article = article
self.message = message
self.result = None # Initialize result
super().__init__(parent, title=title)
def body(self, frame):
tk.Label(frame, text=self.message, padx=10, pady=10).pack()
self.text_widget = tk.Text(frame, padx=10, pady=10, wrap='word', width=50, height=10)
self.text_widget.insert(tk.END, self.article)
self.text_widget.pack(side='left', fill='both', expand=True)
self.user_input = tk.Entry(frame)
self.user_input.pack(pady=10)
scrollbar = tk.Scrollbar(frame, command=self.text_widget.yview)
scrollbar.pack(side='right', fill='y')
self.text_widget.config(yscrollcommand=scrollbar.set)
for button_text in self._buttons:
button = tk.Button(frame, text=button_text, command=lambda text=button_text: self.button_click(text))
button.pack(side=tk.LEFT, padx=10, pady=10)
return self.user_input
def button_click(self, text):
if text == "Upload Article":
self.article = self.text_widget.get("1.0", tk.END).strip()
self.result = (text, self.user_input.get())
self.destroy()
def show_article_dialog(root, article):
message = "Do you want to upload this article to WordPress?"
buttons = ["Upload Article", "Do Not Upload", "Edit Output"]
dialog = CustomDialog(root, "Upload Article?", message, buttons, article)
#root.wait_window(dialog) # Wait for the dialog to close
if hasattr(dialog, 'result'):
return dialog.result
return None, None # Return a default value if dialog was closed unexpectedly
gui.py
Key Functionalities:
- Custom Dialog Creation:
- The
CustomDialog
class extends thesimpledialog.Dialog
of the Tkinter library, providing a customizable modal dialog window. This class is pivotal for creating interactive dialog boxes that capture user inputs and decisions.
- The
- Article Display and Editing Interface:
- The dialog created by
CustomDialog
includes a text widget for displaying the generated article, allowing users to read and optionally edit the content. This feature is crucial for ensuring that users can review and modify AI-generated articles before they are published.
- The dialog created by
- User Decision Handling:
- The GUI offers buttons (such as “Upload Article”, “Do Not Upload”, “Edit Output”) for users to make decisions regarding the article. The script captures these decisions and the potential edits made to the article, illustrating how user feedback is integrated into the content generation process.
- Show Article Dialog Function:
- The
show_article_dialog
function initiates the dialog with the article content and captures the user’s decision and input. This function acts as a bridge between the article generation logic and the GUI, facilitating user interaction.
- The
Complexities:
- Tkinter GUI Development: Utilizing Tkinter to develop a custom dialog demonstrates an understanding of Python’s standard GUI toolkit. It involves handling window events, user inputs, and interface layout, which are fundamental aspects of desktop application development.
- Integration with Content Generation System: The script is designed to integrate seamlessly with the content generation workflow. It interacts with other components of the system, such as the article generation and processing modules, to obtain and return user-modified content.
- User Interaction and Feedback Incorporation: The ability to capture and process user decisions and inputs for AI-generated content highlights the system’s flexibility and responsiveness to user feedback.
import requests
import base64
import json
from io import BytesIO
from PIL import Image
from config import WORDPRESS_API_PASSWORD, WORDPRESS_PASSWORD, WORDPRESS_EMAIL, WORDPRESS_SITE_URL, WORDPRESS_USERNAME
#Word Press Integration Class
class wordPress:
def __init__(self):
self.username = WORDPRESS_USERNAME # Replace with your WordPress email
self.password = WORDPRESS_PASSWORD # Replace with your WordPress password
self.site_url = WORDPRESS_SITE_URL # Replace with your WordPress site URL
self.credentials = f"{self.username}:{self.password}"
self.token = base64.b64encode(self.credentials.encode())
self.headers = {"Authorization": f"Basic {self.token.decode('utf-8')}"}
def category_exists(self, category_name):
# Check if the category already exists
url = f'{WORDPRESS_SITE_URL}/wp-json/wp/v2/categories?search={category_name}'
response = requests.get(url, headers=self.headers)
if response.status_code == 200:
categories = json.loads(response.content)
if categories:
return categories[0]['id']
return None
def create_category(self,category_name):
# Create a new category
url = f'{WORDPRESS_SITE_URL}/wp-json/wp/v2/categories'
data = {
'name': category_name }
response = requests.post(url, headers=self.headers, json=data)
if response.status_code == 201:
category_id = json.loads(response.content)['id']
print(f'Category created with ID: {category_id}')
return category_id
return None
def get_category_id(self,category_name):
# Get the ID of the category
category_id = self.category_exists(category_name)
if category_id:
return category_id
else:
return self.create_category(category_name)
def upload_media_to_wordpress(self,image_url, alt_text):
# Download the image from the URL
response = requests.get(image_url)
img = Image.open(BytesIO(response.content))
# Convert the image to JPEG format
buffer = BytesIO()
img.save(buffer, format="JPEG")
# Upload the image to WordPress
data = {
"alt_text": alt_text,
"media_type": "image/jpeg",
}
files = {'file': ('image.jpg', buffer.getvalue(), 'image/jpeg', {'Expires': '0'})}
response = requests.post(f'{WORDPRESS_SITE_URL}/wp-json/wp/v2/media', headers=self.headers, data=data, files=files)
if response.status_code == 201:
media_id = json.loads(response.content)['id']
data = json.loads(response.text)
print(f'Featured image updated with ID: {media_id}\n')
#data = {'featured_media': media_id}
return media_id, data['guid']['rendered']
else:
return None
def create_post(self, title, content, category_id, featured_media_id):
# Create a post on the WordPress site
url = f"{self.site_url}/wp-json/wp/v2/posts"
data = {
"title": title,
"content": content,
"status": "publish",
"categories": [category_id],
"featured_media": featured_media_id,
}
response = requests.post(url, headers=self.headers, json=data)
if response.status_code == 201:
print(json.loads(response.content))
post_id = json.loads(response.content)["id"]
post_url = json.loads(response.content)["guid"]["rendered"]
print(f"\nPost created with ID: {post_id}")
print(f"\nPost created with url: {post_url}")
return post_id, post_url
else:
print(f"Failed to create post. Status Code: {response.status_code}")
print(f"Response: {response.content}")
return None
wordpress.py
Key Functionalities:
- WordPress Authentication and Initialization:
- Initializes the WordPress integration with necessary credentials, including username and password. It prepares an authentication token for API requests, showcasing an understanding of secure API communication.
- Category Management:
- Provides functions to check if a category already exists (
category_exists
) and to create a new category if needed (create_category
). This feature demonstrates the script’s ability to interact with WordPress’s taxonomy system. - The
get_category_id
function streamlines the process of obtaining a category ID, either by finding an existing category or creating a new one, indicating efficient management of content categorization.
- Provides functions to check if a category already exists (
- Media Uploads to WordPress:
- Implements
upload_media_to_wordpress
to upload images to the WordPress site. It handles image data processing and the intricacies of media file uploads via the WordPress REST API, highlighting the script’s capability in handling media content.
- Implements
- WordPress Post Creation:
- The
create_post
function is pivotal for creating new posts on the WordPress site. It takes essential parameters like title, content, category ID, and media ID to create a well-structured WordPress post, displaying the script’s integration with WordPress content management.
- The
Complexities:
- RESTful API Integration: The script deals with various aspects of WordPress’s REST API, managing categories, media, and posts. This requires handling HTTP requests, processing responses, and understanding WordPress’s API schema.
- Image Processing and Uploads: Converting and uploading images to WordPress, especially handling image data in memory and preparing it for HTTP requests, indicates a sophisticated approach to media management.
- Secure Authentication Handling: Managing secure authentication using base64 encoding and preparing HTTP headers for authenticated requests showcases an understanding of essential web security practices.
- Error Handling and Response Management: The script includes checks for the status of API requests and appropriately handles different response scenarios, ensuring robust and reliable integration.
# utils.py
from turtle import pd
import json
import pandas as pd
import openpyxl
import re
def clean_response_string(response):
# Cleans the response string from the AI to be in a suitable JSON format.
cleaned_string = response.strip().replace('topic_dict =', '').strip()
cleaned_string = cleaned_string.replace("```", "").strip()
cleaned_string = cleaned_string.replace("'", '"')
return cleaned_string
def load_or_initialize_excel(file_name, columns):
# Loads an Excel file into a pandas DataFrame or initializes it if not found.
try:
existing_data = pd.read_excel(file_name)
except FileNotFoundError:
existing_data = pd.DataFrame(columns=columns)
return existing_data
def append_data_to_excel(new_data, file_name):
# Appends new data to an Excel file.
existing_data = load_or_initialize_excel(file_name, new_data.columns)
combined_data = pd.concat([existing_data, new_data], ignore_index=True)
combined_data.to_excel(file_name, index=False)
def clean_article(article):
# Cleans the article by removing placeholders or unwanted sections.
intro_pattern = r'<h\d>\s*Introduction\s*</h\d>'
abstract_pattern = r'<h\d>\s*Abstract\s*</h\d>(\s*<p>.*?</p>)?'
article = re.sub(intro_pattern, '', article, flags=re.IGNORECASE)
article = re.sub(abstract_pattern, '', article, flags=re.IGNORECASE | re.DOTALL)
return article
def parse_json_string(json_string):
# Parses a JSON string and returns a dictionary.
try:
return json.loads(json_string), None
except json.JSONDecodeError as e:
return None, str(e)
def delete_rows_from_worksheet(worksheet, rows):
# Deletes rows from an openpyxl worksheet.
for row in sorted(rows, reverse=True):
worksheet.delete_rows(row)
def save_workbook(workbook, file_path):
# Saves an openpyxl workbook.
workbook.save(file_path)
def load_or_initialize_workbook(file_path, columns):
try:
workbook = openpyxl.load_workbook(file_path)
worksheet = workbook.active
except FileNotFoundError:
workbook = openpyxl.Workbook()
worksheet = workbook.active
for column in columns:
worksheet.append([column])
workbook.save(file_path)
return workbook, worksheet
def read_worksheet(worksheet):
return [row[1] for row in worksheet.iter_rows(min_row=2, values_only=True)]
def delete_matching_rows(worksheet, matching_set):
rows_to_delete = [row for row, value in enumerate(worksheet.iter_rows(min_row=2, values_only=True), start=2) if value[1] in matching_set]
delete_rows_from_worksheet(worksheet, rows_to_delete)
def iterate_rows(worksheet, columns):
for row in worksheet.iter_rows(min_row=2, values_only=True):
yield dict(zip(columns, row))
utils.py
Key Functionalities:
- Data Cleaning and Formatting:
- Implements
clean_response_string
to transform AI response strings into a suitable JSON format, which is crucial for the proper interpretation and use of AI-generated content. - The
clean_article
function removes unwanted placeholders or sections from articles, ensuring the content is well-formatted and presentable for publication.
- Implements
- Excel Workbook Management:
- Functions like
load_or_initialize_excel
,append_data_to_excel
, andsave_workbook
manage Excel workbooks for storing and retrieving data. These functions are vital for maintaining structured data records, such as topics, articles, and image keywords. - Provides capabilities to create new workbooks or load existing ones, append new data, and save changes, demonstrating proficiency in handling Excel files programmatically.
- Functions like
- Worksheet Data Processing:
- The
read_worksheet
function reads data from Excel worksheets, crucial for retrieving stored information for processing. delete_matching_rows
anddelete_rows_from_worksheet
handle the removal of specific rows from worksheets, a necessary feature for maintaining data integrity and relevance.
- The
- JSON Parsing:
parse_json_string
parses JSON strings, converting them into Python dictionaries. This is essential for processing and using JSON-formatted data, especially when working with API responses or AI-generated content.
- Row Iteration:
iterate_rows
provides a generator for iterating over rows in an Excel worksheet, streamlining data access and manipulation in a memory-efficient manner.
Complexities:
- Data Manipulation and Management: Handling data cleaning, formatting, and Excel workbook operations requires a thorough understanding of data structures and file management in Python.
- Integration with AI and Content Generation Components: These utilities are integral to the overall functionality of the system, supporting the AI-driven content generation process and data organization.
- Error Handling and Robustness: The script includes error handling mechanisms, especially in file operations and data parsing, ensuring the system’s robustness and reliability.
- Efficiency in Data Processing: The implementation of generators and efficient data processing techniques highlights a focus on performance, especially important when dealing with large datasets or complex operations.