-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
run/image-processing: add sample #1445
Conversation
run/image-processing/image.js
Outdated
const path = require('path'); | ||
const {Storage} = require('@google-cloud/storage'); | ||
const storage = new Storage(); | ||
const vision = require('@google-cloud/vision').v1p1beta1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason we can't use the default version?
const {promisify} = require('util'); | ||
const path = require('path'); | ||
const {Storage} = require('@google-cloud/storage'); | ||
const storage = new Storage(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd list all requires
before other variables.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per my PR notes, the image.js file is literally functions/imagemagick/index.js, copied over and with region tags replaced. My goal is not to fork it, hence my previous proposal of uniting them around a code templating tool. Can we move this feedback to a separate issue to the GCF code?
(And of course, feedback welcome on how to approach this idea of shared code across samples)
// [START run_imageproc_handler_analyze] | ||
// Blurs uploaded images that are flagged as Adult or Violence. | ||
exports.blurOffensiveImages = async event => { | ||
// This event represents the triggering Cloud Storage object. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use object
in the function signature instead of reassigning it? Looking at the call site, we use data
. Maybe change the parameter to data
or imageData
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe data
isn't the greatest name. But I'd not re-assign immediately.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm, thanks!
Sometimes, I find it more intuitive to read
async foo () => {
await a();
const res = await b();
return res;
}
but the following is the same:
async foo () => {
await a();
return b();
}
// [START run_imageproc_handler_analyze] | ||
// Blurs uploaded images that are flagged as Adult or Violence. | ||
exports.blurOffensiveImages = async event => { | ||
// This event represents the triggering Cloud Storage object. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe data
isn't the greatest name. But I'd not re-assign immediately.
const detections = result.safeSearchAnnotation || {}; | ||
|
||
if ( | ||
detections.adult === 'VERY_LIKELY' || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you want to add a comment here what the other levels are?
run/image-processing/image.js
Outdated
} | ||
} catch (err) { | ||
console.error(`Failed to analyze ${file.name}.`, err); | ||
return Promise.reject(err); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Usually you don't want to manually create promises
when you have async/await
. It's more idiomatic with async/await
to throw instead.
} catch (err) {
console.error(`Failed to analyze ${file.name}.`, err);
throw err; // Or throw new Error(`Failed to analyze ${file.name}.: ${err}`);
}
|
||
// [START run_imageproc_handler_blur] | ||
// Blurs the given file using ImageMagick, and uploads it to another bucket. | ||
const blurImage = async (file, blurredBucketName) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't you have Blurred_bucket_name
as a global variable? Sorry, might be missing it in the GitHub view.
run/image-processing/image.js
Outdated
console.log(`Downloaded ${file.name} to ${tempLocalPath}.`); | ||
} catch (err) { | ||
console.error('File download failed.', err); | ||
return Promise.reject(err); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
throw instead of promise
} | ||
|
||
await new Promise((resolve, reject) => { | ||
gm(tempLocalPath) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you use promisify
on gm
?
@@ -0,0 +1,31 @@ | |||
{ | |||
"name": "nodejs-image-processing", | |||
"version": "1.0.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think if the package is private, you don't need a version. Private means it can't be published.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's important for developers to think about version numbers for all projects even if not publishing, but I can't say I thought about this one. As a practice what do we prefer to do in samples on version and private?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that version numbers are important. In our samples though we never paid much attention to them and I'd prefer not having them than having meaningless numbers.
Code sharing general feedback I'd say for samples, copy and paste duplication is better than a special setup for the sake of DRY. Pros:
Cons:
cc @bcoe if they have thoughts |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't love that we end up with identical files gradually diverging, although I do like that we have folders of code that work in isolation. Also, I imagine tutorials will potentially diverge more over time.
I think this is a wider discussion for outside this PR however 😄 how can we DRY up code when possible, e.g., if the same Node.js docker setup is used in 5 tutorials, while still having a repo that someone can just clone and run.
# Install Imagemagick into the container image. | ||
# For more on system packages review the system packages tutorial. | ||
# https://cloud.google.com/run/docs/tutorials/system-packages#dockerfile | ||
RUN set -ex; \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It sounds like we use imagemagick in a few other samples? Just wondering about the ImageMagick license type, mainly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We also use it in functions/imagemagick, from which the image.js file in this sample is copied. It is also included in App Engine and Cloud Functions runtimes.
I am now looking at applying the feedback here for image.js to functions/imagemagick/index.js to decouple the improvements. |
Should I go ahead and merge this? I suggest we duplicate the code for now and merge if we have a discussion and decide that we don't like the code duplication. Or would it be easier to start with shared resources and copy if we prefer simplicity over DRY? |
…1456) * functions/imagemagick: robustness and idiomatic improvements * functions/imagemagick: lint fixes * functions/imagemagick: reflow require statements to group storage * functions/imagemagick: nodejs style and comment feedback * functions/imagemagick: improve test coverage, add missing file test * functions/imagemagick: allow cleanup to fail gracefully
@fhinkel now that the functions/imagemagick code is updated, I've synced the code here following the instructions at the bottom of the README. I think this is ready for merge. |
This is a new sample demonstrating how Cloud Run can be triggered by Pub/Sub to perform work with GCS for storage, Cloud Vision integration, and command-line utilities.
A few considerations:
Reviewer Actions
In addition to the normal review of this sample, I would like feedback on whether a more automated approach to code sharing would be reasonable at this time. I anticipate more of this kind of sharing and cross-product reuse to come up, especially as Function Frameworks grow.
fhinkel: Code sharing general feedback
grant: Cloud Run sample review
ace: imagemagick sharing/usage
Node.js practices by anyone.