turns-00077.parquet:26175
7a8ded361aaf5b1505ea1820
turn 3/5gpt-4.1-mini-2025-04-14EnglishIndia2610 words
degenerate_repetitionAbsentFinal dense release
USER
Analysis mode selection is a top-level radio. doesnot need this we can make two buttons below Analyze Documents and then on selection of the buttons we can genrate the topics and consolidate summary, so we need to dispaly both button on screen no any radio button no where in sidebar also we can directly get the topics cliking on both of them and display the consolidate summary so give me full code give me full code do not left anything else make it accordingle
ASSISTANT
Certainly! I've updated your Streamlit app so that **instead of a radio button**, you get **two clearly visible buttons side-by-side below the "Analyze Documents" section**:
- **"Analyze Tariffs & Trade"** button
- **"Analyze Sustainability & ESG"** button
Clicking a button triggers analysis for that domain, displays the **corresponding topics in the sidebar**, and shows the **consolidated summary in the main area**.
No radio buttons or other toggles. Both upload and state are shared, and documents can be processed for both modes independently. Sidebar and main content automatically reflect the last analysis mode chosen by button click.
---
### Full updated code:
```python
import streamlit as st
import os
import re
from datetime import datetime
from PyPDF2 import PdfReader
import openai
from io import BytesIO
# ===== Utility Functions =====
def extract_text(file):
try:
reader = PdfReader(file)
return "\n".join([page.extract_text() or "" for page in reader.pages])
except Exception as e:
st.error(f"Error reading {file.name}: {str(e)}")
return ""
# ===== TariffTradeAgent =====
class TariffTradeAgent:
def __init__(self, client, deployment_id):
self.client = client
self.deployment_id = deployment_id
def analyze_document(self, text):
prompt = """
You are a senior tariff and international trade policy analyst assisting a research team working for the CEO of Macy's. Identify all significant tariff and trade policy topics mentioned in the text that could impact Macy's business operations, supply chain, or market opportunities.
For each topic, provide:
- A clear topic name
- Concise 1-sentence summary describing its impact
- Relevance score (1-10)
Output format:
- Topic Name: Summary [Relevance Score]
Example:
- USMCA Trade Agreement: Expected tariff reductions improve apparel import costs [8]
- Chinese Tariffs Impact: Increased tariffs lead to higher electronic goods prices [7]
Text:
"""
response = self.client.chat.completions.create(
model=self.deployment_id,
messages=[
{"role": "system", "content": "Tariff analyst for Macy's CEO"},
{"role": "user", "content": prompt + "\n\n" + text}
],
temperature=0
)
return self._parse_topics(response.choices[0].message.content.strip())
def _parse_topics(self, text):
topics = []
pattern = r'^- (.*?): (.*?) \[(\d+)\]$'
for line in text.split('\n'):
line = line.strip()
match = re.match(pattern, line)
if match:
topics.append({
'name': match.group(1).strip(),
'summary': match.group(2).strip(),
'score': int(match.group(3).strip())
})
return topics
def stream_generate_detail(self, text, topic):
prompt = f"""
You are drafting a detailed briefing for Macy's CEO on the tariff topic '{topic}' extracted from the document.
Provide:
1. An overview.
2. Key insights and direct excerpts.
3. Relevant figures or timelines.
4. Potential impact on Macy's retail operations, supply chain, and overall business.
5. 3-5 strategic recommendations.
Document:
{text}
Topic: {topic}
Deliver as structured markdown suitable for executives.
"""
messages = [
{"role": "system", "content": "Senior tariff analyst briefing to CEO"},
{"role": "user", "content": prompt}
]
response = self.client.chat.completions.create(
model=self.deployment_id,
messages=messages,
temperature=0,
stream=True,
)
return response
def generate_consolidated_summary_from_topics(self, processed_files):
# Build topic map and identify files without topics
topic_map = {}
all_files = set(processed_files.keys())
files_with_topics = set()
for filename, filedata in processed_files.items():
for topic in filedata['topics']:
name = topic['name']
if name not in topic_map:
topic_map[name] = {
'files': set(),
'summaries': [],
'max_score': 0
}
topic_map[name]['files'].add(filename)
topic_map[name]['summaries'].append(topic['summary'])
topic_map[name]['max_score'] = max(topic_map[name]['max_score'], topic['score'])
files_with_topics.add(filename)
# Prepare content note
files_without_topics = all_files - files_with_topics
content_note = (
f"\n\n**Note:** The following documents contained content not captured in topics: {', '.join(files_without_topics)}. "
"Please review separately for additional insights."
if files_without_topics else ""
)
# Build topics text for prompt
sorted_topics = sorted(topic_map.items(), key=lambda x: x[1]['max_score'], reverse=True)
topics_text = []
for name, info in sorted_topics:
files = sorted(info['files'])
summaries = list(set(info['summaries'])) # Deduplicate
score = info['max_score']
topics_text.append(
f"**{name}** (Relevance: {score}/10)\n"
f"- Source Documents: {', '.join(files)}\n"
f"- Key Points:\n" +
'\n'.join([f' - {s}' for s in summaries])
)
topics_block = '\n\n'.join(topics_text)
prompt = f"""
Create a consolidated tariff analysis report for Macy's executive team using these extracted topics:
{topics_block}
Guidelines:
1. Start with executive summary highlighting top 3 issues
2. For each topic:
- Combine insights from different documents
- Specify source documents
- Include numerical data/timelines
- Explain business impact using retail examples
3. Sort by descending relevance score
4. Markdown formatting with clear headings
5. Add "Need Further Review" section for uncaptured documents{content_note}
Avoid technical jargon. Focus on operational impacts and strategic recommendations.
"""
response = self.client.chat.completions.create(
model=self.deployment_id,
messages=[
{"role": "system", "content": "Senior analyst creating consolidated trade report"},
{"role": "user", "content": prompt}
],
temperature=0.1
)
return response.choices[0].message.content.strip()
# ===== SustainabilityAgent =====
class SustainabilityAgent:
def __init__(self, client, deployment_id):
self.client = client
self.deployment_id = deployment_id
def analyze_document(self, text):
prompt = """
You are a senior analyst specializing in Sustainability and ESG (Environmental, Social, and Governance) topics. Identify all significant ESG-related topics mentioned in the text that could impact Macy's corporate responsibility, supply chain ethics, or brand reputation.
For each topic, provide:
- A clear topic name.
- A concise 1-sentence summary describing its impact or relevance.
- A relevance score from 1 (minor mention) to 10 (critical detail).
Output one topic per line with format:
- Topic Name: Summary [Relevance Score]
Examples:
- Carbon Emissions Reduction: Macy's aims to cut carbon footprint 30% by 2030 [9]
- Ethical Sourcing Practices: Strengthening supplier labor standards [8]
- Renewable Energy Use: Increasing use of solar energy in stores [7]
Ignore content unrelated to ESG or sustainability.
Begin analysis. Text:
"""
response = self.client.chat.completions.create(
model=self.deployment_id,
messages=[
{"role": "system", "content": "You analyze sustainability and ESG issues for Macy's management team."},
{"role": "user", "content": prompt + "\n\n" + text}
],
temperature=0
)
return self._parse_topics(response.choices[0].message.content.strip())
def _parse_topics(self, text):
topics = []
pattern = r'^- (.*?): (.*?) \[(\d+)\]$'
for line in text.split('\n'):
line = line.strip()
match = re.match(pattern, line)
if match:
topics.append({
'name': match.group(1).strip(),
'summary': match.group(2).strip(),
'score': int(match.group(3).strip())
})
return topics
def stream_generate_detail(self, text, topic):
prompt = f"""
You are drafting a detailed briefing for Macy's CEO on the sustainability topic '{topic}' extracted from the document.
Provide:
1. An overview.
2. Key insights and direct excerpts.
3. Relevant figures or timelines.
4. Potential impact on Macy's CSR, brand, and supply chain.
5. 3-5 strategic recommendations.
Document:
{text}
Topic: {topic}
Deliver as structured markdown for executives.
"""
messages = [
{"role": "system", "content": "Senior ESG analyst briefing to CEO"},
{"role": "user", "content": prompt}
]
response = self.client.chat.completions.create(
model=self.deployment_id,
messages=messages,
temperature=0,
stream=True,
)
return response
def generate_consolidated_summary_from_topics(self, processed_files):
topic_map = {}
all_files = set(processed_files.keys())
files_with_topics = set()
for filename, filedata in processed_files.items():
for topic in filedata['topics']:
name = topic['name']
if name not in topic_map:
topic_map[name] = {
'files': set(),
'summaries': [],
'max_score': 0,
}
topic_map[name]['files'].add(filename)
topic_map[name]['summaries'].append(topic['summary'])
topic_map[name]['max_score'] = max(topic_map[name]['max_score'], topic['score'])
files_with_topics.add(filename)
files_without_topics = all_files - files_with_topics
content_note = (
f"\n\n**Note:** The following documents contained content not captured in topics: {', '.join(files_without_topics)}. "
"Please review separately for additional insights."
if files_without_topics else ""
)
topics_text_lines = []
sorted_topics = sorted(topic_map.items(), key=lambda x: x[1]['max_score'], reverse=True)
for name, info in sorted_topics:
files_list = ", ".join(sorted(info['files']))
combined_summary = " | ".join(set(info['summaries']))
score = info['max_score']
topics_text_lines.append(f"**{name}** (Files: {files_list}) (Relevance: {score}/10)\n- Key Points: " +
'\n - '.join(set(info['summaries'])))
topics_text = '\n\n'.join(topics_text_lines)
prompt = f"""
You are a senior sustainability analyst preparing an executive summary report for Macy's CEO team.
Topics extracted from documents:
{topics_text}
Please provide:
- An introduction on the importance of these sustainability and ESG topics.
- For each topic: a 2-4 sentence detailed explanation with impacts, key insights, and strategic recommendations.
- Highlight any overarching trends across topics.
- Use clear markdown formatting with headings and bullet points.
- Sort topics from highest to lowest by relevance.
Begin:
"""
response = self.client.chat.completions.create(
model=self.deployment_id,
messages=[
{"role": "system", "content": "Senior ESG analyst summarizing sustainability topics for Macy's management."},
{"role": "user", "content": prompt},
],
temperature=0,
)
return response.choices[0].message.content.strip()
# ===== EnhancedChatAgent (unchanged) =====
class EnhancedChatAgent:
def __init__(self, client, deployment_id):
self.client = client
self.deployment_id = deployment_id
self.question_types = {
'tariff_impact': 'Analyzing tariff rate changes and their financial impacts',
'timeline': 'Identifying implementation timelines and deadlines',
'geopolitical': 'Evaluating geopolitical factors affecting trade policies',
'comparison': 'Comparing policies across different regions',
'compliance': 'Checking regulatory compliance requirements',
'general': 'General analysis on the Question asked by user',
'greetings': 'Greetings and general inquiries',
}
def _classify_question(self, question):
prompt = f"""
Classify this question into one of these categories: {list(self.question_types.keys())}.
Return only the category name.
Question: {question}
"""
response = self.client.chat.completions.create(
model=self.deployment_id,
messages=[
{"role": "system", "content": "Expert question classifier for Macy's analysis"},
{"role": "user", "content": prompt}
],
temperature=0
)
return response.choices[0].message.content.strip().lower()
def _stream_greeting_response(self, question):
prompt = f"""
You are an senoir assistant responding ONLY to greetings from Macy's executive staff. Reply with a polite greeting message only. No additional information but respond properly for every question do not use any other source.
Greeting input:
{question}
Your reply:
"""
messages = [
{"role": "system", "content": "Assistant specialized in greeting responses."},
{"role": "user", "content": prompt}
]
response = self.client.chat.completions.create(
model=self.deployment_id,
messages=messages,
temperature=0,
stream=True
)
return response
def stream_answer(self, question, files_context):
q_type = self._classify_question(question)
if q_type == 'greetings':
response = self._stream_greeting_response(question)
return response, q_type, 'Greeting response'
analysis_approach = self.question_types.get(q_type, 'General analysis')
base_prompt = f"""
You are a senior analyst answering questions for Macy's executive team. Follow these steps:
1. {analysis_approach}
2. Cross-reference all relevant documents
3. Identify numerical data and timelines
4. Assess impacts on retail operations
5. Formulate executive-level recommendations
6. If User ask from a single document, selecting multiple documents give them answer from only the document which is asked for.
7. If User ask from multiple documents, selecting multiple documents give them answer from all the documents.
8. If User ask a question like greetings, answer it with "Hello, how can I help you?" Nothing else from the documents.
Current question type: {q_type.upper()}
Question: {question}
Relevant documents:
{files_context}
Provide a structured response with:
- Clear headings for each section
- Bullet points for key findings
- Bolded key figures and dates
- Separate recommendations section
If information conflicts between documents, note this explicitly.
"""
messages = [
{"role": "system", "content": "Senior analyst synthesizing information from multiple documents"},
{"role": "user", "content": base_prompt}
]
response = self.client.chat.completions.create(
model=self.deployment_id,
messages=messages,
temperature=0,
stream=True
)
return response, q_type, analysis_approach
# ===== Streamlit App Main =====
def main():
st.set_page_config(page_title="Tariff & Trade Analyst Pro", layout="wide")
st.title("📄 Macy's Tariff & Trade Policy Analyzer")
# Initialize session state vars
if "session" not in st.session_state:
st.session_state.session = {
'uploaded_files': {},
'processed_files_tariff': {},
'processed_files_sustainability': {},
'active_file': None,
'active_topic': None,
'topic_details_cache': {}, # (mode, file, topic)
'chat_history': [],
'consolidated_summary_tariff': None,
'consolidated_summary_sustainability': None,
'last_analysis_mode': None # To remember last clicked button ('tariff' or 'sustainability')
}
if "client" not in st.session_state:
st.session_state.client = openai.AzureOpenAI(
api_key=os.getenv("AZURE_API_KEY"),
azure_endpoint=os.getenv("AZURE_ENDPOINT"),
api_version="2023-12-01-preview"
)
if "agent_tariff" not in st.session_state:
deployment = os.getenv("AZURE_DEPLOYMENT")
st.session_state.agent_tariff = TariffTradeAgent(st.session_state.client, deployment)
st.session_state.agent_sustainability = SustainabilityAgent(st.session_state.client, deployment)
st.session_state.chat_agent = EnhancedChatAgent(st.session_state.client, deployment)
sess = st.session_state.session
# File Upload Section (shared)
st.subheader("1. Upload Documents")
uploaded_files = st.file_uploader(
"Upload Macy's earnings transcript PDFs",
type=["pdf"],
accept_multiple_files=True,
key="file_uploader"
)
if uploaded_files:
for file in uploaded_files:
if file.name not in sess['uploaded_files']:
sess['uploaded_files'][file.name] = file.getvalue()
# Analyze Documents Buttons
st.subheader("2. Analyze Documents")
col1, col2 = st.columns(2)
analyze_tariff_clicked = col1.button("🔍 Analyze Tariffs & Trade", type="primary")
analyze_sustain_clicked = col2.button("♻️ Analyze Sustainability & ESG", type="primary")
if analyze_tariff_clicked or analyze_sustain_clicked:
if not sess['uploaded_files']:
st.error("Please upload documents before analyzing.")
st.stop()
if analyze_tariff_clicked:
mode = 'tariff'
agent = st.session_state.agent_tariff
processed_files = sess['processed_files_tariff']
else:
mode = 'sustainability'
agent = st.session_state.agent_sustainability
processed_files = sess['processed_files_sustainability']
with st.spinner(f"Analyzing documents for {mode} topics..."):
for filename, file_bytes in sess['uploaded_files'].items():
if filename not in processed_files:
try:
file_obj = BytesIO(file_bytes)
file_obj.name = filename
text = extract_text(file_obj)
if text:
topics = agent.analyze_document(text)
processed_files[filename] = {
'text': text,
'topics': topics,
'context': text
}
st.toast(f"✅ Processed {filename}")
else:
st.error(f"❌ Failed to process {filename}")
except Exception as e:
st.error(f"Error processing {filename}: {str(e)}")
with st.spinner("Generating consolidated summary..."):
summary_text = agent.generate_consolidated_summary_from_topics(processed_files)
if mode == 'tariff':
sess['consolidated_summary_tariff'] = summary_text
else:
sess['consolidated_summary_sustainability'] = summary_text
sess['last_analysis_mode'] = mode
sess['active_file'] = None # reset active topic selections when mode changes
sess['active_topic'] = None
st.success(f"Analysis & summary generated for {mode}!")
# Determine which mode to display (last button clicked)
mode_to_display = sess['last_analysis_mode']
if mode_to_display is None:
st.info("Click a button above to analyze Tariffs/Trade or Sustainability topics.")
return
# Select appropriate dicts & data based on mode
if mode_to_display == 'tariff':
processed_files = sess['processed_files_tariff']
consolidated_summary = sess['consolidated_summary_tariff']
sidebar_title = "Documents & Tariff Topics"
main_header = "🌟 Consolidated Tariff & Trade Summary"
agent = st.session_state.agent_tariff
else:
processed_files = sess['processed_files_sustainability']
consolidated_summary = sess['consolidated_summary_sustainability']
sidebar_title = "Documents & Sustainability Topics"
main_header = "🌟 Consolidated Sustainability & ESG Summary"
agent = st.session_state.agent_sustainability
# Show Consolidated Summary
st.header(main_header)
if consolidated_summary:
st.markdown(consolidated_summary)
else:
st.info(f"No consolidated summary available yet for {mode_to_display.capitalize()}. Please analyze documents.")
st.markdown("---")
# Sidebar: Documents and Topics for selected mode
st.sidebar.header(sidebar_title)
for filename, filedata in processed_files.items():
expanded = filename == sess['active_file']
with st.sidebar.expander(f"📄 {filename}", expanded=expanded):
topics = sorted(filedata['topics'], key=lambda t: t['score'], reverse=True)
for topic in topics:
is_selected = (sess['active_file'] == filename and sess['active_topic'] == topic['name'])
style = "primary" if is_selected else "secondary"
if st.sidebar.button(f"• {topic['name']} (Score: {topic['score']})",
key=f"{mode_to_display}_topic_{filename}_{topic['name']}",
type=style,
use_container_width=True):
if (sess['active_file'] != filename or sess['active_topic'] != topic['name']):
sess['active_file'] = filename
sess['active_topic'] = topic['name']
# Detailed topic analysis
st.subheader("Detailed Topic Analysis")
if sess['active_file'] and sess['active_topic']:
key_cache = (mode_to_display, sess['active_file'], sess['active_topic'])
if key_cache in sess['topic_details_cache']:
detail = sess['topic_details_cache'][key_cache]
st.markdown(detail)
else:
text = processed_files[sess['active_file']]['context']
topic = sess['active_topic']
placeholder = st.empty()
collected_text = ""
try:
response = agent.stream_generate_detail(text, topic)
for chunk in response:
if hasattr(chunk, "choices") and chunk.choices:
delta = chunk.choices[0].delta
content = getattr(delta, "content", "")
if content:
collected_text += content
placeholder.markdown(collected_text + "▌")
placeholder.markdown(collected_text)
sess['topic_details_cache'][key_cache] = collected_text
except Exception as e:
st.error(f"Error generating detail: {e}")
else:
st.info("Select a file and topic from the sidebar to view detailed analysis.")
st.divider()
# Advanced Chat Section (still Tariff only)
st.subheader("💬 Advanced Document Analysis (Tariff & Trade)")
tariff_files = list(sess['processed_files_tariff'].keys())
selected_files = st.multiselect(
"Select documents for analysis:",
options=tariff_files,
default=[]
)
for msg in sess['chat_history']:
with st.chat_message(msg["role"]):
if msg["role"] == "assistant":
if 'analysis_type' in msg:
st.markdown(f"**Analysis Type:** {msg['analysis_type']}")
st.markdown(f"**Process:** {msg['process']}")
st.markdown("**Findings:**")
st.markdown(msg["content"])
else:
st.markdown(msg["content"])
else:
st.markdown(msg["content"])
if prompt := st.chat_input("Ask a complex question about tariffs and trade policies"):
if not selected_files:
st.error("Please select one or more documents before asking a question.")
st.stop()
sess['chat_history'].append({
"role": "user",
"content": prompt,
"timestamp": datetime.utcnow().isoformat()
})
files_context = "\n\n".join([
f"=== {filename} ===\n{sess['processed_files_tariff'][filename]['context']}"
for filename in selected_files
])
response_container = st.chat_message("assistant")
status_container = response_container.status("Beginning analysis...")
response_placeholder = response_container.empty()
full_response = ""
try:
response_stream, q_type, analysis_approach = st.session_state.chat_agent.stream_answer(
prompt, files_context
)
status_container.update(label=f"Analysis Type: {q_type.upper()}", state="complete", expanded=True)
with response_container.expander("Analysis Process Details"):
st.markdown(f"**Documents Analyzed:**\n" + '\n'.join(['- '+f for f in selected_files]))
for chunk in response_stream:
if hasattr(chunk, "choices") and chunk.choices:
delta = chunk.choices[0].delta
content = getattr(delta, "content", "")
if content:
full_response += content
response_placeholder.markdown(full_response + "▌")
response_placeholder.markdown(full_response)
sess['chat_history'].append({
"role": "assistant",
"content": full_response,
"timestamp": datetime.utcnow().isoformat()
})
except Exception as e:
st.error(f"Error during analysis: {e}")
sess['chat_history'].append({
"role": "assistant",
"content": f"Error processing request: {str(e)}",
"timestamp": datetime.utcnow().isoformat()
})
# Reset session button
if st.button("🔄 Reset Session", type="secondary"):
preserved_keys = ["client", "agent_tariff", "agent_sustainability", "chat_agent"]
preserved = {k: st.session_state[k] for k in preserved_keys if k in st.session_state}
st.session_state.clear()
st.session_state.update(preserved)
st.session_state.session = {
'uploaded_files': {},
'processed_files_tariff': {},
'processed_files_sustainability': {},
'active_file': None,
'active_topic': None,
'topic_details_cache': {},
'chat_history': [],
'consolidated_summary_tariff': None,
'consolidated_summary_sustainability': None,
'last_analysis_mode': None
}
st.experimental_rerun()
if __name__ == "__main__":
main()
```
---
### How this works for you:
- Upload files once.
- Click **"Analyze Tariffs & Trade"** button to analyze tariff topics. Sidebar shows tariff topics and consolidated summary appears.
- Click **"Analyze Sustainability & ESG"** button to analyze sustainability topics. Sidebar and summary update accordingly.
- Sidebar topics and detailed views always show only the last clicked mode's data.
- No radio or extra toggles.
- Chat is still tariff-centered (can be extended if desired).
- Reset button fully resets session except for client/agents.
---
Let me know if you want help adding chat to Sustainability mode or anything else!