import os
import json
import re
import faiss
import numpy as np
import gradio as gr
import plotly.graph_objects as go
import plotly.express as px
import pandas as pd
import tempfile
from dotenv import load_dotenv
from sentence_transformers import SentenceTransformer
from groq import Groq
# ==========================
# OPTIONAL LIBRARIES
# ==========================
try:
from fpdf import FPDF
import kaleido
PDF_AVAILABLE = True
except ImportError:
PDF_AVAILABLE = False
try:
from sklearn.decomposition import PCA
SKLEARN_AVAILABLE = True
except ImportError:
SKLEARN_AVAILABLE = False
def random_projection(embeddings, n_components=3):
np.random.seed(42)
projection = np.random.randn(embeddings.shape[1], n_components)
return np.dot(embeddings, projection)
# ==========================
# LOAD ENV & CONFIG
# ==========================
load_dotenv()
groq_client = Groq(api_key=os.getenv("GROQ_API_KEY"))
BRAND_NAME = os.getenv("BRAND_NAME", "IdeaIQ")
LOGO_PATH = os.getenv("LOGO_PATH", "")
# ==========================
# LOAD DATASET
# ==========================
DATA_PATH = "cleaned_market_trends.json" # adjust if needed
with open(DATA_PATH, "r", encoding="utf-8") as f:
documents = json.load(f)
# ==========================
# EMBEDDINGS + FAISS
# ==========================
embedding_model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
texts = [doc["content"] for doc in documents]
embeddings = embedding_model.encode(texts)
embeddings = np.array(embeddings).astype("float32")
faiss.normalize_L2(embeddings)
dimension = embeddings.shape[1]
faiss_index = faiss.IndexFlatIP(dimension)
faiss_index.add(embeddings)
# ==========================
# RETRIEVAL
# ==========================
def retrieve_context(user_idea, top_k=4):
query_embedding = embedding_model.encode([user_idea])
query_embedding = np.array(query_embedding).astype("float32")
faiss.normalize_L2(query_embedding)
scores, indices = faiss_index.search(query_embedding, top_k)
retrieved_docs = []
similarity_scores = []
for score, idx in zip(scores[0], indices[0]):
retrieved_docs.append(documents[idx])
similarity_scores.append(float(score))
avg_similarity = round(float(np.mean(similarity_scores)), 3)
return retrieved_docs, avg_similarity
# ==========================
# JSON CLEANER
# ==========================
def extract_json(text):
text = re.sub(r"```json", "", text)
text = re.sub(r"```", "", text)
match = re.search(r"\{.*\}", text, re.DOTALL)
if match:
return json.loads(match.group())
raise ValueError("Invalid JSON response")
# ==========================
# LLM ANALYSIS
# ==========================
SYSTEM_PROMPT = """
You are an AI Product Strategy Analyst.
Return ONLY valid JSON.
Do not wrap in markdown.
Strictly follow provided structure.
"""
def analyze_idea(user_idea):
retrieved_docs, avg_similarity = retrieve_context(user_idea)
context_text = "\n\n".join(
[f"{doc['domain']} | {doc['year']} | {doc['content']}" for doc in retrieved_docs]
)
user_prompt = f"""
User Idea:
{user_idea}
Market Context:
{context_text}
Return strictly a JSON object with the following structure. The "market_analysis" list should contain one object per retrieved document (exactly {len(retrieved_docs)} items), with estimated numeric scores based on the document content and your market knowledge.
{{
"idea": "{user_idea}",
"scope": "Low | Medium | High",
"feasibility": "Low | Medium | High",
"estimated_timeline": "X months",
"market_trend_summary": "...",
"uniqueness_analysis": "...",
"risks": ["Risk 1", "Risk 2"],
"actionable_steps": ["Step 1", "Step 2"],
"project_score": 0-10,
"market_analysis": [
{{
"domain": "from document",
"year": "from document",
"category": "e.g., AI, Healthcare, Fintech",
"region": "Global | North America | etc.",
"growth_rate": 0-100,
"innovation_score": 0-100,
"market_potential": 0-100,
"competition_level": 0-100
}},
...
]
}}
"""
response = groq_client.chat.completions.create(
model="llama-3.3-70b-versatile",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_prompt}
],
temperature=0
)
result = extract_json(response.choices[0].message.content)
result.setdefault("scope", "Medium")
result.setdefault("feasibility", "Medium")
result.setdefault("estimated_timeline", "6 months")
result.setdefault("market_trend_summary", "No summary")
result.setdefault("uniqueness_analysis", "No analysis")
result.setdefault("risks", ["Unknown"])
result.setdefault("actionable_steps", ["Unknown"])
result.setdefault("project_score", 5)
result.setdefault("market_analysis", [])
if not result["market_analysis"] and retrieved_docs:
for doc in retrieved_docs:
result["market_analysis"].append({
"domain": doc["domain"],
"year": doc["year"],
"category": "Unknown",
"region": "Global",
"growth_rate": np.random.randint(30, 90),
"innovation_score": np.random.randint(30, 90),
"market_potential": np.random.randint(30, 90),
"competition_level": np.random.randint(30, 90)
})
result["similarity_score"] = avg_similarity
result["retrieved_docs"] = retrieved_docs
return result
# ==========================
# VISUALIZATION FUNCTIONS
# ==========================
def create_gauge(result):
project_score = result["project_score"]
fig = go.Figure(go.Indicator(
mode="gauge+number",
value=project_score,
number={'suffix': "/10", 'font': {'size': 30}},
title={'text': "Project Score", 'font': {'size': 20}},
gauge={
'axis': {'range': [0, 10], 'tickwidth': 1},
'bar': {'color': "darkblue", 'thickness': 0.3},
'bgcolor': "white",
'borderwidth': 2,
'steps': [
{'range': [0, 3], 'color': '#ffcccc'},
{'range': [3, 7], 'color': '#ffffcc'},
{'range': [7, 10], 'color': '#ccffcc'}
],
'threshold': {
'line': {'color': "red", 'width': 4},
'thickness': 0.75,
'value': 7
}
}
))
fig.update_layout(height=250, margin=dict(l=20, r=20, t=40, b=20),
paper_bgcolor='rgba(0,0,0,0)')
return fig
def create_radial_graph(result, visible_nodes=8):
idea = result["idea"]
project_score = result["project_score"]
feasibility = result["feasibility"]
similarity = result["similarity_score"]
scope = result["scope"]
timeline = result["estimated_timeline"]
score_color = f"rgb({255-int(project_score*25)}, {int(project_score*25)}, 0)"
feasibility_color = {"High": "#00cc96", "Medium": "#ffa15e", "Low": "#ef553b"}.get(feasibility, "#636efa")
nodes = [
idea,
f"Scope: {scope}",
f"Feasibility: {feasibility}",
f"Timeline: {timeline}",
"Risks",
"Actionable Steps",
"Uniqueness",
f"Similarity: {similarity}"
]
angle = np.linspace(0, 2*np.pi, len(nodes))
radius = 2.5
x = [0] + list(radius * np.cos(angle[1:]))
y = [0] + list(radius * np.sin(angle[1:]))
colors = [
score_color,
"#1f77b4",
feasibility_color,
"#ff7f0e",
"#d62728",
"#9467bd",
"#17becf",
"#bcbd22"
]
sizes = [60, 35, 35, 35, 40, 40, 35, 35]
hover_texts = [
f"Idea
{idea}
Score: {project_score}/10",
f"Scope
{scope}",
f"Feasibility
{feasibility}",
f"Timeline
{timeline}",
f"Risks
" + "
".join(result["risks"]),
f"Actionable Steps
" + "
".join(result["actionable_steps"]),
f"Uniqueness
{result['uniqueness_analysis']}",
f"Similarity Score
{similarity}"
]
visible = min(visible_nodes, len(nodes))
visible_x = x[:visible]
visible_y = y[:visible]
visible_text = nodes[:visible]
visible_hover = hover_texts[:visible]
visible_colors = colors[:visible]
visible_sizes = sizes[:visible]
edge_x, edge_y = [], []
for i in range(1, visible):
edge_x += [x[0], x[i], None]
edge_y += [y[0], y[i], None]
fig = go.Figure()
fig.add_trace(go.Scatter(
x=edge_x, y=edge_y,
mode='lines',
line=dict(width=1.5, color='#888'),
hoverinfo='none'
))
fig.add_trace(go.Scatter(
x=visible_x, y=visible_y,
mode='markers+text',
text=visible_text,
textposition='bottom center',
hovertext=visible_hover,
hoverinfo='text',
marker=dict(
size=visible_sizes,
color=visible_colors,
line=dict(width=2, color='white')
),
textfont=dict(size=12, color='black')
))
fig.update_layout(
title=dict(text="🚀 Strategic Opportunity Map", font=dict(size=20, family='Arial Black')),
showlegend=False,
xaxis=dict(visible=False),
yaxis=dict(visible=False),
height=550,
plot_bgcolor='rgba(0,0,0,0)',
paper_bgcolor='rgba(0,0,0,0)',
margin=dict(l=20, r=20, t=80, b=20)
)
return fig
def create_3d_market(result):
retrieved_docs = result.get("retrieved_docs", [])
idea = result["idea"]
if not retrieved_docs:
return go.Figure()
doc_texts = [doc["content"] for doc in retrieved_docs]
all_texts = [idea] + doc_texts
all_embeddings = embedding_model.encode(all_texts)
if SKLEARN_AVAILABLE:
pca = PCA(n_components=3)
coords = pca.fit_transform(all_embeddings)
else:
coords = random_projection(all_embeddings, 3)
df = pd.DataFrame({
'x': coords[:,0],
'y': coords[:,1],
'z': coords[:,2],
'label': ['Your Idea'] + [f"{doc['domain']} ({doc['year']})" for doc in retrieved_docs],
'size': [20] + [15]*len(retrieved_docs),
'color': ['red'] + ['blue']*len(retrieved_docs),
'hover': [f"Your Idea
{idea}"] +
[f"{doc['domain']} ({doc['year']})
{doc['content'][:100]}..." for doc in retrieved_docs]
})
fig = px.scatter_3d(df, x='x', y='y', z='z', text='label', size='size', color='color',
hover_data={'hover': True, 'x': False, 'y': False, 'z': False, 'color': False, 'size': False},
title="🧠 Market Landscape (3D Similarity Space)")
fig.update_traces(marker=dict(line=dict(width=2, color='white')),
textposition='top center')
fig.update_layout(height=550, showlegend=False)
return fig
def create_kpi_panel(df):
fig = go.Figure()
metrics = {
"Avg Growth": df["growth_rate"].mean(),
"Innovation Strength": df["innovation_score"].mean(),
"Market Potential": df["market_potential"].mean(),
"Strategic Advantage": (df["innovation_score"] + df["market_potential"] - df["competition_level"]).mean()
}
fig.add_trace(go.Indicator(
mode="number",
value=round(metrics["Avg Growth"], 2),
title={"text": "Avg Growth"},
domain={'x': [0, 0.45], 'y': [0.55, 1]},
number={"font": {"size": 36}}
))
fig.add_trace(go.Indicator(
mode="number",
value=round(metrics["Innovation Strength"], 2),
title={"text": "Innovation Strength"},
domain={'x': [0.55, 1], 'y': [0.55, 1]},
number={"font": {"size": 36}}
))
fig.add_trace(go.Indicator(
mode="number",
value=round(metrics["Market Potential"], 2),
title={"text": "Market Potential"},
domain={'x': [0, 0.45], 'y': [0, 0.45]},
number={"font": {"size": 36}}
))
fig.add_trace(go.Indicator(
mode="number",
value=round(metrics["Strategic Advantage"], 2),
title={"text": "Strategic Advantage"},
domain={'x': [0.55, 1], 'y': [0, 0.45]},
number={"font": {"size": 36}}
))
fig.update_layout(
template="plotly_dark",
height=320,
margin=dict(t=20, b=20, l=20, r=20)
)
return fig
def create_positioning_matrix(df):
fig = px.scatter(
df,
x="competition_level",
y="innovation_score",
size="market_potential",
color="growth_rate",
hover_data=["domain","category","region","year"],
title="Strategic Positioning Matrix",
size_max=50,
color_continuous_scale="Turbo"
)
fig.update_traces(
marker=dict(line=dict(width=1, color='white')),
hovertemplate="%{customdata[0]}
Category: %{customdata[1]}
Region: %{customdata[2]}
Year: %{customdata[3]}
Growth: %{color:.1f}
Growth: %{y:.1f}
Category: %{customdata[0]}
Region: %{customdata[1]}
Domain: %{y}
Potential: %{z:.1f}
AI-Powered Market Intelligence • Real-Time Analysis • Strategic Insights
Powered by Groq LLama 3.3 • FAISS • Sentence‑Transformers