Add podcast research metadata mapping and summary sections
This commit is contained in:
@@ -218,6 +218,9 @@ Listener CTA: {request.analysis.get('listener_cta', 'N/A')}
|
|||||||
|
|
||||||
summary = ""
|
summary = ""
|
||||||
key_insights = []
|
key_insights = []
|
||||||
|
expert_quotes = []
|
||||||
|
listener_cta_suggestions = []
|
||||||
|
mapped_angles = []
|
||||||
|
|
||||||
if raw_content and sources:
|
if raw_content and sources:
|
||||||
logger.warning(f"[Podcast Research] Extracting insights from {len(sources)} sources for user {user_id}")
|
logger.warning(f"[Podcast Research] Extracting insights from {len(sources)} sources for user {user_id}")
|
||||||
@@ -337,13 +340,22 @@ QUALITY STANDARDS:
|
|||||||
try:
|
try:
|
||||||
summary = data.get("summary", "")
|
summary = data.get("summary", "")
|
||||||
key_insights = [PodcastResearchInsight(**insight) for insight in data.get("key_insights", [])]
|
key_insights = [PodcastResearchInsight(**insight) for insight in data.get("key_insights", [])]
|
||||||
|
expert_quotes = data.get("expert_quotes", [])
|
||||||
|
listener_cta_suggestions = data.get("listener_cta_suggestions", [])
|
||||||
|
mapped_angles = data.get("mapped_angles", [])
|
||||||
except Exception as insight_err:
|
except Exception as insight_err:
|
||||||
logger.warning(f"[Podcast Research] Failed to parse insights: {insight_err}. Data keys: {list(data.keys()) if isinstance(data, dict) else 'not a dict'}")
|
logger.warning(f"[Podcast Research] Failed to parse insights: {insight_err}. Data keys: {list(data.keys()) if isinstance(data, dict) else 'not a dict'}")
|
||||||
summary = data.get("summary", "") if isinstance(data, dict) else ""
|
summary = data.get("summary", "") if isinstance(data, dict) else ""
|
||||||
key_insights = []
|
key_insights = []
|
||||||
|
expert_quotes = data.get("expert_quotes", []) if isinstance(data, dict) else []
|
||||||
|
listener_cta_suggestions = data.get("listener_cta_suggestions", []) if isinstance(data, dict) else []
|
||||||
|
mapped_angles = data.get("mapped_angles", []) if isinstance(data, dict) else []
|
||||||
else:
|
else:
|
||||||
summary = ""
|
summary = ""
|
||||||
key_insights = []
|
key_insights = []
|
||||||
|
expert_quotes = []
|
||||||
|
listener_cta_suggestions = []
|
||||||
|
mapped_angles = []
|
||||||
except HTTPException:
|
except HTTPException:
|
||||||
raise
|
raise
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
@@ -423,5 +435,8 @@ QUALITY STANDARDS:
|
|||||||
search_type=result.get("search_type") if isinstance(result, dict) else None,
|
search_type=result.get("search_type") if isinstance(result, dict) else None,
|
||||||
provider=result.get("provider", "exa") if isinstance(result, dict) else "exa",
|
provider=result.get("provider", "exa") if isinstance(result, dict) else "exa",
|
||||||
content=raw_content,
|
content=raw_content,
|
||||||
|
mapped_angles=mapped_angles,
|
||||||
|
expert_quotes=expert_quotes,
|
||||||
|
listener_cta_suggestions=listener_cta_suggestions,
|
||||||
estimate=estimate,
|
estimate=estimate,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -285,6 +285,78 @@ export const ResearchSummary: React.FC<ResearchSummaryProps> = ({
|
|||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Expert Quotes */}
|
||||||
|
<Box sx={{ mb: 3 }}>
|
||||||
|
<Typography variant="h6" sx={{ mb: 1.5, color: "#0f172a", fontWeight: 700 }}>
|
||||||
|
Expert Quotes
|
||||||
|
</Typography>
|
||||||
|
{research.expertQuotes && research.expertQuotes.length > 0 ? (
|
||||||
|
<Stack spacing={1}>
|
||||||
|
{research.expertQuotes.slice(0, 4).map((quote, idx) => (
|
||||||
|
<Paper key={`${quote.source_index}-${idx}`} elevation={0} sx={{ p: 1.5, border: "1px solid rgba(0,0,0,0.06)", borderRadius: 2 }}>
|
||||||
|
<Typography variant="body2" sx={{ color: "#334155", lineHeight: 1.55 }}>
|
||||||
|
“{quote.quote}”
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="caption" sx={{ color: "#64748b", display: "block", mt: 0.5 }}>
|
||||||
|
Source S{quote.source_index}
|
||||||
|
</Typography>
|
||||||
|
</Paper>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
) : (
|
||||||
|
<Typography variant="body2" sx={{ color: "#64748b" }}>
|
||||||
|
No expert quotes extracted yet.
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Listener CTAs */}
|
||||||
|
<Box sx={{ mb: 3 }}>
|
||||||
|
<Typography variant="h6" sx={{ mb: 1.5, color: "#0f172a", fontWeight: 700 }}>
|
||||||
|
Listener CTAs
|
||||||
|
</Typography>
|
||||||
|
{research.listenerCta && research.listenerCta.length > 0 ? (
|
||||||
|
<Stack spacing={1}>
|
||||||
|
{research.listenerCta.slice(0, 4).map((cta, idx) => (
|
||||||
|
<Paper key={`cta-${idx}`} elevation={0} sx={{ p: 1.5, border: "1px solid rgba(0,0,0,0.06)", borderRadius: 2 }}>
|
||||||
|
<Typography variant="body2" sx={{ color: "#334155", lineHeight: 1.55 }}>
|
||||||
|
{cta}
|
||||||
|
</Typography>
|
||||||
|
</Paper>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
) : (
|
||||||
|
<Typography variant="body2" sx={{ color: "#64748b" }}>
|
||||||
|
No listener CTAs suggested yet.
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{/* Mapped Angles */}
|
||||||
|
<Box sx={{ mb: 3 }}>
|
||||||
|
<Typography variant="h6" sx={{ mb: 1.5, color: "#0f172a", fontWeight: 700 }}>
|
||||||
|
Mapped Angles
|
||||||
|
</Typography>
|
||||||
|
{research.mappedAngles && research.mappedAngles.length > 0 ? (
|
||||||
|
<Stack spacing={1}>
|
||||||
|
{research.mappedAngles.slice(0, 4).map((angle, idx) => (
|
||||||
|
<Paper key={`angle-${idx}`} elevation={0} sx={{ p: 1.5, border: "1px solid rgba(0,0,0,0.06)", borderRadius: 2 }}>
|
||||||
|
<Typography variant="subtitle2" sx={{ color: "#0f172a", fontWeight: 700, mb: 0.5 }}>
|
||||||
|
{angle.title || `Angle ${idx + 1}`}
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body2" sx={{ color: "#334155", lineHeight: 1.55 }}>
|
||||||
|
{angle.why || "No rationale provided."}
|
||||||
|
</Typography>
|
||||||
|
</Paper>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
) : (
|
||||||
|
<Typography variant="body2" sx={{ color: "#64748b" }}>
|
||||||
|
No mapped angles available yet.
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
|
||||||
{/* Search Queries Used */}
|
{/* Search Queries Used */}
|
||||||
{research.searchQueries && research.searchQueries.length > 0 && (
|
{research.searchQueries && research.searchQueries.length > 0 && (
|
||||||
<Box sx={{ mt: 4, pt: 3, borderTop: "1px solid rgba(0,0,0,0.04)" }}>
|
<Box sx={{ mt: 4, pt: 3, borderTop: "1px solid rgba(0,0,0,0.04)" }}>
|
||||||
|
|||||||
@@ -198,6 +198,8 @@ const mapExaResearchResponse = (response: any): Research => {
|
|||||||
source_indices: insight.source_indices || []
|
source_indices: insight.source_indices || []
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// Backend keys must match PodcastExaResearchResponse exactly:
|
||||||
|
// expert_quotes, listener_cta_suggestions, mapped_angles
|
||||||
const expertQuotes = (response.expert_quotes || []).map((eq: any) => ({
|
const expertQuotes = (response.expert_quotes || []).map((eq: any) => ({
|
||||||
quote: eq.quote || eq.text || "",
|
quote: eq.quote || eq.text || "",
|
||||||
source_index: eq.source_index ?? 0
|
source_index: eq.source_index ?? 0
|
||||||
|
|||||||
Reference in New Issue
Block a user