Spaces:
				
			
			
	
			
			
		Sleeping
		
	
	
	
			
			
	
	
	
	
		
		
		Sleeping
		
	Fix #31: find & use similar icons when non-existing icon names are generated by the LLM
Browse files- app.py +6 -7
- file_embeddings/embeddings.npy +3 -0
- file_embeddings/icons.npy +3 -0
- global_config.py +5 -2
- helpers/icons_embeddings.py +122 -0
- helpers/pptx_helper.py +27 -34
- langchain_templates/chat_prompts/initial_template_v4_two_cols_img.txt +11 -15
- langchain_templates/chat_prompts/refinement_template_v4_two_cols_img.txt +12 -16
- requirements.txt +4 -2
    	
        app.py
    CHANGED
    
    | @@ -3,9 +3,9 @@ Streamlit app containing the UI and the application logic. | |
| 3 | 
             
            """
         | 
| 4 | 
             
            import datetime
         | 
| 5 | 
             
            import logging
         | 
| 6 | 
            -
            import os
         | 
| 7 | 
             
            import pathlib
         | 
| 8 | 
             
            import random
         | 
|  | |
| 9 | 
             
            import tempfile
         | 
| 10 | 
             
            from typing import List, Union
         | 
| 11 |  | 
| @@ -15,6 +15,10 @@ from langchain_community.chat_message_histories import StreamlitChatMessageHisto | |
| 15 | 
             
            from langchain_core.messages import HumanMessage
         | 
| 16 | 
             
            from langchain_core.prompts import ChatPromptTemplate
         | 
| 17 |  | 
|  | |
|  | |
|  | |
|  | |
| 18 | 
             
            from global_config import GlobalConfig
         | 
| 19 | 
             
            from helpers import llm_helper, pptx_helper, text_helper
         | 
| 20 |  | 
| @@ -68,12 +72,7 @@ def _get_icons_list() -> List[str]: | |
| 68 | 
             
                :return: A llist of the icons.
         | 
| 69 | 
             
                """
         | 
| 70 |  | 
| 71 | 
            -
                 | 
| 72 | 
            -
                items = [
         | 
| 73 | 
            -
                    os.path.basename(str(item)).removesuffix('.png') for item in items
         | 
| 74 | 
            -
                ]
         | 
| 75 | 
            -
             | 
| 76 | 
            -
                return items
         | 
| 77 |  | 
| 78 |  | 
| 79 | 
             
            APP_TEXT = _load_strings()
         | 
|  | |
| 3 | 
             
            """
         | 
| 4 | 
             
            import datetime
         | 
| 5 | 
             
            import logging
         | 
|  | |
| 6 | 
             
            import pathlib
         | 
| 7 | 
             
            import random
         | 
| 8 | 
            +
            import sys
         | 
| 9 | 
             
            import tempfile
         | 
| 10 | 
             
            from typing import List, Union
         | 
| 11 |  | 
|  | |
| 15 | 
             
            from langchain_core.messages import HumanMessage
         | 
| 16 | 
             
            from langchain_core.prompts import ChatPromptTemplate
         | 
| 17 |  | 
| 18 | 
            +
            sys.path.append('..')
         | 
| 19 | 
            +
            sys.path.append('../..')
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            import helpers.icons_embeddings as ice
         | 
| 22 | 
             
            from global_config import GlobalConfig
         | 
| 23 | 
             
            from helpers import llm_helper, pptx_helper, text_helper
         | 
| 24 |  | 
|  | |
| 72 | 
             
                :return: A llist of the icons.
         | 
| 73 | 
             
                """
         | 
| 74 |  | 
| 75 | 
            +
                return ice.get_icons_list()
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
| 76 |  | 
| 77 |  | 
| 78 | 
             
            APP_TEXT = _load_strings()
         | 
    	
        file_embeddings/embeddings.npy
    ADDED
    
    | @@ -0,0 +1,3 @@ | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            version https://git-lfs.github.com/spec/v1
         | 
| 2 | 
            +
            oid sha256:2f11da27237bdf979f27e6b7347e1ea0ac7a375f3492340871ee7f812709f5c9
         | 
