Spaces:
				
			
			
	
			
			
					
		Running
		
	
	
	
			
			
	
	
	
	
		
		
					
		Running
		
	Add bonus contents (search results on the topic) & mini ToS
Browse files- .idea/slide-deck-ai.iml +0 -4
- app.py +34 -1
- global_config.py +2 -0
- llm_helper.py +15 -1
- pptx_helper.py +14 -1
- requirements.txt +1 -0
- strings.json +10 -5
    	
        .idea/slide-deck-ai.iml
    CHANGED
    
    | @@ -7,8 +7,4 @@ | |
| 7 | 
             
                <orderEntry type="inheritedJdk" />
         | 
| 8 | 
             
                <orderEntry type="sourceFolder" forTests="false" />
         | 
| 9 | 
             
              </component>
         | 
| 10 | 
            -
              <component name="PyDocumentationSettings">
         | 
| 11 | 
            -
                <option name="format" value="PLAIN" />
         | 
| 12 | 
            -
                <option name="myDocStringFormat" value="Plain" />
         | 
| 13 | 
            -
              </component>
         | 
| 14 | 
             
            </module>
         | 
|  | |
| 7 | 
             
                <orderEntry type="inheritedJdk" />
         | 
| 8 | 
             
                <orderEntry type="sourceFolder" forTests="false" />
         | 
| 9 | 
             
              </component>
         | 
|  | |
|  | |
|  | |
|  | |
| 10 | 
             
            </module>
         | 
    	
        app.py
    CHANGED
    
    | @@ -1,3 +1,5 @@ | |
|  | |
|  | |
| 1 | 
             
            import json5
         | 
| 2 | 
             
            import time
         | 
| 3 | 
             
            import streamlit as st
         | 
| @@ -149,7 +151,11 @@ def process_slides_contents(text: str, progress_bar: st.progress): | |
| 149 | 
             
                    timestamp = time.time()
         | 
| 150 | 
             
                    output_file_name = f'{session_id}_{timestamp}.pptx'
         | 
