code: import streamlit as st
  from langchain import PromptTemplate
  from utils.studio_style import apply_studio_style
  from utils.studio_style import keyword_label, sentiment_label
  from utils import langchain
  from utils import bedrock
  from utils import config
  from datetime import datetime
  import pandas as pd
  import json
  import logging
  
  st.set_page_config(
      page_title="Summarize Product Reviews",
      page_icon="🛒",
  )
  
  config.get_background()
  
  # Read the CSV file
  @st.cache_data
  def load_data():
      data = pd.read_csv("./data/amazon_vfl_reviews.csv")
      return data
      
  def display_product_review_summary(review):
      
      with st.expander("See output"):
          st.write(review)
      
      # Claude v2.1 always returns text with json
      try:
          # Find the index of the first '{' and the last '}'
          start_idx = review.index('{')
          end_idx = review.rindex('}') + 1
  
          # Extract the JSON string
          json_string = review[start_idx:end_idx]
          
          # Load JSON data
          json_data = json.loads(json_string)
      except json.JSONDecodeError:
          print("Error decoding JSON.")
          return 'Cannot summarize review'
  
      #json_data = json.loads(review)
  
      # Display the summary
      st.subheader("Product Reviews Summary")
  
       # Display the overall sentiment
      formatted_sentiment = sentiment_label(json_data["overall_sentiment"], json_data["overall_sentiment"])
      overall_sentiment =f'<div style="display: inline-block; margin:5px;"><b>Overall Sentiment</b> : {formatted_sentiment}  </div>'
  
      formatted_labels = [
          sentiment_label(keyword_info["sentiment"],keyword_info["keyword"] ) 
          for keyword_info in json_data["keywords_highlight"]
          ]
      
      #st.write(' '.join(formatted_labels), unsafe_allow_html=True)
      summary = f'{overall_sentiment}</br>{json_data["product_reviews_summary"]}</br></br>{"".join(formatted_labels)}'
  
      styled_summary = f'<div class="output-text">{summary}</div>'
      st.markdown(styled_summary, unsafe_allow_html=True)
  
  
  # Your content and interactive elements for the Summarize Product Reviews page
  def generate_review_summary (product_reviews, product_name):
      
      if product_reviews is None:
          return
      
      product_reviews = f"""Product Name:{product_name}\n
      Reviews: {product_reviews}
      """
      map_prompt = """
      Write a concise summary of the following product reviews:
      "{text}"
      CONCISE SUMMARY:
      """
      map_prompt_template = PromptTemplate(template=map_prompt, input_variables=["text"])
  
      combine_prompt = """
      Generate summary about the reviews for [Product Name] based on Product reviews delimited by triple backquotes.
      ```{text}```
  
      Also return overall_sentiment as 'POSITIVE', 'NEGATIVE' or 'MIXED' based on the review summary, 
      and generate maximum 5 most important keywords for the the given product reviews and based on reviews generate sentiment for each keyword. 
      The output should ALWAYS be valid JSON document with text inside the 'outputFormat' below, do NOT add any text in the output before JSON . 
      Don't include any preamble.
      <outputFormat>
          {{
              "product_reviews_summary": "Maximum 200 words summary.",
              "overall_sentiment": "POSITIVE or NEGATIVE or MIXED",
              "keywords_highlight": [
                  {{"keyword": "Quality", "sentiment": "POSITIVE"}},
                  {{"keyword": "Affordability", "sentiment": "NEGATIVE"}},
                  {{"keyword": "Customer Service", "sentiment": "MIXED"}}
              ]
          }}
      </outputFormat>
  
  
      """
      combine_prompt_template = PromptTemplate(template=combine_prompt, input_variables=["text"])
      #modelId = 'amazon.titan-tg1-large'
      # inference_config = {
      #                         "maxTokenCount":3072,
      #                         "stopSequences":[],
      #                         "temperature":0,
      #                         "topP":0.9
      #                         }
      #modelId = 'anthropic.claude-v1'
      inference_config = {
                                  "max_tokens_to_sample":4096,
                                  "temperature":1,
                                  "top_k":250,
                                  "top_p":0.5,
                                  "stop_sequences":[]
                          }
      #print(f'Reviews:{product_reviews}')
      summary = langchain.summarize_long_text(product_reviews, st.session_state.sm_assistant.boto3_bedrock, modelId, inference_config, map_prompt, combine_prompt)
      display_product_review_summary(summary)
      return summary
  
  def style_figure_text(text):
      return f'<div style="font-style:italic; font-size: 0.875em; text-align:center">{text}</div>'
  
  def load_demo():
      # Dropdown to select a product
      selected_product = st.selectbox("Select Product for summarizing reviews:", [None] + list(unique_products), index=0)
  
      if selected_product is not None:
          # Filter data for the selected product
          selected_data = data[data['name'] == selected_product]
  
          # Sort data by date in descending order
          selected_data = selected_data.sort_values(by='date', ascending=False)
  
          # Function to load reviews for the selected product
          def load_reviews(product_name):
              filtered_data = selected_data[selected_data['name'] == product_name]
              unique_reviews = filtered_data.drop_duplicates(subset='review')
              return unique_reviews[['date', 'rating', 'review']]
              #return selected_data[selected_data['name'] == product_name][['date', 'rating', 'review']]
  
          # Load reviews for the selected product
          reviews_df = load_reviews(selected_product)
  
          # Display reviews in a scrollable container
          if not reviews_df.empty:
              # Show "Summarize Reviews" button
              if st.button("Summarize Reviews"):
                  with st.spinner("Summarizing reviews..."):
                      # Concatenate reviews
                      combine_prompt = """
                      Write a concise summary of the following product reviews.
                      Return overall sentiment of the product reviews.
                      SUMMARY:
                      SENTIMENT:
                      """
                      product_reviews = "\n".join(reviews_df['review'])
                      product_reviews = combine_prompt + product_reviews
                      summary = generate_review_summary(product_reviews, selected_product)
  
              st.markdown("#### Product Reviews")
              for _, row in reviews_df.iterrows():
                  st.write(f"Date: {row['date']}")
                  st.write(f"Rating: {row['rating']}")
                  st.write(f"Review: {row['review']}")
                  st.write("-" * 10)
  
          else:
              st.warning("No reviews available for the selected product.")
      else:
          st.info("Select a product to view its reviews.")
  
  @st.cache_data
  def load_arch():
      st.write()
  
      st.image('data/architecture/reviews_1.png')
      st.markdown(
          '''
          When we work with large documents, we can face some challenges as the input text might not fit into the model context length, or the model hallucinates with large documents, or, out of memory errors, etc.
  
          To solve those problems, we are going to show an architecture that is based on the concept of chunking and chaining prompts. This architecture is leveraging [LangChain](https://python.langchain.com/docs/get_started/introduction.html) which is a popular framework for developing applications powered by language models.
          '''
      )
      st.image('data/architecture/reviews_2.png')
      st.markdown(
          '''
          In this architecture:
  
          1. A large document (or a giant file appending small ones) is loaded
          2. Langchain utility is used to split it into multiple smaller chunks (chunking)
          3. First chunk is sent to the model; Model returns the corresponding summary
          4. Langchain gets next chunk and appends it to the returned summary and sends the combined text as a new request to the model; the process repeats until all chunks are processed
          5. In the end, you have final summary based on entire content.
  
          '''
      )
      st.markdown(
          '''
          **LangChain** `load_summarize_chain` provides three ways of summarization:
          1. `stuff` puts all the chunks into one prompt. Thus, this would hit the maximum limit of tokens.
          2. `map_reduce` summarizes each chunk on it's own in a "map" step, combines the summary, and summarizes the combined summary into a final summary in "reduce" step. If the combined summary is too large, it would raise error.
  
          '''
      )
  
      st.markdown(style_figure_text('Figure Ref: <a href="https://python.langchain.com/docs/use_cases/summarization">LangChain Summarization Stuff & Map Reduce</a>')
                  , unsafe_allow_html=True)
      st.image('data/architecture/summarization_lang_stuff_mapreduce.png')
      
      st.markdown('3. `refine` summarizes the first chunk, and then summarizes the second chunk with the first summary. The same process repeats until all chunks are summarized.')
      st.markdown(style_figure_text('Figure Ref: <a href="https://python.langchain.com/docs/modules/chains/document/refine">LangChain Refine Chain</a>')
                  , unsafe_allow_html=True)
      st.image('data/architecture/summarization_lang_stuff_refine.png')
  
  def main():
      with demo:
          load_demo()
      
      with arch:
          load_arch()
  
  @st.cache_resource
  def configure_logging():
      print("init logger")
      logger = logging.getLogger('retail_genai')
      logger.setLevel(logging.DEBUG)
      logger.addHandler(logging.StreamHandler())
      st.session_state.logger = logger
      return logger
  
  if __name__ == "__main__":
      st.title("Summarize Product Reviews")
      #modelId = 'amazon.titan-tg1-xlarge'
      modelId = 'anthropic.claude-v2:1'
      #modelId = 'anthropic.claude-instant-v1'
      data = load_data()
  
      # Get unique product names
      unique_products = data['name'].unique()
  
      keywords = [f'Model Id: {modelId}','Amazon Bedrock API', 'Langchain']
      formatted_labels = [keyword_label(keyword) for keyword in keywords]
      st.write(' '.join(formatted_labels), unsafe_allow_html=True)
      apply_studio_style()
  
      # Add a description for this specific use case
      st.markdown(
          '''
          #### Use Case: 
          ###### Efficiently tackle the challenges of handling extensive product reviews with advanced summarization technique. 
          You can access the dataset used for this demo on Kaggle using the following link:
          [Indian Products on Amazon](https://www.kaggle.com/datasets/nehaprabhavalkar/indian-products-on-amazon?resource=download)
  
          1. **Product**: Select a product to summarize reviews for.
          2. **Summarize Reviews**: Get Summary of reviews for the product. It will both summarize long product reviews, tell the sentiment & extract important keywords.
  
          This architecture effective in summarizing diverse types of content, including call transcripts, meeting notes, books, articles, blog posts, and other relevant textual content. Whether you're dealing with customer feedback, evaluating product sentiment, or conducting in-depth analysis, our summarization technique can enhance your insights and decision-making processes.
          '''
      )
  
      demo, arch,  = st.tabs(["Demo", "Architecture"])
  
      if "logger" not in st.session_state:
          st.session_state.logger = configure_logging()
      
      if "sm_assistant" not in st.session_state:
          st.session_state.sm_assistant = bedrock.BedrockAssistant(modelId, st.session_state.logger)
      main()
