Skip to content

Commit

Permalink
Merge pull request #2 from barun-saha/pylint-fix
Browse files Browse the repository at this point in the history
Pylint and CVE fix
  • Loading branch information
barun-saha authored Mar 23, 2024
2 parents 1d82a0b + 4785fdb commit 10c2c13
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 146 deletions.
64 changes: 30 additions & 34 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from global_config import GlobalConfig


APP_TEXT = json5.loads(open(GlobalConfig.APP_STRINGS_FILE, 'r').read())
APP_TEXT = json5.loads(open(GlobalConfig.APP_STRINGS_FILE, 'r', encoding='utf-8').read())
GB_CONVERTER = 2 ** 30


Expand Down Expand Up @@ -68,18 +68,6 @@ def get_web_search_results_wrapper(text: str) -> List[Tuple[str, str]]:
return results


@st.cache_data
def get_ai_image_wrapper(text: str) -> str:
"""
Fetch and cache a Base 64-encoded image by calling an external API.
:param text: The image prompt
:return: The Base 64-encoded image
"""

return llm_helper.get_ai_image(text)


# def get_disk_used_percentage() -> float:
# """
# Compute the disk usage.
Expand Down Expand Up @@ -111,14 +99,19 @@ def build_ui():

st.title(APP_TEXT['app_name'])
st.subheader(APP_TEXT['caption'])
st.markdown('Powered by [Mistral-7B-Instruct-v0.2](https://huggingface.co/mistralai/Mistral-7B-Instruct-v0.1).')
st.markdown('*If the JSON is generated or parsed incorrectly, try again later by making minor changes '
'to the input text.*')
st.markdown(
'Powered by'
' [Mistral-7B-Instruct-v0.2](https://huggingface.co/mistralai/Mistral-7B-Instruct-v0.2).'
)
st.markdown(
'*If the JSON is generated or parsed incorrectly, try again later by making minor changes'
' to the input text.*'
)

with st.form('my_form'):
# Topic input
try:
with open(GlobalConfig.PRELOAD_DATA_FILE, 'r') as in_file:
with open(GlobalConfig.PRELOAD_DATA_FILE, 'r', encoding='utf-8') as in_file:
preload_data = json5.loads(in_file.read())
except (FileExistsError, FileNotFoundError):
preload_data = {'topic': '', 'audience': ''}
Expand Down Expand Up @@ -158,7 +151,8 @@ def build_ui():
st.text(APP_TEXT['tos2'])

st.markdown(
'![Visitors](https://api.visitorbadge.io/api/visitors?path=https%3A%2F%2Fhuggingface.co%2Fspaces%2Fbarunsaha%2Fslide-deck-ai&countColor=%23263759)'
'![Visitors]'
'(https://api.visitorbadge.io/api/visitors?path=https%3A%2F%2Fhuggingface.co%2Fspaces%2Fbarunsaha%2Fslide-deck-ai&countColor=%23263759)'
)


