escribano 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +297 -0
- package/dist/0_types.js +279 -0
- package/dist/actions/classify-session.js +77 -0
- package/dist/actions/create-contexts.js +44 -0
- package/dist/actions/create-topic-blocks.js +68 -0
- package/dist/actions/extract-metadata.js +24 -0
- package/dist/actions/generate-artifact-v3.js +296 -0
- package/dist/actions/generate-artifact.js +61 -0
- package/dist/actions/generate-summary-v3.js +260 -0
- package/dist/actions/outline-index.js +204 -0
- package/dist/actions/process-recording-v2.js +494 -0
- package/dist/actions/process-recording-v3.js +412 -0
- package/dist/actions/process-session.js +183 -0
- package/dist/actions/publish-summary-v3.js +303 -0
- package/dist/actions/sync-to-outline.js +196 -0
- package/dist/adapters/audio.silero.adapter.js +69 -0
- package/dist/adapters/cap.adapter.js +94 -0
- package/dist/adapters/capture.cap.adapter.js +107 -0
- package/dist/adapters/capture.filesystem.adapter.js +124 -0
- package/dist/adapters/embedding.ollama.adapter.js +141 -0
- package/dist/adapters/intelligence.adapter.js +202 -0
- package/dist/adapters/intelligence.mlx.adapter.js +395 -0
- package/dist/adapters/intelligence.ollama.adapter.js +741 -0
- package/dist/adapters/publishing.outline.adapter.js +75 -0
- package/dist/adapters/storage.adapter.js +81 -0
- package/dist/adapters/storage.fs.adapter.js +83 -0
- package/dist/adapters/transcription.whisper.adapter.js +206 -0
- package/dist/adapters/video.ffmpeg.adapter.js +405 -0
- package/dist/adapters/whisper.adapter.js +168 -0
- package/dist/batch-context.js +329 -0
- package/dist/db/helpers.js +50 -0
- package/dist/db/index.js +95 -0
- package/dist/db/migrate.js +80 -0
- package/dist/db/repositories/artifact.sqlite.js +77 -0
- package/dist/db/repositories/cluster.sqlite.js +92 -0
- package/dist/db/repositories/context.sqlite.js +75 -0
- package/dist/db/repositories/index.js +10 -0
- package/dist/db/repositories/observation.sqlite.js +70 -0
- package/dist/db/repositories/recording.sqlite.js +56 -0
- package/dist/db/repositories/subject.sqlite.js +64 -0
- package/dist/db/repositories/topic-block.sqlite.js +45 -0
- package/dist/db/types.js +4 -0
- package/dist/domain/classification.js +60 -0
- package/dist/domain/context.js +97 -0
- package/dist/domain/index.js +2 -0
- package/dist/domain/observation.js +17 -0
- package/dist/domain/recording.js +41 -0
- package/dist/domain/segment.js +93 -0
- package/dist/domain/session.js +93 -0
- package/dist/domain/time-range.js +38 -0
- package/dist/domain/transcript.js +79 -0
- package/dist/index.js +173 -0
- package/dist/pipeline/context.js +162 -0
- package/dist/pipeline/events.js +2 -0
- package/dist/prerequisites.js +226 -0
- package/dist/scripts/rebuild-index.js +53 -0
- package/dist/scripts/seed-fixtures.js +290 -0
- package/dist/services/activity-segmentation.js +333 -0
- package/dist/services/activity-segmentation.test.js +191 -0
- package/dist/services/app-normalization.js +212 -0
- package/dist/services/cluster-merge.js +69 -0
- package/dist/services/clustering.js +237 -0
- package/dist/services/debug.js +58 -0
- package/dist/services/frame-sampling.js +318 -0
- package/dist/services/signal-extraction.js +106 -0
- package/dist/services/subject-grouping.js +342 -0
- package/dist/services/temporal-alignment.js +99 -0
- package/dist/services/vlm-enrichment.js +84 -0
- package/dist/services/vlm-service.js +130 -0
- package/dist/stats/index.js +3 -0
- package/dist/stats/observer.js +65 -0
- package/dist/stats/repository.js +36 -0
- package/dist/stats/resource-tracker.js +86 -0
- package/dist/stats/types.js +1 -0
- package/dist/test-classification-prompts.js +181 -0
- package/dist/tests/cap.adapter.test.js +75 -0
- package/dist/tests/capture.cap.adapter.test.js +69 -0
- package/dist/tests/classify-session.test.js +140 -0
- package/dist/tests/db/repositories.test.js +243 -0
- package/dist/tests/domain/time-range.test.js +31 -0
- package/dist/tests/integration.test.js +84 -0
- package/dist/tests/intelligence.adapter.test.js +102 -0
- package/dist/tests/intelligence.ollama.adapter.test.js +178 -0
- package/dist/tests/process-v2.test.js +90 -0
- package/dist/tests/services/clustering.test.js +112 -0
- package/dist/tests/services/frame-sampling.test.js +152 -0
- package/dist/tests/utils/ocr.test.js +76 -0
- package/dist/tests/utils/parallel.test.js +57 -0
- package/dist/tests/visual-observer.test.js +175 -0
- package/dist/utils/id-normalization.js +15 -0
- package/dist/utils/index.js +9 -0
- package/dist/utils/model-detector.js +154 -0
- package/dist/utils/ocr.js +80 -0
- package/dist/utils/parallel.js +32 -0
- package/migrations/001_initial.sql +109 -0
- package/migrations/002_clusters.sql +41 -0
- package/migrations/003_observations_vlm_fields.sql +14 -0
- package/migrations/004_observations_unique.sql +18 -0
- package/migrations/005_processing_stats.sql +29 -0
- package/migrations/006_vlm_raw_response.sql +6 -0
- package/migrations/007_subjects.sql +23 -0
- package/migrations/008_artifacts_recording.sql +6 -0
- package/migrations/009_artifact_subjects.sql +10 -0
- package/package.json +82 -0
- package/prompts/action-items.md +55 -0
- package/prompts/blog-draft.md +54 -0
- package/prompts/blog-research.md +87 -0
- package/prompts/card.md +54 -0
- package/prompts/classify-segment.md +38 -0
- package/prompts/classify.md +37 -0
- package/prompts/code-snippets.md +163 -0
- package/prompts/extract-metadata.md +149 -0
- package/prompts/notes.md +83 -0
- package/prompts/runbook.md +123 -0
- package/prompts/standup.md +50 -0
- package/prompts/step-by-step.md +125 -0
- package/prompts/subject-grouping.md +31 -0
- package/prompts/summary-v3.md +89 -0
- package/prompts/summary.md +77 -0
- package/prompts/topic-classifier.md +24 -0
- package/prompts/topic-extract.md +13 -0
- package/prompts/vlm-batch.md +21 -0
- package/prompts/vlm-single.md +19 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prerequisite Checker for Escribano CLI
|
|
3
|
+
*
|
|
4
|
+
* Checks for required dependencies and provides install instructions
|
|
5
|
+
*/
|
|
6
|
+
import { execSync } from 'node:child_process';
|
|
7
|
+
const LLM_MODEL_TIERS = [
|
|
8
|
+
{ model: 'qwen3.5:27b', tier: 4, minRamGB: 32, label: 'best' },
|
|
9
|
+
{ model: 'qwen3:14b', tier: 3, minRamGB: 20, label: 'very good' },
|
|
10
|
+
{ model: 'qwen3:8b', tier: 2, minRamGB: 10, label: 'good' },
|
|
11
|
+
{ model: 'qwen3:4b', tier: 1, minRamGB: 6, label: 'minimum' },
|
|
12
|
+
];
|
|
13
|
+
const PREREQUISITES = [
|
|
14
|
+
{
|
|
15
|
+
name: 'Node.js',
|
|
16
|
+
found: false,
|
|
17
|
+
installCommand: 'brew install node',
|
|
18
|
+
notes: 'Requires Node.js 20+',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: 'ffmpeg',
|
|
22
|
+
found: false,
|
|
23
|
+
installCommand: 'brew install ffmpeg',
|
|
24
|
+
notes: 'Required for video processing and scene detection',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: 'whisper-cli',
|
|
28
|
+
found: false,
|
|
29
|
+
installCommand: 'brew install whisper-cpp',
|
|
30
|
+
notes: 'Required for audio transcription',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: 'ollama',
|
|
34
|
+
found: false,
|
|
35
|
+
installCommand: 'brew install ollama',
|
|
36
|
+
notes: 'Required for LLM summary generation',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'ollama (running)',
|
|
40
|
+
found: false,
|
|
41
|
+
installCommand: 'ollama serve',
|
|
42
|
+
notes: 'Ollama server must be running',
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: 'LLM model',
|
|
46
|
+
found: false,
|
|
47
|
+
installCommand: 'ollama pull qwen3:8b',
|
|
48
|
+
notes: 'Any of: qwen3.5:27b, qwen3:14b, qwen3:8b, qwen3:4b',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: 'Python 3',
|
|
52
|
+
found: false,
|
|
53
|
+
installCommand: 'brew install python3',
|
|
54
|
+
notes: 'Required for MLX-VLM frame analysis',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: 'mlx-vlm',
|
|
58
|
+
found: false,
|
|
59
|
+
installCommand: 'pip install mlx-vlm',
|
|
60
|
+
notes: 'VLM library for frame analysis (Apple Silicon)',
|
|
61
|
+
},
|
|
62
|
+
];
|
|
63
|
+
function checkCommand(command, args = ['--version']) {
|
|
64
|
+
try {
|
|
65
|
+
const output = execSync(`${command} ${args.join(' ')}`, {
|
|
66
|
+
encoding: 'utf-8',
|
|
67
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
68
|
+
timeout: 5000,
|
|
69
|
+
});
|
|
70
|
+
const version = output.split('\n')[0].trim().slice(0, 50);
|
|
71
|
+
return { found: true, version };
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return { found: false };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function checkOllamaRunning() {
|
|
78
|
+
try {
|
|
79
|
+
execSync('curl -s http://localhost:11434/api/tags', {
|
|
80
|
+
encoding: 'utf-8',
|
|
81
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
82
|
+
timeout: 5000,
|
|
83
|
+
});
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function getInstalledOllamaModels() {
|
|
91
|
+
try {
|
|
92
|
+
const output = execSync('ollama list', {
|
|
93
|
+
encoding: 'utf-8',
|
|
94
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
95
|
+
timeout: 10000,
|
|
96
|
+
});
|
|
97
|
+
const lines = output.split('\n').slice(1);
|
|
98
|
+
return lines
|
|
99
|
+
.map((line) => line.split(/\s+/)[0])
|
|
100
|
+
.filter((m) => m && m.length > 0);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return [];
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function checkLLMModels() {
|
|
107
|
+
const installed = getInstalledOllamaModels();
|
|
108
|
+
const foundModels = [];
|
|
109
|
+
let bestAvailable = null;
|
|
110
|
+
let bestTier = 0;
|
|
111
|
+
for (const tier of LLM_MODEL_TIERS) {
|
|
112
|
+
const found = installed.some((m) => m.startsWith(tier.model.split(':')[0]));
|
|
113
|
+
if (found) {
|
|
114
|
+
foundModels.push(tier.model);
|
|
115
|
+
if (tier.tier > bestTier) {
|
|
116
|
+
bestTier = tier.tier;
|
|
117
|
+
bestAvailable = tier.model;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
found: foundModels.length > 0,
|
|
123
|
+
foundModels,
|
|
124
|
+
bestAvailable,
|
|
125
|
+
installCommand: 'ollama pull qwen3:8b',
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function checkPythonPackage(packageName) {
|
|
129
|
+
try {
|
|
130
|
+
execSync(`python3 -c "import ${packageName}"`, {
|
|
131
|
+
encoding: 'utf-8',
|
|
132
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
133
|
+
timeout: 5000,
|
|
134
|
+
});
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
export function checkPrerequisites() {
|
|
142
|
+
const results = [];
|
|
143
|
+
for (const prereq of PREREQUISITES) {
|
|
144
|
+
const result = { ...prereq };
|
|
145
|
+
switch (prereq.name) {
|
|
146
|
+
case 'Node.js': {
|
|
147
|
+
const check = checkCommand('node', ['--version']);
|
|
148
|
+
result.found = check.found;
|
|
149
|
+
result.version = check.version;
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
case 'ffmpeg': {
|
|
153
|
+
const check = checkCommand('ffmpeg', ['-version']);
|
|
154
|
+
result.found = check.found;
|
|
155
|
+
result.version = check.version?.split(' ')[2];
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
case 'whisper-cli': {
|
|
159
|
+
const check = checkCommand('whisper-cli', ['--version']);
|
|
160
|
+
result.found = check.found;
|
|
161
|
+
result.version = check.version;
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
case 'ollama': {
|
|
165
|
+
const check = checkCommand('ollama', ['--version']);
|
|
166
|
+
result.found = check.found;
|
|
167
|
+
result.version = check.version;
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
case 'ollama (running)': {
|
|
171
|
+
result.found = checkOllamaRunning();
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
case 'LLM model': {
|
|
175
|
+
const check = checkLLMModels();
|
|
176
|
+
result.found = check.found;
|
|
177
|
+
if (check.bestAvailable) {
|
|
178
|
+
result.version = check.bestAvailable;
|
|
179
|
+
result.notes = `Found: ${check.foundModels.join(', ')}`;
|
|
180
|
+
}
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
case 'Python 3': {
|
|
184
|
+
const check = checkCommand('python3', ['--version']);
|
|
185
|
+
result.found = check.found;
|
|
186
|
+
result.version = check.version;
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
case 'mlx-vlm': {
|
|
190
|
+
result.found = checkPythonPackage('mlx_vlm');
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
results.push(result);
|
|
195
|
+
}
|
|
196
|
+
return results;
|
|
197
|
+
}
|
|
198
|
+
export function printDoctorResults(results) {
|
|
199
|
+
console.log('Checking prerequisites...\n');
|
|
200
|
+
const missing = [];
|
|
201
|
+
for (const result of results) {
|
|
202
|
+
const icon = result.found ? '✓' : '✗';
|
|
203
|
+
const version = result.version ? ` (${result.version})` : '';
|
|
204
|
+
console.log(`${icon} ${result.name}${version}`);
|
|
205
|
+
if (!result.found) {
|
|
206
|
+
missing.push(result);
|
|
207
|
+
if (result.installCommand) {
|
|
208
|
+
console.log(` → Install: ${result.installCommand}`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
else if (result.notes) {
|
|
212
|
+
console.log(` ${result.notes}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
console.log('');
|
|
216
|
+
if (missing.length === 0) {
|
|
217
|
+
console.log('✓ All prerequisites satisfied. Ready to process recordings.');
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
console.log(`Missing ${missing.length} prerequisite${missing.length > 1 ? 's' : ''}.`);
|
|
221
|
+
console.log('Run the install commands above and try again.');
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
export function hasMissingPrerequisites(results) {
|
|
225
|
+
return results.some((r) => !r.found);
|
|
226
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Escribano - Rebuild Index Script
|
|
3
|
+
*
|
|
4
|
+
* Rebuilds the global session index in Outline without reprocessing recordings.
|
|
5
|
+
* Use this when the index gets out of sync with published summaries.
|
|
6
|
+
*/
|
|
7
|
+
import { updateGlobalIndex } from '../actions/outline-index.js';
|
|
8
|
+
import { createOutlinePublishingService } from '../adapters/publishing.outline.adapter.js';
|
|
9
|
+
import { getDbPath, getRepositories } from '../db/index.js';
|
|
10
|
+
function getOutlineConfig() {
|
|
11
|
+
const url = process.env.ESCRIBANO_OUTLINE_URL;
|
|
12
|
+
const token = process.env.ESCRIBANO_OUTLINE_TOKEN;
|
|
13
|
+
if (!url || !token) {
|
|
14
|
+
console.error('Error: ESCRIBANO_OUTLINE_URL and ESCRIBANO_OUTLINE_TOKEN must be set');
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
url,
|
|
19
|
+
token,
|
|
20
|
+
collectionName: process.env.ESCRIBANO_OUTLINE_COLLECTION ?? 'Escribano Sessions',
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
async function main() {
|
|
24
|
+
console.log('Escribano - Rebuild Index');
|
|
25
|
+
console.log('');
|
|
26
|
+
const outlineConfig = getOutlineConfig();
|
|
27
|
+
if (!outlineConfig) {
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
// Initialize database
|
|
31
|
+
console.log('Initializing database...');
|
|
32
|
+
const repos = getRepositories();
|
|
33
|
+
console.log(`Database ready: ${getDbPath()}`);
|
|
34
|
+
console.log('');
|
|
35
|
+
// Get count of published recordings
|
|
36
|
+
const publishedRecordings = repos.recordings.findByStatus('published');
|
|
37
|
+
console.log(`Found ${publishedRecordings.length} published recordings`);
|
|
38
|
+
console.log('');
|
|
39
|
+
// Initialize publishing service
|
|
40
|
+
const publishing = createOutlinePublishingService(outlineConfig);
|
|
41
|
+
// Update global index
|
|
42
|
+
console.log('Rebuilding global index...');
|
|
43
|
+
const indexResult = await updateGlobalIndex(repos, publishing, {
|
|
44
|
+
collectionName: outlineConfig.collectionName,
|
|
45
|
+
});
|
|
46
|
+
console.log('');
|
|
47
|
+
console.log('✓ Index rebuilt successfully!');
|
|
48
|
+
console.log(`Index URL: ${indexResult.url}`);
|
|
49
|
+
}
|
|
50
|
+
main().catch((error) => {
|
|
51
|
+
console.error('Error:', error.message);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
});
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seed Fixtures for Escribano Artifact Testing
|
|
3
|
+
*
|
|
4
|
+
* Injects synthetic sessions with realistic transcripts into storage
|
|
5
|
+
* to test all 8 artifact generation prompts.
|
|
6
|
+
*/
|
|
7
|
+
import { createFsStorageService } from '../adapters/storage.fs.adapter.js';
|
|
8
|
+
const storage = createFsStorageService();
|
|
9
|
+
const createBaseSession = (id, transcript, classification) => {
|
|
10
|
+
const date = new Date();
|
|
11
|
+
return {
|
|
12
|
+
id,
|
|
13
|
+
recording: {
|
|
14
|
+
id: `rec-${id}`,
|
|
15
|
+
source: { type: 'raw', originalPath: `/fixtures/${id}` },
|
|
16
|
+
videoPath: null,
|
|
17
|
+
audioMicPath: `/fixtures/${id}/audio.mp3`,
|
|
18
|
+
audioSystemPath: null,
|
|
19
|
+
duration: transcript.duration,
|
|
20
|
+
capturedAt: date,
|
|
21
|
+
},
|
|
22
|
+
transcripts: [{ source: 'mic', transcript }],
|
|
23
|
+
visualLogs: [],
|
|
24
|
+
segments: [],
|
|
25
|
+
status: 'classified',
|
|
26
|
+
classification,
|
|
27
|
+
metadata: null,
|
|
28
|
+
artifacts: [],
|
|
29
|
+
createdAt: date,
|
|
30
|
+
updatedAt: date,
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
const FIXTURES = [
|
|
34
|
+
// 1. DEBUGGING -> Runbook
|
|
35
|
+
createBaseSession('fixture-debugging', {
|
|
36
|
+
fullText: "Okay, I'm seeing a hydration error in the console. 'Text content does not match server-rendered HTML'. It's happening in the Header component. Let me check the code. Ah, I see, I'm using a random number in the rendering. That's a classic mistake. The server generates one number, the client generates another. I should move this to a useEffect or use a constant. Let me try using a fixed ID for now. Okay, applied the fix. Refreshing... Error is gone. Verification successful.",
|
|
37
|
+
segments: [
|
|
38
|
+
{
|
|
39
|
+
id: '1',
|
|
40
|
+
start: 0,
|
|
41
|
+
end: 10,
|
|
42
|
+
text: "Okay, I'm seeing a hydration error in the console.",
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: '2',
|
|
46
|
+
start: 10,
|
|
47
|
+
end: 20,
|
|
48
|
+
text: "'Text content does not match server-rendered HTML'.",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: '3',
|
|
52
|
+
start: 20,
|
|
53
|
+
end: 30,
|
|
54
|
+
text: "It's happening in the Header component. Let me check the code.",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: '4',
|
|
58
|
+
start: 30,
|
|
59
|
+
end: 45,
|
|
60
|
+
text: "Ah, I see, I'm using a random number in the rendering. That's a classic mistake.",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
id: '5',
|
|
64
|
+
start: 45,
|
|
65
|
+
end: 60,
|
|
66
|
+
text: 'I should move this to a useEffect or use a constant.',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
id: '6',
|
|
70
|
+
start: 60,
|
|
71
|
+
end: 75,
|
|
72
|
+
text: 'Let me try using a fixed ID for now. Okay, applied the fix.',
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: '7',
|
|
76
|
+
start: 75,
|
|
77
|
+
end: 90,
|
|
78
|
+
text: 'Refreshing... Error is gone. Verification successful.',
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
language: 'en',
|
|
82
|
+
duration: 90,
|
|
83
|
+
}, { meeting: 0, debugging: 95, tutorial: 10, learning: 20, working: 30 }),
|
|
84
|
+
// 2. TUTORIAL -> Step-by-Step
|
|
85
|
+
createBaseSession('fixture-tutorial', {
|
|
86
|
+
fullText: "Today I will show you how to set up a Docker container for a Node.js app. First, you need to create a Dockerfile in your root directory. Inside, start with 'FROM node:18'. Then set the working directory to /app. Next, copy the package.json and run 'npm install'. After that, copy the rest of your files. Finally, expose port 3000 and run 'node index.js'. To build it, run 'docker build -t my-app .'. Then run it with 'docker run -p 3000:3000 my-app'. If you see an error about port already in use, make sure to stop any other containers first.",
|
|
87
|
+
segments: [
|
|
88
|
+
{
|
|
89
|
+
id: '1',
|
|
90
|
+
start: 0,
|
|
91
|
+
end: 10,
|
|
92
|
+
text: 'Today I will show you how to set up a Docker container for a Node.js app.',
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
id: '2',
|
|
96
|
+
start: 10,
|
|
97
|
+
end: 25,
|
|
98
|
+
text: 'First, you need to create a Dockerfile in your root directory.',
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
id: '3',
|
|
102
|
+
start: 25,
|
|
103
|
+
end: 35,
|
|
104
|
+
text: "Inside, start with 'FROM node:18'. Then set the working directory to /app.",
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
id: '4',
|
|
108
|
+
start: 35,
|
|
109
|
+
end: 50,
|
|
110
|
+
text: "Next, copy the package.json and run 'npm install'. After that, copy the rest of your files.",
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
id: '5',
|
|
114
|
+
start: 50,
|
|
115
|
+
end: 65,
|
|
116
|
+
text: "Finally, expose port 3000 and run 'node index.js'.",
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
id: '6',
|
|
120
|
+
start: 65,
|
|
121
|
+
end: 80,
|
|
122
|
+
text: "To build it, run 'docker build -t my-app .'.",
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
id: '7',
|
|
126
|
+
start: 80,
|
|
127
|
+
end: 95,
|
|
128
|
+
text: "Then run it with 'docker run -p 3000:3000 my-app'.",
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
id: '8',
|
|
132
|
+
start: 95,
|
|
133
|
+
end: 110,
|
|
134
|
+
text: 'If you see an error about port already in use, make sure to stop any other containers first.',
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
language: 'en',
|
|
138
|
+
duration: 110,
|
|
139
|
+
}, { meeting: 0, debugging: 5, tutorial: 95, learning: 10, working: 40 }),
|
|
140
|
+
// 3. WORKING -> Code Snippets
|
|
141
|
+
createBaseSession('fixture-working', {
|
|
142
|
+
fullText: "I'm going to implement the auth middleware today. I'll use JWT for session management. First, let me define the verifyToken function. It should take the request, response, and next function. I'll pull the token from the Authorization header. If it starts with 'Bearer ', I'll strip that. Then I use jwt.verify with our secret key. If it fails, I return a 401. If it passes, I attach the user payload to the request and call next. This looks solid. I should also add a check for token expiration.",
|
|
143
|
+
segments: [
|
|
144
|
+
{
|
|
145
|
+
id: '1',
|
|
146
|
+
start: 0,
|
|
147
|
+
end: 15,
|
|
148
|
+
text: "I'm going to implement the auth middleware today. I'll use JWT for session management.",
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
id: '2',
|
|
152
|
+
start: 15,
|
|
153
|
+
end: 30,
|
|
154
|
+
text: 'First, let me define the verifyToken function. It should take req, res, and next.',
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
id: '3',
|
|
158
|
+
start: 30,
|
|
159
|
+
end: 45,
|
|
160
|
+
text: "I'll pull the token from the Authorization header. If it starts with 'Bearer ', I'll strip that.",
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
id: '4',
|
|
164
|
+
start: 45,
|
|
165
|
+
end: 60,
|
|
166
|
+
text: 'Then I use jwt.verify with our secret key. If it fails, I return a 401.',
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
id: '5',
|
|
170
|
+
start: 60,
|
|
171
|
+
end: 75,
|
|
172
|
+
text: 'If it passes, I attach the user payload to the request and call next.',
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
id: '6',
|
|
176
|
+
start: 75,
|
|
177
|
+
end: 90,
|
|
178
|
+
text: 'This looks solid. I should also add a check for token expiration.',
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
language: 'en',
|
|
182
|
+
duration: 90,
|
|
183
|
+
}, { meeting: 10, debugging: 10, tutorial: 20, learning: 15, working: 90 }),
|
|
184
|
+
// 4. LEARNING -> Research Notes
|
|
185
|
+
createBaseSession('fixture-learning', {
|
|
186
|
+
fullText: "Let me understand how vector databases work. They store data as high-dimensional vectors, which are just arrays of numbers. This allows for similarity search, which is different from traditional keyword search. I'm looking at Pinecone and Milvus. Pinecone is a managed service, very easy to start. Milvus is open-source and highly scalable. Similarity is calculated using cosine similarity or Euclidean distance. This is crucial for RAG applications because it allows the LLM to find relevant context from a large knowledge base. The main challenge seems to be index management and dimensionality reduction.",
|
|
187
|
+
segments: [
|
|
188
|
+
{
|
|
189
|
+
id: '1',
|
|
190
|
+
start: 0,
|
|
191
|
+
end: 15,
|
|
192
|
+
text: 'Let me understand how vector databases work. They store data as high-dimensional vectors.',
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
id: '2',
|
|
196
|
+
start: 15,
|
|
197
|
+
end: 30,
|
|
198
|
+
text: 'This allows for similarity search, which is different from traditional keyword search.',
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
id: '3',
|
|
202
|
+
start: 30,
|
|
203
|
+
end: 45,
|
|
204
|
+
text: "I'm looking at Pinecone and Milvus. Pinecone is managed, Milvus is open-source.",
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
id: '4',
|
|
208
|
+
start: 45,
|
|
209
|
+
end: 60,
|
|
210
|
+
text: 'Similarity is calculated using cosine similarity or Euclidean distance.',
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
id: '5',
|
|
214
|
+
start: 60,
|
|
215
|
+
end: 75,
|
|
216
|
+
text: 'This is crucial for RAG applications for finding relevant context.',
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
id: '6',
|
|
220
|
+
start: 75,
|
|
221
|
+
end: 90,
|
|
222
|
+
text: 'The main challenge seems to be index management and dimensionality reduction.',
|
|
223
|
+
},
|
|
224
|
+
],
|
|
225
|
+
language: 'en',
|
|
226
|
+
duration: 90,
|
|
227
|
+
}, { meeting: 5, debugging: 0, tutorial: 10, learning: 95, working: 20 }),
|
|
228
|
+
// 5. MEETING -> Action Items / Summary
|
|
229
|
+
createBaseSession('fixture-meeting', {
|
|
230
|
+
fullText: "Thanks for joining the Q1 planning meeting. Our main goal is to launch the mobile app by March. Alice, you are in charge of the UI design, please finish the mockups by next Friday. Bob, you need to set up the backend API, specifically the user authentication and profile endpoints. I will handle the stakeholder communication and budget. We decided to use React Native for the app to save time. We still need to decide on the push notification provider. Let's meet again next Tuesday to review progress.",
|
|
231
|
+
segments: [
|
|
232
|
+
{
|
|
233
|
+
id: '1',
|
|
234
|
+
start: 0,
|
|
235
|
+
end: 10,
|
|
236
|
+
text: 'Thanks for joining the Q1 planning meeting. Our main goal is to launch the mobile app by March.',
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
id: '2',
|
|
240
|
+
start: 10,
|
|
241
|
+
end: 25,
|
|
242
|
+
text: 'Alice, you are in charge of the UI design, please finish the mockups by next Friday.',
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
id: '3',
|
|
246
|
+
start: 25,
|
|
247
|
+
end: 40,
|
|
248
|
+
text: 'Bob, you need to set up the backend API, user authentication and profile endpoints.',
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
id: '4',
|
|
252
|
+
start: 40,
|
|
253
|
+
end: 55,
|
|
254
|
+
text: 'I will handle the stakeholder communication and budget.',
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
id: '5',
|
|
258
|
+
start: 55,
|
|
259
|
+
end: 70,
|
|
260
|
+
text: 'We decided to use React Native for the app to save time.',
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
id: '6',
|
|
264
|
+
start: 70,
|
|
265
|
+
end: 85,
|
|
266
|
+
text: 'We still need to decide on the push notification provider.',
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
id: '7',
|
|
270
|
+
start: 85,
|
|
271
|
+
end: 100,
|
|
272
|
+
text: "Let's meet again next Tuesday to review progress.",
|
|
273
|
+
},
|
|
274
|
+
],
|
|
275
|
+
language: 'en',
|
|
276
|
+
duration: 100,
|
|
277
|
+
}, { meeting: 95, debugging: 0, tutorial: 5, learning: 20, working: 10 }),
|
|
278
|
+
];
|
|
279
|
+
async function seed() {
|
|
280
|
+
console.log('🌱 Seeding synthetic session fixtures...');
|
|
281
|
+
for (const session of FIXTURES) {
|
|
282
|
+
await storage.saveSession(session);
|
|
283
|
+
console.log(` ✓ Seeded session: ${session.id}`);
|
|
284
|
+
}
|
|
285
|
+
console.log('✅ Seeding complete.');
|
|
286
|
+
}
|
|
287
|
+
seed().catch((err) => {
|
|
288
|
+
console.error('❌ Seeding failed:', err);
|
|
289
|
+
process.exit(1);
|
|
290
|
+
});
|