| 3 | 
            +
            size 95360
         | 
    	
        file_embeddings/icons.npy
    ADDED
    
    | @@ -0,0 +1,3 @@ | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            version https://git-lfs.github.com/spec/v1
         | 
| 2 | 
            +
            oid sha256:248012493bfb0d29c38a62a32204544e1a3eab9d0971e9c31d5d99216a8809c4
         | 
| 3 | 
            +
            size 21704
         | 
    	
        global_config.py
    CHANGED
    
    | @@ -20,8 +20,8 @@ class GlobalConfig: | |
| 20 | 
             
                HF_LLM_MODEL_NAME = 'mistralai/Mistral-Nemo-Instruct-2407'
         | 
| 21 | 
             
                LLM_MODEL_TEMPERATURE = 0.2
         | 
| 22 | 
             
                LLM_MODEL_MIN_OUTPUT_LENGTH = 100
         | 
| 23 | 
            -
                LLM_MODEL_MAX_OUTPUT_LENGTH = 4 * 4096
         | 
| 24 | 
            -
                LLM_MODEL_MAX_INPUT_LENGTH = 750
         | 
| 25 |  | 
| 26 | 
             
                HUGGINGFACEHUB_API_TOKEN = os.environ.get('HUGGINGFACEHUB_API_TOKEN', '')
         | 
| 27 | 
             
                METAPHOR_API_KEY = os.environ.get('METAPHOR_API_KEY', '')
         | 
| @@ -36,6 +36,9 @@ class GlobalConfig: | |
| 36 |  | 
| 37 | 
             
                LLM_PROGRESS_MAX = 90
         | 
| 38 | 
             
                ICONS_DIR = 'icons/png128/'
         | 
