Skip to content

Commit 357cba3

Browse files
committedApr 22, 2024·
Fixed issue with Gemini API
1 parent 180f28a commit 357cba3

15 files changed

+188
-186
lines changed
 

‎README.md

+19-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,28 @@
1-
# AI Content Generation Toolkit - Alwrity
2-
![](https://github.com/AJaySi/AI-Blog-Writer/blob/main/workspace/keyword_blog.gif)
1+
# How to Use AI Content Generation Toolkit - Alwrity
2+
3+
1). Visit alwrity.com, Under tools section, you will find some AI content writing tools, which are Free & No-Signup.
4+
**Note:** Although, this is limited, as is our wallet & Resources.
5+
6+
2). For complete AI content toolkit, alwrity offers a commandline App. Its a BYOK model(Bring Your Own Key).
7+
**Note:** (🗯️ commandline, byok and shit) ... Now, before you run away 🏃💨
8+
9+
If you have 💻 Laptop + 🛜 Internet + 20 minutes, you will be generating blogs, articles etc with just few words.
10+
11+
**[Getting Started for Absolute Begginers]**(https://www.alwrity.com/post/getting-started-with-alwrity-ai-writer)
12+
13+
Getting started for pretentious Developers : Continue Reading.....
14+
15+
**If you still Get stuck, Open a issue here & say pretty please** :: https://github.com/AJaySi/AI-Writer/issues
16+
317

418
## Introduction
519

620
Alwrity automates and enhances the process of blog creation, optimization, and management.
721
Leveraging AI technologies, it assists content creators and digital marketers in generating, formatting, and uploading blog content efficiently. The toolkit integrates advanced AI models for text generation, image creation, and data analysis, streamlining the content creation pipeline.
822

23+
# AI Content Generation Toolkit - Alwrity
24+
![](https://github.com/AJaySi/AI-Blog-Writer/blob/main/workspace/keyword_blog.gif)
25+
926
---
1027

1128
## Getting Started 🚀 🤞🤞🤞

‎alwrity.py

+24-24
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import typer
77
from prompt_toolkit.shortcuts import checkboxlist_dialog, message_dialog, input_dialog
8+
from prompt_toolkit.shortcuts import radiolist_dialog
89
from prompt_toolkit import prompt
910
from prompt_toolkit.styles import Style
1011
from prompt_toolkit.shortcuts import radiolist_dialog
@@ -20,7 +21,8 @@
2021

2122
app = typer.Typer()
2223

23-
from lib.utils.alwrity_utils import blog_from_audio, blog_from_keyword, do_web_research, do_web_research, write_story, essay_writer, blog_tools, competitor_analysis
24+
from lib.utils.alwrity_utils import blog_from_audio, blog_from_keyword, do_web_research, do_web_research
25+
from lib.utils.alwrity_utils import write_story, essay_writer, blog_tools, competitor_analysis, image_to_text_writer, image_generator
2426

2527

2628
def prompt_for_time_range():
@@ -61,10 +63,11 @@ def start_interactive_mode():
6163
("AI Blog Writer", "AI Blog Writer"),
6264
("AI Story Writer", "AI Story Writer"),
6365
("AI Essay Writer", "AI Essay Writer"),
66+
("AI Image to Text Writer", "AI Image to Text Writer"),
6467
("Online Blog Tools/Apps", "Online Blog Tools/Apps"),
6568
("Do keyword Research", "Do keyword Research"),
6669
("Competitor Analysis", "Competitor Analysis"),
67-
("Create Blog Images(TBD)", "Create Blog Images(TBD)"),
70+
("Create Blog Images", "Create Blog Images"),
6871
("AI Social Media(TBD)", "AI Social Media(TBD)"),
6972
("Quit", "Quit")
7073
]
@@ -76,10 +79,12 @@ def start_interactive_mode():
7679
write_story()
7780
elif mode == 'AI Essay Writer':
7881
essay_writer()
82+
elif mode == 'AI Image to Text Writer':
83+
image_to_text_writer()
7984
elif mode == 'Do keyword Research':
8085
do_web_research()
81-
elif mode == 'Create Blog Images(TBD)':
82-
faq_generator()
86+
elif mode == 'Create Blog Images':
87+
image_generator()
8388
elif mode == 'Competitor Analysis':
8489
competitor_analysis()
8590
elif mode == 'Online Blog Tools/Apps':
@@ -105,8 +110,7 @@ def check_search_apis():
105110
"""
106111

107112
# Use rich.print for styling and hyperlinking
108-
print("\n\n🙋♂️ 🙋♂️ Before doing web research, ensure the following API keys are available:")
109-
print("Blogen uses Basic, Semantic, Neural web search using above APIs for contextual blog generation.\n")
113+
print("Alwrity uses Basic, Semantic, Neural web search using above APIs for contextual blog generation.\n")
110114

111115
api_keys = {
112116
"METAPHOR_API_KEY": "Metaphor AI Key (Get it here: [link=https://dashboard.exa.ai/login]Metaphor API[/link])",
@@ -121,7 +125,6 @@ def check_search_apis():
121125
if os.getenv(key) is None:
122126
# Use rich.print for styling and hyperlinking
123127
print(f"[bold red]✖ 🚫 {key} is missing:[/bold red] [blue underline]Get {key} API Key[/blue underline]")
124-
typer.echo(f"[bold red]✖ 🚫 {key} is missing:[/bold red] [link={key}]Get {key} API Key[/link]")
125128
missing_keys.append((key, description))
126129

127130
if missing_keys:
@@ -142,10 +145,12 @@ def get_api_key(api_key: str, api_description: str):
142145
api_key (str): The name of the API key variable.
143146
api_description (str): The description of the API key.
144147
"""
145-
user_input = typer.prompt(f"\n\n🙆💩💩🙆 - Please enter {api_key} API Key:")
148+
print("\n\n")
149+
print(f"[bold green] 🙋 Attention Here: 🙋 -- {api_description}")
150+
user_input = typer.prompt(f"💩 -**Please Enter(copy/paste) {api_key} API Key** - Here🙋:")
146151
with open(".env", "a") as env_file:
147152
env_file.write(f"{api_key}={user_input}\n")
148-
print(f"✅ {api_description} API Key added to .env file.")
153+
print(f"✅ API Key added to .env file.")
149154

150155

151156
def write_blog():
@@ -172,22 +177,20 @@ def check_llm_environs():
172177
""" Function to check which LLM api is given. """
173178
# Load .env file
174179
load_dotenv(Path('.env'))
175-
# Check if GPT_PROVIDER is defined in .env file
176180
gpt_provider = os.getenv("GPT_PROVIDER")
177181

178182
# Disable unsupported GPT providers
179183
supported_providers = ['google', 'openai', 'mistralai']
180184
if gpt_provider is None or gpt_provider.lower() not in map(str.lower, supported_providers):
181185
# Prompt user to select a provider
182-
selected_provider = radiolistbox(
183-
msg='Select your preferred GPT provider:',
184-
title='GPT Provider Selection',
185-
choices=["Google", "OpenAI", "MistralAI/WIP", "Ollama (TBD)"],
186-
default_choice="Google"
187-
)
188-
gpt_provider = selected_provider
186+
gpt_provider = radiolist_dialog(
187+
title="Select your GPT Provider(llm) from 'google', 'openai', 'mistralai'",
188+
values=[("google", "Google Gemini Pro"), ("openai", "OpenAI- ChatGPT"), ("mistralai", "MistralAI/WIP")]).run()
189189
# Update .env file
190190
os.environ["GPT_PROVIDER"] = gpt_provider
191+
with open(".env", "a") as env_file:
192+
env_file.write(f"GPT_PROVIDER=gpt_provider\n")
193+
print(f"✅ API Key added to .env file.")
191194

192195
if gpt_provider.lower() == "google":
193196
api_key_var = "GEMINI_API_KEY"
@@ -198,9 +201,9 @@ def check_llm_environs():
198201
elif gpt_provider.lower() == "mistralai":
199202
api_key_var = "MISTRAL_API_KEY"
200203
missing_api_msg = "To get your MistralAI API key, please visit: https://mistralai.com/api"
201-
else:
202-
print("Unrecognised/Unsupported GPT provider. Check your main_config and environs.")
203-
exit(1)
204+
205+
if api_key_var not in os.environ:
206+
get_api_key(api_key_var, missing_api_msg)
204207

205208

206209
def check_internet():
@@ -233,13 +236,10 @@ def create_env_file():
233236

234237

235238
if __name__ == "__main__":
236-
print("Checking Internet, lets get the basics right.")
237239
check_internet()
238-
print("Create .env file, if not Present working directory")
239240
create_env_file()
240-
print("Check Metaphor, Tavily, YOU.com Search API keys.")
241+
os.system("clear" if os.name == "posix" else "cls")
241242
check_search_apis()
242-
print("Check LLM details & AI Model to use.")
243243
check_llm_environs()
244244
os.environ["SEARCH_SAVE_FILE"] = os.path.join(os.getcwd(), "workspace",
245245
"web_research_report" + "_" + datetime.now().strftime("%Y-%m-%d_%H-%M-%S"))

‎lib/gpt_providers/image_to_text_gen/gemini_image_details.py

-79
This file was deleted.

‎lib/gpt_providers/text_generation/ai_essay_writer.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ def ai_essay_generator(essay_title, selected_essay_type, selected_education_leve
132132
load_dotenv(Path('../.env'))
133133
genai.configure(api_key=os.getenv('GEMINI_API_KEY'))
134134
# Initialize the generative model
135-
model = genai.GenerativeModel('gemini-1.0-pro')
135+
model = genai.GenerativeModel('gemini-pro')
136136

137137
# Generate prompts
138138
try:

‎lib/gpt_providers/text_generation/gemini_pro_text.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
)
2020

2121

22-
#@retry(wait=wait_random_exponential(min=1, max=60), stop=stop_after_attempt(6))
22+
@retry(wait=wait_random_exponential(min=1, max=60), stop=stop_after_attempt(6))
2323
def gemini_text_response(prompt, temperature, top_p, n, max_tokens):
2424
""" Common functiont to get response from gemini pro Text. """
2525
#FIXME: Include : https://github.com/google-gemini/cookbook/blob/main/quickstarts/rest/System_instructions_REST.ipynb
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from PIL import Image
2+
import requests
3+
4+
# Ensure you sign up for an account to obtain an API key:
5+
# https://platform.stability.ai/
6+
# Your API key can be found here after account creation:
7+
# https://platform.stability.ai/account/keys
8+
9+
10+
def generate_stable_diffusion_image(prompt):
11+
"""
12+
Generate images using Stable Diffusion API based on a given prompt.
13+
14+
Args:
15+
prompt (str): The prompt to generate the image.
16+
image_dir (str): The directory where the image will be saved.
17+
18+
Raises:
19+
Warning: If the adult content classifier is triggered.
20+
Exception: For any issues during image generation or saving.
21+
"""
22+
api_key = os.getenv('STABILITY_API_KEY')
23+
24+
response = requests.post(
25+
f"https://api.stability.ai/v2beta/stable-image/generate/sd3",
26+
headers={
27+
"authorization": f"Bearer {api_key}",
28+
"accept": "image/*"
29+
},
30+
files={"none": ''},
31+
data={
32+
"prompt": prompt,
33+
"output_format": "webp",
34+
},
35+
)
36+
37+
if response.status_code == 200:
38+
with open("./dog-wearing-glasses.jpeg", 'wb') as file:
39+
file.write(response.content)
40+
else:
41+
raise Exception(str(response.json()))

‎lib/text_to_image/generate_image_from_prompt.py ‎lib/gpt_providers/text_to_image_generation/generate_image_from_prompt.py

+10-13
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@
2020
format="<level>{level}</level>|<green>{file}:{line}:{function}</green>| {message}"
2121
)
2222

