Skip to content

Commit

Permalink
Fixed errors when generating tips
Browse files Browse the repository at this point in the history
  • Loading branch information
srgtuszy committed Oct 22, 2024
1 parent 0fd9c5b commit c2ae165
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 42 deletions.
87 changes: 67 additions & 20 deletions functions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,53 @@ const admin = require("firebase-admin");
const { onCall } = require("firebase-functions/v2/https");
const { defineSecret } = require('firebase-functions/params');
const { onInit } = require('firebase-functions/v2/core');
const { GoogleGenerativeAI } = require("@google/generative-ai");
const { GoogleGenerativeAI, SchemaType } = require("@google/generative-ai");
const { functions } = require('firebase-functions');
const geminiKey = defineSecret('GEMINI_API_KEY');

admin.initializeApp();
const db = admin.firestore();

const schema = {
description: "List of tips",
type: SchemaType.ARRAY,
items: {
type: SchemaType.OBJECT,
properties: {
tip: {
type: SchemaType.STRING,
description: "The tip value",
nullable: false,
},
},
required: ["tip"],
},
};

let genAI, model;
onInit(() => {
genAI = new GoogleGenerativeAI(geminiKey.value());
model = genAI.getGenerativeModel({ model: "gemini-1.5-flash" });
model = genAI.getGenerativeModel({
model: "gemini-1.5-pro",
generationConfig: {
responseMimeType: "application/json",
responseSchema: schema,
},
});
});

exports.triggerGenerateTips = onCall({cors: true}, async (req, res) => {
exports.triggerGenerateTips = onCall({cors: true}, async (data, context) => {
console.log("Generating tips");
const measurements = await fetchMeasurements();
console.log(`Fetched ${measurements.length} measurements`);
const tips = await generateTips(measurements);
tips.forEach(async (tip) => {
await db.collection("tips").add(tip);
});

const tipsCollection = db.collection("tips");
const tipsPromises = tips.map(tip => tipsCollection.add(tip));
await Promise.all(tipsPromises);

console.log(`Generated ${tips.length} tips`);
res.send({data: tips});
return {data: tips};
});

async function fetchMeasurements() {
Expand All @@ -38,20 +63,13 @@ async function fetchMeasurements() {
}

async function generateTips(measurements) {
console.log('Generating tips using Gemini...');

// Prepare the prompt by appending the measurements
console.log('Generating tips using Gemini...');
const table = await collectionToTable(db.collection("electricity"));
console.log(table);
const prompt = `
Given the following electricity measurements:
${JSON.stringify(measurements, null, 2)}
Please provide 3 tips on how the user can increase sustainability. The tips should be concise and actionable. Provide the response in JSON format like:
[
{"tip": "First tip"},
{"tip": "Second tip"},
{"tip": "Third tip"}
]
`;
Given the following electricity measurements: ${table}. The kwh means kilowatt hours and the date is the date of the measurement.
Please provide several tips on how the user can increase sustainability. The tips should be concise and actionable. Each tip should refer to concrete
measurements that the user can take to reduce their electricity consumption. Reference those measurements in the tips. Mention if the energy usage is too high or too low.`;
try {
const result = await model.generateContent(prompt);
const generatedText = removeMarkdown(result.response.text());
Expand All @@ -64,6 +82,35 @@ Please provide 3 tips on how the user can increase sustainability. The tips shou
}
}

async function collectionToTable(collectionRef) {
const snapshot = await collectionRef.get();
const documents = snapshot.docs.map(doc => doc.data());

if (documents.length === 0) {
return "No documents found in the collection.";
}

// Determine table headers from the first document
const headers = Object.keys(documents[0]);

// Build the table string
let tableString = `| ${headers.join(' | ')} |\n`;
tableString += `| ${headers.map(() => '---').join(' | ')} |\n`;

documents.forEach(doc => {
const row = headers.map(header => {
const value = doc[header];
if (value.toDate != null) {
return value.toDate().toLocaleString();
}
return value;
}).join(' | ');
tableString += `| ${row} |\n`;
});

return tableString;
}

function removeMarkdown(text) {
// Remove horizontal rules
text = text.replace(/^(-\s*?|\*\s*?|_\s*?){3,}\s*$/gm, '');
Expand Down
49 changes: 27 additions & 22 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -202,29 +202,34 @@ class _HomePageState extends State<HomePage> {
builder: (context, snapshot) {
if (snapshot.hasData) {
final tips = snapshot.data!;
return GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 1.5,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
itemCount: tips.length,
itemBuilder: (context, index) {
final tip = tips[index];
return Card(
child: Padding(
padding: const EdgeInsets.all(10),
child: Center(
child: Text(
tip.tip,
textAlign: TextAlign.center,
),
),
return LayoutBuilder(
builder: (context, constraints) {
final double cardWidth = (constraints.maxWidth - 10) / 2;
return GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
childAspectRatio: cardWidth / 100,
),
itemCount: tips.length,
itemBuilder: (context, index) {
final tip = tips[index];
return Card(
child: Padding(
padding: const EdgeInsets.all(10),
child: Center(
child: Text(
tip.tip,
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 14),
),
),
),
);
},
);
},
);
Expand Down

0 comments on commit c2ae165

Please sign in to comment.