apis: langchain.PromptTemplate
extract_api: [((329, 402), 'streamlit.set_page_config', 'st.set_page_config', ([], {'page_title': '"""Summarize Product Reviews"""', 'page_icon': '"""🛒"""'}), "(page_title='Summarize Product Reviews', page_icon='🛒')\n", (347, 402), True, 'import streamlit as st\n'), ((415, 438), 'utils.config.get_background', 'config.get_background', ([], {}), '()\n', (436, 438), False, 'from utils import config\n'), ((503, 547), 'pandas.read_csv', 'pd.read_csv', (['"""./data/amazon_vfl_reviews.csv"""'], {}), "('./data/amazon_vfl_reviews.csv')\n", (514, 547), True, 'import pandas as pd\n'), ((1220, 1259), 'streamlit.subheader', 'st.subheader', (['"""Product Reviews Summary"""'], {}), "('Product Reviews Summary')\n", (1232, 1259), True, 'import streamlit as st\n'), ((1324, 1403), 'utils.studio_style.sentiment_label', 'sentiment_label', (["json_data['overall_sentiment']", "json_data['overall_sentiment']"], {}), "(json_data['overall_sentiment'], json_data['overall_sentiment'])\n", (1339, 1403), False, 'from utils.studio_style import keyword_label, sentiment_label\n'), ((1966, 2017), 'streamlit.markdown', 'st.markdown', (['styled_summary'], {'unsafe_allow_html': '(True)'}), '(styled_summary, unsafe_allow_html=True)\n', (1977, 2017), True, 'import streamlit as st\n'), ((2463, 2524), 'langchain.PromptTemplate', 'PromptTemplate', ([], {'template': 'map_prompt', 'input_variables': "['text']"}), "(template=map_prompt, input_variables=['text'])\n", (2477, 2524), False, 'from langchain import PromptTemplate\n'), ((3603, 3668), 'langchain.PromptTemplate', 'PromptTemplate', ([], {'template': 'combine_prompt', 'input_variables': "['text']"}), "(template=combine_prompt, input_variables=['text'])\n", (3617, 3668), False, 'from langchain import PromptTemplate\n'), ((4353, 4508), 'utils.langchain.summarize_long_text', 'langchain.summarize_long_text', (['product_reviews', 'st.session_state.sm_assistant.boto3_bedrock', 'modelId', 'inference_config', 'map_prompt', 'combine_prompt'], {}), '(product_reviews, st.session_state.\n    sm_assistant.boto3_bedrock, modelId, inference_config, map_prompt,\n    combine_prompt)\n', (4382, 4508), False, 'from utils import langchain\n'), ((6926, 6936), 'streamlit.write', 'st.write', ([], {}), '()\n', (6934, 6936), True, 'import streamlit as st\n'), ((6942, 6985), 'streamlit.image', 'st.image', (['"""data/architecture/reviews_1.png"""'], {}), "('data/architecture/reviews_1.png')\n", (6950, 6985), True, 'import streamlit as st\n'), ((6990, 7569), 'streamlit.markdown', 'st.markdown', (['"""\n        When we work with large documents, we can face some challenges as the input text might not fit into the model context length, or the model hallucinates with large documents, or, out of memory errors, etc.\n\n        To solve those problems, we are going to show an architecture that is based on the concept of chunking and chaining prompts. This architecture is leveraging [LangChain](https://python.langchain.com/docs/get_started/introduction.html) which is a popular framework for developing applications powered by language models.\n        """'], {}), '(\n    """\n        When we work with large documents, we can face some challenges as the input text might not fit into the model context length, or the model hallucinates with large documents, or, out of memory errors, etc.\n\n        To solve those problems, we are going to show an architecture that is based on the concept of chunking and chaining prompts. This architecture is leveraging [LangChain](https://python.langchain.com/docs/get_started/introduction.html) which is a popular framework for developing applications powered by language models.\n        """\n    )\n', (7001, 7569), True, 'import streamlit as st\n'), ((7578, 7621), 'streamlit.image', 'st.image', (['"""data/architecture/reviews_2.png"""'], {}), "('data/architecture/reviews_2.png')\n", (7586, 7621), True, 'import streamlit as st\n'), ((7626, 8204), 'streamlit.markdown', 'st.markdown', (['"""\n        In this architecture:\n\n        1. A large document (or a giant file appending small ones) is loaded\n        2. Langchain utility is used to split it into multiple smaller chunks (chunking)\n        3. First chunk is sent to the model; Model returns the corresponding summary\n        4. Langchain gets next chunk and appends it to the returned summary and sends the combined text as a new request to the model; the process repeats until all chunks are processed\n        5. In the end, you have final summary based on entire content.\n\n        """'], {}), '(\n    """\n        In this architecture:\n\n        1. A large document (or a giant file appending small ones) is loaded\n        2. Langchain utility is used to split it into multiple smaller chunks (chunking)\n        3. First chunk is sent to the model; Model returns the corresponding summary\n        4. Langchain gets next chunk and appends it to the returned summary and sends the combined text as a new request to the model; the process repeats until all chunks are processed\n        5. In the end, you have final summary based on entire content.\n\n        """\n    )\n', (7637, 8204), True, 'import streamlit as st\n'), ((8213, 8673), 'streamlit.markdown', 'st.markdown', (['"""\n        **LangChain** `load_summarize_chain` provides three ways of summarization:\n        1. `stuff` puts all the chunks into one prompt. Thus, this would hit the maximum limit of tokens.\n        2. `map_reduce` summarizes each chunk on it\'s own in a "map" step, combines the summary, and summarizes the combined summary into a final summary in "reduce" step. If the combined summary is too large, it would raise error.\n\n        """'], {}), '(\n    """\n        **LangChain** `load_summarize_chain` provides three ways of summarization:\n        1. `stuff` puts all the chunks into one prompt. Thus, this would hit the maximum limit of tokens.\n        2. `map_reduce` summarizes each chunk on it\'s own in a "map" step, combines the summary, and summarizes the combined summary into a final summary in "reduce" step. If the combined summary is too large, it would raise error.\n\n        """\n    )\n', (8224, 8673), True, 'import streamlit as st\n'), ((8889, 8957), 'streamlit.image', 'st.image', (['"""data/architecture/summarization_lang_stuff_mapreduce.png"""'], {}), "('data/architecture/summarization_lang_stuff_mapreduce.png')\n", (8897, 8957), True, 'import streamlit as st\n'), ((8967, 9150), 'streamlit.markdown', 'st.markdown', (['"""3. `refine` summarizes the first chunk, and then summarizes the second chunk with the first summary. The same process repeats until all chunks are summarized."""'], {}), "(\n    '3. `refine` summarizes the first chunk, and then summarizes the second chunk with the first summary. The same process repeats until all chunks are summarized.'\n    )\n", (8978, 9150), True, 'import streamlit as st\n'), ((9338, 9403), 'streamlit.image', 'st.image', (['"""data/architecture/summarization_lang_stuff_refine.png"""'], {}), "('data/architecture/summarization_lang_stuff_refine.png')\n", (9346, 9403), True, 'import streamlit as st\n'), ((9575, 9608), 'logging.getLogger', 'logging.getLogger', (['"""retail_genai"""'], {}), "('retail_genai')\n", (9592, 9608), False, 'import logging\n'), ((9778, 9815), 'streamlit.title', 'st.title', (['"""Summarize Product Reviews"""'], {}), "('Summarize Product Reviews')\n", (9786, 9815), True, 'import streamlit as st\n'), ((10255, 10275), 'utils.studio_style.apply_studio_style', 'apply_studio_style', ([], {}), '()\n', (10273, 10275), False, 'from utils.studio_style import apply_studio_style\n'), ((10332, 11358), 'streamlit.markdown', 'st.markdown', (['"""\n        #### Use Case: \n        ###### Efficiently tackle the challenges of handling extensive product reviews with advanced summarization technique. \n        You can access the dataset used for this demo on Kaggle using the following link:\n        [Indian Products on Amazon](https://www.kaggle.com/datasets/nehaprabhavalkar/indian-products-on-amazon?resource=download)\n\n        1. **Product**: Select a product to summarize reviews for.\n        2. **Summarize Reviews**: Get Summary of reviews for the product. It will both summarize long product reviews, tell the sentiment & extract important keywords.\n\n        This architecture effective in summarizing diverse types of content, including call transcripts, meeting notes, books, articles, blog posts, and other relevant textual content. Whether you\'re dealing with customer feedback, evaluating product sentiment, or conducting in-depth analysis, our summarization technique can enhance your insights and decision-making processes.\n        """'], {}), '(\n    """\n        #### Use Case: \n        ###### Efficiently tackle the challenges of handling extensive product reviews with advanced summarization technique. \n        You can access the dataset used for this demo on Kaggle using the following link:\n        [Indian Products on Amazon](https://www.kaggle.com/datasets/nehaprabhavalkar/indian-products-on-amazon?resource=download)\n\n        1. **Product**: Select a product to summarize reviews for.\n        2. **Summarize Reviews**: Get Summary of reviews for the product. It will both summarize long product reviews, tell the sentiment & extract important keywords.\n\n        This architecture effective in summarizing diverse types of content, including call transcripts, meeting notes, books, articles, blog posts, and other relevant textual content. Whether you\'re dealing with customer feedback, evaluating product sentiment, or conducting in-depth analysis, our summarization technique can enhance your insights and decision-making processes.\n        """\n    )\n', (10343, 11358), True, 'import streamlit as st\n'), ((11383, 11416), 'streamlit.tabs', 'st.tabs', (["['Demo', 'Architecture']"], {}), "(['Demo', 'Architecture'])\n", (11390, 11416), True, 'import streamlit as st\n'), ((627, 652), 'streamlit.expander', 'st.expander', (['"""See output"""'], {}), "('See output')\n", (638, 652), True, 'import streamlit as st\n'), ((662, 678), 'streamlit.write', 'st.write', (['review'], {}), '(review)\n', (670, 678), True, 'import streamlit as st\n'), ((1016, 1039), 'json.loads', 'json.loads', (['json_string'], {}), '(json_string)\n', (1026, 1039), False, 'import json\n'), ((1569, 1636), 'utils.studio_style.sentiment_label', 'sentiment_label', (["keyword_info['sentiment']", "keyword_info['keyword']"], {}), "(keyword_info['sentiment'], keyword_info['keyword'])\n", (1584, 1636), False, 'from utils.studio_style import keyword_label, sentiment_label\n'), ((6840, 6888), 'streamlit.info', 'st.info', (['"""Select a product to view its reviews."""'], {}), "('Select a product to view its reviews.')\n", (6847, 6888), True, 'import streamlit as st\n'), ((9666, 9689), 'logging.StreamHandler', 'logging.StreamHandler', ([], {}), '()\n', (9687, 9689), False, 'import logging\n'), ((10138, 10160), 'utils.studio_style.keyword_label', 'keyword_label', (['keyword'], {}), '(keyword)\n', (10151, 10160), False, 'from utils.studio_style import keyword_label, sentiment_label\n'), ((11605, 11663), 'utils.bedrock.BedrockAssistant', 'bedrock.BedrockAssistant', (['modelId', 'st.session_state.logger'], {}), '(modelId, st.session_state.logger)\n', (11629, 11663), False, 'from utils import bedrock\n'), ((5811, 5841), 'streamlit.button', 'st.button', (['"""Summarize Reviews"""'], {}), "('Summarize Reviews')\n", (5820, 5841), True, 'import streamlit as st\n'), ((6459, 6494), 'streamlit.markdown', 'st.markdown', (['"""#### Product Reviews"""'], {}), "('#### Product Reviews')\n", (6470, 6494), True, 'import streamlit as st\n'), ((6761, 6821), 'streamlit.warning', 'st.warning', (['"""No reviews available for the selected product."""'], {}), "('No reviews available for the selected product.')\n", (6771, 6821), True, 'import streamlit as st\n'), ((6560, 6592), 'streamlit.write', 'st.write', (['f"""Date: {row[\'date\']}"""'], {}), '(f"Date: {row[\'date\']}")\n', (6568, 6592), True, 'import streamlit as st\n'), ((6609, 6645), 'streamlit.write', 'st.write', (['f"""Rating: {row[\'rating\']}"""'], {}), '(f"Rating: {row[\'rating\']}")\n', (6617, 6645), True, 'import streamlit as st\n'), ((6662, 6698), 'streamlit.write', 'st.write', (['f"""Review: {row[\'review\']}"""'], {}), '(f"Review: {row[\'review\']}")\n', (6670, 6698), True, 'import streamlit as st\n'), ((6715, 6733), 'streamlit.write', 'st.write', (["('-' * 10)"], {}), "('-' * 10)\n", (6723, 6733), True, 'import streamlit as st\n'), ((5864, 5900), 'streamlit.spinner', 'st.spinner', (['"""Summarizing reviews..."""'], {}), "('Summarizing reviews...')\n", (5874, 5900), True, 'import streamlit as st\n')]