@@ -15,116 +15,115 @@ const db = admin.firestore();
1515// 2. AI SETUP
1616const genAI = new GoogleGenerativeAI ( process . env . GEMINI_API_KEY ) ;
1717
18- // CATEGORY CONFIGURATION
1918const 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
5251async 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 - z 0 - 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 - z 0 - 9 ] / g, '_' ) ;
126+ fs . writeFileSync ( path . join ( targetFolder , `${ cleanName } .md` ) , text ) ;
127+ }
128+
129+ run ( ) . catch ( console . error ) ;
0 commit comments