feat: enhance InsightPrompts and components with additional data handling

- Updated InsightPrompts to clarify user request counting guidelines.
- Modified App.js to pass new props (topGoals, topTools) to ProjectAreas and ImpressiveWorkflows components.
- Enhanced ProjectAreas and ImpressiveWorkflows components to utilize new props for improved data visualization.
- Refactored FrictionPoints component layout to use grid display for better responsiveness.
- Removed legacy insight-app.js file to streamline the codebase.
- Expanded StaticInsightTypes to include primarySuccess, outcomes, and topGoals for better data structure.
This commit is contained in:
DragonnZhang 2026-02-09 14:54:31 +08:00
parent 4c32f4b646
commit af21e7fdd9
6 changed files with 155 additions and 1153 deletions

View file

@ -281,8 +281,14 @@ export class DataProcessor {
if (onProgress) onProgress('Generating qualitative insights', 80);
const qualitative = await this.generateQualitativeInsights(metrics, facets);
// Aggregate satisfaction and friction data from facets
const { satisfactionAgg, frictionAgg } = this.aggregateFacetsData(facets);
// Aggregate satisfaction, friction, success and outcome data from facets
const {
satisfactionAgg,
frictionAgg,
primarySuccessAgg,
outcomesAgg,
goalsAgg,
} = this.aggregateFacetsData(facets);
if (onProgress) onProgress('Finalizing report', 100);
@ -291,6 +297,9 @@ export class DataProcessor {
qualitative,
satisfaction: satisfactionAgg,
friction: frictionAgg,
primarySuccess: primarySuccessAgg,
outcomes: outcomesAgg,
topGoals: goalsAgg,
};
}
@ -298,9 +307,15 @@ export class DataProcessor {
private aggregateFacetsData(facets: SessionFacets[]): {
satisfactionAgg: Record<string, number>;
frictionAgg: Record<string, number>;
primarySuccessAgg: Record<string, number>;
outcomesAgg: Record<string, number>;
goalsAgg: Record<string, number>;
} {
const satisfactionAgg: Record<string, number> = {};
const frictionAgg: Record<string, number> = {};
const primarySuccessAgg: Record<string, number> = {};
const outcomesAgg: Record<string, number> = {};
const goalsAgg: Record<string, number> = {};
facets.forEach((facet) => {
// Aggregate satisfaction
@ -312,9 +327,31 @@ export class DataProcessor {
Object.entries(facet.friction_counts).forEach(([fric, count]) => {
frictionAgg[fric] = (frictionAgg[fric] || 0) + count;
});
// Aggregate primary success
if (facet.primary_success && facet.primary_success !== 'none') {
primarySuccessAgg[facet.primary_success] =
(primarySuccessAgg[facet.primary_success] || 0) + 1;
}
// Aggregate outcomes
if (facet.outcome) {
outcomesAgg[facet.outcome] = (outcomesAgg[facet.outcome] || 0) + 1;
}
// Aggregate goals
Object.entries(facet.goal_categories).forEach(([goal, count]) => {
goalsAgg[goal] = (goalsAgg[goal] || 0) + count;
});
});
return { satisfactionAgg, frictionAgg };
return {
satisfactionAgg,
frictionAgg,
primarySuccessAgg,
outcomesAgg,
goalsAgg,
};
}
private async generateQualitativeInsights(

View file

@ -5,7 +5,15 @@ CRITICAL GUIDELINES:
1. **goal_categories**: Count ONLY what the USER explicitly asked for.
- DO NOT count Qwen's autonomous codebase exploration
- DO NOT count work Qwen decided to do on its own
- ONLY count when user says "can you...", "please...", "I need...", "let's..."
- ONLY count when user says "can you...", "please...", "I need...", "let's...
- POSSIBLE CATEGORIES (but be open to others that appear in the data):
- bug_fix
- feature_request
- debugging
- test_creation
- code_refactoring
- documentation_update
"
2. **user_satisfaction_counts**: Base ONLY on explicit user signals.
- "Yay!", "great!", "perfect!" happy

View file

@ -40,7 +40,11 @@ function InsightApp({ data }) {
{data.qualitative && (
<>
<ProjectAreas qualitative={data.qualitative} />
<ProjectAreas
qualitative={data.qualitative}
topGoals={data.topGoals}
topTools={data.topTools}
/>
</>
)}
@ -54,7 +58,11 @@ function InsightApp({ data }) {
{data.qualitative && (
<>
<ImpressiveWorkflows qualitative={data.qualitative} />
<ImpressiveWorkflows
qualitative={data.qualitative}
primarySuccess={data.primarySuccess}
outcomes={data.outcomes}
/>
<FrictionPoints
qualitative={data.qualitative}
satisfaction={data.satisfaction}

View file

@ -62,10 +62,13 @@ function NavToc() {
);
}
function ProjectAreas({ qualitative }) {
function ProjectAreas({ qualitative, topGoals, topTools }) {
const { projectAreas } = qualitative;
if (!Array.isArray(projectAreas?.areas) || !projectAreas.areas.length)
return null;
// Convert topTools (array of tuples) to object for chart if needed
const topToolsObj = Array.isArray(topTools)
? Object.fromEntries(topTools)
: topTools;
return (
<>
@ -75,18 +78,47 @@ function ProjectAreas({ qualitative }) {
>
What You Work On
</h2>
<div className="project-areas">
{projectAreas.areas.map((area, idx) => (
<div key={idx} className="project-area">
<div className="area-header">
<span className="area-name">{area.name}</span>
<span className="area-count">~{area.session_count} sessions</span>
{Array.isArray(projectAreas?.areas) && projectAreas.areas.length > 0 && (
<div className="project-areas mb-6">
{projectAreas.areas.map((area, idx) => (
<div key={idx} className="project-area">
<div className="area-header">
<span className="area-name">{area.name}</span>
<span className="area-count">
~{area.session_count} sessions
</span>
</div>
<div className="area-desc">
<MarkdownText>{area.description}</MarkdownText>
</div>
</div>
<div className="area-desc">
<MarkdownText>{area.description}</MarkdownText>
</div>
</div>
))}
))}
</div>
)}
<div
style={{
display: 'grid',
gridTemplateColumns: 'repeat(2, 1fr)',
gap: '24px',
marginBottom: '24px',
}}
>
{topGoals && Object.keys(topGoals).length > 0 && (
<HorizontalBarChart
data={topGoals}
title="What You Wanted"
color="#0ea5e9"
/>
)}
{topToolsObj && Object.keys(topToolsObj).length > 0 && (
<HorizontalBarChart
data={topToolsObj}
title="Top Tools Used"
color="#6366f1"
/>
)}
</div>
</>
);
@ -119,7 +151,7 @@ function InteractionStyle({ qualitative }) {
);
}
function ImpressiveWorkflows({ qualitative }) {
function ImpressiveWorkflows({ qualitative, primarySuccess, outcomes }) {
const { impressiveWorkflows } = qualitative;
if (!impressiveWorkflows) return null;
@ -147,12 +179,55 @@ function ImpressiveWorkflows({ qualitative }) {
</div>
))}
</div>
<div
style={{
display: 'grid',
gridTemplateColumns: 'repeat(2, 1fr)',
gap: '24px',
marginTop: '24px',
marginBottom: '24px',
}}
>
{primarySuccess && Object.keys(primarySuccess).length > 0 && (
<HorizontalBarChart
data={primarySuccess}
title="What Helped Most (Qwen's Capabilities)"
color="#3b82f6"
allowedKeys={[
'fast_accurate_search',
'correct_code_edits',
'good_explanations',
'proactive_help',
'multi_file_changes',
'good_debugging',
]}
/>
)}
{outcomes && Object.keys(outcomes).length > 0 && (
<HorizontalBarChart
data={outcomes}
title="Outcomes"
color="#8b5cf6"
allowedKeys={[
'fully_achieved',
'mostly_achieved',
'partially_achieved',
'not_achieved',
'unclear_from_transcript',
]}
/>
)}
</div>
</>
);
}
// Format label for display (capitalize and replace underscores with spaces)
function formatLabel(label) {
if (label === 'unclear_from_transcript') {
return 'Unclear';
}
return label
.split('_')
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
@ -197,6 +272,7 @@ function HorizontalBarChart({
fontSize: '13px',
fontWeight: 700,
color: '#64748b',
marginTop: 0,
marginBottom: '16px',
textTransform: 'uppercase',
letterSpacing: '0.5px',
@ -324,7 +400,8 @@ function FrictionPoints({ qualitative, satisfaction, friction }) {
{/* Facets Data Charts */}
<div
style={{
display: 'flex',
display: 'grid',
gridTemplateColumns: 'repeat(2, 1fr)',
gap: '24px',
marginTop: '24px',
marginBottom: '24px',

View file

@ -28,6 +28,9 @@ export interface InsightData {
qualitative?: QualitativeInsights;
satisfaction?: Record<string, number>;
friction?: Record<string, number>;
primarySuccess?: Record<string, number>;
outcomes?: Record<string, number>;
topGoals?: Record<string, number>;
}
export interface StreakData {