| 151 |  | 
| 152 | 
            -
                    pptx_helper.generate_powerpoint_presentation( | 
|  | |
|  | |
|  | |
|  | |
| 153 | 
             
                    progress_bar.progress(100, text='Done!')
         | 
| 154 |  | 
| 155 | 
             
                    # st.download_button('Download file', binary_contents)  # Defaults to 'application/octet-stream'
         | 
| @@ -157,6 +163,33 @@ def process_slides_contents(text: str, progress_bar: st.progress): | |
| 157 | 
             
                    with open(output_file_name, 'rb') as f:
         | 
| 158 | 
             
                        st.download_button('Download PPTX file', f, file_name=output_file_name)
         | 
| 159 |  | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 160 |  | 
| 161 | 
             
            def button_clicked(button):
         | 
| 162 | 
             
                """
         | 
|  | |
| 1 | 
            +
            from typing import List
         | 
| 2 | 
            +
             | 
| 3 | 
             
            import json5
         | 
| 4 | 
             
            import time
         | 
| 5 | 
             
            import streamlit as st
         | 
|  | |
| 151 | 
             
                    timestamp = time.time()
         | 
| 152 | 
             
                    output_file_name = f'{session_id}_{timestamp}.pptx'
         | 
| 153 |  | 
| 154 | 
            +
                    all_headers = pptx_helper.generate_powerpoint_presentation(
         | 
| 155 | 
            +
                        json_str,
         | 
| 156 | 
            +
                        as_yaml=False,
         | 
| 157 | 
            +
                        output_file_name=output_file_name
         | 
| 158 | 
            +
                    )
         | 
| 159 | 
             
                    progress_bar.progress(100, text='Done!')
         | 
| 160 |  | 
| 161 | 
             
                    # st.download_button('Download file', binary_contents)  # Defaults to 'application/octet-stream'
         | 
|  | |
| 163 | 
             
                    with open(output_file_name, 'rb') as f:
         | 
| 164 | 
             
                        st.download_button('Download PPTX file', f, file_name=output_file_name)
         | 
| 165 |  | 
| 166 | 
            +
                    show_bonus_stuff(all_headers)
         | 
| 167 | 
            +
             | 
| 168 | 
            +
                    st.divider()
         | 
| 169 | 
            +
                    st.text(APP_TEXT['tos'])
         | 
| 170 | 
            +
                    st.text(APP_TEXT['tos2'])
         | 
| 171 | 
            +
             | 
| 172 | 
            +
             | 
| 173 | 
            +
            def show_bonus_stuff(ppt_headers: List):
         | 
| 174 | 
            +
                """
         | 
| 175 | 
            +
                Show relevant links and images for the presentation topic.
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                :param ppt_headers: A list of all slide headers
         | 
| 178 | 
            +
                """
         | 
| 179 | 
            +
             | 
| 180 | 
            +
                st.divider()
         | 
| 181 | 
            +
                st.header(APP_TEXT['section_headers'][3])
         | 
| 182 | 
            +
                st.caption(APP_TEXT['section_captions'][3])
         | 
| 183 | 
            +
             | 
| 184 | 
            +
                st.write(APP_TEXT['urls_info'])
         | 
| 185 | 
            +
             | 
| 186 | 
            +
                # Use the presentation title and the slides headers to find relevant info online
         | 
| 187 | 
            +
                ppt_text = ' '.join(ppt_headers)
         | 
| 188 | 
            +
                search_results = llm_helper.get_related_websites(ppt_text)
         | 
| 189 | 
            +
             | 
| 190 | 
            +
                for a_result in search_results.results:
         | 
| 191 | 
            +
                    st.markdown(f'[{a_result.title}]({a_result.url})')
         | 
| 192 | 
            +
             | 
| 193 |  | 
| 194 | 
             
            def button_clicked(button):
         | 
| 195 | 
             
                """
         | 
    	
        global_config.py
    CHANGED
    
    | @@ -22,6 +22,8 @@ class GlobalConfig: | |
| 22 | 
             
                LLM_MODEL_MAX_OUTPUT_LENGTH: int = 2000
         | 
| 23 | 
             
                LLM_MODEL_MAX_INPUT_LENGTH: int = 1000
         | 
| 24 |  | 
|  | |
|  | |
| 25 | 
             
                APP_STRINGS_FILE = 'strings.json'
         | 
| 26 | 
             
                PRELOAD_DATA_FILE = 'examples/example_02.json'
         | 
| 27 | 
             
                SLIDES_TEMPLATE_FILE = 'langchain_templates/template_07.txt'
         | 
|  | |
| 22 | 
             
                LLM_MODEL_MAX_OUTPUT_LENGTH: int = 2000
         | 
| 23 | 
             
                LLM_MODEL_MAX_INPUT_LENGTH: int = 1000
         | 
| 24 |  | 
| 25 | 
            +
                METAPHOR_API_KEY = os.environ.get('METAPHOR_API_KEY', '')
         | 
| 26 | 
            +
             | 
| 27 | 
             
                APP_STRINGS_FILE = 'strings.json'
         | 
| 28 | 
             
                PRELOAD_DATA_FILE = 'examples/example_02.json'
         | 
| 29 | 
             
                SLIDES_TEMPLATE_FILE = 'langchain_templates/template_07.txt'
         | 
    	
        llm_helper.py
    CHANGED
    
    | @@ -1,3 +1,4 @@ | |
|  | |
| 1 | 
             
            from langchain import PromptTemplate
         | 
| 2 | 
             
            from langchain.llms import Clarifai
         | 
| 3 |  | 
| @@ -7,6 +8,7 @@ from global_config import GlobalConfig | |
| 7 | 
             
            prompt = None
         | 
| 8 | 
             
            llm_contents = None
         | 
| 9 | 
             
            llm_yaml = None
         | 
|  | |
| 10 |  | 
| 11 |  | 
| 12 | 
             
            def get_llm(use_gpt: bool) -> Clarifai:
         | 
| @@ -192,6 +194,18 @@ Output: | |
| 192 | 
             
                return output
         | 
| 193 |  | 
| 194 |  | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 195 | 
             
            if __name__ == '__main__':
         | 
| 196 | 
            -
                 | 
|  | |
|  | |
|  | |
| 197 |  | 
|  | |
| 1 | 
            +
            import metaphor_python as metaphor
         | 
| 2 | 
             
            from langchain import PromptTemplate
         | 
| 3 | 
             
            from langchain.llms import Clarifai
         | 
| 4 |  | 
|  | |
| 8 | 
             
            prompt = None
         | 
| 9 | 
             
            llm_contents = None
         | 
| 10 | 
             
            llm_yaml = None
         | 
| 11 | 
            +
            metaphor_client = None
         | 
| 12 |  | 
| 13 |  | 
| 14 | 
             
            def get_llm(use_gpt: bool) -> Clarifai:
         | 
|  | |
| 194 | 
             
                return output
         | 
| 195 |  | 
| 196 |  | 
| 197 | 
            +
            def get_related_websites(query: str) -> metaphor.api.SearchResponse:
         | 
| 198 | 
            +
                global metaphor_client
         | 
| 199 | 
            +
             | 
| 200 | 
            +
                if not metaphor_client:
         | 
| 201 | 
            +
                    metaphor_client = metaphor.Metaphor(api_key=GlobalConfig.METAPHOR_API_KEY)
         | 
| 202 | 
            +
             | 
| 203 | 
            +
                return metaphor_client.search(query, use_autoprompt=True, num_results=5)
         | 
| 204 | 
            +
             | 
| 205 | 
            +
             | 
| 206 | 
             
            if __name__ == '__main__':
         | 
| 207 | 
            +
                results = get_related_websites('5G AI WiFi 6')
         | 
| 208 | 
            +
             | 
| 209 | 
            +
                for a_result in results.results:
         | 
| 210 | 
            +
                    print(a_result.title, a_result.url, a_result.extract)
         | 
| 211 |  | 
    	
        pptx_helper.py
    CHANGED
    
    | @@ -1,3 +1,4 @@ | |
|  | |
| 1 | 
             
            import json5
         | 
| 2 | 
             
            import pptx
         | 
| 3 | 
             
            import re
         | 
| @@ -5,10 +6,17 @@ import yaml | |
| 5 |  | 
| 6 | 
             
            from pptx.dml.color import RGBColor
         | 
| 7 |  | 
|  | |
| 8 | 
             
            PATTERN = re.compile(r"^slide[ ]+\d+:", re.IGNORECASE)
         | 
| 9 |  | 
| 10 |  | 
| 11 | 
             
            def remove_slide_number_from_heading(header: str) -> str:
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 12 | 
             
                if PATTERN.match(header):
         | 
| 13 | 
             
                    idx = header.find(':')
         | 
| 14 | 
             
                    header = header[idx + 1:]
         | 
| @@ -16,13 +24,14 @@ def remove_slide_number_from_heading(header: str) -> str: | |
| 16 | 
             
                return header
         | 
| 17 |  | 
| 18 |  | 
| 19 | 
            -
            def generate_powerpoint_presentation(structured_data: str, as_yaml: bool, output_file_name: str):
         | 
| 20 | 
             
                """
         | 
| 21 | 
             
                Create and save a PowerPoint presentation file containing the contents in JSON or YAML format.
         | 
| 22 |  | 
| 23 | 
             
                :param structured_data: The presentation contents as "JSON" (may contain trailing commas) or YAML
         | 
| 24 | 
             
                :param as_yaml: True if the input data is in YAML format; False if it is in JSON format
         | 
| 25 | 
             
                :param output_file_name: The name of the PPTX file to save as
         | 
|  | |
| 26 | 
             
                """
         | 
| 27 |  | 
| 28 | 
             
                if as_yaml:
         | 
| @@ -46,6 +55,7 @@ def generate_powerpoint_presentation(structured_data: str, as_yaml: bool, output | |
| 46 | 
             
                title.text = parsed_data['title']
         | 
| 47 | 
             
                print(f'Title is: {title.text}')
         | 
| 48 | 
             
                subtitle.text = 'by Myself and SlideDeck AI :)'
         | 
|  | |
| 49 |  | 
| 50 | 
             
                background = slide.background
         | 
| 51 | 
             
                background.fill.solid()
         | 
| @@ -61,6 +71,7 @@ def generate_powerpoint_presentation(structured_data: str, as_yaml: bool, output | |
| 61 | 
             
                    title_shape = shapes.title
         | 
| 62 | 
             
                    body_shape = shapes.placeholders[1]
         | 
| 63 | 
             
                    title_shape.text = remove_slide_number_from_heading(a_slide['heading'])
         | 
|  | |
| 64 | 
             
                    text_frame = body_shape.text_frame
         | 
| 65 |  | 
| 66 | 
             
                    for an_item in a_slide['bullet_points']:
         | 
| @@ -90,6 +101,8 @@ def generate_powerpoint_presentation(structured_data: str, as_yaml: bool, output | |
| 90 |  | 
| 91 | 
             
                presentation.save(output_file_name)
         | 
| 92 |  | 
|  | |
|  | |
| 93 |  | 
| 94 | 
             
            if __name__ == '__main__':
         | 
| 95 | 
             
                generate_powerpoint_presentation(
         | 
|  | |
| 1 | 
            +
            from typing import List
         | 
| 2 | 
             
            import json5
         | 
| 3 | 
             
            import pptx
         | 
| 4 | 
             
            import re
         | 
|  | |
| 6 |  | 
| 7 | 
             
            from pptx.dml.color import RGBColor
         | 
| 8 |  | 
| 9 | 
            +
             | 
| 10 | 
             
            PATTERN = re.compile(r"^slide[ ]+\d+:", re.IGNORECASE)
         | 
| 11 |  | 
| 12 |  | 
| 13 | 
             
            def remove_slide_number_from_heading(header: str) -> str:
         | 
| 14 | 
            +
                """
         | 
| 15 | 
            +
                Remove the slide number from a given slide header.
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                :param header: The header of a slide
         | 
| 18 | 
            +
                """
         | 
| 19 | 
            +
             | 
| 20 | 
             
                if PATTERN.match(header):
         | 
| 21 | 
             
                    idx = header.find(':')
         | 
| 22 | 
             
                    header = header[idx + 1:]
         | 
|  | |
| 24 | 
             
                return header
         | 
| 25 |  | 
| 26 |  | 
| 27 | 
            +
            def generate_powerpoint_presentation(structured_data: str, as_yaml: bool, output_file_name: str) -> List:
         | 
| 28 | 
             
                """
         | 
| 29 | 
             
                Create and save a PowerPoint presentation file containing the contents in JSON or YAML format.
         | 
| 30 |  | 
| 31 | 
             
                :param structured_data: The presentation contents as "JSON" (may contain trailing commas) or YAML
         | 
| 32 | 
             
                :param as_yaml: True if the input data is in YAML format; False if it is in JSON format
         | 
| 33 | 
             
                :param output_file_name: The name of the PPTX file to save as
         | 
| 34 | 
            +
                :return A list of presentation title and slides headers
         | 
| 35 | 
             
                """
         | 
| 36 |  | 
| 37 | 
             
                if as_yaml:
         | 
|  | |
| 55 | 
             
                title.text = parsed_data['title']
         | 
| 56 | 
             
                print(f'Title is: {title.text}')
         | 
| 57 | 
             
                subtitle.text = 'by Myself and SlideDeck AI :)'
         | 
| 58 | 
            +
                all_headers = [title.text, ]
         | 
| 59 |  | 
| 60 | 
             
                background = slide.background
         | 
| 61 | 
             
                background.fill.solid()
         | 
|  | |
| 71 | 
             
                    title_shape = shapes.title
         | 
| 72 | 
             
                    body_shape = shapes.placeholders[1]
         | 
| 73 | 
             
                    title_shape.text = remove_slide_number_from_heading(a_slide['heading'])
         | 
| 74 | 
            +
                    all_headers.append(title_shape.text)
         | 
| 75 | 
             
                    text_frame = body_shape.text_frame
         | 
| 76 |  | 
| 77 | 
             
                    for an_item in a_slide['bullet_points']:
         | 
|  | |
| 101 |  | 
| 102 | 
             
                presentation.save(output_file_name)
         | 
| 103 |  | 
| 104 | 
            +
                return all_headers
         | 
| 105 | 
            +
             | 
| 106 |  | 
| 107 | 
             
            if __name__ == '__main__':
         | 
| 108 | 
             
                generate_powerpoint_presentation(
         | 
    	
        requirements.txt
    CHANGED
    
    | @@ -5,5 +5,6 @@ streamlit~=1.26.0 | |
| 5 | 
             
            clarifai==9.7.4
         | 
| 6 |  | 
| 7 | 
             
            python-pptx
         | 
|  | |
| 8 | 
             
            json5~=0.9.14
         | 
| 9 | 
             
            PyYAML~=6.0.1
         | 
|  | |
| 5 | 
             
            clarifai==9.7.4
         | 
| 6 |  | 
| 7 | 
             
            python-pptx
         | 
| 8 | 
            +
            metaphor-python
         | 
| 9 | 
             
            json5~=0.9.14
         | 
| 10 | 
             
            PyYAML~=6.0.1
         | 
    	
        strings.json
    CHANGED
    
    | @@ -5,19 +5,24 @@ | |
| 5 | 
             
                    "Step 1: Generate your content",
         | 
| 6 | 
             
                    "Step 2: Make it structured",
         | 
| 7 | 
             
                    "Step 3: Create the slides",
         | 
|  | |
| 8 | 
             
                ],
         | 
| 9 | 
             
                "section_captions": [
         | 
| 10 | 
            -
                    "Let | 
| 11 | 
            -
                    "Let | 
| 12 | 
            -
                    "Let | 
|  | |
| 13 | 
             
                ],
         | 
| 14 | 
             
                "input_labels": [
         | 
| 15 | 
            -
                    "**Describe the topic of the presentation. Avoid mentioning the count of slides.**\n*Note: the output may be short or truncated due to API limitations.*" | 
| 16 | 
             
                ],
         | 
| 17 | 
             
                "button_labels": [
         | 
| 18 | 
             
                    "Generate slides content",
         | 
| 19 | 
             
                    "Generate JSON",
         | 
| 20 | 
             
                    "Make the slides"
         | 
| 21 | 
             
                ],
         | 
| 22 | 
            -
                " | 
|  | |
|  | |
|  | |
| 23 | 
             
            }
         | 
|  | |
| 5 | 
             
                    "Step 1: Generate your content",
         | 
| 6 | 
             
                    "Step 2: Make it structured",
         | 
| 7 | 
             
                    "Step 3: Create the slides",
         | 
| 8 | 
            +
                    "Bonus Materials"
         | 
| 9 | 
             
                ],
         | 
| 10 | 
             
                "section_captions": [
         | 
| 11 | 
            +
                    "Let's start by generating some contents for your slides",
         | 
| 12 | 
            +
                    "Let's now convert the above generated contents into JSON",
         | 
| 13 | 
            +
                    "Let's now create the slides for you",
         | 
| 14 | 
            +
                    "Wait, there's some more good stuff for you!"
         | 
| 15 | 
             
                ],
         | 
| 16 | 
             
                "input_labels": [
         | 
| 17 | 
            +
                    "**Describe the topic of the presentation. Avoid mentioning the count of slides.**\n*Note: the output may be short or truncated due to API limitations.*"
         | 
| 18 | 
             
                ],
         | 
| 19 | 
             
                "button_labels": [
         | 
| 20 | 
             
                    "Generate slides content",
         | 
| 21 | 
             
                    "Generate JSON",
         | 
| 22 | 
             
                    "Make the slides"
         | 
| 23 | 
             
                ],
         | 
| 24 | 
            +
                "urls_info": "Here is a list of some online resources that you can consult for further information on this topic:",
         | 
| 25 | 
            +
                "content_generation_failure_error": "Unfortunately, SlideDeck AI failed to generate any content for you! Please try again later.",
         | 
| 26 | 
            +
                "tos": "SlideDeck AI is an experimental prototype, and it has its limitations.\nPlease carefully review any and all AI-generated content.",
         | 
| 27 | 
            +
                "tos2": "By using SlideDeck AI, you agree to fair and responsible usage.\nNo liability assumed by any party."
         | 
| 28 | 
             
            }
         |