Improved analysis screen on focused mode.
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
import ExportControls from './components/ExportControls.svelte';
|
import ExportControls from './components/ExportControls.svelte';
|
||||||
import HelpModal from './components/HelpModal.svelte';
|
import HelpModal from './components/HelpModal.svelte';
|
||||||
import FormRecommendation from './components/FormRecommendation.svelte';
|
import FormRecommendation from './components/FormRecommendation.svelte';
|
||||||
|
import AnalysisTransitionBanner from './components/AnalysisTransitionBanner.svelte';
|
||||||
import { BicorderClassifier } from './bicorder-classifier';
|
import { BicorderClassifier } from './bicorder-classifier';
|
||||||
|
|
||||||
// Load bicorder data and model from build-time constants
|
// Load bicorder data and model from build-time constants
|
||||||
@@ -57,12 +58,12 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Analysis screens (not in shortform)
|
// Analysis screens (shown in both shortform and longform)
|
||||||
if (!isShortForm) {
|
// Show useful/not-useful gradient first (index 3), then the others
|
||||||
data.analysis.forEach((gradient, index) => {
|
const analysisOrder = [3, 0, 1, 2]; // useful/not-useful, hardness, polarization, bureaucratic
|
||||||
screens.push({ type: 'analysis', index, gradient });
|
analysisOrder.forEach((index) => {
|
||||||
});
|
screens.push({ type: 'analysis', index, gradient: data.analysis[index] });
|
||||||
}
|
});
|
||||||
|
|
||||||
// Export screen
|
// Export screen
|
||||||
screens.push({ type: 'export' });
|
screens.push({ type: 'export' });
|
||||||
@@ -106,7 +107,80 @@
|
|||||||
return filled.repeat(filledCount) + empty.repeat(emptyCount);
|
return filled.repeat(filledCount) + empty.repeat(emptyCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
$: progressBar = generateProgressBar(currentScreen + 1, totalScreens);
|
// Calculate total diagnostic screens (metadata + gradients only)
|
||||||
|
$: diagnosticScreenCount = screens.filter(s => s.type === 'metadata' || s.type === 'gradient').length;
|
||||||
|
|
||||||
|
// Calculate current position within diagnostic screens
|
||||||
|
$: diagnosticProgress = currentScreenData?.type === 'metadata' || currentScreenData?.type === 'gradient'
|
||||||
|
? currentScreen + 1
|
||||||
|
: diagnosticScreenCount; // Show as complete when in analysis or export
|
||||||
|
|
||||||
|
$: progressBar = generateProgressBar(diagnosticProgress, diagnosticScreenCount);
|
||||||
|
|
||||||
|
// Detect if we're on the first analysis screen
|
||||||
|
$: isFirstAnalysisScreen = currentScreenData?.type === 'analysis' &&
|
||||||
|
screens.findIndex(s => s.type === 'analysis') === currentScreen;
|
||||||
|
|
||||||
|
// Calculate completed gradients for the banner
|
||||||
|
$: completedGradientsCount = data.diagnostic
|
||||||
|
.flatMap(set => set.gradients)
|
||||||
|
.filter(g => !data.metadata.shortform || g.shortform)
|
||||||
|
.filter(g => g.value !== null).length;
|
||||||
|
|
||||||
|
$: totalGradientsCount = data.diagnostic
|
||||||
|
.flatMap(set => set.gradients)
|
||||||
|
.filter(g => !data.metadata.shortform || g.shortform).length;
|
||||||
|
|
||||||
|
// Calculate form recommendation (shared by FormRecommendation and AnalysisTransitionBanner)
|
||||||
|
let formRecommendation: any = null;
|
||||||
|
let hasEnoughDataForRecommendation = false;
|
||||||
|
|
||||||
|
$: {
|
||||||
|
// Collect ratings from diagnostic data
|
||||||
|
const ratings: Record<string, number> = {};
|
||||||
|
let valueCount = 0;
|
||||||
|
let shortFormTotal = 0;
|
||||||
|
|
||||||
|
data.diagnostic.forEach((diagnosticSet) => {
|
||||||
|
const setName = diagnosticSet.set_name;
|
||||||
|
diagnosticSet.gradients.forEach((gradient) => {
|
||||||
|
// Count shortform gradients
|
||||||
|
if (gradient.shortform) {
|
||||||
|
shortFormTotal++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gradient.value !== null) {
|
||||||
|
const dimensionName = `${setName}_${gradient.term_left}_vs_${gradient.term_right}`;
|
||||||
|
ratings[dimensionName] = gradient.value;
|
||||||
|
|
||||||
|
// Only count shortform values for the threshold
|
||||||
|
if (gradient.shortform) {
|
||||||
|
valueCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Only calculate if at least half of shortform gradients are complete
|
||||||
|
const threshold = Math.ceil(shortFormTotal / 2);
|
||||||
|
hasEnoughDataForRecommendation = valueCount >= threshold;
|
||||||
|
|
||||||
|
if (hasEnoughDataForRecommendation && data.metadata.shortform) {
|
||||||
|
try {
|
||||||
|
const prediction = classifier.predict(ratings, { detailed: true });
|
||||||
|
const assessment = classifier.assessShortFormReadiness(ratings);
|
||||||
|
formRecommendation = {
|
||||||
|
...prediction,
|
||||||
|
...assessment,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error calculating form recommendation:', error);
|
||||||
|
formRecommendation = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
formRecommendation = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Load saved state from localStorage
|
// Load saved state from localStorage
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
@@ -351,8 +425,8 @@
|
|||||||
|
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<FormRecommendation
|
<FormRecommendation
|
||||||
{classifier}
|
recommendation={formRecommendation}
|
||||||
diagnosticData={data.diagnostic}
|
hasEnoughData={hasEnoughDataForRecommendation}
|
||||||
isShortForm={data.metadata.shortform}
|
isShortForm={data.metadata.shortform}
|
||||||
on:switchToLongForm={handleSwitchToLongForm}
|
on:switchToLongForm={handleSwitchToLongForm}
|
||||||
/>
|
/>
|
||||||
@@ -480,6 +554,28 @@
|
|||||||
<div class="focused-screen gradient-screen">
|
<div class="focused-screen gradient-screen">
|
||||||
<div class="screen-category">ANALYSIS</div>
|
<div class="screen-category">ANALYSIS</div>
|
||||||
|
|
||||||
|
{#if isFirstAnalysisScreen}
|
||||||
|
<AnalysisTransitionBanner
|
||||||
|
recommendation={formRecommendation}
|
||||||
|
isShortForm={data.metadata.shortform}
|
||||||
|
completedGradients={completedGradientsCount}
|
||||||
|
allAnalysisGradients={data.analysis}
|
||||||
|
on:switchToLongForm={handleSwitchToLongForm}
|
||||||
|
on:jumpToExport={() => {
|
||||||
|
// Jump to the export screen (last screen)
|
||||||
|
currentScreen = screens.length - 1;
|
||||||
|
}}
|
||||||
|
on:updateAnalysis={(e) => {
|
||||||
|
data.analysis[e.detail.index].value = e.detail.value;
|
||||||
|
data = data;
|
||||||
|
}}
|
||||||
|
on:updateAnalysisNotes={(e) => {
|
||||||
|
data.analysis[e.detail.index].notes = e.detail.notes;
|
||||||
|
data = data;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<div class="gradient-focused">
|
<div class="gradient-focused">
|
||||||
<div class="term-desc left-desc">
|
<div class="term-desc left-desc">
|
||||||
<div class="term-name">← {screen.gradient.term_left}</div>
|
<div class="term-name">← {screen.gradient.term_left}</div>
|
||||||
@@ -554,7 +650,7 @@
|
|||||||
>
|
>
|
||||||
{progressBar}
|
{progressBar}
|
||||||
</div>
|
</div>
|
||||||
<div class="progress-numbers">{currentScreen + 1} / {totalScreens}</div>
|
<div class="progress-numbers">{diagnosticProgress} / {diagnosticScreenCount}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
359
bicorder-app/src/components/AnalysisTransitionBanner.svelte
Normal file
359
bicorder-app/src/components/AnalysisTransitionBanner.svelte
Normal file
@@ -0,0 +1,359 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
import AnalysisDisplay from './AnalysisDisplay.svelte';
|
||||||
|
import type { AnalysisGradient } from '../types';
|
||||||
|
|
||||||
|
export let recommendation: any = null;
|
||||||
|
export let isShortForm: boolean;
|
||||||
|
export let completedGradients: number;
|
||||||
|
export let allAnalysisGradients: AnalysisGradient[];
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher<{
|
||||||
|
switchToLongForm: void;
|
||||||
|
jumpToExport: void;
|
||||||
|
updateAnalysis: { index: number; value: number | null };
|
||||||
|
updateAnalysisNotes: { index: number; notes: string };
|
||||||
|
}>();
|
||||||
|
|
||||||
|
$: hasRecommendation = recommendation?.recommendedForm === 'long';
|
||||||
|
|
||||||
|
let showAllAnalysis = false;
|
||||||
|
|
||||||
|
function handleSwitchToLongForm() {
|
||||||
|
dispatch('switchToLongForm');
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleJumpToExport() {
|
||||||
|
dispatch('jumpToExport');
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleAllAnalysis() {
|
||||||
|
showAllAnalysis = !showAllAnalysis;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="transition-banner">
|
||||||
|
<div class="banner-content">
|
||||||
|
<div class="banner-header">
|
||||||
|
<div class="completion-icon">✓</div>
|
||||||
|
<div class="header-text">
|
||||||
|
<h3>Diagnostics Complete</h3>
|
||||||
|
<p class="subtext">Analysis calculated from {completedGradients} gradient{completedGradients !== 1 ? 's' : ''}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Recommendation Alert (if applicable) -->
|
||||||
|
{#if isShortForm && hasRecommendation && recommendation}
|
||||||
|
<div class="recommendation-alert">
|
||||||
|
<div class="alert-header">
|
||||||
|
<span class="alert-icon">⚠</span>
|
||||||
|
<strong>Long Form Recommended</strong>
|
||||||
|
</div>
|
||||||
|
<div class="alert-body">
|
||||||
|
<p class="alert-message">
|
||||||
|
{#if recommendation.confidence < 60}
|
||||||
|
• Low classification confidence ({recommendation.confidence}%)<br>
|
||||||
|
{/if}
|
||||||
|
{#if recommendation.completeness < 50}
|
||||||
|
• Incomplete data ({recommendation.completeness}% of dimensions)<br>
|
||||||
|
{/if}
|
||||||
|
{#if recommendation.distanceToBoundary < 0.5}
|
||||||
|
• Protocol near boundary between families<br>
|
||||||
|
{/if}
|
||||||
|
{#if recommendation.coverage < 75}
|
||||||
|
• Missing key dimensions for reliable short-form classification ({recommendation.coverage}% coverage)<br>
|
||||||
|
{/if}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<!-- Action Buttons -->
|
||||||
|
<div class="action-buttons">
|
||||||
|
<button class="action-btn view-analysis-btn" on:click={toggleAllAnalysis}>
|
||||||
|
{showAllAnalysis ? '▼' : '▶'} {showAllAnalysis ? 'Hide' : 'View'} All Analysis
|
||||||
|
</button>
|
||||||
|
<button class="action-btn export-btn" on:click={handleJumpToExport}>
|
||||||
|
Export Readings →
|
||||||
|
</button>
|
||||||
|
{#if isShortForm}
|
||||||
|
<button class="action-btn longform-btn" on:click={handleSwitchToLongForm}>
|
||||||
|
Switch to Long Form & Restart →
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- All Analysis Gradients (expandable) -->
|
||||||
|
{#if showAllAnalysis}
|
||||||
|
<div class="all-analysis-section">
|
||||||
|
<div class="analysis-header">All Analysis Gradients</div>
|
||||||
|
{#each allAnalysisGradients as gradient, index}
|
||||||
|
{#if index !== 3}
|
||||||
|
<div class="analysis-item">
|
||||||
|
<AnalysisDisplay
|
||||||
|
{gradient}
|
||||||
|
focusedMode={false}
|
||||||
|
on:change={(e) => dispatch('updateAnalysis', { index, value: e.detail })}
|
||||||
|
on:notes={(e) => dispatch('updateAnalysisNotes', { index, notes: e.detail })}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.transition-banner {
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
animation: fadeInSlide 0.5s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeInSlide {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-10px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-content {
|
||||||
|
border: 2px solid var(--border-color);
|
||||||
|
background: var(--input-bg);
|
||||||
|
padding: 1.5rem;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-content::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 3px;
|
||||||
|
background: linear-gradient(90deg,
|
||||||
|
transparent 0%,
|
||||||
|
var(--fg-color) 20%,
|
||||||
|
var(--fg-color) 80%,
|
||||||
|
transparent 100%);
|
||||||
|
opacity: 0.3;
|
||||||
|
animation: shimmer 2s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes shimmer {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-100%);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(100%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.completion-icon {
|
||||||
|
font-size: 2rem;
|
||||||
|
color: #4ade80;
|
||||||
|
animation: checkPop 0.5s ease-out 0.2s both;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes checkPop {
|
||||||
|
0% {
|
||||||
|
transform: scale(0);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: scale(1.2);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-text h3 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
letter-spacing: 0.05rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtext {
|
||||||
|
margin: 0.25rem 0 0 0;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.recommendation-alert {
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding: 1rem;
|
||||||
|
background: rgba(251, 191, 36, 0.1);
|
||||||
|
border: 2px solid #fbbf24;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-icon {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: #fbbf24;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-header strong {
|
||||||
|
font-size: 1rem;
|
||||||
|
color: #fbbf24;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-body {
|
||||||
|
padding-left: 1.7rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-message {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-buttons {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.75rem;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.75rem;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
font-weight: bold;
|
||||||
|
border: 2px solid var(--border-color);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
border-radius: 3px;
|
||||||
|
background: var(--bg-color);
|
||||||
|
color: var(--fg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
border-color: var(--fg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.export-btn {
|
||||||
|
background: var(--fg-color);
|
||||||
|
color: var(--bg-color);
|
||||||
|
border-color: var(--fg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.export-btn:hover {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.longform-btn {
|
||||||
|
background: #fbbf24;
|
||||||
|
color: #1a1a2e;
|
||||||
|
border-color: #fbbf24;
|
||||||
|
}
|
||||||
|
|
||||||
|
.longform-btn:hover {
|
||||||
|
background: #f59e0b;
|
||||||
|
border-color: #f59e0b;
|
||||||
|
box-shadow: 0 2px 8px rgba(251, 191, 36, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-analysis-btn {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.all-analysis-section {
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
padding: 1rem;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
background: var(--bg-color);
|
||||||
|
animation: slideDown 0.3s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideDown {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
max-height: 0;
|
||||||
|
padding: 0 1rem;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
max-height: 2000px;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.analysis-header {
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.analysis-item {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.analysis-item:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.banner-content {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-header {
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.completion-icon {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-text h3 {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtext {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-body {
|
||||||
|
padding-left: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
padding: 0.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.all-analysis-section {
|
||||||
|
padding: 0.75rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import type { BicorderClassifier } from '../bicorder-classifier';
|
|
||||||
|
|
||||||
export let classifier: BicorderClassifier;
|
export let recommendation: any = null;
|
||||||
export let diagnosticData: any;
|
export let hasEnoughData: boolean;
|
||||||
export let isShortForm: boolean;
|
export let isShortForm: boolean;
|
||||||
|
|
||||||
const dispatch = createEventDispatcher<{
|
const dispatch = createEventDispatcher<{
|
||||||
@@ -11,56 +10,6 @@
|
|||||||
}>();
|
}>();
|
||||||
|
|
||||||
let isExpanded = false;
|
let isExpanded = false;
|
||||||
let recommendation: any = null;
|
|
||||||
let hasEnoughData = false;
|
|
||||||
|
|
||||||
// Calculate recommendation based on current diagnostic data
|
|
||||||
$: {
|
|
||||||
// Collect ratings from diagnostic data
|
|
||||||
const ratings: Record<string, number> = {};
|
|
||||||
let valueCount = 0;
|
|
||||||
let shortFormTotal = 0;
|
|
||||||
|
|
||||||
diagnosticData.forEach((diagnosticSet: any) => {
|
|
||||||
const setName = diagnosticSet.set_name;
|
|
||||||
diagnosticSet.gradients.forEach((gradient: any) => {
|
|
||||||
// Count shortform gradients
|
|
||||||
if (gradient.shortform) {
|
|
||||||
shortFormTotal++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gradient.value !== null) {
|
|
||||||
const dimensionName = `${setName}_${gradient.term_left}_vs_${gradient.term_right}`;
|
|
||||||
ratings[dimensionName] = gradient.value;
|
|
||||||
|
|
||||||
// Only count shortform values for the threshold
|
|
||||||
if (gradient.shortform) {
|
|
||||||
valueCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Only show if at least half of shortform gradients are complete
|
|
||||||
const threshold = Math.ceil(shortFormTotal / 2);
|
|
||||||
hasEnoughData = valueCount >= threshold;
|
|
||||||
|
|
||||||
if (hasEnoughData && isShortForm) {
|
|
||||||
try {
|
|
||||||
const prediction = classifier.predict(ratings, { detailed: true });
|
|
||||||
const assessment = classifier.assessShortFormReadiness(ratings);
|
|
||||||
recommendation = {
|
|
||||||
...prediction,
|
|
||||||
...assessment,
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error getting form recommendation:', error);
|
|
||||||
recommendation = null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
recommendation = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleExpanded() {
|
function toggleExpanded() {
|
||||||
isExpanded = !isExpanded;
|
isExpanded = !isExpanded;
|
||||||
@@ -147,9 +96,9 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</p>
|
</p>
|
||||||
<button class="switch-btn" on:click={handleSwitchToLongForm}>
|
<button class="switch-btn" on:click={handleSwitchToLongForm}>
|
||||||
Switch to Long Form →
|
Switch to Long Form & Restart →
|
||||||
</button>
|
</button>
|
||||||
<p class="note">All your current values will be preserved.</p>
|
<p class="note">Returns to the beginning. All your current values will be preserved.</p>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="recommendation-message good">
|
<div class="recommendation-message good">
|
||||||
|
|||||||
Reference in New Issue
Block a user