Skip to content

Commit 6ad1d36

Browse files
update
1 parent a8359ea commit 6ad1d36

File tree

2 files changed

+83
-84
lines changed

2 files changed

+83
-84
lines changed

.github/workflows/hourly-ai.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
- name: Install dependencies
2424
run: |
2525
npm init -y
26-
npm install firebase-admin @google/generative-ai
26+
npm install firebase-admin @google/generative-ai@latest
2727
2828
- name: Execute AI Script
2929
env:

scripts/generate-ai-tip.js

Lines changed: 82 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -15,116 +15,115 @@ const db = admin.firestore();
1515
// 2. AI SETUP
1616
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
1717

18-
// CATEGORY CONFIGURATION
1918
const categoryMap = {
2019
"performance": {
2120
name: "Performance Tools Hub",
2221
folder: "performance",
23-
tools: ["JMeter", "NeoLoad", "LoadRunner", "k6", "Locust", "Gatling"],
24-
focus: "Load testing strategies, scripting bottlenecks, and tool-specific optimizations."
22+
tools: ["JMeter", "NeoLoad", "LoadRunner", "k6", "Locust"],
23+
focus: "Load testing strategies and tool-specific optimizations."
2524
},
2625
"sre": {
2726
name: "SRE & Observability",
2827
folder: "sre",
29-
tools: ["Kubernetes", "AKS", "Azure-Monitor", "Grafana", "Datadog", "Dynatrace", "AppDynamics"],
30-
focus: "Reliability engineering, SLIs/SLOs, Error Budgets, and Infrastructure Observability."
28+
tools: ["Kubernetes", "AKS", "Azure-Monitor", "Grafana", "Datadog"],
29+
focus: "Reliability engineering and SLIs/SLOs."
3130
},
3231
"devops": {
3332
name: "DevOps & CI/CD",
3433
folder: "devops",
35-
tools: ["GitHub-Actions", "Jenkins", "Docker", "Linux-Kernel-Tuning", "Terraform", "Ansible"],
36-
focus: "Pipeline automation, container orchestration, and OS-level performance tuning."
34+
tools: ["GitHub-Actions", "Jenkins", "Docker", "Terraform"],
35+
focus: "Pipeline automation and container orchestration."
3736
},
3837
"performance_mastery": {
3938
name: "Basics to Advanced Mastery",
4039
folder: "performance_mastery",
41-
tools: ["Fundamentals", "Workload-Design", "Queueing-Theory", "Bottleneck-Analysis", "Capacity-Planning"],
42-
focus: "The professional roadmap: explaining core concepts like Little's Law from absolute basics to architectural expert level."
40+
tools: ["Fundamentals", "Workload-Design", "Bottleneck-Analysis"],
41+
focus: "Core performance concepts from beginner to expert level."
4342
},
4443
"trends_ai": {
4544
name: "Innovation & AI Trends",
4645
folder: "trends_ai",
47-
tools: ["GenAI-in-Testing", "Predictive-Analytics", "Autonomous-Load-Testing", "LLM-Optimizations", "Tech-Trends-2025"],
48-
focus: "Cutting-edge updates: How AI is transforming performance, autonomous remediation, and the future of engineering."
46+
tools: ["GenAI-in-Testing", "Autonomous-Load-Testing", "Tech-Trends-2026"],
47+
focus: "How AI and new trends are changing SRE and Testing."
4948
}
5049
};
5150

