seshat-scribe 0.0.1 → 0.0.3
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/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/generate.js +10 -0
- package/dist/commands/generate.js.map +1 -1
- package/dist/core/artist.d.ts.map +1 -1
- package/dist/core/artist.js +18 -7
- package/dist/core/artist.js.map +1 -1
- package/dist/core/planner.d.ts.map +1 -1
- package/dist/core/planner.js +43 -6
- package/dist/core/planner.js.map +1 -1
- package/dist/core/writer.d.ts.map +1 -1
- package/dist/core/writer.js +34 -16
- package/dist/core/writer.js.map +1 -1
- package/dist/lib/usage.d.ts +32 -0
- package/dist/lib/usage.d.ts.map +1 -0
- package/dist/lib/usage.js +80 -0
- package/dist/lib/usage.js.map +1 -0
- package/package.json +6 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAAC,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuI3E"}
|
|
@@ -6,6 +6,7 @@ import { planBlogPost } from '../core/planner.js';
|
|
|
6
6
|
import { writeBlogPost } from '../core/writer.js';
|
|
7
7
|
import { generateImage } from '../core/artist.js';
|
|
8
8
|
import { gold, cyan, error, info, scrollWritten } from '../lib/output.js';
|
|
9
|
+
import { resetUsage, formatUsageSummary } from '../lib/usage.js';
|
|
9
10
|
/**
|
|
10
11
|
* Main command: Generate a new blog post with image
|
|
11
12
|
*/
|
|
@@ -25,6 +26,7 @@ export async function generate(options = {}) {
|
|
|
25
26
|
console.log('');
|
|
26
27
|
console.log(gold.bold('⟡ Seshat awakens...'));
|
|
27
28
|
console.log('');
|
|
29
|
+
resetUsage();
|
|
28
30
|
// Step 1: Analyze existing content
|
|
29
31
|
const analyzeSpinner = ora({
|
|
30
32
|
text: cyan('Reading the archives...'),
|
|
@@ -120,6 +122,14 @@ export async function generate(options = {}) {
|
|
|
120
122
|
error(err instanceof Error ? err.message : 'Unknown error');
|
|
121
123
|
process.exit(1);
|
|
122
124
|
}
|
|
125
|
+
// Usage summary
|
|
126
|
+
const usageLines = formatUsageSummary();
|
|
127
|
+
if (usageLines.length > 0) {
|
|
128
|
+
console.log('');
|
|
129
|
+
for (const line of usageLines) {
|
|
130
|
+
info(line);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
123
133
|
// Victory!
|
|
124
134
|
scrollWritten();
|
|
125
135
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,GAAG,MAAM,KAAK,CAAC;AAGtB,OAAO,EAAE,cAAc,EAA0B,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,IAAI,
|
|
1
|
+
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"artist.d.ts","sourceRoot":"","sources":["../../src/core/artist.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"artist.d.ts","sourceRoot":"","sources":["../../src/core/artist.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAiBjD;;GAEG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,YAAY,EACpB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,CA8DjB"}
|
package/dist/core/artist.js
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import fs from 'fs/promises';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { createGenAIClient, SafetyFilterLevel, PersonGeneration } from '../lib/gemini.js';
|
|
4
|
+
import { addUsage } from '../lib/usage.js';
|
|
5
|
+
const IMAGE_MODEL = 'imagen-4.0-generate-001';
|
|
6
|
+
function pickOne(arr) {
|
|
7
|
+
return arr[Math.floor(Math.random() * arr.length)];
|
|
8
|
+
}
|
|
9
|
+
const STYLE_OVERLAYS = [
|
|
10
|
+
'Style: Digital drawing, hand-drawn aesthetic, slightly imperfect and organic. Warm, approachable colors. Indie illustration or personal blog. Avoid: corporate stock, 3D renders, overly polished.',
|
|
11
|
+
'Style: Muted, film-like colors; slight grain. Feels like a 70s book cover or vintage poster. Avoid: bright flat colors, slick digital look.',
|
|
12
|
+
'Style: Bold shapes, limited palette (2–3 colors), graphic and poster-like. High contrast. Avoid: detailed realism, busy compositions.',
|
|
13
|
+
'Style: Soft, painterly; visible brush strokes. Not photorealistic. Avoid: sharp vectors, corporate clip art.',
|
|
14
|
+
'Style: Minimal: lots of negative space, one strong focal point, restrained colors. Avoid: busy, maximalist.',
|
|
15
|
+
'Style: Slightly surreal or unexpected: one odd angle, scale, or juxtaposition. Still readable. Avoid: generic stock imagery.',
|
|
16
|
+
];
|
|
4
17
|
/**
|
|
5
18
|
* Generate an image using Gemini's Imagen 4.0 model
|
|
6
19
|
*/
|
|
@@ -11,17 +24,14 @@ export async function generateImage(config, imagePrompt, slug) {
|
|
|
11
24
|
await fs.mkdir(assetsPath, { recursive: true });
|
|
12
25
|
try {
|
|
13
26
|
const ai = createGenAIClient();
|
|
14
|
-
// Enhance
|
|
27
|
+
// Enhance with a randomly chosen style overlay so images vary across runs
|
|
28
|
+
const overlay = pickOne(STYLE_OVERLAYS);
|
|
15
29
|
const enhancedPrompt = `${imagePrompt}
|
|
16
30
|
|
|
17
|
-
|
|
18
|
-
Should look human-made, not overly polished or synthetic.
|
|
19
|
-
Warm, approachable colors with a personal touch.
|
|
20
|
-
Think indie illustration or personal blog header art.
|
|
21
|
-
Avoid: Corporate stock photo look, 3D renders, photorealistic AI art, overly perfect compositions.`;
|
|
31
|
+
${overlay}`;
|
|
22
32
|
// Generate the image using the correct API with timeout
|
|
23
33
|
const imagePromise = ai.models.generateImages({
|
|
24
|
-
model:
|
|
34
|
+
model: IMAGE_MODEL,
|
|
25
35
|
prompt: enhancedPrompt,
|
|
26
36
|
config: {
|
|
27
37
|
numberOfImages: 1,
|
|
@@ -43,6 +53,7 @@ Avoid: Corporate stock photo look, 3D renders, photorealistic AI art, overly per
|
|
|
43
53
|
// Convert base64 to buffer and save
|
|
44
54
|
const imageBuffer = Buffer.from(generatedImage.image.imageBytes, 'base64');
|
|
45
55
|
await fs.writeFile(imagePath, imageBuffer);
|
|
56
|
+
addUsage({ type: 'generateImages', model: IMAGE_MODEL, imageCount: 1 });
|
|
46
57
|
return imagePath;
|
|
47
58
|
}
|
|
48
59
|
catch (error) {
|
package/dist/core/artist.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"artist.js","sourceRoot":"","sources":["../../src/core/artist.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"artist.js","sourceRoot":"","sources":["../../src/core/artist.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAC1F,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAG3C,MAAM,WAAW,GAAG,yBAAyB,CAAC;AAE9C,SAAS,OAAO,CAAI,GAAQ;IAC1B,OAAO,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,cAAc,GAAa;IAC/B,oMAAoM;IACpM,6IAA6I;IAC7I,uIAAuI;IACvI,8GAA8G;IAC9G,6GAA6G;IAC7G,8HAA8H;CAC/H,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAoB,EACpB,WAAmB,EACnB,IAAY;IAEZ,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IACjE,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,IAAI,MAAM,CAAC,CAAC;IAEvD,qCAAqC;IACrC,MAAM,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEhD,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,iBAAiB,EAAE,CAAC;QAE/B,0EAA0E;QAC1E,MAAM,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;QACxC,MAAM,cAAc,GAAG,GAAG,WAAW;;EAEvC,OAAO,EAAE,CAAC;QAER,wDAAwD;QACxD,MAAM,YAAY,GAAG,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;YAC5C,KAAK,EAAE,WAAW;YAClB,MAAM,EAAE,cAAc;YACtB,MAAM,EAAE;gBACN,cAAc,EAAE,CAAC;gBACjB,WAAW,EAAE,MAAM,EAAE,wBAAwB;gBAC7C,iBAAiB,EAAE,iBAAiB,CAAC,mBAAmB;gBACxD,gBAAgB,EAAE,gBAAgB,CAAC,WAAW;aAC/C;SACF,CAAC,CAAC;QAEH,2BAA2B;QAC3B,MAAM,cAAc,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAC/C,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC,EAAE,KAAK,CAAC,CACnF,CAAC;QAEF,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,cAAc,CAAC,CAAiC,CAAC;QAEpG,IAAI,CAAC,QAAQ,CAAC,eAAe,IAAI,QAAQ,CAAC,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QACxC,CAAC;QAED,MAAM,cAAc,GAAG,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAEnD,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAC5C,CAAC;QAED,oCAAoC;QACpC,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAC3E,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAE3C,QAAQ,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC;QAExE,OAAO,SAAS,CAAC;IACnB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,4BAA4B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC;QACtG,OAAO,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;QAErD,0CAA0C;QAC1C,MAAM,cAAc,GAAG,sBAAsB,CAAC,IAAI,CAAC,CAAC;QACpD,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;QAEvD,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,sBAAsB,CAAC,IAAY;IAC1C,gDAAgD;IAChD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/E,MAAM,GAAG,GAAG,IAAI,GAAG,GAAG,CAAC;IAEvB,OAAO;;;gDAGuC,GAAG;kDACD,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,GAAG;;;;;MAK5D,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE;;;;;OAKpC,CAAC;AACR,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planner.d.ts","sourceRoot":"","sources":["../../src/core/planner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"planner.d.ts","sourceRoot":"","sources":["../../src/core/planner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AA+BjD;;GAEG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;EAMzB,CAAC;AAEH,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD;;GAEG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,QAAQ,CAAC,CA+DnB"}
|
package/dist/core/planner.js
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { createGenAIClient } from '../lib/gemini.js';
|
|
3
|
+
import { addUsage, fromGenerateContentResponse } from '../lib/usage.js';
|
|
4
|
+
const PLAN_MODEL = 'gemini-3-flash-preview';
|
|
5
|
+
function pickOne(arr) {
|
|
6
|
+
return arr[Math.floor(Math.random() * arr.length)];
|
|
7
|
+
}
|
|
8
|
+
const TITLE_ARCHETYPES = [
|
|
9
|
+
{ instruction: 'Phrase the title as a question.', example: 'Why Does X Still Break in Production?' },
|
|
10
|
+
{ instruction: 'Use a how-to format.', example: 'How to X Without Y' },
|
|
11
|
+
{ instruction: 'Use a short, declarative statement.', example: 'X Is Underrated' },
|
|
12
|
+
{ instruction: 'Use a provocative or contrarian angle.', example: 'Stop Doing X (Do Y Instead)' },
|
|
13
|
+
{ instruction: 'Use an understated, curiosity-driven title.', example: 'A Small Thing About X' },
|
|
14
|
+
{ instruction: 'Use a list or collection format.', example: '3 Things I Wish I Knew About X' },
|
|
15
|
+
{ instruction: 'Use a title that suggests a story or journey.', example: 'How I Finally Understood X' },
|
|
16
|
+
{ instruction: 'Use a single punchy phrase or a few words.', example: 'Defaults Matter' },
|
|
17
|
+
{ instruction: 'Use a "what nobody tells you" or insider angle.', example: 'What Nobody Tells You About X' },
|
|
18
|
+
];
|
|
19
|
+
const IMAGE_STYLE_DIRECTIONS = [
|
|
20
|
+
{ direction: 'Minimalist line art or iconography; lots of negative space.', example: 'Single continuous line forming a symbol, one accent color on white' },
|
|
21
|
+
{ direction: 'Moody, atmospheric; shallow depth of field or soft focus; like a film still.', example: 'Blurred background, one sharp object, muted palette' },
|
|
22
|
+
{ direction: 'Bold graphic shapes, limited palette (2–3 colors), poster-like.', example: 'Flat geometric shapes, high contrast, no gradients' },
|
|
23
|
+
{ direction: 'Sketchy, hand-drawn; pencil or ink; deliberately imperfect.', example: 'Quick sketch or doodle, visible strokes, unpolished' },
|
|
24
|
+
{ direction: 'Collage or mixed media; layered textures, paper, or found elements.', example: 'Cut-paper, tape, or layered scraps; tactile' },
|
|
25
|
+
{ direction: 'Abstract: gradients, blobs, or organic shapes; no literal objects.', example: 'Soft blobs or waves, dreamy, no recognizable objects' },
|
|
26
|
+
{ direction: 'Flat illustration with one strong accent color on a neutral base.', example: 'Simple shapes, one pop of color, rest muted' },
|
|
27
|
+
{ direction: 'Retro or vintage: 70s book cover, old textbook diagram, or poster.', example: 'Grainy, sepia or faded colors, old typography feel' },
|
|
28
|
+
];
|
|
3
29
|
/**
|
|
4
30
|
* Schema for the blog post plan returned by Gemini
|
|
5
31
|
*/
|
|
@@ -17,6 +43,8 @@ export async function planBlogPost(config, context) {
|
|
|
17
43
|
const ai = createGenAIClient();
|
|
18
44
|
const existingTitles = context.posts.map((p) => p.title).join('\n - ');
|
|
19
45
|
const existingTopics = context.recentTopics.join(', ');
|
|
46
|
+
const titleArchetype = pickOne(TITLE_ARCHETYPES);
|
|
47
|
+
const imageStyle = pickOne(IMAGE_STYLE_DIRECTIONS);
|
|
20
48
|
const prompt = `Plan a new blog post for a developer blog.
|
|
21
49
|
|
|
22
50
|
**Existing Content:**
|
|
@@ -31,24 +59,33 @@ export async function planBlogPost(config, context) {
|
|
|
31
59
|
2. Make it specific and valuable to developers
|
|
32
60
|
3. Avoid duplicating existing posts
|
|
33
61
|
4. Vary from recent posts (if last posts were about X, pick something different)
|
|
34
|
-
5. Create a clear, specific title (not generic)
|
|
35
62
|
|
|
36
|
-
|
|
63
|
+
**Title (important – follow this format):**
|
|
64
|
+
${titleArchetype.instruction} Example: "${titleArchetype.example}"
|
|
65
|
+
- If the existing titles above mostly use one format (e.g. how-to or questions), pick a *different* format for this one.
|
|
66
|
+
- Avoid generic or templated titles. Be specific to the topic.
|
|
67
|
+
|
|
68
|
+
**Image:**
|
|
69
|
+
Describe the header image to match this style: ${imageStyle.direction}
|
|
70
|
+
Example: "${imageStyle.example}" — adapt to the post's topic. Do NOT use a generic "blog header" or "minimalist illustration" phrase; describe a concrete scene, metaphor, or mood.
|
|
37
71
|
|
|
38
72
|
**Output JSON:**
|
|
39
73
|
{
|
|
40
|
-
"title": "
|
|
74
|
+
"title": "<your title in the chosen format>",
|
|
41
75
|
"slug": "url-friendly-slug",
|
|
42
|
-
"description": "One sentence
|
|
76
|
+
"description": "One sentence: vary the phrasing (e.g. benefit, question, or punchy statement — not always 'This post covers X').",
|
|
43
77
|
"tags": ["primary-tag", "related-tag", "context-tag"],
|
|
44
|
-
"imagePrompt": "
|
|
78
|
+
"imagePrompt": "<your image description matching the style above>"
|
|
45
79
|
}
|
|
46
80
|
|
|
47
81
|
Return only valid JSON.`;
|
|
48
82
|
const response = await ai.models.generateContent({
|
|
49
|
-
model:
|
|
83
|
+
model: PLAN_MODEL,
|
|
50
84
|
contents: prompt,
|
|
51
85
|
});
|
|
86
|
+
const u = fromGenerateContentResponse(PLAN_MODEL, response.usageMetadata);
|
|
87
|
+
if (u)
|
|
88
|
+
addUsage(u);
|
|
52
89
|
const text = response.text?.trim() || '';
|
|
53
90
|
// Clean up the response (remove markdown code blocks if present)
|
|
54
91
|
let jsonText = text;
|
package/dist/core/planner.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planner.js","sourceRoot":"","sources":["../../src/core/planner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"planner.js","sourceRoot":"","sources":["../../src/core/planner.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../../src/core/writer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../../src/core/writer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAmBjD;;GAEG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,YAAY,EACpB,IAAI,EAAE,QAAQ,GACb,OAAO,CAAC,MAAM,CAAC,CAmEjB"}
|
package/dist/core/writer.js
CHANGED
|
@@ -1,4 +1,19 @@
|
|
|
1
1
|
import { createGenAIClient } from '../lib/gemini.js';
|
|
2
|
+
import { addUsage, fromGenerateContentResponse } from '../lib/usage.js';
|
|
3
|
+
const WRITE_MODEL = 'gemini-3-flash-preview';
|
|
4
|
+
function pickOne(arr) {
|
|
5
|
+
return arr[Math.floor(Math.random() * arr.length)];
|
|
6
|
+
}
|
|
7
|
+
const OPENING_STYLES = [
|
|
8
|
+
{ instruction: 'Start with 1–2 sentences on why this matters to the reader.' },
|
|
9
|
+
{ instruction: 'Open with a question that the post will answer.' },
|
|
10
|
+
{ instruction: 'Open with a bold or surprising claim, then back it up.' },
|
|
11
|
+
{ instruction: 'Open with a very short anecdote or moment (2–3 sentences) that leads into the topic.' },
|
|
12
|
+
{ instruction: 'Dive straight into the technical content; no preamble. Start with a concrete example or definition.' },
|
|
13
|
+
{ instruction: 'Start with an understated, almost casual observation that draws the reader in.' },
|
|
14
|
+
{ instruction: 'Start by contradicting a common belief or practice, then explain.' },
|
|
15
|
+
{ instruction: 'Start with a specific frustration or "this used to confuse me" and then resolve it.' },
|
|
16
|
+
];
|
|
2
17
|
/**
|
|
3
18
|
* Use Gemini to write a complete MDX blog post
|
|
4
19
|
*/
|
|
@@ -9,34 +24,34 @@ export async function writeBlogPost(config, plan) {
|
|
|
9
24
|
// Pick the first tag from the plan
|
|
10
25
|
const primaryTag = plan.tags[0] || 'general';
|
|
11
26
|
const frontmatterFormat = getFrontmatterFormat(config.framework, plan.title, plan.description, currentDate, primaryTag);
|
|
12
|
-
const
|
|
27
|
+
const opening = pickOne(OPENING_STYLES);
|
|
28
|
+
const prompt = `Write a technical blog post in MDX format. Clear, valuable, focused on helping readers understand. Vary your voice — avoid sounding like a generic AI or a template.
|
|
13
29
|
|
|
14
30
|
**Post Details:**
|
|
15
31
|
- Title: ${plan.title}
|
|
16
32
|
- Description: ${plan.description}
|
|
17
33
|
- Tag: ${primaryTag}
|
|
18
34
|
|
|
35
|
+
**Opening (follow this for the first paragraph):**
|
|
36
|
+
${opening.instruction}
|
|
37
|
+
Do NOT start with "In this article we will...", "In today's post...", or similar. Each post should feel like it was written on a different day.
|
|
38
|
+
|
|
19
39
|
**Writing Style:**
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
- Write like you're helping a colleague understand something
|
|
40
|
+
- Prose that delivers value without fluff or filler
|
|
41
|
+
- First-person when it fits ("I found", "I learned"); not every sentence
|
|
42
|
+
- Vary sentence length and rhythm — short and long, not uniform
|
|
43
|
+
- It's okay to be a bit idiosyncratic or opinionated
|
|
44
|
+
- Use examples and code to clarify; show real code, not pseudo-code
|
|
45
|
+
- Explain the "why" behind decisions; include edge cases or gotchas when relevant
|
|
27
46
|
|
|
28
47
|
**Structure:**
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
- Use clear headings to organize ideas
|
|
48
|
+
- Use clear headings, but don't follow a cookie-cutter pattern (e.g. not always Intro → Background → Solution → Conclusion with equal weight)
|
|
49
|
+
- Let the topic dictate structure: some posts need a long setup, others can jump in
|
|
32
50
|
- Include practical code examples where helpful
|
|
33
|
-
- Vary your structure - don't follow a template
|
|
34
51
|
|
|
35
52
|
**Technical Quality:**
|
|
36
53
|
- Be accurate and specific
|
|
37
|
-
-
|
|
38
|
-
- Explain the "why" behind decisions
|
|
39
|
-
- Include edge cases or gotchas when relevant
|
|
54
|
+
- Avoid formulaic transitions ("Furthermore", "Moreover", "It's worth noting that" as crutches)
|
|
40
55
|
|
|
41
56
|
**Tone: ${config.tone}**
|
|
42
57
|
|
|
@@ -49,9 +64,12 @@ After the frontmatter, start your content immediately. No import statements.
|
|
|
49
64
|
|
|
50
65
|
Write a focused, valuable post that helps developers understand ${plan.title}.`;
|
|
51
66
|
const response = await ai.models.generateContent({
|
|
52
|
-
model:
|
|
67
|
+
model: WRITE_MODEL,
|
|
53
68
|
contents: prompt,
|
|
54
69
|
});
|
|
70
|
+
const u = fromGenerateContentResponse(WRITE_MODEL, response.usageMetadata);
|
|
71
|
+
if (u)
|
|
72
|
+
addUsage(u);
|
|
55
73
|
let content = response.text?.trim() || '';
|
|
56
74
|
// Clean up: remove wrapping code blocks if Gemini added them
|
|
57
75
|
if (content.startsWith('```')) {
|
package/dist/core/writer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/core/writer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/core/writer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini/Imagen usage and cost tracking
|
|
3
|
+
*
|
|
4
|
+
* Prices from https://ai.google.dev/pricing (check for updates).
|
|
5
|
+
* Token rates are USD per 1M tokens; image rate is USD per image.
|
|
6
|
+
*/
|
|
7
|
+
export type GenerateContentUsage = {
|
|
8
|
+
type: 'generateContent';
|
|
9
|
+
model: string;
|
|
10
|
+
promptTokenCount: number;
|
|
11
|
+
candidatesTokenCount: number;
|
|
12
|
+
};
|
|
13
|
+
export type GenerateImagesUsage = {
|
|
14
|
+
type: 'generateImages';
|
|
15
|
+
model: string;
|
|
16
|
+
imageCount: number;
|
|
17
|
+
};
|
|
18
|
+
export type UsageRecord = GenerateContentUsage | GenerateImagesUsage;
|
|
19
|
+
export declare function resetUsage(): void;
|
|
20
|
+
export declare function addUsage(record: UsageRecord): void;
|
|
21
|
+
export declare function getUsage(): readonly UsageRecord[];
|
|
22
|
+
export declare function getTotalCost(): number;
|
|
23
|
+
export declare function formatUsageSummary(): string[];
|
|
24
|
+
/**
|
|
25
|
+
* Extract a UsageRecord from a generateContent response.usageMetadata.
|
|
26
|
+
* Returns undefined if usageMetadata or token counts are missing.
|
|
27
|
+
*/
|
|
28
|
+
export declare function fromGenerateContentResponse(model: string, usageMetadata?: {
|
|
29
|
+
promptTokenCount?: number;
|
|
30
|
+
candidatesTokenCount?: number;
|
|
31
|
+
} | null): GenerateContentUsage | undefined;
|
|
32
|
+
//# sourceMappingURL=usage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../src/lib/usage.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,iBAAiB,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,oBAAoB,GAAG,mBAAmB,CAAC;AAuCrE,wBAAgB,UAAU,IAAI,IAAI,CAEjC;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAElD;AAED,wBAAgB,QAAQ,IAAI,SAAS,WAAW,EAAE,CAEjD;AAED,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wBAAgB,kBAAkB,IAAI,MAAM,EAAE,CA0B7C;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,MAAM,EACb,aAAa,CAAC,EAAE;IAAE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAAC,oBAAoB,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAClF,oBAAoB,GAAG,SAAS,CAMlC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini/Imagen usage and cost tracking
|
|
3
|
+
*
|
|
4
|
+
* Prices from https://ai.google.dev/pricing (check for updates).
|
|
5
|
+
* Token rates are USD per 1M tokens; image rate is USD per image.
|
|
6
|
+
*/
|
|
7
|
+
// USD per 1M tokens (input, output) for text models; USD per image for Imagen
|
|
8
|
+
const PRICING = {
|
|
9
|
+
'gemini-3-flash-preview': { inputPer1M: 0.5, outputPer1M: 3.0 },
|
|
10
|
+
'gemini-3-pro-preview': { inputPer1M: 2.0, outputPer1M: 12.0 },
|
|
11
|
+
'gemini-2.0-flash': { inputPer1M: 0.1, outputPer1M: 0.4 },
|
|
12
|
+
'imagen-4.0-generate-001': { perImage: 0.04 },
|
|
13
|
+
};
|
|
14
|
+
function getPricing(model) {
|
|
15
|
+
return PRICING[model];
|
|
16
|
+
}
|
|
17
|
+
function estimateCost(record) {
|
|
18
|
+
const p = getPricing(record.model);
|
|
19
|
+
if (!p)
|
|
20
|
+
return 0;
|
|
21
|
+
if (record.type === 'generateContent') {
|
|
22
|
+
if ('inputPer1M' in p && 'outputPer1M' in p) {
|
|
23
|
+
const input = (record.promptTokenCount / 1_000_000) * p.inputPer1M;
|
|
24
|
+
const output = (record.candidatesTokenCount / 1_000_000) * p.outputPer1M;
|
|
25
|
+
return input + output;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (record.type === 'generateImages' && 'perImage' in p) {
|
|
29
|
+
return record.imageCount * p.perImage;
|
|
30
|
+
}
|
|
31
|
+
return 0;
|
|
32
|
+
}
|
|
33
|
+
const store = [];
|
|
34
|
+
export function resetUsage() {
|
|
35
|
+
store.length = 0;
|
|
36
|
+
}
|
|
37
|
+
export function addUsage(record) {
|
|
38
|
+
store.push(record);
|
|
39
|
+
}
|
|
40
|
+
export function getUsage() {
|
|
41
|
+
return store;
|
|
42
|
+
}
|
|
43
|
+
export function getTotalCost() {
|
|
44
|
+
return store.reduce((sum, r) => sum + estimateCost(r), 0);
|
|
45
|
+
}
|
|
46
|
+
export function formatUsageSummary() {
|
|
47
|
+
const lines = [];
|
|
48
|
+
let total = 0;
|
|
49
|
+
for (const r of store) {
|
|
50
|
+
const cost = estimateCost(r);
|
|
51
|
+
total += cost;
|
|
52
|
+
if (r.type === 'generateContent') {
|
|
53
|
+
const p = getPricing(r.model);
|
|
54
|
+
const name = p ? '' : ' (unknown pricing)';
|
|
55
|
+
lines.push(` ${r.model}: ${r.promptTokenCount} in / ${r.candidatesTokenCount} out → $${cost.toFixed(4)}${name}`);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
lines.push(` ${r.model}: ${r.imageCount} image(s) → $${cost.toFixed(4)}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (store.length > 0) {
|
|
62
|
+
lines.unshift('API usage:');
|
|
63
|
+
lines.push(` Total (est.): $${total.toFixed(4)}`);
|
|
64
|
+
}
|
|
65
|
+
return lines;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Extract a UsageRecord from a generateContent response.usageMetadata.
|
|
69
|
+
* Returns undefined if usageMetadata or token counts are missing.
|
|
70
|
+
*/
|
|
71
|
+
export function fromGenerateContentResponse(model, usageMetadata) {
|
|
72
|
+
if (!usageMetadata)
|
|
73
|
+
return undefined;
|
|
74
|
+
const prompt = usageMetadata.promptTokenCount ?? 0;
|
|
75
|
+
const candidates = usageMetadata.candidatesTokenCount ?? 0;
|
|
76
|
+
if (prompt === 0 && candidates === 0)
|
|
77
|
+
return undefined;
|
|
78
|
+
return { type: 'generateContent', model, promptTokenCount: prompt, candidatesTokenCount: candidates };
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=usage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/lib/usage.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "seshat-scribe",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "The Autonomous Scribe for Static Blogs - AI-powered content generation using Google Gemini",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -11,7 +11,11 @@
|
|
|
11
11
|
"build": "tsc",
|
|
12
12
|
"dev": "tsx src/index.ts",
|
|
13
13
|
"prepare": "npm run build",
|
|
14
|
-
"test": "echo \"No tests yet\" && exit 0"
|
|
14
|
+
"test": "echo \"No tests yet\" && exit 0",
|
|
15
|
+
"release:dry": "npm run build && npm publish --dry-run",
|
|
16
|
+
"release:patch": "npm test && npm version patch -m 'Release v%s' && npm publish && git push && git push --tags",
|
|
17
|
+
"release:minor": "npm test && npm version minor -m 'Release v%s' && npm publish && git push && git push --tags",
|
|
18
|
+
"release:major": "npm test && npm version major -m 'Release v%s' && npm publish && git push && git push --tags"
|
|
15
19
|
},
|
|
16
20
|
"keywords": [
|
|
17
21
|
"blog",
|