Expand All @@ -173,20 +167,17 @@ def generate_presentation(topic: str, pptx_template: str, progress_bar):
"""

topic_length = len(topic)
logging.debug(f'Input length:: topic: {topic_length}')
logging.debug('Input length:: topic: %s', topic_length)

if topic_length >= 10:
logging.debug(
f'Topic: {topic}\n'
)

logging.debug('Topic: %s', topic)
target_length = min(topic_length, GlobalConfig.LLM_MODEL_MAX_INPUT_LENGTH)

try:
# Step 1: Generate the contents in JSON format using an LLM
json_str = process_slides_contents(topic[:target_length], progress_bar)
logging.debug(f'{topic[:target_length]=}')
logging.debug(f'{len(json_str)=}')
logging.debug('Truncated topic: %s', topic[:target_length])
logging.debug('Length of JSON: %d', len(json_str))

# Step 2: Generate the slide deck based on the template specified
if len(json_str) > 0:
Expand All @@ -196,8 +187,10 @@ def generate_presentation(topic: str, pptx_template: str, progress_bar):
icon="💡️"
)
else:
st.error('Unfortunately, JSON generation failed, so the next steps would lead to nowhere.'
' Try again or come back later.')
st.error(
'Unfortunately, JSON generation failed, so the next steps would lead'
' to nowhere. Try again or come back later.'
)
return

all_headers = generate_slide_deck(json_str, pptx_template, progress_bar)
Expand Down Expand Up @@ -225,15 +218,14 @@ def process_slides_contents(text: str, progress_bar: st.progress) -> str:
json_str = ''

try:
logging.info(f'Calling LLM for content generation on the topic: {text}')
logging.info('Calling LLM for content generation on the topic: %s', text)
json_str = get_contents_wrapper(text)
except Exception as ex:
st.error(f'An exception occurred while trying to convert to JSON.'
f' It could be because of heavy traffic or something else.'
f' Try doing it again or try again later.\n'
f' Error message: {ex}')

# logging.debug(f'JSON: {json_str}')
st.error(
f'An exception occurred while trying to convert to JSON. It could be because of heavy'
f' traffic or something else. Try doing it again or try again later.'
f'\nError message: {ex}'
)

progress_bar.progress(50, text='Contents generated')

Expand Down Expand Up @@ -316,6 +308,10 @@ def show_bonus_stuff(ppt_headers: List[str]):


def main():
"""
Trigger application run.
"""

build_ui()


Expand Down
18 changes: 2 additions & 16 deletions global_config.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,14 @@
import os

from dataclasses import dataclass
from dotenv import load_dotenv
import os


load_dotenv()


@dataclass(frozen=True)
class GlobalConfig:
# CLARIFAI_PAT = os.environ.get('CLARIFAI_PAT', '')
# CLARIFAI_USER_ID = 'meta'
# CLARIFAI_APP_ID = 'Llama-2'
# CLARIFAI_MODEL_ID = 'llama2-13b-chat'
#
# CLARIFAI_USER_ID_GPT = 'openai'
# CLARIFAI_APP_ID_GPT = 'chat-completion'
# CLARIFAI_MODEL_ID_GPT = 'GPT-4' # 'GPT-3_5-turbo'
#
# CLARIFAI_USER_ID_SD = 'stability-ai'
# CLARIFAI_APP_ID_SD = 'stable-diffusion-2'
# CLARIFAI_MODEL_ID_SD = 'stable-diffusion-xl'
# CLARIFAI_MODEL_VERSION_ID_SD = '0c919cc1edfc455dbc96207753f178d7'

HF_LLM_MODEL_NAME = 'mistralai/Mistral-7B-Instruct-v0.2'
LLM_MODEL_TEMPERATURE: float = 0.2
LLM_MODEL_MIN_OUTPUT_LENGTH: int = 50
Expand Down Expand Up @@ -51,4 +38,3 @@ class GlobalConfig:
'caption': 'Marvel in a monochrome dream'
}
}

98 changes: 10 additions & 88 deletions llm_helper.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import json
import logging
import time
import requests
from langchain.llms import Clarifai

from global_config import GlobalConfig

Expand All @@ -18,36 +15,6 @@
# llm = None


def get_llm(use_gpt: bool) -> Clarifai:
"""
Get a large language model (hosted by Clarifai).
:param use_gpt: True if GPT-3.5 is required; False is Llama 2 is required
"""

if use_gpt:
_ = Clarifai(
pat=GlobalConfig.CLARIFAI_PAT,
user_id=GlobalConfig.CLARIFAI_USER_ID_GPT,
app_id=GlobalConfig.CLARIFAI_APP_ID_GPT,
model_id=GlobalConfig.CLARIFAI_MODEL_ID_GPT,
verbose=True,
# temperature=0.1,
)
else:
_ = Clarifai(
pat=GlobalConfig.CLARIFAI_PAT,
user_id=GlobalConfig.CLARIFAI_USER_ID,
app_id=GlobalConfig.CLARIFAI_APP_ID,
model_id=GlobalConfig.CLARIFAI_MODEL_ID,
verbose=True,
# temperature=0.1,
)
# print(llm)

return _


def hf_api_query(payload: dict):
"""
Invoke HF inference end-point API.
Expand All @@ -56,9 +23,14 @@ def hf_api_query(payload: dict):
:return: The output from the LLM
"""

# logging.debug(f'{payload=}')
response = requests.post(HF_API_URL, headers=HF_API_HEADERS, json=payload)
return response.json()
try:
response = requests.post(HF_API_URL, headers=HF_API_HEADERS, json=payload, timeout=15)
result = response.json()
except requests.exceptions.Timeout as te:
logging.error('*** Error: hf_api_query timeout! %s', str(te))
result = {}

return result


def generate_slides_content(topic: str) -> str:
Expand All @@ -69,7 +41,7 @@ def generate_slides_content(topic: str) -> str:
:return: The content in JSON format
"""

