MinzChan/ChatGPT-PPT-Generate-With-Azure-OpenAI-API
1
1import glob2import os3import random4import re5import string6 7import gradio as gr8 9import openai10from icrawler import ImageDownloader11from icrawler.builtin import GoogleImageCrawler, BingImageCrawler12from uuid import uuid413from pptx import Presentation14 15bad_coding_practice = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in16 range(16))17 18 19def refresh_bad_coding_practice():20 global bad_coding_practice21 bad_coding_practice = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits)22 for _ in range(16))23 return24 25 26class PrefixNameDownloader(ImageDownloader):27 28 def get_filename(self, task, default_ext):29 filename = super(PrefixNameDownloader, self).get_filename(30 task, default_ext)31 print(bad_coding_practice)32 return 'prefix_' + bad_coding_practice + filename33 34 35def generate_ppt(file, topic, slide_length, api_type, api_base, api_version, api_key):36 print(file.name)37 38 root = Presentation(file.name)39 40 openai.api_type = api_type41 openai.api_base = api_base42 openai.api_version = api_version43 openai.api_key = api_key44 45 message = f"""46 Create content for a slideshow presentation.47 The content's topic is {topic}. 48 The slideshow is {slide_length} slides long. 49 The content is written in the language of the content I give you above.50 51 52 You are allowed to use the following slide types:53 54 Slide types:55 Title Slide - (Title, Subtitle)56 Content Slide - (Title, Content)57 Image Slide - (Title, Content, Image)58 Thanks Slide - (Title)59 60 Put this tag before the Title Slide: [L_TS]61 Put this tag before the Content Slide: [L_CS]62 Put this tag before the Image Slide: [L_IS]63 Put this tag before the Thanks Slide: [L_THS]64 65 Put "[SLIDEBREAK]" after each slide 66 67 For example:68 [L_TS]69 [TITLE]Mental Health[/TITLE]70 71 [SLIDEBREAK]72 73 [L_CS] 74 [TITLE]Mental Health Definition[/TITLE]75 [CONTENT]76 1. Definition: A person’s condition with regard to their psychological and emotional well-being77 2. Can impact one's physical health78 3. Stigmatized too often.79 [/CONTENT]80 81 [SLIDEBREAK]82 83 Put this tag before the Title: [TITLE]84 Put this tag after the Title: [/TITLE]85 Put this tag before the Subitle: [SUBTITLE]86 Put this tag after the Subtitle: [/SUBTITLE]87 Put this tag before the Content: [CONTENT]88 Put this tag after the Content: [/CONTENT]89 Put this tag before the Image: [IMAGE]90 Put this tag after the Image: [/IMAGE]91 92 Elaborate on the Content, provide as much information as possible.93 You put a [/CONTENT] at the end of the Content.94 Do not reply as if you are talking about the slideshow itself. (ex. "Include pictures here about...")95 Do not include any special characters (?, !, ., :, ) in the Title.96 Do not include any additional information in your response and stick to the format."""97 98 if api_type in ("azure", "azure_ad", "azuread"):99 response = openai.ChatCompletion.create(100 engine="GPT-35-Turbo",101 messages=[102 {"role": "user", "content": message}103 ]104 )105 else:106 response = openai.ChatCompletion.create(107 model="gpt-3.5-turbo",108 messages=[109 {"role": "user", "content": message}110 ]111 ) 112 113 # """ Ref for slide types:114 # 0 -> title and subtitle115 # 1 -> title and content116 # 2 -> section header117 # 3 -> two content118 # 4 -> Comparison119 # 5 -> Title only120 # 6 -> Blank121 # 7 -> Content with caption122 # 8 -> Pic with caption123 # """124 125 def delete_all_slides():126 for i in range(len(root.slides) - 1, -1, -1):127 r_id = root.slides._sldIdLst[i].rId128 root.part.drop_rel(r_id)129 del root.slides._sldIdLst[i]130 131 def create_title_slide(title, subtitle):132 layout = root.slide_layouts[0]133 slide = root.slides.add_slide(layout)134 slide.shapes.title.text = title135 slide.placeholders[1].text = subtitle136 137 def create_section_header_slide(title):138 layout = root.slide_layouts[2]139 slide = root.slides.add_slide(layout)140 slide.shapes.title.text = title141 142 def create_title_and_content_slide(title, content):143 layout = root.slide_layouts[1]144 slide = root.slides.add_slide(layout)145 slide.shapes.title.text = title146 slide.placeholders[1].text = content147 148 def create_title_and_content_and_image_slide(title, content, image_query):149 layout = root.slide_layouts[8]150 slide = root.slides.add_slide(layout)151 slide.shapes.title.text = title152 slide.placeholders[2].text = content153 refresh_bad_coding_practice()154 bing_crawler = GoogleImageCrawler(downloader_cls=PrefixNameDownloader, storage={'root_dir': os.getcwd()})155 bing_crawler.crawl(keyword=image_query, max_num=1)156 dir_path = os.path.dirname(os.path.realpath(__file__))157 file_name = glob.glob(f"prefix_{bad_coding_practice}*")158 print(file_name)159 img_path = os.path.join(dir_path, file_name[0])160 slide.shapes.add_picture(img_path, slide.placeholders[1].left, slide.placeholders[1].top,161 slide.placeholders[1].width, slide.placeholders[1].height)162 163 def find_text_in_between_tags(text, start_tag, end_tag):164 start_pos = text.find(start_tag)165 end_pos = text.find(end_tag)166 result = []167 while start_pos > -1 and end_pos > -1:168 text_between_tags = text[start_pos + len(start_tag):end_pos]169 result.append(text_between_tags)170 start_pos = text.find(start_tag, end_pos + len(end_tag))171 end_pos = text.find(end_tag, start_pos)172 res1 = "".join(result)173 res2 = re.sub(r"\[IMAGE\].*?\[/IMAGE\]", '', res1)174 if len(result) > 0:175 return res2176 else:177 return ""178 179 def search_for_slide_type(text):180 tags = ["[L_TS]", "[L_CS]", "[L_IS]", "[L_THS]"]181 found_text = next((s for s in tags if s in text), None)182 return found_text183 184 def parse_response(reply):185 list_of_slides = reply.split("[SLIDEBREAK]")186 for slide in list_of_slides:187 slide_type = search_for_slide_type(slide)188 if slide_type == "[L_TS]":189 create_title_slide(find_text_in_between_tags(str(slide), "[TITLE]", "[/TITLE]"),190 find_text_in_between_tags(str(slide), "[SUBTITLE]", "[/SUBTITLE]"))191 elif slide_type == "[L_CS]":192 create_title_and_content_slide("".join(find_text_in_between_tags(str(slide), "[TITLE]", "[/TITLE]")),193 "".join(find_text_in_between_tags(str(slide), "[CONTENT]",194 "[/CONTENT]")))195 elif slide_type == "[L_IS]":196 create_title_and_content_and_image_slide("".join(find_text_in_between_tags(str(slide), "[TITLE]",197 "[/TITLE]")),198 "".join(find_text_in_between_tags(str(slide), "[CONTENT]",199 "[/CONTENT]")),200 "".join(find_text_in_between_tags(str(slide), "[IMAGE]",201 "[/IMAGE]")))202 elif slide_type == "[L_THS]":203 create_section_header_slide("".join(find_text_in_between_tags(str(slide), "[TITLE]", "[/TITLE]")))204 205 def find_title():206 return root.slides[0].shapes.title.text207 208 delete_all_slides()209 210 print(response)211 212 parse_response(response['choices'][0]['message']['content'])213 214 name_ = str(uuid4()).replace('-', '')215 216 root.save(f"./{name_}.pptx")217 218 print("done")219 220 dir_path = "./"221 prefix = "prefix_"222 223 for file_name in os.listdir(dir_path):224 if file_name.startswith(prefix):225 file_path = os.path.join(dir_path, file_name)226 if os.path.isfile(file_path):227 os.remove(file_path)228 229 return f"./{name_}.pptx"230 231 232with gr.Blocks(title="ChatGPT PPT框架生成") as demo:233 gr.Markdown("""<h1><center>ChatGPT PPT框架生成</center></h1>""")234 with gr.Row():235 with gr.Column():236 openai_type = gr.Textbox(label="OpenAI API Type", placeholder="azure,azure_ad and azuread for Azure OpenAI, open_ai for OpenAI official", value="azure")237 openai_base = gr.Textbox(label="OpenAI API Base", placeholder="https://xxx.openai.azure.com/ for Azure OpenAI, https://api.openai.com/v1 for OpenAI official", value="https://xxx.openai.azure.com/")238 openai_version = gr.Textbox(label="OpenAI API Version", value="2023-03-15-preview")239 openai_token = gr.Textbox(label="OpenAI API Key", placeholder="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx for Azure OpenAI, sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx for OpenAI official",)240 topic = gr.Textbox(label="PPT的主题或内容")241 length = gr.Slider(minimum=1, maximum=50, value=6, label="生成的PPT页数", step=1)242 theme = gr.File(value="./theme.pptx", file_types=['pptx', 'ppt'], label="PPT模版")243 output_file = gr.File(interactive=False)244 245 topic.submit(246 fn=generate_ppt,247 inputs=[theme, topic, length, openai_type, openai_base, openai_version, openai_token],248 outputs=[output_file]249 )250 251 submit = gr.Button("生成")252 submit.click(253 fn=generate_ppt,254 inputs=[theme, topic, length, openai_type, openai_base, openai_version, openai_token],255 outputs=[output_file]256 )257 258if __name__ == "__main__":259 demo.launch()260 