5251
async function run() {
53-
try {
54-
// Selection Logic: Pick a random category and tool
55-
const keys = Object.keys(categoryMap);
56-
const selectedCatKey = keys[Math.floor(Math.random() * keys.length)];
57-
const category = categoryMap[selectedCatKey];
58-
const selectedTool = category.tools[Math.floor(Math.random() * category.tools.length)];
59-
60-
console.log(`🚀 Little's Law Team is generating content for: ${selectedTool} (${category.name})`);
61-
62-
// Model initialization (Using the most stable high-speed model)
63-
const model = genAI.getGenerativeModel({ model: "gemini-1.5-flash" });
64-
65-
const prompt = `
66-
ACT AS: The Senior Leadership Team at Little's Law Academy. You are world-class Architects with 30 years of history.
67-
TOPIC: ${selectedTool}.
68-
CATEGORY: ${category.name}.
69-
THEME: ${category.focus}.
70-
71-
GOAL: Write a technical briefing (Approx 350 words) for our students.
72-
IMPORTANT: Do not mention AI. Speak as 'We, the Little's Law Team'.
73-
74-
STRUCTURE (Use Strictly valid Markdown):
75-
# ${selectedTool} Internal Team Briefing
76-
77-
## ⚡ From the Trenches (Experience)
78-
Share an emotional and highly specific "war story" from our team's history. Talk about a 3 AM system collapse, a critical latency spike in production, or the stress of a failing BFCM load test. Connect this emotionally to why ${selectedTool} is vital.
79-
80-
## 🛠️ Architecture Deep-Dive
81-
Break down a complex technical concept. Talk about specific metrics (P99 latency, Throughput vs Goodput, TCP handshakes, or Heap usage). Explain the internal mechanics.
82-
83-
## 💻 Technical Implementation
84-
Provide one exact technical example that our team recommends. This MUST be a code block (CLI command, YAML config, JMeter Groovy snippet, or Python k6 script).
85-
86-
## 💡 Our Engineering Philosophy
87-
One closing piece of mentorship/wisdom regarding the current tech landscape or the rise of AI in our field.
88-
89-
TONE: High-authority, expert-level, yet inspiring and mentorship-focused.
90-
`;
91-
92-
const result = await model.generateContent(prompt);
93-
const response = await result.response;
94-
const markdownContent = response.text();
95-
96-
if (!markdownContent) throw new Error("Empty response from Engine");
97-
98-
// 1. SYNC TO FIREBASE (Site-wide Banner)
99-
await db.collection('admin_data').doc('hourly_tip').set({
100-
content: markdownContent,
101-
tool: selectedTool,
102-
folder: category.folder,
103-
author: "Little's Law Team",
104-
lastUpdated: new Date().toISOString()
105-
});
106-
107-
// 2. SYNC TO GITHUB (Create Folders & Save Markdown)
108-
const baseDocsDir = path.join(__dirname, '../docs');
109-
const targetFolder = path.join(baseDocsDir, category.folder);
110-
111-
// Ensure path exists
112-
if (!fs.existsSync(targetFolder)) {
113-
fs.mkdirSync(targetFolder, { recursive: true });
52+
// Attempt these models in order of preference
53+
const modelNames = ["gemini-1.5-flash", "gemini-pro"];
54+
let successfulGeneration = false;
55+
56+
// Pick content first
57+
const keys = Object.keys(categoryMap);
58+
const selectedCatKey = keys[Math.floor(Math.random() * keys.length)];
59+
const category = categoryMap[selectedCatKey];
60+
const selectedTool = category.tools[Math.floor(Math.random() * category.tools.length)];
61+
62+
for (const modelName of modelNames) {
63+
if (successfulGeneration) break;
64+
65+
try {
66+
console.log(`📡 Trying generation with model: ${modelName}...`);
67+
const model = genAI.getGenerativeModel({ model: modelName });
68+
69+
const prompt = `
70+
ACT AS: The Senior Leadership Team at Little's Law Academy. You are world-class Architects.
71+
TOPIC: ${selectedTool}.
72+
CATEGORY: ${category.name}.
73+
GOAL: Write a technical masterclass (350 words) for our students.
74+
75+
STRUCTURE:
76+
# ${selectedTool} Internal Team Briefing
77+
## ⚡ From the Trenches
78+
Tell an emotional war story about this topic from our team's 30-year history.
79+
## 🛠️ Architecture Deep-Dive
80+
Technical analysis of P99 metrics, bottlenecks, or internal mechanics.
81+
## 💻 Technical Implementation
82+
Provide a code snippet or CLI command (formatted in a markdown code block).
83+
## 💡 Team Wisdom
84+
A closing mentor tip.
85+
86+
IMPORTANT: Do not mention AI. Only say "Little's Law Team".
87+
`;
88+
89+
const result = await model.generateContent(prompt);
90+
const response = await result.response;
91+
const text = response.text();
92+
93+
if (text) {
94+
console.log(`✅ Success using ${modelName}`);
95+
await saveResult(text, selectedTool, category);
96+
successfulGeneration = true;
97+
}
98+
99+
} catch (error) {
100+
console.warn(`⚠️ Model ${modelName} failed or not found. trying next...`);
114101
}
102+
}
115103

116-
// Clean name for file consistency
117-
const cleanName = selectedTool.toLowerCase().replace(/[^a-z0-9]/g, '_');
118-
const filePath = path.join(targetFolder, `${cleanName}.md`);
119-
120-
fs.writeFileSync(filePath, markdownContent);
121-
122-
console.log(`✅ CONTENT PUBLISHED: docs/${category.folder}/${cleanName}.md`);
123-
124-
} catch (error) {
125-
console.error("❌ Fatal Team Content Error:", error.message);
104+
if (!successfulGeneration) {
105+
console.error("❌ All AI models failed. Check your API Key permissions and quota.");
126106
process.exit(1);
127107
}
128108
}
129109

130-
run();
110+
async function saveResult(text, tool, category) {
111+
// Save to Firebase
112+
await db.collection('admin_data').doc('hourly_tip').set({
113+
content: text,
114+
tool: tool,
115+
folder: category.folder,
116+
author: "Little's Law Team",
117+
lastUpdated: new Date().toISOString()
118+
});
119+
120+
// Save to GitHub
121+
const baseDocsDir = path.join(__dirname, '../docs');
122+
const targetFolder = path.join(baseDocsDir, category.folder);
123+
if (!fs.existsSync(targetFolder)) fs.mkdirSync(targetFolder, { recursive: true });
124+
125+
const cleanName = tool.toLowerCase().replace(/[^a-z0-9]/g, '_');
126+
fs.writeFileSync(path.join(targetFolder, `${cleanName}.md`), text);
127+
}
128+
129+
run().catch(console.error);

0 commit comments

Comments
 (0)