with open(GlobalConfig.SLIDES_TEMPLATE_FILE, 'r') as in_file:
with open(GlobalConfig.SLIDES_TEMPLATE_FILE, 'r', encoding='utf-8') as in_file:
template_txt = in_file.read().strip()
template_txt = template_txt.replace('<REPLACE_PLACEHOLDER>', topic)

Expand Down Expand Up @@ -98,61 +70,11 @@ def generate_slides_content(topic: str) -> str:
# logging.debug(f'{json_end_idx=}')
output = output[:json_end_idx]

logging.debug(f'{output=}')
logging.debug('generate_slides_content: output: %s', output)

return output


def get_ai_image(text: str) -> str:
"""
Get a Stable Diffusion-generated image based on a given text.
:param text: The input text
:return: The Base 64-encoded image
"""

url = f'''https://api.clarifai.com/v2/users/{GlobalConfig.CLARIFAI_USER_ID_SD}/apps/{GlobalConfig.CLARIFAI_APP_ID_SD}/models/{GlobalConfig.CLARIFAI_MODEL_ID_SD}/versions/{GlobalConfig.CLARIFAI_MODEL_VERSION_ID_SD}/outputs'''
headers = {
"Content-Type": "application/json",
"Authorization": f'Key {GlobalConfig.CLARIFAI_PAT}'
}
data = {
"inputs": [
{
"data": {
"text": {
"raw": text
}
}
}
]
}

# print('*** AI image generator...')
# print(url)

start = time.time()
response = requests.post(
url=url,
headers=headers,
data=json.dumps(data)
)
stop = time.time()

# print('Response:', response, response.status_code)
logging.debug('Image generation took', stop - start, 'seconds')
img_data = ''

if response.ok:
# print('*** Clarifai SDXL request: Response OK')
json_data = json.loads(response.text)
img_data = json_data['outputs'][0]['data']['image']['base64']
else:
logging.error('*** Image generation failed:', response.text)

return img_data


if __name__ == '__main__':
# results = get_related_websites('5G AI WiFi 6')
#
Expand Down
17 changes: 11 additions & 6 deletions pptx_helper.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import logging
import pathlib
import re
import tempfile
from typing import List, Tuple

import json5
import logging
import pptx
import re
import yaml

from global_config import GlobalConfig
Expand Down Expand Up @@ -57,7 +58,8 @@ def generate_powerpoint_presentation(
"""
Create and save a PowerPoint presentation file containing the contents in JSON or YAML format.
:param structured_data: The presentation contents as "JSON" (may contain trailing commas) or YAML
:param structured_data: The presentation contents as "JSON" (may contain trailing commas) or
YAML
:param as_yaml: True if the input data is in YAML format; False if it is in JSON format
:param slides_template: The PPTX template to use
:param output_file_path: The path of the PPTX file to save as
Expand All @@ -69,13 +71,16 @@ def generate_powerpoint_presentation(
try:
parsed_data = yaml.safe_load(structured_data)
except yaml.parser.ParserError as ype:
logging.error(f'*** YAML parse error: {ype}')
logging.error('*** YAML parse error: %s', str(ype))
parsed_data = {'title': '', 'slides': []}
else:
# The structured "JSON" might contain trailing commas, so using json5
parsed_data = json5.loads(structured_data)

logging.debug(f"*** Using PPTX template: {GlobalConfig.PPTX_TEMPLATE_FILES[slides_template]['file']}")
logging.debug(
"*** Using PPTX template: %s",
GlobalConfig.PPTX_TEMPLATE_FILES[slides_template]['file']
)
presentation = pptx.Presentation(GlobalConfig.PPTX_TEMPLATE_FILES[slides_template]['file'])

# The title slide
Expand All @@ -84,7 +89,7 @@ def generate_powerpoint_presentation(
title = slide.shapes.title
subtitle = slide.placeholders[1]
title.text = parsed_data['title']
logging.debug(f'Title is: {title.text}')
logging.debug('Presentation title is: %s', title.text)
subtitle.text = 'by Myself and SlideDeck AI :)'
all_headers = [title.text, ]

Expand Down
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
python-dotenv[cli]~=1.0.0
langchain~=0.0.273
langchain~=0.1.13
# huggingface_hub
streamlit~=1.26.0
streamlit~=1.32.2
clarifai==9.7.4

python-pptx
Expand Down

0 comments on commit 10c2c13

Please # to comment.