23-
from .gpt_providers.openai_gpt_provider import generate_dalle2_images, generate_dalle3_images, openai_chatgpt
24-
from .stabl_diff_img2html import generate_stable_diffusion_image
23+
#from .gen_dali2_images
24+
from .gen_dali3_images import generate_dalle3_images
25+
from .gen_stabl_diff_img import generate_stable_diffusion_image
2526

2627

27-
def generate_image(user_prompt, image_dir, image_engine="dalle3"):
28+
def generate_image(user_prompt, image_engine="dalle3"):
2829
"""
2930
The generation API endpoint creates an image based on a text prompt.
3031
@@ -40,18 +41,14 @@ def generate_image(user_prompt, image_dir, image_engine="dalle3"):
4041
Must be one of "url" or "b64_json". Defaults to "url".
4142
--> user (str): A unique identifier representing your end-user, which will help OpenAI to monitor and detect abuse.
4243
"""
43-
logger.info(f"Generated blog images will be stored at: {image_dir=}")
44-
4544
img_prompt = generate_img_prompt(user_prompt)
4645
# call the OpenAI API to generate image from prompt.
47-
logger.info(f"Calling openai.image.generate with prompt: {img_prompt}")
46+
logger.info(f"Calling image.generate with prompt: {img_prompt}")
4847

