I was trying out this codelab code snippet by Google. I wanted to alter it in a way so that the Vision API metadata would be stored in a relational MySQL using the CloudSQL service - following their examples on how to connect Cloud Functions with CloudSQL.
The code I ended up deploys but upon triggering the function (by uploading a new image) I get a vague 'connection error' in the logs with no more information. This is my code at this moment:
const vision = require('@google-cloud/vision');
const Storage = require('@google-cloud/storage');
const client = new vision.ImageAnnotatorClient();
const winston = require('winston');
const {LoggingWinston} = require('@google-cloud/logging-winston');
const loggingWinston = new LoggingWinston();
const logger = winston.createLogger({
level: 'info',
transports: [new winston.transports.Console(), loggingWinston],
});
const createUnixSocketPool = async (config) => {
const dbSocketPath = "/cloudsql"
return await mysql.createPool({
user: 'root',
password: 'mypassword',
database: 'mydatabase',
socketPath: `${dbSocketPath}/cs-03-282615:europe-west1:mydatabase`,
...config
});
}
const createPool = async () => {
const config = {
connectionLimit: 5,
connectTimeout: 10000,
acquireTimeout: 10000,
waitForConnections: true,
queueLimit: 0,
}
return await createUnixSocketPool(config);
};
let pool;
const poolPromise = createPool()
.then(async (pool) => {
return pool;
})
.catch((err) => {
logger.error(err);
process.exit(1)
});
exports.vision_analysis = async (event, context, pool) => {
console.log(`Event: ${JSON.stringify(event)}`);
const filename = event.name;
const filebucket = event.bucket;
console.log(`New picture uploaded ${filename} in ${filebucket}`);
const request = {
image: { source: { imageUri: `gs://${filebucket}/${filename}` } },
features: [
{ type: 'LABEL_DETECTION' },
{ type: 'IMAGE_PROPERTIES' },
{ type: 'SAFE_SEARCH_DETECTION' }
]
};
// invoking the Vision API
const [response] = await client.annotateImage(request);
console.log(`Raw vision output for: ${filename}: ${JSON.stringify(response)}`);
if (response.error === null) {
// listing the labels found in the picture
const labels = response.labelAnnotations
.sort((ann1, ann2) => ann2.score - ann1.score)
.map(ann => ann.description)
console.log(`Labels: ${labels.join(', ')}`);
// retrieving the dominant color of the picture
const color = response.imagePropertiesAnnotation.dominantColors.colors
.sort((c1, c2) => c2.score - c1.score)[0].color;
const colorHex = decColorToHex(color.red, color.green, color.blue);
console.log(`Colors: ${colorHex}`);
// determining if the picture is safe to show
const safeSearch = response.safeSearchAnnotation;
const isSafe = ["adult", "spoof", "medical", "violence", "racy"].every(k =>
!['LIKELY', 'VERY_LIKELY'].includes(safeSearch[k]));
console.log(`Safe? ${isSafe}`);
if (isSafe) {
const pool = await poolPromise();
const stmt = 'INSERT INTO sc_03_metadata_schema (labels, color, created) VALUES (?, ?, ?)';
await pool.query(stmt, [labels, colorHex, NOW()]);
console.log("Stored metadata in CloudSQL");
}
} else {
throw new Error(`Vision API error: code ${response.error.code}, message: "${response.error.message}"`);
}
};
function decColorToHex(r, g, b) {
return '#' + Number(r).toString(16).padStart(2, '0') +
Number(g).toString(16).padStart(2, '0') +
Number(b).toString(16).padStart(2, '0');
}
The full error is as such: Error Logs