oussnaji commited on
Commit
f2b0fc4
Β·
verified Β·
1 Parent(s): a56fc4e

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +336 -0
app.py ADDED
@@ -0,0 +1,336 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import requests
3
+ import json
4
+ import plotly.graph_objects as go
5
+ import plotly.express as px
6
+ from typing import Dict, List, Any
7
+ import time
8
+ import pandas as pd
9
+
10
+ # Page configuration
11
+ st.set_page_config(
12
+ page_title="Market Research & Analysis Platform",
13
+ layout="wide",
14
+ initial_sidebar_state="expanded"
15
+ )
16
+
17
+ # Custom styling (updated for dark mode)
18
+ st.markdown("""
19
+ <style>
20
+ .main {
21
+ background-color: #121212;
22
+ color: #ffffff;
23
+ }
24
+ .insight-card {
25
+ background-color: #1e1e1e;
26
+ padding: 1.5rem;
27
+ border-radius: 8px;
28
+ box-shadow: 0 2px 4px rgba(255,255,255,0.1);
29
+ margin: 1rem 0;
30
+ }
31
+ .metric-card {
32
+ background-color: #1e1e1e;
33
+ padding: 1rem;
34
+ border-radius: 4px;
35
+ margin: 0.5rem 0;
36
+ }
37
+ .source-card {
38
+ background-color: #2e2e2e;
39
+ padding: 0.5rem;
40
+ border-radius: 4px;
41
+ font-size: 0.9rem;
42
+ margin-top: 0.5rem;
43
+ color: #ffffff;
44
+ }
45
+ .highlight-text {
46
+ color: #4c6ef5;
47
+ font-weight: bold;
48
+ }
49
+ </style>
50
+ """, unsafe_allow_html=True)
51
+
52
+ def query_perplexity(query: str, context: Dict) -> Dict:
53
+ url = "https://api.perplexity.ai/chat/completions"
54
+ headers = {
55
+ "Authorization": f"Bearer {st.secrets['PERPLEXITY_API_KEY']}",
56
+ "Content-Type": "application/json"
57
+ }
58
+ payload = {
59
+ "model": "llama-3.1-sonar-small-128k-online",
60
+ "messages": [
61
+ {"role": "system", "content": get_system_prompt(context)},
62
+ {"role": "user", "content": query}
63
+ ],
64
+ "temperature": 0.2,
65
+ "max_tokens": 4096,
66
+ "top_p": 0.9,
67
+ "search_domain_filter": ["perplexity.ai"],
68
+ "return_images": False,
69
+ "return_related_questions": False,
70
+ "search_recency_filter": context.get('timeframe', 'month')
71
+ }
72
+ try:
73
+ response = requests.post(url, headers=headers, json=payload)
74
+ if response.status_code == 200:
75
+ return {
76
+ "status": "success",
77
+ "data": response.json(),
78
+ "citations": response.json().get("citations", [])
79
+ }
80
+ else:
81
+ return {"status": "error", "message": f"API Error: {response.status_code}"}
82
+ except Exception as e:
83
+ return {"status": "error", "message": str(e)}
84
+
85
+ def get_system_prompt(context: Dict) -> str:
86
+ # Adjust the prompt if Executive style and Comprehensive depth are selected.
87
+ if context.get("style", "").lower() == "executive" and context.get("depth", "").lower() == "comprehensive":
88
+ return f"""You are an expert market research analyst focusing on {context['focus_area']}.
89
+ Provide a high-level executive summary with key insights and concrete metrics.
90
+ Analysis style: Executive
91
+ Depth: Comprehensive
92
+ Timeline: Past {context['timeframe']}
93
+
94
+ Format your response with clear sections:
95
+ 1. Executive Summary
96
+ 2. Key Metrics
97
+ 3. Market Position
98
+ 4. Growth Analysis
99
+ 5. Strategic Recommendations
100
+
101
+ Include specific numbers, percentages, and actionable insights."""
102
+ else:
103
+ return f"""You are an expert market research analyst focusing on {context['focus_area']}.
104
+ Provide detailed analysis with concrete metrics and specific insights.
105
+ Analysis style: {context['style']}
106
+ Depth: {context['depth']}
107
+ Timeline: Past {context['timeframe']}
108
+
109
+ Format your response with clear sections:
110
+ 1. Key Metrics
111
+ 2. Market Position
112
+ 3. Growth Analysis
113
+ 4. Competitive Insights
114
+ 5. Strategic Recommendations
115
+
116
+ Include specific numbers, percentages, and actionable insights."""
117
+
118
+ def parse_perplexity_response(response: Dict) -> Dict:
119
+ try:
120
+ content = response['data']['choices'][0]['message']['content']
121
+ citations = response.get('citations', [])
122
+ sections = {
123
+ 'key_metrics': [],
124
+ 'market_position': [],
125
+ 'growth_analysis': [],
126
+ 'competitive_insights': [],
127
+ 'recommendations': []
128
+ }
129
+ current_section = None
130
+ for line in content.split('\n'):
131
+ line = line.strip()
132
+ if not line:
133
+ continue
134
+ lower_line = line.lower()
135
+ if 'key metric' in lower_line:
136
+ current_section = 'key_metrics'
137
+ elif 'market position' in lower_line:
138
+ current_section = 'market_position'
139
+ elif 'growth' in lower_line:
140
+ current_section = 'growth_analysis'
141
+ elif 'competiti' in lower_line:
142
+ current_section = 'competitive_insights'
143
+ elif 'recommend' in lower_line:
144
+ current_section = 'recommendations'
145
+ elif current_section and line.startswith(('-', 'β€’', '*')):
146
+ sections[current_section].append(line.lstrip('-β€’* '))
147
+ return {"status": "success", "sections": sections, "citations": citations}
148
+ except Exception as e:
149
+ return {"status": "error", "message": str(e)}
150
+
151
+ def extract_metrics(content: Dict) -> Dict:
152
+ metrics = {
153
+ 'market_share': [],
154
+ 'growth_rate': [],
155
+ 'competitive_position': [],
156
+ 'innovation_score': []
157
+ }
158
+ try:
159
+ for section in content['sections'].values():
160
+ for line in section:
161
+ if '%' in line or any(char.isdigit() for char in line):
162
+ if 'market share' in line.lower():
163
+ metrics['market_share'].append(extract_number(line))
164
+ elif 'growth' in line.lower():
165
+ metrics['growth_rate'].append(extract_number(line))
166
+ elif 'position' in line.lower():
167
+ metrics['competitive_position'].append(extract_number(line))
168
+ elif 'innovation' in line.lower():
169
+ metrics['innovation_score'].append(extract_number(line))
170
+ return metrics
171
+ except Exception as e:
172
+ st.error(f"Error extracting metrics: {str(e)}")
173
+ return metrics
174
+
175
+ def extract_number(text: str) -> float:
176
+ import re
177
+ numbers = re.findall(r'[-+]?\d*\.?\d+%?', text)
178
+ if numbers:
179
+ number = numbers[0]
180
+ return float(number.replace('%', '')) if '%' in number else float(number)
181
+ return 0.0
182
+
183
+ def create_visualizations(metrics: Dict, context: Dict) -> Dict:
184
+ charts = {}
185
+ if metrics['market_share'] and metrics['competitive_position']:
186
+ fig = go.Figure()
187
+ categories = ['Market Share', 'Growth Rate', 'Competitive Position', 'Innovation Score']
188
+ values = [
189
+ metrics['market_share'][0] if metrics['market_share'] else 0,
190
+ metrics['growth_rate'][0] if metrics['growth_rate'] else 0,
191
+ metrics['competitive_position'][0] if metrics['competitive_position'] else 0,
192
+ metrics['innovation_score'][0] if metrics['innovation_score'] else 0
193
+ ]
194
+ fig.add_trace(go.Scatterpolar(
195
+ r=values,
196
+ theta=categories,
197
+ fill='toself',
198
+ name=context['company_name']
199
+ ))
200
+ fig.update_layout(
201
+ polar=dict(radialaxis=dict(visible=True, range=[0, 100])),
202
+ showlegend=False,
203
+ title=f"Market Position Analysis - {context['company_name']}"
204
+ )
205
+ charts['market_position'] = fig
206
+ if metrics['growth_rate']:
207
+ fig = go.Figure()
208
+ fig.add_trace(go.Scatter(
209
+ y=metrics['growth_rate'],
210
+ mode='lines+markers',
211
+ name='Growth Rate'
212
+ ))
213
+ fig.update_layout(
214
+ title=f"Growth Trend Analysis - {context['company_name']}",
215
+ yaxis_title='Growth Rate (%)',
216
+ showlegend=True
217
+ )
218
+ charts['growth_trend'] = fig
219
+ return charts
220
+
221
+ def format_insights(content: Dict) -> str:
222
+ """Format detailed analysis with sub-titles for each section"""
223
+ formatted = ""
224
+ section_titles = {
225
+ 'key_metrics': 'πŸ“Š Key Metrics',
226
+ 'market_position': '🎯 Market Position',
227
+ 'growth_analysis': 'πŸ“ˆ Growth Analysis',
228
+ 'competitive_insights': 'πŸ” Competitive Insights',
229
+ 'recommendations': 'πŸ’‘ Strategic Recommendations'
230
+ }
231
+ for section, title in section_titles.items():
232
+ if content['sections'].get(section):
233
+ formatted += f"\n### {title}\n\n"
234
+ for idx, point in enumerate(content['sections'][section], start=1):
235
+ formatted += f"- **{idx}.** {point}\n"
236
+ return formatted
237
+
238
+ def main():
239
+ st.title("Market Research & Analysis Platform")
240
+ st.markdown("Real-time market insights with data-driven analysis")
241
+
242
+ with st.sidebar:
243
+ st.header("Analysis Parameters")
244
+ company_name = st.text_input("Company/Product Name", placeholder="e.g., Tesla, OpenAI, Snowflake")
245
+ industry = st.selectbox("Industry", ["Technology", "AI/ML", "SaaS", "Fintech", "E-commerce", "Healthcare", "Energy", "Other"])
246
+ st.markdown("### Analysis Configuration")
247
+ focus_area = st.multiselect("Focus Areas", ["Market Position", "Growth Trajectory", "Technology Stack", "Competitive Analysis", "Innovation Trends", "Investment Outlook"], default=["Market Position", "Growth Trajectory"])
248
+ timeframe = st.select_slider("Analysis Timeframe", options=["week", "month", "quarter", "year"], value="month")
249
+ depth = st.select_slider("Analysis Depth", options=["Brief", "Detailed", "Comprehensive"], value="Detailed")
250
+ style = st.selectbox("Report Style", ["Technical", "Business", "Executive"], index=1)
251
+ competitors = st.text_input("Key Competitors (optional)", placeholder="Comma-separated names")
252
+
253
+ if st.button("Generate Analysis", type="primary"):
254
+ if not company_name:
255
+ st.warning("Please enter a company name.")
256
+ return
257
+
258
+ analysis_context = {
259
+ "company_name": company_name,
260
+ "industry": industry,
261
+ "focus_area": ", ".join(focus_area),
262
+ "timeframe": timeframe,
263
+ "depth": depth,
264
+ "style": style,
265
+ "competitors": competitors
266
+ }
267
+
268
+ with st.spinner("Generating market analysis..."):
269
+ progress_bar = st.progress(0)
270
+ status_text = st.empty()
271
+ try:
272
+ status_text.text("Gathering market intelligence...")
273
+ progress_bar.progress(20)
274
+ research_response = query_perplexity(
275
+ f"Provide a detailed market analysis for {company_name} in the {industry} industry, focusing on {', '.join(focus_area)}",
276
+ analysis_context
277
+ )
278
+ if research_response["status"] != "success":
279
+ st.error("Failed to gather market intelligence.")
280
+ return
281
+
282
+ status_text.text("Processing insights...")
283
+ progress_bar.progress(40)
284
+ parsed_content = parse_perplexity_response(research_response)
285
+ if parsed_content["status"] != "success":
286
+ st.error("Failed to process insights.")
287
+ return
288
+
289
+ status_text.text("Generating visualizations...")
290
+ progress_bar.progress(60)
291
+ metrics = extract_metrics(parsed_content)
292
+ charts = create_visualizations(metrics, analysis_context)
293
+
294
+ status_text.text("Preparing analysis report...")
295
+ progress_bar.progress(80)
296
+ tabs = st.tabs(["Overview", "Detailed Analysis", "Visualizations"])
297
+
298
+ with tabs[0]:
299
+ st.markdown("## Executive Summary", unsafe_allow_html=True)
300
+ if metrics:
301
+ cols = st.columns(len(metrics))
302
+ for col, (metric, values) in zip(cols, metrics.items()):
303
+ if values:
304
+ col.metric(metric.replace('_', ' ').title(), f"{values[0]:.1f}%")
305
+ if parsed_content["citations"]:
306
+ st.markdown("### Sources")
307
+ for citation in parsed_content["citations"]:
308
+ st.markdown(f'<div class="source-card">{citation}</div>', unsafe_allow_html=True)
309
+
310
+ with tabs[1]:
311
+ st.markdown(format_insights(parsed_content), unsafe_allow_html=True)
312
+
313
+ with tabs[2]:
314
+ for chart_name, fig in charts.items():
315
+ st.plotly_chart(fig, use_container_width=True)
316
+
317
+ progress_bar.progress(100)
318
+ status_text.text("Analysis complete!")
319
+
320
+ st.download_button(
321
+ "Download Analysis",
322
+ data=json.dumps({
323
+ "context": analysis_context,
324
+ "insights": parsed_content["sections"],
325
+ "metrics": metrics,
326
+ "citations": parsed_content["citations"]
327
+ }, indent=2),
328
+ file_name=f"market_analysis_{company_name}.json",
329
+ mime="application/json"
330
+ )
331
+ except Exception as e:
332
+ st.error(f"An error occurred: {str(e)}")
333
+ return
334
+
335
+ if __name__ == "__main__":
336
+ main()