|  | |
|  | |
|  | |
| 39 |  | 
| 40 | 
             
                PPTX_TEMPLATE_FILES = {
         | 
| 41 | 
             
                    'Basic': {
         | 
|  | |
| 20 | 
             
                HF_LLM_MODEL_NAME = 'mistralai/Mistral-Nemo-Instruct-2407'
         | 
| 21 | 
             
                LLM_MODEL_TEMPERATURE = 0.2
         | 
| 22 | 
             
                LLM_MODEL_MIN_OUTPUT_LENGTH = 100
         | 
| 23 | 
            +
                LLM_MODEL_MAX_OUTPUT_LENGTH = 4 * 4096  # tokens
         | 
| 24 | 
            +
                LLM_MODEL_MAX_INPUT_LENGTH = 750  # characters
         | 
| 25 |  | 
| 26 | 
             
                HUGGINGFACEHUB_API_TOKEN = os.environ.get('HUGGINGFACEHUB_API_TOKEN', '')
         | 
| 27 | 
             
                METAPHOR_API_KEY = os.environ.get('METAPHOR_API_KEY', '')
         | 
|  | |
| 36 |  | 
| 37 | 
             
                LLM_PROGRESS_MAX = 90
         | 
| 38 | 
             
                ICONS_DIR = 'icons/png128/'
         | 
| 39 | 
            +
                TINY_BERT_MODEL = 'gaunernst/bert-tiny-uncased'
         | 
| 40 | 
            +
                EMBEDDINGS_FILE_NAME = 'file_embeddings/embeddings.npy'
         | 
| 41 | 
            +
                ICONS_FILE_NAME = 'file_embeddings/icons.npy'
         | 
| 42 |  | 
| 43 | 
             
                PPTX_TEMPLATE_FILES = {
         | 
| 44 | 
             
                    'Basic': {
         | 
    	
        helpers/icons_embeddings.py
    ADDED
    
    | @@ -0,0 +1,122 @@ | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | 
|  | |
| 1 | 
            +
            """
         | 
| 2 | 
            +
            Generate and save the embeddings of a pre-defined list of icons.
         | 
| 3 | 
            +
            Compare them with keywords embeddings to find most relevant icons.
         | 
| 4 | 
            +
            """
         | 
| 5 | 
            +
            import os
         | 
| 6 | 
            +
            import pathlib
         | 
| 7 | 
            +
            import sys
         | 
| 8 | 
            +
            from typing import List, Tuple
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            import numpy as np
         | 
| 11 | 
            +
            from sklearn.metrics.pairwise import cosine_similarity
         | 
| 12 | 
            +
            from transformers import BertTokenizer, BertModel
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            sys.path.append('..')
         | 
| 15 | 
            +
            sys.path.append('../..')
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            from global_config import GlobalConfig
         | 
| 18 | 
            +
             | 
| 19 | 
            +
             | 
| 20 | 
            +
            tokenizer = BertTokenizer.from_pretrained(GlobalConfig.TINY_BERT_MODEL)
         | 
| 21 | 
            +
            model = BertModel.from_pretrained(GlobalConfig.TINY_BERT_MODEL)
         | 
| 22 | 
            +
             | 
| 23 | 
            +
             | 
| 24 | 
            +
            def get_icons_list() -> List[str]:
         | 
| 25 | 
            +
                """
         | 
| 26 | 
            +
                Get a list of available icons.
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                :return: The icons file names.
         | 
| 29 | 
            +
                """
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                items = pathlib.Path('../' + GlobalConfig.ICONS_DIR).glob('*.png')
         | 
| 32 | 
            +
                items = [
         | 
| 33 | 
            +
                    os.path.basename(str(item)).removesuffix('.png') for item in items
         | 
| 34 | 
            +
                ]
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                return items
         | 
| 37 | 
            +
             | 
| 38 | 
            +
             | 
| 39 | 
            +
            def get_embeddings(texts) -> np.ndarray:
         | 
| 40 | 
            +
                """
         | 
| 41 | 
            +
                Generate embeddings for a list of texts using a pre-trained language model.
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                :param texts: A string or a list of strings to be converted into embeddings.
         | 
| 44 | 
            +
                :type texts: Union[str, List[str]]
         | 
| 45 | 
            +
                :return: A NumPy array containing the embeddings for the input texts.
         | 
| 46 | 
            +
                :rtype: numpy.ndarray
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                :raises ValueError: If the input is not a string or a list of strings, or if any element
         | 
| 49 | 
            +
                in the list is not a string.
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                Example usage:
         | 
| 52 | 
            +
                >>> keyword = 'neural network'
         | 
| 53 | 
            +
                >>> file_names = ['neural_network_icon.png', 'data_analysis_icon.png', 'machine_learning.png']
         | 
| 54 | 
            +
                >>> keyword_embeddings = get_embeddings(keyword)
         | 
| 55 | 
            +
                >>> file_name_embeddings = get_embeddings(file_names)
         | 
| 56 | 
            +
                """
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                inputs = tokenizer(texts, return_tensors='pt', padding=True, max_length=128, truncation=True)
         | 
| 59 | 
            +
                outputs = model(**inputs)
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                return outputs.last_hidden_state.mean(dim=1).detach().numpy()
         | 
| 62 | 
            +
             | 
| 63 | 
            +
             | 
| 64 | 
            +
            def save_icons_embeddings():
         | 
| 65 | 
            +
                """
         | 
| 66 | 
            +
                Generate and save the embeddings for the icon file names.
         | 
| 67 | 
            +
                """
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                file_names = get_icons_list()
         | 
| 70 | 
            +
                file_name_embeddings = get_embeddings(file_names)
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                # Save embeddings to a file
         | 
| 73 | 
            +
                np.save(GlobalConfig.EMBEDDINGS_FILE_NAME, file_name_embeddings)
         | 
| 74 | 
            +
                np.save(GlobalConfig.ICONS_FILE_NAME, file_names)  # Save file names for reference
         | 
| 75 | 
            +
             | 
| 76 | 
            +
             | 
| 77 | 
            +
            def load_saved_embeddings() -> Tuple[np.ndarray, np.ndarray]:
         | 
| 78 | 
            +
                """
         | 
| 79 | 
            +
                Load precomputed embeddings and icons file names.
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                :return: The embeddings and the icon file names.
         | 
| 82 | 
            +
                """
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                file_name_embeddings = np.load(GlobalConfig.EMBEDDINGS_FILE_NAME)
         | 
| 85 | 
            +
                file_names = np.load(GlobalConfig.ICONS_FILE_NAME)
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                return file_name_embeddings, file_names
         | 
| 88 | 
            +
             | 
| 89 | 
            +
             | 
| 90 | 
            +
            def find_icons(keywords: List[str]) -> List[str]:
         | 
| 91 | 
            +
                """
         | 
| 92 | 
            +
                Find relevant icon file names for a list of keywords.
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                :param keywords: The list of one or more keywords.
         | 
| 95 | 
            +
                :return: A list of the file names relevant for each keyword.
         | 
| 96 | 
            +
                """
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                keyword_embeddings = get_embeddings(keywords)
         | 
| 99 | 
            +
                file_name_embeddings, file_names = load_saved_embeddings()
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                # Compute similarity
         | 
| 102 | 
            +
                similarities = cosine_similarity(keyword_embeddings, file_name_embeddings)
         | 
| 103 | 
            +
                icon_files = file_names[np.argmax(similarities, axis=-1)]
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                return icon_files
         | 
| 106 | 
            +
             | 
| 107 | 
            +
             | 
| 108 | 
            +
            def main():
         | 
| 109 | 
            +
                """
         | 
| 110 | 
            +
                Example usage.
         | 
| 111 | 
            +
                """
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                # Run this again if icons are to be added/removed
         | 
| 114 | 
            +
                # save_icons_embeddings()
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                keywords = ['deep learning', 'library', 'universe', 'brain', 'cybersecurity', 'gaming', '']
         | 
| 117 | 
            +
                icon_files = find_icons(keywords)
         | 
| 118 | 
            +
                print(f'The relevant icon files are: {icon_files}')
         | 
| 119 | 
            +
             | 
| 120 | 
            +
             | 
| 121 | 
            +
            if __name__ == '__main__':
         | 
| 122 | 
            +
                main()
         | 
    	
        helpers/pptx_helper.py
    CHANGED
    
    | @@ -19,6 +19,7 @@ from pptx.shapes.placeholder import PicturePlaceholder, SlidePlaceholder | |
| 19 | 
             
            sys.path.append('..')
         | 
| 20 | 
             
            sys.path.append('../..')
         | 
| 21 |  | 
|  | |
| 22 | 
             
            import helpers.image_search as ims
         | 
| 23 | 
             
            from global_config import GlobalConfig
         | 
| 24 |  | 
| @@ -493,24 +494,28 @@ def _handle_icons_ideas( | |
| 493 |  | 
| 494 | 
             
                    # Calculate the total width of all pictures and the spacing
         | 
| 495 | 
             
                    total_width = n_items * ICON_SIZE
         | 
| 496 | 
            -
                    # slide_width = presentation.slide_width
         | 
| 497 | 
             
                    spacing = (pptx.util.Inches(slide_width_inch) - total_width) / (n_items + 1)
         | 
| 498 | 
            -
             | 
| 499 | 
            -
             | 
| 500 | 
            -
             | 
| 501 | 
            -
                        match  | 
| 502 | 
            -
             | 
| 503 | 
            -
                         | 
| 504 | 
            -
             | 
| 505 | 
            -
             | 
| 506 | 
            -
             | 
| 507 | 
            -
             | 
| 508 | 
            -
                        accompanying_text =  | 
| 509 | 
            -
                        icon_path = f'{GlobalConfig.ICONS_DIR}/{ | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 510 |  | 
| 511 | 
             
                        left = spacing + idx * (ICON_SIZE + spacing)
         | 
| 512 | 
            -
                        top = INCHES_3
         | 
| 513 | 
            -
             | 
| 514 | 
             
                        # Calculate the center position for alignment
         | 
| 515 | 
             
                        center = left + ICON_SIZE / 2
         | 
| 516 |  | 
| @@ -526,30 +531,18 @@ def _handle_icons_ideas( | |
| 526 | 
             
                        shape.shadow.inherit = False
         | 
| 527 |  | 
| 528 | 
             
                        # Set the icon's background shape color
         | 
| 529 | 
            -
                        color = random.choice(ICON_COLORS)
         | 
| 530 | 
            -
                        shape.fill.fore_color.rgb = color
         | 
| 531 | 
            -
                        shape.line.color.rgb = color
         | 
| 532 |  | 
| 533 | 
             
                        # Add the icon image on top of the colored shape
         | 
| 534 | 
            -
                         | 
| 535 | 
            -
                            slide.shapes.add_picture(icon_path, left, top, height=ICON_SIZE)
         | 
| 536 | 
            -
                        except FileNotFoundError:
         | 
| 537 | 
            -
                            logger.error(
         | 
| 538 | 
            -
                                'Icon %s not found...using generic step number as icon...',
         | 
| 539 | 
            -
                                icon_name
         | 
| 540 | 
            -
                            )
         | 
| 541 | 
            -
                            step_icon_path = f'{GlobalConfig.ICONS_DIR}/{idx + 1}-circle.png'
         | 
| 542 | 
            -
                            if os.path.exists(step_icon_path):
         | 
| 543 | 
            -
                                slide.shapes.add_picture(step_icon_path, left, top, height=ICON_SIZE)
         | 
| 544 |  | 
| 545 | 
             
                        # Add a text box below the shape
         | 
| 546 | 
            -
                        text_top = top + ICON_SIZE + INCHES_0_2
         | 
| 547 | 
            -
                        text_left = center - text_box_size / 2  # Center the text box horizontally
         | 
| 548 | 
            -
                        # text_box = slide.shapes.add_textbox(text_left, text_top, text_box_size, text_box_size)
         | 
| 549 | 
             
                        text_box = slide.shapes.add_shape(
         | 
| 550 | 
             
                            MSO_AUTO_SHAPE_TYPE.ROUNDED_RECTANGLE,
         | 
| 551 | 
            -
                             | 
| 552 | 
            -
                             | 
|  | |
|  | |
| 553 | 
             
                        )
         | 
| 554 | 
             
                        text_frame = text_box.text_frame
         | 
| 555 | 
             
                        text_frame.text = accompanying_text
         | 
| @@ -955,7 +948,7 @@ if __name__ == '__main__': | |
| 955 | 
             
                  "bullet_points": [
         | 
| 956 | 
             
                    "[[brain]] Human-like intelligence and decision-making",
         | 
| 957 | 
             
                    "[[robot]] Automation and physical tasks",
         | 
| 958 | 
            -
                    "[[ | 
| 959 | 
             
                    "[[lightbulb]] Insights and predictions",
         | 
| 960 | 
             
                    "[[globe2]] Global connectivity and impact"
         | 
| 961 | 
             
                  ],
         | 
|  | |
| 19 | 
             
            sys.path.append('..')
         | 
| 20 | 
             
            sys.path.append('../..')
         | 
| 21 |  | 
| 22 | 
            +
            import helpers.icons_embeddings as ice
         | 
| 23 | 
             
            import helpers.image_search as ims
         | 
| 24 | 
             
            from global_config import GlobalConfig
         | 
| 25 |  | 
|  | |
| 494 |  | 
| 495 | 
             
                    # Calculate the total width of all pictures and the spacing
         | 
| 496 | 
             
                    total_width = n_items * ICON_SIZE
         | 
|  | |
| 497 | 
             
                    spacing = (pptx.util.Inches(slide_width_inch) - total_width) / (n_items + 1)
         | 
| 498 | 
            +
                    top = INCHES_3
         | 
| 499 | 
            +
             | 
| 500 | 
            +
                    icons_texts = [
         | 
| 501 | 
            +
                        (match.group(1), match.group(2)) for match in [
         | 
| 502 | 
            +
                            ICONS_REGEX.search(item) for item in items
         | 
| 503 | 
            +
                        ]
         | 
| 504 | 
            +
                    ]
         | 
| 505 | 
            +
                    fallback_icon_files = ice.find_icons([item[0] for item in icons_texts])
         | 
| 506 | 
            +
             | 
| 507 | 
            +
                    for idx, item in enumerate(icons_texts):
         | 
| 508 | 
            +
                        icon, accompanying_text = item
         | 
| 509 | 
            +
                        icon_path = f'{GlobalConfig.ICONS_DIR}/{icon}.png'
         | 
| 510 | 
            +
             | 
| 511 | 
            +
                        if not os.path.exists(icon_path):
         | 
| 512 | 
            +
                            logger.warning(
         | 
| 513 | 
            +
                                'Icon not found: %s...using fallback icon: %s',
         | 
| 514 | 
            +
                                icon, fallback_icon_files[idx]
         | 
| 515 | 
            +
                            )
         | 
| 516 | 
            +
                            icon_path = f'{GlobalConfig.ICONS_DIR}/{fallback_icon_files[idx]}.png'
         | 
| 517 |  | 
| 518 | 
             
                        left = spacing + idx * (ICON_SIZE + spacing)
         | 
|  | |
|  | |
| 519 | 
             
                        # Calculate the center position for alignment
         | 
| 520 | 
             
                        center = left + ICON_SIZE / 2
         | 
| 521 |  | 
|  | |
| 531 | 
             
                        shape.shadow.inherit = False
         | 
| 532 |  | 
| 533 | 
             
                        # Set the icon's background shape color
         | 
| 534 | 
            +
                        shape.fill.fore_color.rgb = shape.line.color.rgb = random.choice(ICON_COLORS)
         | 
|  | |
|  | |
| 535 |  | 
| 536 | 
             
                        # Add the icon image on top of the colored shape
         | 
| 537 | 
            +
                        slide.shapes.add_picture(icon_path, left, top, height=ICON_SIZE)
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 538 |  | 
| 539 | 
             
                        # Add a text box below the shape
         | 
|  | |
|  | |
|  | |
| 540 | 
             
                        text_box = slide.shapes.add_shape(
         | 
| 541 | 
             
                            MSO_AUTO_SHAPE_TYPE.ROUNDED_RECTANGLE,
         | 
| 542 | 
            +
                            left=center - text_box_size / 2,  # Center the text box horizontally
         | 
| 543 | 
            +
                            top=top + ICON_SIZE + INCHES_0_2,
         | 
| 544 | 
            +
                            width=text_box_size,
         | 
| 545 | 
            +
                            height=text_box_size
         | 
| 546 | 
             
                        )
         | 
| 547 | 
             
                        text_frame = text_box.text_frame
         | 
| 548 | 
             
                        text_frame.text = accompanying_text
         | 
|  | |
| 948 | 
             
                  "bullet_points": [
         | 
| 949 | 
             
                    "[[brain]] Human-like intelligence and decision-making",
         | 
| 950 | 
             
                    "[[robot]] Automation and physical tasks",
         | 
| 951 | 
            +
                    "[[]] Data processing and cloud computing",
         | 
| 952 | 
             
                    "[[lightbulb]] Insights and predictions",
         | 
| 953 | 
             
                    "[[globe2]] Global connectivity and impact"
         | 
| 954 | 
             
                  ],
         | 
    	
        langchain_templates/chat_prompts/initial_template_v4_two_cols_img.txt
    CHANGED
    
    | @@ -13,22 +13,18 @@ In addition, for each slide, add image keywords based on the content of the resp | |
| 13 | 
             
            These keywords will be later used to search for images from the Web relevant to the slide content.
         | 
| 14 |  | 
| 15 | 
             
            In addition, create one slide containing 4 TO 6 icons (pictograms) illustrating some key ideas/aspects/concepts relevant to the topic.
         | 
| 16 | 
            -
            In this slide, each line of text will begin with the name of  | 
| 17 | 
            -
             | 
| 18 | 
            -
            If you need an icon that is unavailable in the <ICONS> section, you may select a conceptually similar icon's name from <ICONS>.
         | 
| 19 | 
            -
            For example, if an icon for "neural network" is unavailable, you may choose the "deep-learning" icon from <ICONS>.
         | 
| 20 | 
            -
            However, you MUST NEVER generate any icon name not mentioned in the <ICONS> section.
         | 
| 21 | 
            -
             | 
| 22 | 
            -
            The content of each slide should be VERBOSE, DESCRIPTIVE, and very DETAILED.
         | 
| 23 | 
            -
             | 
| 24 | 
            -
            ALWAYS add a concluding slide at the end, containing a list of the key takeaways and an optional call-to-action if relevant to the context.
         | 
| 25 | 
            -
            Unless explicitly instructed, create 10 TO 12 SLIDES in total.
         | 
| 26 | 
            -
             | 
| 27 |  | 
| 28 | 
             
            <ICONS>
         | 
| 29 | 
             
            {icons_list}
         | 
| 30 | 
             
            </ICONS>
         | 
| 31 |  | 
|  | |
|  | |
|  | |
|  | |
|  | |
| 32 |  | 
| 33 | 
             
            ### Topic:
         | 
| 34 | 
             
            {question}
         | 
| @@ -64,10 +60,10 @@ The output must be only a valid and syntactically correct JSON adhering to the f | |
| 64 | 
             
                    {{
         | 
| 65 | 
             
                        "heading": "A slide illustrating key ideas/aspects/concepts (Hint: generate an appropriate heading)",
         | 
| 66 | 
             
                        "bullet_points": [
         | 
| 67 | 
            -
                            "[[ | 
| 68 | 
            -
                            "[[ | 
| 69 | 
            -
                            "[[ | 
| 70 | 
            -
                            "[[ | 
| 71 | 
             
                        ],
         | 
| 72 | 
             
                        "key_message": "",
         | 
| 73 | 
             
                        "img_keywords": ""
         | 
|  | |
| 13 | 
             
            These keywords will be later used to search for images from the Web relevant to the slide content.
         | 
| 14 |  | 
| 15 | 
             
            In addition, create one slide containing 4 TO 6 icons (pictograms) illustrating some key ideas/aspects/concepts relevant to the topic.
         | 
| 16 | 
            +
            In this slide, each line of text will begin with the name of a relevant icon enclosed between [[ and ]].
         | 
| 17 | 
            +
            Select appropriate and exact icon names from the <ICONS> section provided below.
         | 
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
|  | |
| 18 |  | 
| 19 | 
             
            <ICONS>
         | 
| 20 | 
             
            {icons_list}
         | 
| 21 | 
             
            </ICONS>
         | 
| 22 |  | 
| 23 | 
            +
            The content of each slide should be VERBOSE, DESCRIPTIVE, and very DETAILED. Each bullet point should be detailed and explanatory, not just short phrases.
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            ALWAYS add a concluding slide at the end, containing a list of the key takeaways and an optional call-to-action if relevant to the context.
         | 
| 26 | 
            +
            Unless explicitly instructed with the topic, create 10 TO 12 SLIDES in total. You must never create more tha 15 slides.
         | 
| 27 | 
            +
             | 
| 28 |  | 
| 29 | 
             
            ### Topic:
         | 
| 30 | 
             
            {question}
         | 
|  | |
| 60 | 
             
                    {{
         | 
| 61 | 
             
                        "heading": "A slide illustrating key ideas/aspects/concepts (Hint: generate an appropriate heading)",
         | 
| 62 | 
             
                        "bullet_points": [
         | 
| 63 | 
            +
                            "[[icon name]] Some text",
         | 
| 64 | 
            +
                            "[[another icon name]] Some words describing this aspect",
         | 
| 65 | 
            +
                            "[[icon]] Another aspect highlighted here",
         | 
| 66 | 
            +
                            "[[an icon]] Another point here",
         | 
| 67 | 
             
                        ],
         | 
| 68 | 
             
                        "key_message": "",
         | 
| 69 | 
             
                        "img_keywords": ""
         | 
    	
        langchain_templates/chat_prompts/refinement_template_v4_two_cols_img.txt
    CHANGED
    
    | @@ -14,21 +14,17 @@ In addition, for each slide, add image keywords based on the content of the resp | |
| 14 | 
             
            These keywords will be later used to search for images from the Web relevant to the slide content.
         | 
| 15 |  | 
| 16 | 
             
            In addition, create one slide containing 4 TO 6 icons (pictograms) illustrating some key ideas/aspects/concepts relevant to the topic.
         | 
| 17 | 
            -
            In this slide, each line of text will begin with the name of  | 
| 18 | 
            -
             | 
| 19 | 
            -
            If you need an icon that is unavailable in the <ICONS> section, you may select a conceptually similar icon's name from <ICONS>.
         | 
| 20 | 
            -
            For example, if an icon for "neural network" is unavailable, you may choose the "deep-learning" icon from <ICONS>.
         | 
| 21 | 
            -
            However, you MUST NEVER generate any icon name not mentioned in the <ICONS> section.
         | 
| 22 |  | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
            Unless explicitly instructed, create 10 TO 12 SLIDES in total.
         | 
| 27 |  | 
|  | |
| 28 |  | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
            </Icons>
         | 
| 32 |  | 
| 33 |  | 
| 34 | 
             
            ### List of instructions:
         | 
| @@ -69,10 +65,10 @@ The output must be only a valid and syntactically correct JSON adhering to the f | |
| 69 | 
             
                    {{
         | 
| 70 | 
             
                        "heading": "A slide illustrating key ideas/aspects/concepts (Hint: generate an appropriate heading)",
         | 
| 71 | 
             
                        "bullet_points": [
         | 
| 72 | 
            -
                            "[[ | 
| 73 | 
            -
                            "[[ | 
| 74 | 
            -
                            "[[ | 
| 75 | 
            -
                            "[[ | 
| 76 | 
             
                        ],
         | 
| 77 | 
             
                        "key_message": "",
         | 
| 78 | 
             
                        "img_keywords": ""
         | 
|  | |
| 14 | 
             
            These keywords will be later used to search for images from the Web relevant to the slide content.
         | 
| 15 |  | 
| 16 | 
             
            In addition, create one slide containing 4 TO 6 icons (pictograms) illustrating some key ideas/aspects/concepts relevant to the topic.
         | 
| 17 | 
            +
            In this slide, each line of text will begin with the name of a relevant icon enclosed between [[ and ]].
         | 
| 18 | 
            +
            Select appropriate and exact icon names from the <ICONS> section provided below.
         | 
|  | |
|  | |
|  | |
| 19 |  | 
| 20 | 
            +
            <ICONS>
         | 
| 21 | 
            +
            {icons_list}
         | 
| 22 | 
            +
            </ICONS>
         | 
|  | |
| 23 |  | 
| 24 | 
            +
            The content of each slide should be VERBOSE, DESCRIPTIVE, and very DETAILED. Each bullet point should be detailed and explanatory, not just short phrases.
         | 
| 25 |  | 
| 26 | 
            +
            ALWAYS add a concluding slide at the end, containing a list of the key takeaways and an optional call-to-action if relevant to the context.
         | 
| 27 | 
            +
            Unless explicitly specified in the instructions below, create 10 TO 12 SLIDES in total. You must never create more tha 15 slides.
         | 
|  | |
| 28 |  | 
| 29 |  | 
| 30 | 
             
            ### List of instructions:
         | 
|  | |
| 65 | 
             
                    {{
         | 
| 66 | 
             
                        "heading": "A slide illustrating key ideas/aspects/concepts (Hint: generate an appropriate heading)",
         | 
| 67 | 
             
                        "bullet_points": [
         | 
| 68 | 
            +
                            "[[icon name]] Some text",
         | 
| 69 | 
            +
                            "[[another icon name]] Some words describing this aspect",
         | 
| 70 | 
            +
                            "[[icon]] Another aspect highlighted here",
         | 
| 71 | 
            +
                            "[[an icon]] Another point here",
         | 
| 72 | 
             
                        ],
         | 
| 73 | 
             
                        "key_message": "",
         | 
| 74 | 
             
                        "img_keywords": ""
         | 
    	
        requirements.txt
    CHANGED
    
    | @@ -16,9 +16,11 @@ metaphor-python | |
| 16 | 
             
            json5~=0.9.14
         | 
| 17 | 
             
            requests~=2.31.0
         | 
| 18 |  | 
| 19 | 
            -
            transformers~=4. | 
| 20 | 
             
            langchain-community
         | 
| 21 |  | 
| 22 | 
             
            urllib3~=2.2.1
         | 
| 23 | 
             
            lxml~=4.9.3
         | 
| 24 | 
            -
            tqdm~=4.64.1
         | 
|  | |
|  | 
|  | |
| 16 | 
             
            json5~=0.9.14
         | 
| 17 | 
             
            requests~=2.31.0
         | 
| 18 |  | 
| 19 | 
            +
            transformers~=4.44.0
         | 
| 20 | 
             
            langchain-community
         | 
| 21 |  | 
| 22 | 
             
            urllib3~=2.2.1
         | 
| 23 | 
             
            lxml~=4.9.3
         | 
| 24 | 
            +
            tqdm~=4.64.1
         | 
| 25 | 
            +
            numpy~=1.25.2
         | 
| 26 | 
            +
            scikit-learn~=1.5.1
         | 
