@haposoft/cafekit 0.13.4 → 0.14.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/README.md +2 -23
- package/bin/lib/i18n.js +2 -2
- package/bin/lib/manifest.js +15 -0
- package/bin/lib/opencode-install.js +0 -14
- package/bin/phases/claude-runtime.js +4 -1
- package/bin/phases/claude-settings.js +38 -7
- package/bin/phases/root-config.js +5 -24
- package/package.json +1 -1
- package/src/claude/agents/ui-ux-designer.md +4 -4
- package/src/claude/gitignore +4 -11
- package/src/claude/hooks/__tests__/privacy-block.test.js +79 -0
- package/src/claude/hooks/__tests__/session-writeenv.test.js +68 -0
- package/src/claude/hooks/__tests__/spec-gate.test.js +270 -0
- package/src/claude/hooks/privacy-block.cjs +22 -2
- package/src/claude/hooks/session.cjs +5 -1
- package/src/claude/hooks/spec-gate.cjs +173 -0
- package/src/claude/hooks/spec-state.cjs +10 -17
- package/src/claude/hooks/task-scaffold-guard.cjs +4 -2
- package/src/claude/migration-manifest.json +5 -5
- package/src/claude/rules/skill-domain-routing.md +2 -3
- package/src/claude/rules/skill-workflow-routing.md +2 -11
- package/src/claude/rules/state-sync.md +4 -0
- package/src/claude/runtime.json +4 -0
- package/src/claude/scripts/validate-docs.cjs +4 -7
- package/src/claude/scripts/validate-spec-output.cjs +29 -9
- package/src/claude/settings/settings.json +4 -0
- package/src/claude/skills/ai-multimodal/.env.example +11 -13
- package/src/claude/skills/ai-multimodal/SKILL.md +1 -1
- package/src/claude/skills/ai-multimodal/references/audio-processing.md +25 -27
- package/src/claude/skills/ai-multimodal/references/video-analysis.md +23 -27
- package/src/claude/skills/ai-multimodal/references/vision-understanding.md +26 -26
- package/src/claude/skills/ai-multimodal/scripts/check_setup.py +1 -1
- package/src/claude/skills/ai-multimodal/scripts/gemini_batch_process.py +7 -9
- package/src/claude/skills/brainstorm/SKILL.md +1 -2
- package/src/claude/skills/docx/SKILL.md +1 -1
- package/src/claude/skills/frontend-design/SKILL.md +1 -1
- package/src/claude/skills/frontend-design/references/ai-multimodal-overview.md +4 -4
- package/src/claude/skills/frontend-design/references/analysis-techniques.md +3 -3
- package/src/claude/skills/frontend-design/references/asset-generation.md +2 -2
- package/src/claude/skills/frontend-design/references/design-extraction-overview.md +4 -4
- package/src/claude/skills/frontend-design/references/extraction-best-practices.md +3 -3
- package/src/claude/skills/frontend-design/references/technical-accessibility.md +1 -1
- package/src/claude/skills/frontend-design/references/technical-optimization.md +1 -1
- package/src/claude/skills/frontend-design/references/technical-overview.md +2 -2
- package/src/claude/skills/frontend-design/references/technical-workflows.md +6 -6
- package/src/claude/skills/frontend-design/references/visual-analysis-overview.md +3 -3
- package/src/claude/skills/inspect/SKILL.md +3 -3
- package/src/claude/skills/inspect/references/external-gemini-inspection.md +9 -9
- package/src/claude/skills/pdf/SKILL.md +1 -1
- package/src/claude/skills/pptx/SKILL.md +1 -1
- package/src/claude/skills/specs/SKILL.md +1 -1
- package/src/claude/skills/xlsx/SKILL.md +1 -1
- package/src/opencode/AGENTS.md +1 -2
- package/src/opencode/plugins/session.ts +2 -2
- package/src/opencode/plugins/spec-state.ts +244 -0
- package/src/opencode/plugins/task-scaffold-guard.ts +161 -0
- package/src/claude/scripts/browser-tool.cjs +0 -138
- package/src/claude/skills/delegate/SKILL.md +0 -124
- package/src/claude/skills/delegate/references/codex-delegation.md +0 -71
- package/src/claude/skills/delegate/references/grok-delegation.md +0 -84
- package/src/claude/skills/generate-graph/LICENSE +0 -21
- package/src/claude/skills/generate-graph/README.md +0 -523
- package/src/claude/skills/generate-graph/SKILL.md +0 -429
- package/src/claude/skills/generate-graph/agentloop-core.svg +0 -101
- package/src/claude/skills/generate-graph/agents/openai.yaml +0 -4
- package/src/claude/skills/generate-graph/assets/samples/sample-style1-flat.png +0 -0
- package/src/claude/skills/generate-graph/assets/samples/sample-style2-dark.png +0 -0
- package/src/claude/skills/generate-graph/assets/samples/sample-style3-blueprint.png +0 -0
- package/src/claude/skills/generate-graph/assets/samples/sample-style4-notion.png +0 -0
- package/src/claude/skills/generate-graph/assets/samples/sample-style5-glass.png +0 -0
- package/src/claude/skills/generate-graph/assets/samples/sample-style6-claude.png +0 -0
- package/src/claude/skills/generate-graph/assets/samples/sample-style7-openai.png +0 -0
- package/src/claude/skills/generate-graph/fixtures/agent-memory-types-style4.json +0 -181
- package/src/claude/skills/generate-graph/fixtures/api-flow-style7.json +0 -40
- package/src/claude/skills/generate-graph/fixtures/mem0-style1.json +0 -297
- package/src/claude/skills/generate-graph/fixtures/microservices-style3.json +0 -64
- package/src/claude/skills/generate-graph/fixtures/multi-agent-style5.json +0 -45
- package/src/claude/skills/generate-graph/fixtures/system-architecture-style6.json +0 -48
- package/src/claude/skills/generate-graph/fixtures/tool-call-style2.json +0 -182
- package/src/claude/skills/generate-graph/package.json +0 -42
- package/src/claude/skills/generate-graph/references/icons.md +0 -281
- package/src/claude/skills/generate-graph/references/style-1-flat-icon.md +0 -108
- package/src/claude/skills/generate-graph/references/style-2-dark-terminal.md +0 -107
- package/src/claude/skills/generate-graph/references/style-3-blueprint.md +0 -113
- package/src/claude/skills/generate-graph/references/style-4-notion-clean.md +0 -94
- package/src/claude/skills/generate-graph/references/style-5-glassmorphism.md +0 -125
- package/src/claude/skills/generate-graph/references/style-6-claude-official.md +0 -209
- package/src/claude/skills/generate-graph/references/style-7-openai.md +0 -215
- package/src/claude/skills/generate-graph/references/style-diagram-matrix.md +0 -135
- package/src/claude/skills/generate-graph/references/svg-layout-best-practices.md +0 -100
- package/src/claude/skills/generate-graph/scripts/generate-diagram.sh +0 -157
- package/src/claude/skills/generate-graph/scripts/generate-from-template.py +0 -1556
- package/src/claude/skills/generate-graph/scripts/test-all-styles.sh +0 -135
- package/src/claude/skills/generate-graph/scripts/validate-svg.sh +0 -292
- package/src/claude/skills/generate-graph/templates/agent-architecture.svg +0 -28
- package/src/claude/skills/generate-graph/templates/architecture.svg +0 -23
- package/src/claude/skills/generate-graph/templates/comparison-matrix.svg +0 -14
- package/src/claude/skills/generate-graph/templates/data-flow.svg +0 -28
- package/src/claude/skills/generate-graph/templates/er-diagram.svg +0 -21
- package/src/claude/skills/generate-graph/templates/flowchart.svg +0 -21
- package/src/claude/skills/generate-graph/templates/sequence.svg +0 -20
- package/src/claude/skills/generate-graph/templates/state-machine.svg +0 -20
- package/src/claude/skills/generate-graph/templates/timeline.svg +0 -19
- package/src/claude/skills/generate-graph/templates/use-case.svg +0 -21
- package/src/claude/skills/impact-analysis/SKILL.md +0 -276
- package/src/claude/skills/impact-analysis/references/change-detection.md +0 -270
- package/src/claude/skills/impact-analysis/references/dependency-scouting.md +0 -338
- package/src/claude/skills/impact-analysis/references/edge-case-identification.md +0 -439
- package/src/claude/skills/impact-analysis/references/industry-techniques.md +0 -695
- package/src/claude/skills/impact-analysis/references/practical-techniques-guide.md +0 -753
- package/src/claude/skills/impact-analysis/references/project-detection.md +0 -704
- package/src/claude/skills/impact-analysis/references/react-native-customization.md +0 -508
- package/src/claude/skills/impact-analysis/references/report-template.md +0 -604
- package/src/claude/skills/impact-analysis/references/test-scenario-generation.md +0 -459
- package/src/claude/skills/impact-analysis/scripts/README.md +0 -476
- package/src/claude/skills/impact-analysis/scripts/ast-analyze.js +0 -403
- package/src/claude/skills/impact-analysis/scripts/calculate-risk.js +0 -475
- package/src/claude/skills/impact-analysis/scripts/find-dependencies.sh +0 -202
- package/src/claude/skills/impact-analysis/scripts/run-analysis.sh +0 -312
|
@@ -53,17 +53,14 @@ function main() {
|
|
|
53
53
|
|
|
54
54
|
const linkIssues = checkBrokenLinks(docsDir);
|
|
55
55
|
if (linkIssues.length > 0) {
|
|
56
|
-
console.
|
|
56
|
+
console.error(`\n❌ FAIL: ${linkIssues.length} broken relative link(s) found:`);
|
|
57
57
|
linkIssues.forEach(issue => {
|
|
58
|
-
console.
|
|
58
|
+
console.error(`- ${path.relative(process.cwd(), issue.file)} -> ./${issue.brokenLink} (target missing)`);
|
|
59
59
|
});
|
|
60
|
-
|
|
61
|
-
console.log('✅ Validation verified! Zero broken integrity links detected across the system.');
|
|
60
|
+
process.exit(1);
|
|
62
61
|
}
|
|
63
62
|
|
|
64
|
-
|
|
65
|
-
// aggressive deep-code grepping functions (function tracing) have been stripped.
|
|
66
|
-
// This ensures document validation pipeline triggers definitively under < 1s (Zero-latency verification).
|
|
63
|
+
console.log('✅ PASS: no broken relative links detected.');
|
|
67
64
|
}
|
|
68
65
|
|
|
69
66
|
main();
|
|
@@ -203,11 +203,13 @@ function extractContractDefs(designText) {
|
|
|
203
203
|
}
|
|
204
204
|
|
|
205
205
|
/**
|
|
206
|
-
* From a task body, return the contracts it claims plus
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
206
|
+
* From a task body, return the contracts it claims plus its local contract
|
|
207
|
+
* copies. Shape: { names: string[], blocks: Map<name, string>, firstBlock: string|null }
|
|
208
|
+
* `names` come from a `Contracts: A, B` line. `blocks` maps every
|
|
209
|
+
* `<!-- contract:NAME -->` marker in the task to its fenced block, so a task
|
|
210
|
+
* carrying multiple contracts has EACH copy verified (not just the first).
|
|
211
|
+
* `firstBlock` keeps the legacy fallback for single-contract tasks that copy
|
|
212
|
+
* the block without repeating the marker.
|
|
211
213
|
*/
|
|
212
214
|
function extractTaskContracts(taskText) {
|
|
213
215
|
const names = [];
|
|
@@ -218,9 +220,10 @@ function extractTaskContracts(taskText) {
|
|
|
218
220
|
if (name) names.push(name);
|
|
219
221
|
}
|
|
220
222
|
}
|
|
223
|
+
const blocks = extractContractDefs(taskText); // same marker+fence grammar as design.md
|
|
221
224
|
const blockMatch = taskText.match(/```[^\n]*\n([\s\S]*?)\n```/);
|
|
222
|
-
const
|
|
223
|
-
return { names,
|
|
225
|
+
const firstBlock = blockMatch ? normalizeBlock(blockMatch[1]) : null;
|
|
226
|
+
return { names, blocks, firstBlock };
|
|
224
227
|
}
|
|
225
228
|
|
|
226
229
|
function validateSpec(specDir) {
|
|
@@ -393,16 +396,33 @@ function validateSpec(specDir) {
|
|
|
393
396
|
// (after whitespace normalization). This catches BE/FE drift like
|
|
394
397
|
// user_name vs userName before integration.
|
|
395
398
|
if (contractDefs.size > 0) {
|
|
396
|
-
const { names,
|
|
399
|
+
const { names, blocks, firstBlock } = extractTaskContracts(content);
|
|
397
400
|
for (const name of names) {
|
|
398
401
|
if (!contractDefs.has(name)) {
|
|
399
402
|
errors.push(`${taskFile}: declares unknown contract "${name}" (not defined in design.md)`);
|
|
400
403
|
continue;
|
|
401
404
|
}
|
|
402
|
-
|
|
405
|
+
// Prefer the task's marker-tagged copy for this contract; fall back to
|
|
406
|
+
// the first fenced block only for single-contract tasks (legacy format).
|
|
407
|
+
const localCopy = blocks.has(name)
|
|
408
|
+
? blocks.get(name)
|
|
409
|
+
: (names.length === 1 ? firstBlock : null);
|
|
410
|
+
if (localCopy === null) {
|
|
411
|
+
if (names.length > 1) {
|
|
412
|
+
errors.push(`${taskFile}: contract "${name}" has no <!-- contract:${name} --> tagged block (multi-contract tasks must tag each copy)`);
|
|
413
|
+
}
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
416
|
+
if (localCopy !== contractDefs.get(name)) {
|
|
403
417
|
errors.push(`${taskFile}: contract "${name}" body diverges from the canonical definition in design.md`);
|
|
404
418
|
}
|
|
405
419
|
}
|
|
420
|
+
// Marker-tagged blocks not declared on the Contracts: line are drift risks.
|
|
421
|
+
for (const taggedName of blocks.keys()) {
|
|
422
|
+
if (!names.includes(taggedName)) {
|
|
423
|
+
warnings.push(`${taskFile}: carries <!-- contract:${taggedName} --> block but does not declare it on the Contracts: line`);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
406
426
|
}
|
|
407
427
|
}
|
|
408
428
|
|
|
@@ -41,16 +41,16 @@ GEMINI_API_KEY=your_api_key_here
|
|
|
41
41
|
|
|
42
42
|
# --- Image Generation ---
|
|
43
43
|
# Used by: --task generate (image)
|
|
44
|
-
# Default:
|
|
44
|
+
# Default: gemma-4-31b-it-image (Nano Banana Flash - fast, cost-effective)
|
|
45
45
|
# Alternative: imagen-4.0-generate-001 (production quality)
|
|
46
46
|
# NOTE: All image generation requires billing - no free tier available (limit: 0)
|
|
47
47
|
# Options:
|
|
48
|
-
#
|
|
49
|
-
#
|
|
48
|
+
# gemma-4-31b-it-image - Nano Banana Flash: fast, ~$1/1M tokens (DEFAULT)
|
|
49
|
+
# gemma-4-31b-it-image-preview - Nano Banana Pro: 4K text, reasoning (requires billing)
|
|
50
50
|
# imagen-4.0-generate-001 - Imagen 4 Standard: production quality (~$0.02/image)
|
|
51
51
|
# imagen-4.0-ultra-generate-001 - Imagen 4 Ultra: maximum quality (~$0.04/image)
|
|
52
52
|
# imagen-4.0-fast-generate-001 - Imagen 4 Fast: speed-optimized (~$0.01/image)
|
|
53
|
-
# IMAGE_GEN_MODEL=
|
|
53
|
+
# IMAGE_GEN_MODEL=gemma-4-31b-it-image
|
|
54
54
|
|
|
55
55
|
# --- Video Generation ---
|
|
56
56
|
# Used by: --task generate-video (new capability)
|
|
@@ -65,17 +65,15 @@ GEMINI_API_KEY=your_api_key_here
|
|
|
65
65
|
|
|
66
66
|
# --- Multimodal Analysis ---
|
|
67
67
|
# Used by: --task analyze, transcribe, extract
|
|
68
|
-
# Default:
|
|
68
|
+
# Default: gemma-4-31b-it
|
|
69
69
|
# Options:
|
|
70
|
-
#
|
|
71
|
-
#
|
|
72
|
-
# gemini-2.5-pro - Highest quality
|
|
73
|
-
# MULTIMODAL_MODEL=gemini-2.5-flash
|
|
70
|
+
# gemma-4-31b-it - Best price/performance (recommended)
|
|
71
|
+
# MULTIMODAL_MODEL=gemma-4-31b-it
|
|
74
72
|
|
|
75
73
|
# --- Legacy Compatibility ---
|
|
76
74
|
# Generic model override (use specific variables above instead)
|
|
77
|
-
# GEMINI_MODEL=
|
|
78
|
-
# GEMINI_IMAGE_GEN_MODEL=
|
|
75
|
+
# GEMINI_MODEL=gemma-4-31b-it
|
|
76
|
+
# GEMINI_IMAGE_GEN_MODEL=gemma-4-31b-it-image
|
|
79
77
|
|
|
80
78
|
# ============================================================================
|
|
81
79
|
# MiniMax API Configuration (Optional - for image/video/speech/music generation)
|
|
@@ -223,8 +221,8 @@ GEMINI_API_KEY=your_api_key_here
|
|
|
223
221
|
# 5. Free tier limits: 15 RPM, 1M-4M TPM, 1,500 RPD
|
|
224
222
|
# 6. Vertex AI requires GCP authentication via gcloud CLI
|
|
225
223
|
# 7. Model defaults (Dec 2025):
|
|
226
|
-
# - Image gen:
|
|
224
|
+
# - Image gen: gemma-4-31b-it-image (Nano Banana Flash - default)
|
|
227
225
|
# - Image gen: imagen-4.0-generate-001 (alternative for production)
|
|
228
226
|
# - Video gen: veo-3.1-generate-preview
|
|
229
|
-
# - Analysis:
|
|
227
|
+
# - Analysis: gemma-4-31b-it
|
|
230
228
|
# 8. Preview models (veo-3.1, gemini-3) may have API changes
|
|
@@ -43,7 +43,7 @@ export GEMINI_API_KEY_2="key2" # auto-rotates on rate limit
|
|
|
43
43
|
## Models
|
|
44
44
|
|
|
45
45
|
### Google Gemini
|
|
46
|
-
- **Analysis**: `gemma-4-31b-it` (recommended), `
|
|
46
|
+
- **Analysis**: `gemma-4-31b-it` (recommended), `gemma-4-31b-it` (advanced)
|
|
47
47
|
|
|
48
48
|
## Scripts
|
|
49
49
|
|
|
@@ -42,7 +42,7 @@ myfile = client.files.upload(file='meeting.mp3')
|
|
|
42
42
|
|
|
43
43
|
# Transcribe
|
|
44
44
|
response = client.models.generate_content(
|
|
45
|
-
model='
|
|
45
|
+
model='gemma-4-31b-it',
|
|
46
46
|
contents=['Generate a transcript of the speech.', myfile]
|
|
47
47
|
)
|
|
48
48
|
print(response.text)
|
|
@@ -52,7 +52,7 @@ print(response.text)
|
|
|
52
52
|
|
|
53
53
|
```python
|
|
54
54
|
response = client.models.generate_content(
|
|
55
|
-
model='
|
|
55
|
+
model='gemma-4-31b-it',
|
|
56
56
|
contents=['Generate transcript with timestamps in MM:SS format.', myfile]
|
|
57
57
|
)
|
|
58
58
|
```
|
|
@@ -61,7 +61,7 @@ response = client.models.generate_content(
|
|
|
61
61
|
|
|
62
62
|
```python
|
|
63
63
|
response = client.models.generate_content(
|
|
64
|
-
model='
|
|
64
|
+
model='gemma-4-31b-it',
|
|
65
65
|
contents=['Transcribe with speaker labels. Format: [Speaker 1], [Speaker 2], etc.', myfile]
|
|
66
66
|
)
|
|
67
67
|
```
|
|
@@ -70,7 +70,7 @@ response = client.models.generate_content(
|
|
|
70
70
|
|
|
71
71
|
```python
|
|
72
72
|
response = client.models.generate_content(
|
|
73
|
-
model='
|
|
73
|
+
model='gemma-4-31b-it',
|
|
74
74
|
contents=['Transcribe only the segment from 02:30 to 05:15.', myfile]
|
|
75
75
|
)
|
|
76
76
|
```
|
|
@@ -81,7 +81,7 @@ response = client.models.generate_content(
|
|
|
81
81
|
|
|
82
82
|
```python
|
|
83
83
|
response = client.models.generate_content(
|
|
84
|
-
model='
|
|
84
|
+
model='gemma-4-31b-it',
|
|
85
85
|
contents=['Summarize key points in 5 bullets with timestamps.', myfile]
|
|
86
86
|
)
|
|
87
87
|
```
|
|
@@ -91,19 +91,19 @@ response = client.models.generate_content(
|
|
|
91
91
|
```python
|
|
92
92
|
# Music analysis
|
|
93
93
|
response = client.models.generate_content(
|
|
94
|
-
model='
|
|
94
|
+
model='gemma-4-31b-it',
|
|
95
95
|
contents=['Identify the musical instruments and genre.', myfile]
|
|
96
96
|
)
|
|
97
97
|
|
|
98
98
|
# Environmental sounds
|
|
99
99
|
response = client.models.generate_content(
|
|
100
|
-
model='
|
|
100
|
+
model='gemma-4-31b-it',
|
|
101
101
|
contents=['Identify all sounds: voices, music, ambient noise.', myfile]
|
|
102
102
|
)
|
|
103
103
|
|
|
104
104
|
# Birdsong identification
|
|
105
105
|
response = client.models.generate_content(
|
|
106
|
-
model='
|
|
106
|
+
model='gemma-4-31b-it',
|
|
107
107
|
contents=['Identify bird species based on their calls.', myfile]
|
|
108
108
|
)
|
|
109
109
|
```
|
|
@@ -112,7 +112,7 @@ response = client.models.generate_content(
|
|
|
112
112
|
|
|
113
113
|
```python
|
|
114
114
|
response = client.models.generate_content(
|
|
115
|
-
model='
|
|
115
|
+
model='gemma-4-31b-it',
|
|
116
116
|
contents=['What is discussed from 10:30 to 15:45? Provide key points.', myfile]
|
|
117
117
|
)
|
|
118
118
|
```
|
|
@@ -127,13 +127,13 @@ myfile = client.files.upload(file='large-audio.mp3')
|
|
|
127
127
|
|
|
128
128
|
# First query
|
|
129
129
|
response1 = client.models.generate_content(
|
|
130
|
-
model='
|
|
130
|
+
model='gemma-4-31b-it',
|
|
131
131
|
contents=['Transcribe this', myfile]
|
|
132
132
|
)
|
|
133
133
|
|
|
134
134
|
# Second query (reuses same file)
|
|
135
135
|
response2 = client.models.generate_content(
|
|
136
|
-
model='
|
|
136
|
+
model='gemma-4-31b-it',
|
|
137
137
|
contents=['Summarize this', myfile]
|
|
138
138
|
)
|
|
139
139
|
```
|
|
@@ -147,7 +147,7 @@ with open('small-audio.mp3', 'rb') as f:
|
|
|
147
147
|
audio_bytes = f.read()
|
|
148
148
|
|
|
149
149
|
response = client.models.generate_content(
|
|
150
|
-
model='
|
|
150
|
+
model='gemma-4-31b-it',
|
|
151
151
|
contents=[
|
|
152
152
|
'Describe this audio',
|
|
153
153
|
types.Part.from_bytes(data=audio_bytes, mime_type='audio/mp3')
|
|
@@ -161,14 +161,14 @@ response = client.models.generate_content(
|
|
|
161
161
|
|
|
162
162
|
| Model | Quality | Speed | Cost/1M tokens |
|
|
163
163
|
|-------|---------|-------|----------------|
|
|
164
|
-
| `
|
|
165
|
-
| `
|
|
164
|
+
| `gemma-4-31b-it-native-audio-preview-09-2025` | High | Fast | $10 |
|
|
165
|
+
| `gemma-4-31b-it` TTS mode | Premium | Slower | $20 |
|
|
166
166
|
|
|
167
167
|
### Basic TTS
|
|
168
168
|
|
|
169
169
|
```python
|
|
170
170
|
response = client.models.generate_content(
|
|
171
|
-
model='
|
|
171
|
+
model='gemma-4-31b-it-native-audio-preview-09-2025',
|
|
172
172
|
contents='Generate audio: Welcome to today\'s episode.'
|
|
173
173
|
)
|
|
174
174
|
|
|
@@ -182,19 +182,19 @@ with open('output.wav', 'wb') as f:
|
|
|
182
182
|
```python
|
|
183
183
|
# Professional tone
|
|
184
184
|
response = client.models.generate_content(
|
|
185
|
-
model='
|
|
185
|
+
model='gemma-4-31b-it-native-audio-preview-09-2025',
|
|
186
186
|
contents='Generate audio in a professional, clear tone: Welcome to our quarterly earnings call.'
|
|
187
187
|
)
|
|
188
188
|
|
|
189
189
|
# Casual and friendly
|
|
190
190
|
response = client.models.generate_content(
|
|
191
|
-
model='
|
|
191
|
+
model='gemma-4-31b-it-native-audio-preview-09-2025',
|
|
192
192
|
contents='Generate audio in a friendly, conversational tone: Hey there! Let\'s dive into today\'s topic.'
|
|
193
193
|
)
|
|
194
194
|
|
|
195
195
|
# Narrative style
|
|
196
196
|
response = client.models.generate_content(
|
|
197
|
-
model='
|
|
197
|
+
model='gemma-4-31b-it-native-audio-preview-09-2025',
|
|
198
198
|
contents='Generate audio in a narrative, storytelling tone: Once upon a time, in a land far away...'
|
|
199
199
|
)
|
|
200
200
|
```
|
|
@@ -244,9 +244,7 @@ response = client.models.generate_content(
|
|
|
244
244
|
- 9.5 hours = 1,094,400 tokens
|
|
245
245
|
|
|
246
246
|
**Model selection**:
|
|
247
|
-
- Use `
|
|
248
|
-
- Upgrade to `gemini-2.5-pro` ($3/1M tokens) for complex analysis
|
|
249
|
-
- For high-volume: `gemini-1.5-flash` ($0.70/1M tokens)
|
|
247
|
+
- Use `gemma-4-31b-it` for transcription and analysis (read model from `.claude/runtime.json`: `gemini.model`)
|
|
250
248
|
|
|
251
249
|
**Reduce costs**:
|
|
252
250
|
- Process only relevant segments using timestamps
|
|
@@ -265,7 +263,7 @@ def transcribe_with_retry(file_path, max_retries=3):
|
|
|
265
263
|
try:
|
|
266
264
|
myfile = client.files.upload(file=file_path)
|
|
267
265
|
response = client.models.generate_content(
|
|
268
|
-
model='
|
|
266
|
+
model='gemma-4-31b-it',
|
|
269
267
|
contents=['Transcribe with timestamps', myfile]
|
|
270
268
|
)
|
|
271
269
|
return response.text
|
|
@@ -283,7 +281,7 @@ def transcribe_with_retry(file_path, max_retries=3):
|
|
|
283
281
|
|
|
284
282
|
```python
|
|
285
283
|
response = client.models.generate_content(
|
|
286
|
-
model='
|
|
284
|
+
model='gemma-4-31b-it',
|
|
287
285
|
contents=[
|
|
288
286
|
'''Transcribe this meeting with:
|
|
289
287
|
1. Speaker labels
|
|
@@ -299,7 +297,7 @@ response = client.models.generate_content(
|
|
|
299
297
|
|
|
300
298
|
```python
|
|
301
299
|
response = client.models.generate_content(
|
|
302
|
-
model='
|
|
300
|
+
model='gemma-4-31b-it',
|
|
303
301
|
contents=[
|
|
304
302
|
'''Create podcast summary with:
|
|
305
303
|
1. Main topics with timestamps
|
|
@@ -315,7 +313,7 @@ response = client.models.generate_content(
|
|
|
315
313
|
|
|
316
314
|
```python
|
|
317
315
|
response = client.models.generate_content(
|
|
318
|
-
model='
|
|
316
|
+
model='gemma-4-31b-it',
|
|
319
317
|
contents=[
|
|
320
318
|
'''Analyze interview:
|
|
321
319
|
1. Questions asked with timestamps
|
|
@@ -331,7 +329,7 @@ response = client.models.generate_content(
|
|
|
331
329
|
|
|
332
330
|
```python
|
|
333
331
|
response = client.models.generate_content(
|
|
334
|
-
model='
|
|
332
|
+
model='gemma-4-31b-it',
|
|
335
333
|
contents=[
|
|
336
334
|
'''Verify audio content:
|
|
337
335
|
1. Check for specific keywords or phrases
|
|
@@ -348,7 +346,7 @@ response = client.models.generate_content(
|
|
|
348
346
|
```python
|
|
349
347
|
# Gemini auto-detects language
|
|
350
348
|
response = client.models.generate_content(
|
|
351
|
-
model='
|
|
349
|
+
model='gemma-4-31b-it',
|
|
352
350
|
contents=['Transcribe this audio and translate to English if needed.', myfile]
|
|
353
351
|
)
|
|
354
352
|
```
|
|
@@ -22,12 +22,8 @@ Comprehensive guide for video understanding, temporal analysis, and YouTube proc
|
|
|
22
22
|
|
|
23
23
|
## Model Selection
|
|
24
24
|
|
|
25
|
-
###
|
|
26
|
-
- **
|
|
27
|
-
|
|
28
|
-
### Gemini 2.5 Series (Recommended)
|
|
29
|
-
- **gemini-2.5-pro**: Best quality, 1M-2M context
|
|
30
|
-
- **gemini-2.5-flash**: Balanced, 1M-2M context (recommended)
|
|
25
|
+
### Recommended
|
|
26
|
+
- **gemma-4-31b-it**: 1M-2M context, balanced quality/speed (read model from `.claude/runtime.json`: `gemini.model`)
|
|
31
27
|
|
|
32
28
|
### Context Windows
|
|
33
29
|
- **2M token models**: ~2 hours (default) or ~6 hours (low-res)
|
|
@@ -57,7 +53,7 @@ if myfile.state.name == 'FAILED':
|
|
|
57
53
|
|
|
58
54
|
# Analyze
|
|
59
55
|
response = client.models.generate_content(
|
|
60
|
-
model='
|
|
56
|
+
model='gemma-4-31b-it',
|
|
61
57
|
contents=['Summarize this video in 3 key points', myfile]
|
|
62
58
|
)
|
|
63
59
|
print(response.text)
|
|
@@ -69,7 +65,7 @@ print(response.text)
|
|
|
69
65
|
from google.genai import types
|
|
70
66
|
|
|
71
67
|
response = client.models.generate_content(
|
|
72
|
-
model='
|
|
68
|
+
model='gemma-4-31b-it',
|
|
73
69
|
contents=[
|
|
74
70
|
'Summarize the main topics discussed',
|
|
75
71
|
types.Part.from_uri(
|
|
@@ -87,7 +83,7 @@ with open('short-clip.mp4', 'rb') as f:
|
|
|
87
83
|
video_bytes = f.read()
|
|
88
84
|
|
|
89
85
|
response = client.models.generate_content(
|
|
90
|
-
model='
|
|
86
|
+
model='gemma-4-31b-it',
|
|
91
87
|
contents=[
|
|
92
88
|
'What happens in this video?',
|
|
93
89
|
types.Part.from_bytes(data=video_bytes, mime_type='video/mp4')
|
|
@@ -102,7 +98,7 @@ response = client.models.generate_content(
|
|
|
102
98
|
```python
|
|
103
99
|
# Analyze specific time range
|
|
104
100
|
response = client.models.generate_content(
|
|
105
|
-
model='
|
|
101
|
+
model='gemma-4-31b-it',
|
|
106
102
|
contents=[
|
|
107
103
|
'Summarize this segment',
|
|
108
104
|
types.Part.from_video_metadata(
|
|
@@ -119,7 +115,7 @@ response = client.models.generate_content(
|
|
|
119
115
|
```python
|
|
120
116
|
# Lower FPS for static content (saves tokens)
|
|
121
117
|
response = client.models.generate_content(
|
|
122
|
-
model='
|
|
118
|
+
model='gemma-4-31b-it',
|
|
123
119
|
contents=[
|
|
124
120
|
'Analyze this presentation',
|
|
125
121
|
types.Part.from_video_metadata(
|
|
@@ -131,7 +127,7 @@ response = client.models.generate_content(
|
|
|
131
127
|
|
|
132
128
|
# Higher FPS for fast-moving content
|
|
133
129
|
response = client.models.generate_content(
|
|
134
|
-
model='
|
|
130
|
+
model='gemma-4-31b-it',
|
|
135
131
|
contents=[
|
|
136
132
|
'Analyze rapid movements in this sports video',
|
|
137
133
|
types.Part.from_video_metadata(
|
|
@@ -155,7 +151,7 @@ for video in [video1, video2]:
|
|
|
155
151
|
video = client.files.get(name=video.name)
|
|
156
152
|
|
|
157
153
|
response = client.models.generate_content(
|
|
158
|
-
model='
|
|
154
|
+
model='gemma-4-31b-it',
|
|
159
155
|
contents=[
|
|
160
156
|
'Compare these two product demos. Which explains features better?',
|
|
161
157
|
video1,
|
|
@@ -170,7 +166,7 @@ response = client.models.generate_content(
|
|
|
170
166
|
|
|
171
167
|
```python
|
|
172
168
|
response = client.models.generate_content(
|
|
173
|
-
model='
|
|
169
|
+
model='gemma-4-31b-it',
|
|
174
170
|
contents=[
|
|
175
171
|
'What happens at 01:15 and how does it relate to 02:30?',
|
|
176
172
|
myfile
|
|
@@ -182,7 +178,7 @@ response = client.models.generate_content(
|
|
|
182
178
|
|
|
183
179
|
```python
|
|
184
180
|
response = client.models.generate_content(
|
|
185
|
-
model='
|
|
181
|
+
model='gemma-4-31b-it',
|
|
186
182
|
contents=[
|
|
187
183
|
'''Create a timeline with timestamps:
|
|
188
184
|
- Key events
|
|
@@ -199,7 +195,7 @@ response = client.models.generate_content(
|
|
|
199
195
|
|
|
200
196
|
```python
|
|
201
197
|
response = client.models.generate_content(
|
|
202
|
-
model='
|
|
198
|
+
model='gemma-4-31b-it',
|
|
203
199
|
contents=[
|
|
204
200
|
'Identify all scene changes with timestamps and describe each scene',
|
|
205
201
|
myfile
|
|
@@ -213,7 +209,7 @@ response = client.models.generate_content(
|
|
|
213
209
|
|
|
214
210
|
```python
|
|
215
211
|
response = client.models.generate_content(
|
|
216
|
-
model='
|
|
212
|
+
model='gemma-4-31b-it',
|
|
217
213
|
contents=[
|
|
218
214
|
'Transcribe the audio from this video',
|
|
219
215
|
myfile
|
|
@@ -225,7 +221,7 @@ response = client.models.generate_content(
|
|
|
225
221
|
|
|
226
222
|
```python
|
|
227
223
|
response = client.models.generate_content(
|
|
228
|
-
model='
|
|
224
|
+
model='gemma-4-31b-it',
|
|
229
225
|
contents=[
|
|
230
226
|
'''Transcribe with visual context:
|
|
231
227
|
- Audio transcription
|
|
@@ -241,7 +237,7 @@ response = client.models.generate_content(
|
|
|
241
237
|
|
|
242
238
|
```python
|
|
243
239
|
response = client.models.generate_content(
|
|
244
|
-
model='
|
|
240
|
+
model='gemma-4-31b-it',
|
|
245
241
|
contents=[
|
|
246
242
|
'Transcribe with speaker labels and timestamps',
|
|
247
243
|
myfile
|
|
@@ -255,7 +251,7 @@ response = client.models.generate_content(
|
|
|
255
251
|
|
|
256
252
|
```python
|
|
257
253
|
response = client.models.generate_content(
|
|
258
|
-
model='
|
|
254
|
+
model='gemma-4-31b-it',
|
|
259
255
|
contents=[
|
|
260
256
|
'''Summarize this video:
|
|
261
257
|
1. Main topic and purpose
|
|
@@ -271,7 +267,7 @@ response = client.models.generate_content(
|
|
|
271
267
|
|
|
272
268
|
```python
|
|
273
269
|
response = client.models.generate_content(
|
|
274
|
-
model='
|
|
270
|
+
model='gemma-4-31b-it',
|
|
275
271
|
contents=[
|
|
276
272
|
'''Create educational materials:
|
|
277
273
|
1. List key concepts taught
|
|
@@ -287,7 +283,7 @@ response = client.models.generate_content(
|
|
|
287
283
|
|
|
288
284
|
```python
|
|
289
285
|
response = client.models.generate_content(
|
|
290
|
-
model='
|
|
286
|
+
model='gemma-4-31b-it',
|
|
291
287
|
contents=[
|
|
292
288
|
'List all actions performed in this tutorial with timestamps',
|
|
293
289
|
myfile
|
|
@@ -299,7 +295,7 @@ response = client.models.generate_content(
|
|
|
299
295
|
|
|
300
296
|
```python
|
|
301
297
|
response = client.models.generate_content(
|
|
302
|
-
model='
|
|
298
|
+
model='gemma-4-31b-it',
|
|
303
299
|
contents=[
|
|
304
300
|
'''Review video content:
|
|
305
301
|
1. Identify any problematic content
|
|
@@ -315,7 +311,7 @@ response = client.models.generate_content(
|
|
|
315
311
|
|
|
316
312
|
```python
|
|
317
313
|
response = client.models.generate_content(
|
|
318
|
-
model='
|
|
314
|
+
model='gemma-4-31b-it',
|
|
319
315
|
contents=[
|
|
320
316
|
'''Analyze interview:
|
|
321
317
|
1. Questions asked (timestamps)
|
|
@@ -332,7 +328,7 @@ response = client.models.generate_content(
|
|
|
332
328
|
|
|
333
329
|
```python
|
|
334
330
|
response = client.models.generate_content(
|
|
335
|
-
model='
|
|
331
|
+
model='gemma-4-31b-it',
|
|
336
332
|
contents=[
|
|
337
333
|
'''Analyze sports video:
|
|
338
334
|
1. Key plays with timestamps
|
|
@@ -362,7 +358,7 @@ response = client.models.generate_content(
|
|
|
362
358
|
youtube_uri = 'https://www.youtube.com/watch?v=dQw4w9WgXcQ'
|
|
363
359
|
|
|
364
360
|
response = client.models.generate_content(
|
|
365
|
-
model='
|
|
361
|
+
model='gemma-4-31b-it',
|
|
366
362
|
contents=[
|
|
367
363
|
'Create chapter markers with timestamps',
|
|
368
364
|
types.Part.from_uri(uri=youtube_uri, mime_type='video/mp4')
|
|
@@ -444,7 +440,7 @@ class VideoAnalysis(BaseModel):
|
|
|
444
440
|
duration: str
|
|
445
441
|
|
|
446
442
|
response = client.models.generate_content(
|
|
447
|
-
model='
|
|
443
|
+
model='gemma-4-31b-it',
|
|
448
444
|
contents=['Analyze this video', myfile],
|
|
449
445
|
config=genai.types.GenerateContentConfig(
|
|
450
446
|
response_mime_type='application/json',
|