CoolFace
Apppublic

EditsPaarth/PowerPoint-AI

sourceHugging Facemitupdated 2y agoView on Hugging Face
0likes
legacy_app.py294 linesDownload Raw Back to root
1import pathlib2import logging3import tempfile4from typing import List, Tuple5 6import json57import metaphor_python as metaphor8import streamlit as st9 10from helpers import llm_helper, pptx_helper11from global_config import GlobalConfig12 13 14APP_TEXT = json5.loads(open(GlobalConfig.APP_STRINGS_FILE, 'r', encoding='utf-8').read())15GB_CONVERTER = 2 ** 3016 17 18logger = logging.getLogger(__name__)19 20 21@st.cache_data22def get_contents_wrapper(text: str) -> str:23    """24    Fetch and cache the slide deck contents on a topic by calling an external API.25 26    :param text: The presentation topic.27    :return: The slide deck contents or outline in JSON format.28    """29 30    logger.info('LLM call because of cache miss...')31    return llm_helper.generate_slides_content(text).strip()32 33 34@st.cache_resource35def get_metaphor_client_wrapper() -> metaphor.Metaphor:36    """37    Create a Metaphor client for semantic Web search.38 39    :return: Metaphor instance.40    """41 42    return metaphor.Metaphor(api_key=GlobalConfig.METAPHOR_API_KEY)43 44 45@st.cache_data46def get_web_search_results_wrapper(text: str) -> List[Tuple[str, str]]:47    """48    Fetch and cache the Web search results on a given topic.49 50    :param text: The topic.51    :return: A list of (title, link) tuples.52    """53 54    results = []55    search_results = get_metaphor_client_wrapper().search(56        text,57        use_autoprompt=True,58        num_results=559    )60 61    for a_result in search_results.results:62        results.append((a_result.title, a_result.url))63 64    return results65 66 67def build_ui():68    """69    Display the input elements for content generation. Only covers the first step.70    """71 72    # get_disk_used_percentage()73 74    st.title(APP_TEXT['app_name'])75    st.subheader(APP_TEXT['caption'])76    st.markdown(77        'Powered by'78        ' [Mistral-7B-Instruct-v0.2](https://huggingface.co/mistralai/Mistral-7B-Instruct-v0.2).'79    )80    st.markdown(81        '*If the JSON is generated or parsed incorrectly, try again later by making minor changes'82        ' to the input text.*'83    )84 85    with st.form('my_form'):86        # Topic input87        try:88            with open(GlobalConfig.PRELOAD_DATA_FILE, 'r', encoding='utf-8') as in_file:89                preload_data = json5.loads(in_file.read())90        except (FileExistsError, FileNotFoundError):91            preload_data = {'topic': '', 'audience': ''}92 93        topic = st.text_area(94            APP_TEXT['input_labels'][0],95            value=preload_data['topic']96        )97 98        texts = list(GlobalConfig.PPTX_TEMPLATE_FILES.keys())99        captions = [GlobalConfig.PPTX_TEMPLATE_FILES[x]['caption'] for x in texts]100 101        pptx_template = st.radio(102            'Select a presentation template:',103            texts,104            captions=captions,105            horizontal=True106        )107 108        st.divider()109        submit = st.form_submit_button('Generate slide deck')110 111    if submit:112        # st.write(f'Clicked {time.time()}')113        st.session_state.submitted = True114 115    # https://github.com/streamlit/streamlit/issues/3832#issuecomment-1138994421116    if 'submitted' in st.session_state:117        progress_text = 'Generating the slides...give it a moment'118        progress_bar = st.progress(0, text=progress_text)119 120        topic_txt = topic.strip()121        generate_presentation(topic_txt, pptx_template, progress_bar)122 123    st.divider()124    st.text(APP_TEXT['tos'])125    st.text(APP_TEXT['tos2'])126 127    st.markdown(128        '![Visitors]'129        '(https://api.visitorbadge.io/api/visitors?path=https%3A%2F%2Fhuggingface.co%2Fspaces%2Fbarunsaha%2Fslide-deck-ai&countColor=%23263759)'130    )131 132 133def generate_presentation(topic: str, pptx_template: str, progress_bar):134    """135    Process the inputs to generate the slides.136 137    :param topic: The presentation topic based on which contents are to be generated.138    :param pptx_template: The PowerPoint template name to be used.139    :param progress_bar: Progress bar from the page.140    """141 142    topic_length = len(topic)143    logger.debug('Input length:: topic: %s', topic_length)144 145    if topic_length >= 10:146        logger.debug('Topic: %s', topic)147        target_length = min(topic_length, GlobalConfig.LLM_MODEL_MAX_INPUT_LENGTH)148 149        try:150            # Step 1: Generate the contents in JSON format using an LLM151            json_str = process_slides_contents(topic[:target_length], progress_bar)152            logger.debug('Truncated topic: %s', topic[:target_length])153            logger.debug('Length of JSON: %d', len(json_str))154 155            # Step 2: Generate the slide deck based on the template specified156            if len(json_str) > 0:157                st.info(158                    'Tip: The generated content doesn\'t look so great?'159                    ' Need alternatives? Just change your description text and try again.',160                    icon="💡️"161                )162            else:163                st.error(164                    'Unfortunately, JSON generation failed, so the next steps would lead'165                    ' to nowhere. Try again or come back later.'166                )167                return168 169            all_headers = generate_slide_deck(json_str, pptx_template, progress_bar)170 171            # Step 3: Bonus stuff: Web references and AI art172            show_bonus_stuff(all_headers)173 174        except ValueError as ve:175            st.error(f'Unfortunately, an error occurred: {ve}! '176                     f'Please change the text, try again later, or report it, sharing your inputs.')177 178    else:179        st.error('Not enough information provided! Please be little more descriptive :)')180 181 182def process_slides_contents(text: str, progress_bar: st.progress) -> str:183    """184    Convert given text into structured data and display. Update the UI.185 186    :param text: The topic description for the presentation.187    :param progress_bar: Progress bar for this step.188    :return: The contents as a JSON-formatted string.189    """190 191    json_str = ''192 193    try:194        logger.info('Calling LLM for content generation on the topic: %s', text)195        json_str = get_contents_wrapper(text)196    except Exception as ex:197        st.error(198            f'An exception occurred while trying to convert to JSON. It could be because of heavy'199            f' traffic or something else. Try doing it again or try again later.'200            f'\nError message: {ex}'201        )202 203    progress_bar.progress(50, text='Contents generated')204 205    with st.expander('The generated contents (in JSON format)'):206        st.code(json_str, language='json')207 208    return json_str209 210 211def generate_slide_deck(json_str: str, pptx_template: str, progress_bar) -> List:212    """213    Create a slide deck.214 215    :param json_str: The contents in JSON format.216    :param pptx_template: The PPTX template name.217    :param progress_bar: Progress bar.218    :return: A list of all slide headers and the title.219    """220 221    progress_text = 'Creating the slide deck...give it a moment'222    progress_bar.progress(75, text=progress_text)223 224    # # Get a unique name for the file to save -- use the session ID225    # ctx = st_sr.get_script_run_ctx()226    # session_id = ctx.session_id227    # timestamp = time.time()228    # output_file_name = f'{session_id}_{timestamp}.pptx'229 230    temp = tempfile.NamedTemporaryFile(delete=False, suffix='.pptx')231    path = pathlib.Path(temp.name)232 233    logger.info('Creating PPTX file...')234    all_headers = pptx_helper.generate_powerpoint_presentation(235        json_str,236        slides_template=pptx_template,237        output_file_path=path238    )239    progress_bar.progress(100, text='Done!')240 241    with open(path, 'rb') as f:242        st.download_button('Download PPTX file', f, file_name='Presentation.pptx')243 244    if temp:245        temp.close()246 247    return all_headers248 249 250def show_bonus_stuff(ppt_headers: List[str]):251    """252    Show bonus stuff for the presentation.253 254    :param ppt_headers: A list of the slide headings.255    """256 257    # Use the presentation title and the slide headers to find relevant info online258    logger.info('Calling Metaphor search...')259    ppt_text = ' '.join(ppt_headers)260    search_results = get_web_search_results_wrapper(ppt_text)261    md_text_items = []262 263    for (title, link) in search_results:264        md_text_items.append(f'[{title}]({link})')265 266    with st.expander('Related Web references'):267        st.markdown('\n\n'.join(md_text_items))268 269    logger.info('Done!')270 271    # # Avoid image generation. It costs time and an API call, so just limit to the text generation.272    # with st.expander('AI-generated image on the presentation topic'):273    #     logger.info('Calling SDXL for image generation...')274    #     # img_empty.write('')275    #     # img_text.write(APP_TEXT['image_info'])276    #     image = get_ai_image_wrapper(ppt_text)277    #278    #     if len(image) > 0:279    #         image = base64.b64decode(image)280    #         st.image(image, caption=ppt_text)281    #         st.info('Tip: Right-click on the image to save it.', icon="💡️")282    #         logger.info('Image added')283 284 285def main():286    """287    Trigger application run.288    """289 290    build_ui()291 292 293if __name__ == '__main__':294    main()