Skip to content

Commit 927185a

Browse files
authored
Merge pull request #2 from Eilodon/claude/upgrade-project-plan-7G0jJ
Claude/upgrade project plan 7 g0j j
2 parents 3a3c735 + f34a2a8 commit 927185a

20 files changed

Lines changed: 2484 additions & 119 deletions

components/HistoryPanel.tsx

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useState, useMemo } from 'react';
2-
import { History, TrendingUp, X, Trash2, Fingerprint, Map } from 'lucide-react';
3-
import { ConversationEntry, ConsciousnessArchetype } from '../types';
2+
import { History, TrendingUp, X, Trash2, Brain, Map } from 'lucide-react';
3+
import { ConversationEntry } from '../types';
44
import { dbService } from '../services/db';
55

66
interface Props {
@@ -18,43 +18,43 @@ export const HistoryPanel: React.FC<Props> = ({ history, onClear }) => {
1818
// Use history prop directly
1919
const displayData = history;
2020

21-
// Helper for safe access
22-
const safeMetric = (entry: ConversationEntry, key: 'coherence' | 'presence' | 'entanglement') => {
23-
return entry.quantum_metrics ? entry.quantum_metrics[key] : 0;
21+
// Helper for safe access to mindfulness metrics
22+
const safeMetric = (entry: ConversationEntry, key: 'attention_stability' | 'present_moment_awareness' | 'emotional_regulation') => {
23+
return entry.mindfulness_metrics ? entry.mindfulness_metrics[key] : 0;
2424
};
2525

26-
const avgCoherence = displayData.reduce((sum, e) => sum + safeMetric(e, 'coherence'), 0) / (displayData.length || 1);
27-
const avgPresence = displayData.reduce((sum, e) => sum + safeMetric(e, 'presence'), 0) / (displayData.length || 1);
28-
const avgEntanglement = displayData.reduce((sum, e) => sum + safeMetric(e, 'entanglement'), 0) / (displayData.length || 1);
29-
30-
// DETERMINE CONSCIOUSNESS DNA ARCHETYPE
31-
let archetype: ConsciousnessArchetype = 'The Seeker';
32-
let description = "Bạn đang trên hành trình tìm kiếm sự bình an.";
33-
34-
if (avgPresence > 0.7 && avgCoherence > 0.7) {
35-
archetype = 'The Warrior'; // High discipline
36-
description = "Bạn khả năng định tâm vững chãi như núi.";
37-
} else if (avgEntanglement > 0.7) {
38-
archetype = 'The Healer'; // High connection
39-
description = "Trái tim bạn rộng mở và kết nối sâu sắc với vạn vật.";
40-
} else if (avgCoherence > 0.8) {
41-
archetype = 'The Observer'; // High coherence
42-
description = "Bạn nhìn thấu bản chất vấn đề với sự tĩnh lặng.";
26+
const avgAttentionStability = displayData.reduce((sum, e) => sum + safeMetric(e, 'attention_stability'), 0) / (displayData.length || 1);
27+
const avgPresentMomentAwareness = displayData.reduce((sum, e) => sum + safeMetric(e, 'present_moment_awareness'), 0) / (displayData.length || 1);
28+
const avgEmotionalRegulation = displayData.reduce((sum, e) => sum + safeMetric(e, 'emotional_regulation'), 0) / (displayData.length || 1);
29+
30+
// DETERMINE MINDFULNESS PROFILE (clinically based)
31+
let profileTitle = "Developing Awareness";
32+
let description = "Bạn đang xây dựng nền tảng chánh niệm.";
33+
34+
if (avgPresentMomentAwareness > 0.7 && avgAttentionStability > 0.7) {
35+
profileTitle = "Strong Practice"; // High discipline
36+
description = "Bạn đã phát triển khả năng định tâm vững chãi.";
37+
} else if (avgEmotionalRegulation > 0.7) {
38+
profileTitle = "Emotional Balance"; // High regulation
39+
description = "Bạn điều tiết cảm xúc một cách khéo léo.";
40+
} else if (avgAttentionStability > 0.8) {
41+
profileTitle = "Focused Attention"; // High attention
42+
description = "Bạn có khả năng tập trung ổn định tốt.";
4343
}
4444

4545
return {
4646
displayData,
47-
avgCoherence,
48-
avgPresence,
49-
avgEntanglement,
50-
archetype,
47+
avgAttentionStability,
48+
avgPresentMomentAwareness,
49+
avgEmotionalRegulation,
50+
profileTitle,
5151
description
5252
};
5353
}, [history]);
5454

5555
if (!analysis) return null;
5656

57-
const { displayData, avgCoherence, avgPresence, avgEntanglement, archetype, description } = analysis;
57+
const { displayData, avgAttentionStability, avgPresentMomentAwareness, avgEmotionalRegulation, profileTitle, description } = analysis;
5858

5959
const emotionColor = {
6060
anxious: 'border-orange-400 bg-orange-50',
@@ -87,27 +87,27 @@ export const HistoryPanel: React.FC<Props> = ({ history, onClear }) => {
8787
{/* Header */}
8888
<div className="bg-gradient-to-r from-stone-800 to-stone-900 text-amber-50 p-4 rounded-t-2xl flex items-center justify-between shadow-sm">
8989
<div className="flex items-center gap-2">
90-
<Fingerprint size={18} className="text-amber-400" />
91-
<h3 className="font-bold text-sm tracking-wide uppercase">Consciousness DNA</h3>
90+
<Brain size={18} className="text-amber-400" />
91+
<h3 className="font-bold text-sm tracking-wide uppercase">Mindfulness Profile</h3>
9292
</div>
9393
<button onClick={() => setIsOpen(false)} className="hover:bg-white/10 rounded-full p-1 transition-colors">
9494
<X size={18} />
9595
</button>
9696
</div>
9797

98-
{/* DNA Profile (New Feature) */}
98+
{/* Mindfulness Profile (Clinical Metrics) */}
9999
<div className="bg-stone-50 p-5 border-b border-stone-200">
100100
<div className="text-center mb-3">
101-
<span className="text-[10px] uppercase tracking-[0.2em] text-stone-400">Your Archetype</span>
102-
<h4 className="text-xl font-serif font-bold text-stone-800 mt-1">{archetype}</h4>
101+
<span className="text-[10px] uppercase tracking-[0.2em] text-stone-400">Practice Level</span>
102+
<h4 className="text-xl font-serif font-bold text-stone-800 mt-1">{profileTitle}</h4>
103103
<p className="text-xs text-stone-500 italic mt-1">{description}</p>
104104
</div>
105-
106-
{/* Mini DNA Bar Chart */}
105+
106+
{/* Mindfulness Metrics Bar Chart */}
107107
<div className="space-y-2 mt-4">
108-
<DnaBar label="Presence" value={avgPresence} color="bg-emerald-500" />
109-
<DnaBar label="Connection" value={avgEntanglement} color="bg-purple-500" />
110-
<DnaBar label="Clarity" value={avgCoherence} color="bg-blue-500" />
108+
<DnaBar label="Present Moment" value={avgPresentMomentAwareness} color="bg-emerald-500" />
109+
<DnaBar label="Emotion Regulation" value={avgEmotionalRegulation} color="bg-purple-500" />
110+
<DnaBar label="Attention" value={avgAttentionStability} color="bg-blue-500" />
111111
</div>
112112
</div>
113113

@@ -132,8 +132,8 @@ export const HistoryPanel: React.FC<Props> = ({ history, onClear }) => {
132132
<span className="text-[10px] text-stone-400 font-mono">{timeStr}</span>
133133
</div>
134134
<div className="flex gap-3 text-[10px] font-medium opacity-80">
135-
<span className="text-blue-600">C: {Math.round((entry.quantum_metrics?.coherence || 0) * 100)}</span>
136-
<span className="text-purple-600">E: {Math.round((entry.quantum_metrics?.entanglement || 0) * 100)}</span>
135+
<span className="text-blue-600">Attn: {Math.round((entry.mindfulness_metrics?.attention_stability || 0) * 100)}</span>
136+
<span className="text-purple-600">Reg: {Math.round((entry.mindfulness_metrics?.emotional_regulation || 0) * 100)}</span>
137137
</div>
138138
</div>
139139
);

components/NarrativeMemory.tsx

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
import React, { useEffect, useState } from 'react';
2+
import { BookOpen, TrendingUp, Target, AlertTriangle, X } from 'lucide-react';
3+
import { ConversationMemory } from '../types';
4+
import { ConversationMemoryService } from '../services/conversationMemoryService';
5+
6+
interface Props {
7+
isOpen: boolean;
8+
onClose: () => void;
9+
language: 'vi' | 'en';
10+
}
11+
12+
export const NarrativeMemory: React.FC<Props> = ({ isOpen, onClose, language }) => {
13+
const [memory, setMemory] = useState<ConversationMemory | null>(null);
14+
const [loading, setLoading] = useState(true);
15+
16+
useEffect(() => {
17+
if (isOpen) {
18+
loadMemory();
19+
}
20+
}, [isOpen]);
21+
22+
const loadMemory = async () => {
23+
setLoading(true);
24+
try {
25+
const data = await ConversationMemoryService.getMemory();
26+
setMemory(data);
27+
} catch (error) {
28+
console.error('[NarrativeMemory] Load failed:', error);
29+
}
30+
setLoading(false);
31+
};
32+
33+
if (!isOpen) return null;
34+
35+
const text = language === 'vi' ? {
36+
title: "Hành Trình Của Bạn",
37+
themes: "Chủ Đề Chính",
38+
progress: "Tiến Bộ",
39+
events: "Sự Kiện Gần Đây",
40+
triggers: "Yếu Tố Khởi Phát",
41+
baseline: "Tâm Trạng Cơ Bản",
42+
close: "Đóng",
43+
noData: "Chưa có dữ liệu",
44+
loading: "Đang tải..."
45+
} : {
46+
title: "Your Journey",
47+
themes: "Key Themes",
48+
progress: "Progress Markers",
49+
events: "Recent Events",
50+
triggers: "Identified Triggers",
51+
baseline: "Emotional Baseline",
52+
close: "Close",
53+
noData: "No data yet",
54+
loading: "Loading..."
55+
};
56+
57+
return (
58+
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm p-4">
59+
<div className="bg-white rounded-2xl shadow-2xl max-w-2xl w-full max-h-[85vh] overflow-y-auto">
60+
{/* Header */}
61+
<div className="bg-gradient-to-r from-indigo-600 to-purple-600 text-white p-6 rounded-t-2xl sticky top-0 z-10">
62+
<div className="flex items-center justify-between">
63+
<div className="flex items-center gap-3">
64+
<BookOpen size={24} />
65+
<h2 className="text-2xl font-bold">{text.title}</h2>
66+
</div>
67+
<button
68+
onClick={onClose}
69+
className="p-2 rounded-full hover:bg-white/20 transition-colors"
70+
>
71+
<X size={20} />
72+
</button>
73+
</div>
74+
</div>
75+
76+
{loading ? (
77+
<div className="p-12 text-center text-stone-500">
78+
{text.loading}
79+
</div>
80+
) : !memory ? (
81+
<div className="p-12 text-center text-stone-500">
82+
{text.noData}
83+
</div>
84+
) : (
85+
<div className="p-6 space-y-6">
86+
{/* Recurring Themes */}
87+
{memory.narrative.recurring_themes.length > 0 && (
88+
<Section
89+
icon={<TrendingUp size={18} className="text-orange-500" />}
90+
title={text.themes}
91+
>
92+
<div className="flex flex-wrap gap-2">
93+
{memory.narrative.recurring_themes.map((theme, idx) => (
94+
<span
95+
key={idx}
96+
className="px-3 py-1.5 bg-orange-50 text-orange-700 rounded-full text-sm font-medium border border-orange-200"
97+
>
98+
{theme}
99+
</span>
100+
))}
101+
</div>
102+
</Section>
103+
)}
104+
105+
{/* Progress Markers */}
106+
{memory.narrative.progress_markers.length > 0 && (
107+
<Section
108+
icon={<Target size={18} className="text-green-500" />}
109+
title={text.progress}
110+
>
111+
<ul className="space-y-2">
112+
{memory.narrative.progress_markers.map((marker, idx) => (
113+
<li
114+
key={idx}
115+
className="flex items-center gap-2 text-sm text-stone-700"
116+
>
117+
<div className="w-2 h-2 rounded-full bg-green-500"></div>
118+
{marker}
119+
</li>
120+
))}
121+
</ul>
122+
</Section>
123+
)}
124+
125+
{/* Recent Events */}
126+
{memory.narrative.key_events.length > 0 && (
127+
<Section
128+
icon={<BookOpen size={18} className="text-blue-500" />}
129+
title={text.events}
130+
>
131+
<div className="space-y-3">
132+
{memory.narrative.key_events.slice(-5).reverse().map((event, idx) => (
133+
<div
134+
key={idx}
135+
className="p-3 bg-blue-50 rounded-lg border border-blue-200"
136+
>
137+
<div className="flex items-center justify-between mb-1">
138+
<span className="text-xs font-bold text-blue-700 uppercase">
139+
{event.emotion}
140+
</span>
141+
<span className="text-xs text-blue-600">
142+
{new Date(event.timestamp).toLocaleDateString(language === 'vi' ? 'vi-VN' : 'en-US')}
143+
</span>
144+
</div>
145+
<p className="text-sm text-stone-700 line-clamp-2">
146+
{event.event}
147+
</p>
148+
</div>
149+
))}
150+
</div>
151+
</Section>
152+
)}
153+
154+
{/* Triggers */}
155+
{memory.emotional_baseline.triggers.size > 0 && (
156+
<Section
157+
icon={<AlertTriangle size={18} className="text-amber-500" />}
158+
title={text.triggers}
159+
>
160+
<div className="space-y-2">
161+
{Array.from(memory.emotional_baseline.triggers.entries())
162+
.sort((a, b) => b[1] - a[1])
163+
.slice(0, 5)
164+
.map(([trigger, intensity]) => (
165+
<div key={trigger} className="flex items-center gap-3">
166+
<div className="flex-1">
167+
<div className="flex items-center justify-between mb-1">
168+
<span className="text-sm font-medium text-stone-700">
169+
{trigger}
170+
</span>
171+
<span className="text-xs text-stone-500">
172+
{Math.round(intensity * 100)}%
173+
</span>
174+
</div>
175+
<div className="w-full bg-stone-200 rounded-full h-1.5">
176+
<div
177+
className="h-full bg-amber-500 rounded-full transition-all"
178+
style={{ width: `${intensity * 100}%` }}
179+
/>
180+
</div>
181+
</div>
182+
</div>
183+
))}
184+
</div>
185+
</Section>
186+
)}
187+
188+
{/* Emotional Baseline */}
189+
<Section
190+
icon={<TrendingUp size={18} className="text-purple-500" />}
191+
title={text.baseline}
192+
>
193+
<div className="bg-purple-50 rounded-lg p-4 border border-purple-200">
194+
<div className="flex items-center justify-between mb-2">
195+
<span className="text-sm text-purple-700 font-medium">
196+
{language === 'vi' ? 'Điểm trung bình' : 'Average Score'}
197+
</span>
198+
<span className="text-2xl font-bold text-purple-900">
199+
{memory.emotional_baseline.baseline_mood.toFixed(1)}/10
200+
</span>
201+
</div>
202+
{memory.emotional_baseline.current_deviation !== 0 && (
203+
<div className="text-xs text-purple-600">
204+
{memory.emotional_baseline.current_deviation > 0 ? '↑' : '↓'}{' '}
205+
{language === 'vi' ? 'Hiện tại' : 'Currently'}{' '}
206+
{Math.abs(memory.emotional_baseline.current_deviation).toFixed(1)}{' '}
207+
{memory.emotional_baseline.current_deviation > 0
208+
? language === 'vi' ? 'cao hơn' : 'above'
209+
: language === 'vi' ? 'thấp hơn' : 'below'
210+
}{' '}
211+
{language === 'vi' ? 'mức cơ bản' : 'baseline'}
212+
</div>
213+
)}
214+
</div>
215+
</Section>
216+
</div>
217+
)}
218+
219+
{/* Footer */}
220+
<div className="border-t border-stone-200 p-4 bg-stone-50 rounded-b-2xl">
221+
<button
222+
onClick={onClose}
223+
className="w-full py-3 px-4 rounded-lg bg-gradient-to-r from-indigo-600 to-purple-600 hover:from-indigo-700 hover:to-purple-700 text-white font-medium transition-all shadow-lg"
224+
>
225+
{text.close}
226+
</button>
227+
</div>
228+
</div>
229+
</div>
230+
);
231+
};
232+
233+
interface SectionProps {
234+
icon: React.ReactNode;
235+
title: string;
236+
children: React.ReactNode;
237+
}
238+
239+
const Section: React.FC<SectionProps> = ({ icon, title, children }) => {
240+
return (
241+
<div className="space-y-3">
242+
<div className="flex items-center gap-2">
243+
{icon}
244+
<h3 className="font-semibold text-stone-800">{title}</h3>
245+
</div>
246+
<div className="pl-7">{children}</div>
247+
</div>
248+
);
249+
};

0 commit comments

Comments
 (0)