49-
if 'dalle2' in image_engine:
50-
image_stored_at = generate_dalle2_images(img_prompt, image_dir)
51-
elif 'dalle3' in image_engine:
52-
image_stored_at = generate_dalle3_images(img_prompt, image_dir)
53-
elif 'stable_diffusion' in image_engine:
54-
image_stored_at = generate_stable_diffusion_image(img_prompt, image_dir)
48+
if 'Dalle3' in image_engine:
49+
image_stored_at = generate_dalle3_images(img_prompt)
50+
elif 'Stable Diffusion' in image_engine:
51+
image_stored_at = generate_stable_diffusion_image(img_prompt)
5552

5653
return image_stored_at
5754

@@ -72,5 +69,5 @@ def generate_img_prompt(user_prompt):
7269
Advice for creating prompt for image from the given text(no more than 150 words).
7370
Reply with only one answer and no descrition. Generate image prompt for the below text.
7471
Text: {user_prompt}"""
75-
response = openai_chatgpt(prompt)
72+
response = (prompt)
7673
return response

‎lib/text_to_image/stabl_diff_img2html.py

-66
This file was deleted.

‎lib/utils/alwrity_utils.py

+92
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
from prompt_toolkit.shortcuts import checkboxlist_dialog, message_dialog, input_dialog
77
from prompt_toolkit import prompt
8+
from prompt_toolkit.completion import WordCompleter
9+
from prompt_toolkit.validation import Validator, ValidationError
810
from prompt_toolkit.shortcuts import radiolist_dialog
911

1012
from lib.ai_web_researcher.gpt_online_researcher import gpt_web_researcher
@@ -13,6 +15,7 @@
1315
from lib.ai_writers.speech_to_blog.main_audio_to_blog import generate_audio_blog
1416
from lib.gpt_providers.text_generation.ai_story_writer import ai_story_generator
1517
from lib.gpt_providers.text_generation.ai_essay_writer import ai_essay_generator
18+
from lib.gpt_providers.text_to_image_generation.generate_image_from_prompt import generate_image
1619

1720

1821
def blog_from_audio():
@@ -258,6 +261,95 @@ def blog_tools():
258261
).run()
259262

260263

264+
def image_generator():
265+
""" Generate image from given text """
266+
print("Enter your long string below---")
267+
img_prompt = prompt("Enter text to create image from:: ")
268+
269+
img_models = WordCompleter(['Stability-Stable-Diffusion', 'Dalle2', 'Dalle3'], ignore_case=True)
270+
print("Choose between:: Stable-Diffusion, Dalle2, Dalle3")
271+
img_model = prompt('Choose the image model to use for generation: ', completer=img_models, validator=ModelTypeValidator())
272+
273+
print(f"{img_prompt}----{img_model}")
274+
try:
275+
generate_image(img_prompt, img_model)
276+
except Exception as err:
277+
print(f"Failed to generate image: {err}")
278+
279+
280+
281+
class ModelTypeValidator(Validator):
282+
def validate(self, document):
283+
if document.text.lower() not in ['stability-stable-diffusion', 'dalle2', 'dalle3']:
284+
raise ValidationError(message='Please choose a valid Text to image model.')
285+
286+
287+
def image_to_text_writer():
288+
""" IMage to Text Content Generation"""
289+
os.system("clear" if os.name == "posix" else "cls")
290+
text = "_______________________________________________________________________\n"
291+
text += "\n⚠️ Alert! 💥❓💥\n"
292+
text += "Provide Inputs Below to Continue..\n"
293+
text += "_______________________________________________________________________\n\n"
294+
print(text)
295+
296+
print("Make sure the file path is correct and the file is one of the following image types: PNG, JPEG, WEBP, HEIC, HEIF.\n")
297+
298+
file_location = prompt('⚠️ Enter the image file location: ', validator=FileTypeValidator())
299+
if file_location:
300+
writing_completer = WordCompleter(['Blog', 'Food Recipe', 'Alt Text', 'Marketing Copy'], ignore_case=True)
301+
print("Choose between 'Blog', 'Food Recipe', 'Alt Text', 'Marketing Copy'")
302+
writing_type = prompt('Select the type of writing: ', completer=writing_completer, validator=WritingTypeValidator())
303+
304+
prompt_gemini = None
305+
if writing_type.lower() == 'blog':
306+
prompt_gemini = "Given an image of a product and its target audience, write an engaging marketing description",
307+
elif writing_type.lower() == 'food recipe':
308+
prompt_gemini = """I have the ingredients above. Not sure what to cook for lunch.
309+
Show me a list of foods with the recipes.
310+
Accurately identify the baked good in the image and provide an appropriate and recipe consistent with your analysis.
311+
Write a short, engaging blog post based on this picture.
312+
It should include a description of the meal in the photo and talk about my journey meal prepping.
313+
"""
314+
elif writing_type.lower() == 'alt text':
315+
prompt_gemini = """Given an image from my blog, generate 3 different ALT texts.
316+
The image alt text should be of maximum 2 lines. It should be descriptive and SEO optimised."""
317+
elif writing_type.lower() == 'marketing copy':
318+
prompt_gemini = "Given an image of a product and its target audience, write an engaging marketing description"
319+
320+
print("TBD/FIXME: Will be taken up soon..")
321+
322+
323+
class WritingTypeValidator(Validator):
324+
def validate(self, document):
325+
writing_type = document.text.strip().lower()
326+
if writing_type not in ['blog', 'food recipe', 'alt text', 'marketing copy']:
327+
raise ValidationError(message="Please select a valid writing type: Blog, Food Recipe, Alt Text, or Marketing Copy.")
328+
329+
330+
class FileTypeValidator(Validator):
331+
def validate(self, document):
332+
file_path = document.text.strip()
333+
if not os.path.exists(file_path):
334+
raise ValidationError(message="File does not exist.")
335+
elif not self.is_valid_file_type(file_path):
336+
raise ValidationError(message="Unsupported file type or MIME type. Please select an image file.")
337+
338+
def is_valid_file_type(self, file_path):
339+
# Define supported MIME types for image files
340+
supported_types = ['image/png', 'image/jpeg', 'image/webp', 'image/heic', 'image/heif']
341+
file_mime_type = self.get_file_mime_type(file_path)
342+
return file_mime_type in supported_types
343+
344+
def get_file_mime_type(self, file_path):
345+
# Placeholder function to get the MIME type of the file
346+
# You can use libraries like magic or mimetypes for this purpose
347+
# Example:
348+
# import magic
349+
# mime = magic.Magic(mime=True)
350+
# return mime.from_file(file_path)
351+
return 'image/png' # Placeholder value for demonstration
352+
261353

262354
def competitor_analysis():
263355
text = "_______________________________________________________________________\n"

0 commit comments

Comments
 (0)
Please sign in to comment.