diff --git a/README.md b/README.md index 0435e0ddd2..573c8867a6 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ on Google Cloud Platform. * [Google Cloud Prediction API](#google-cloud-prediction-api) * [Google Cloud Speech API (Beta)](#google-cloud-speech-api-beta) * [Google Translate API](#google-translate-api) + * [Google Cloud Video Intelligence API](#google-cloud-video-intelligence-api) * [Google Cloud Vision API](#google-cloud-vision-api) * [**Management Tools**](#management-tools) * [Stackdriver Debugger](#stackdriver-debugger) @@ -334,6 +335,16 @@ View the [Translate API Node.js samples][translate_samples]. [translate_docs]: https://cloud.google.com/translate/docs/ [translate_samples]: translate +#### Google Cloud Video Intelligence API + +The [Cloud Video Intelligence API][video_intelligence_docs] allows developers to +use Google video analysis technology as part of their applications. + +View the [Cloud Video Intelligence API Node.js samples][video_intelligence_samples]. + +[video_intelligence_docs]: https://cloud.google.com/video-intelligence/docs/ +[video_intelligence_samples]: https://github.com/googleapis/nodejs-video-intelligence/tree/master/samples + #### Google Cloud Vision API The [Cloud Vision API][vision_docs] allows developers to easily integrate vision diff --git a/circle.yml b/circle.yml index e04fddfc2e..42635db152 100644 --- a/circle.yml +++ b/circle.yml @@ -108,6 +108,4 @@ deployment: - node scripts/build "storage-transfer" - node scripts/build "trace" - node scripts/build "translate" - # TODO: This build times out. Does video need more than 10 minutes? - # - node scripts/build "video" - node scripts/build "vision" diff --git a/video/README.md b/video/README.md index 05da66feb4..8d997187cc 100644 --- a/video/README.md +++ b/video/README.md @@ -1,77 +1,5 @@ -Google Cloud Platform logo +Samples for the [Google Cloud Video Intelligence API Node.js Client][client] +have moved to [github.com/googleapis/nodejs-video-intelligence/tree/master/samples/][samples]. -# Google Cloud Video Intelligence API Node.js Samples - -[![Build](https://storage.googleapis.com/cloud-docs-samples-badges/GoogleCloudPlatform/nodejs-docs-samples/nodejs-docs-samples-videointelligence.svg)]() - -The [Cloud Video Intelligence API](https://cloud.google.com/video-intelligence) allows developers to use Google video analysis technology as part of their applications. - -## Table of Contents - -* [Setup](#setup) -* [Samples](#samples) - * [Video Intelligence](#video-intelligence) -* [Running the tests](#running-the-tests) - -## Setup - -1. Read [Prerequisites][prereq] and [How to run a sample][run] first. -1. Install dependencies: - - With **npm**: - - npm install - - With **yarn**: - - yarn install - -[prereq]: ../README.md#prerequisites -[run]: ../README.md#how-to-run-a-sample - -## Samples - -### Video Intelligence - -View the [documentation][video_0_docs] or the [source code][video_0_code]. - -__Usage:__ `node analyze.js --help` - -``` -Commands: - faces Analyzes faces in a video stored in Google Cloud Storage using the Cloud Video Intelligence API. - shots Analyzes shot angles in a video stored in Google Cloud Storage using the Cloud Video - Intelligence API. - labels-gcs Labels objects in a video stored in Google Cloud Storage using the Cloud Video Intelligence API. - labels-file Labels objects in a video stored locally using the Cloud Video Intelligence API. - safe-search Detects explicit content in a video stored in Google Cloud Storage. - -Options: - --help Show help [boolean] - -Examples: - node analyze.js faces gs://demomaker/larry_sergey_ice_bucket_short.mp4 - node analyze.js shots gs://demomaker/sushi.mp4 - node analyze.js labels-gcs gs://demomaker/tomatoes.mp4 - node analyze.js labels-file resources/cat.mp4 - node analyze.js safe-search gs://demomaker/tomatoes.mp4 - -For more information, see https://cloud.google.com/video-intelligence/docs -``` - -[video_0_docs]: https://cloud.google.com/video-intelligence/docs -[video_0_code]: analyze.js - -## Running the tests - -1. Set the **GCLOUD_PROJECT** and **GOOGLE_APPLICATION_CREDENTIALS** environment variables. - -1. Run the tests: - - With **npm**: - - npm test - - With **yarn**: - - yarn test +[client]: https://github.com/googleapis/nodejs-video-intelligence +[samples]: https://github.com/googleapis/nodejs-video-intelligence/tree/master/samples diff --git a/video/analyze.js b/video/analyze.js deleted file mode 100644 index f82c904a8c..0000000000 --- a/video/analyze.js +++ /dev/null @@ -1,357 +0,0 @@ -/** - * Copyright 2017, Google, Inc. - * Licensed under the Apache License, Version 2.0 (the `License`); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an `AS IS` BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -'use strict'; - -function analyzeFaces (gcsUri) { - // [START analyze_faces] - // Imports the Google Cloud Video Intelligence library - const Video = require('@google-cloud/video-intelligence'); - - // Instantiates a client - const video = Video(); - - // The GCS filepath of the video to analyze - // const gcsUri = 'gs://my-bucket/my-video.mp4'; - - const request = { - inputUri: gcsUri, - features: ['FACE_DETECTION'] - }; - - // Detects faces in a video - video.annotateVideo(request) - .then((results) => { - const operation = results[0]; - console.log('Waiting for operation to complete...'); - return operation.promise(); - }) - .then((results) => { - // Gets faces - const faces = results[0].annotationResults[0].faceAnnotations; - faces.forEach((face, faceIdx) => { - console.log(`Face #${faceIdx}`); - console.log(`\tThumbnail size: ${face.thumbnail.length}`); - face.segments.forEach((segment, segmentIdx) => { - segment = segment.segment; - if (segment.startTimeOffset.seconds === undefined) { - segment.startTimeOffset.seconds = 0; - } - if (segment.startTimeOffset.nanos === undefined) { - segment.startTimeOffset.nanos = 0; - } - if (segment.endTimeOffset.seconds === undefined) { - segment.endTimeOffset.seconds = 0; - } - if (segment.endTimeOffset.nanos === undefined) { - segment.endTimeOffset.nanos = 0; - } - console.log(`\tAppearance #${segmentIdx}:`); - console.log(`\t\tStart: ${segment.startTimeOffset.seconds}` + - `.${(segment.startTimeOffset.nanos / 1e6).toFixed(0)}s`); - console.log(`\t\tEnd: ${segment.endTimeOffset.seconds}.` + - `${(segment.endTimeOffset.nanos / 1e6).toFixed(0)}s`); - }); - console.log(`\tLocations:`); - }); - }) - .catch((err) => { - console.error('ERROR:', err); - }); - // [END analyze_faces] -} - -function analyzeLabelsGCS (gcsUri) { - // [START analyze_labels_gcs] - // Imports the Google Cloud Video Intelligence library - const Video = require('@google-cloud/video-intelligence'); - - // Instantiates a client - const video = Video({ - servicePath: `videointelligence.googleapis.com` - }); - - // The GCS filepath of the video to analyze - // const gcsUri = 'gs://my-bucket/my-video.mp4'; - - const request = { - inputUri: gcsUri, - features: ['LABEL_DETECTION'] - }; - - // Detects labels in a video - video.annotateVideo(request) - .then((results) => { - const operation = results[0]; - console.log('Waiting for operation to complete...'); - return operation.promise(); - }) - .then((results) => { - // Gets annotations for video - const annotations = results[0].annotationResults[0]; - - const labels = annotations.segmentLabelAnnotations; - labels.forEach((label) => { - console.log(`Label ${label.entity.description} occurs at:`); - label.segments.forEach((segment) => { - let time = segment.segment; - if (time.startTimeOffset.seconds === undefined) { - time.startTimeOffset.seconds = 0; - } - if (time.startTimeOffset.nanos === undefined) { - time.startTimeOffset.nanos = 0; - } - if (time.endTimeOffset.seconds === undefined) { - time.endTimeOffset.seconds = 0; - } - if (time.endTimeOffset.nanos === undefined) { - time.endTimeOffset.nanos = 0; - } - console.log(`\tStart: ${time.startTimeOffset.seconds}` + - `.${(time.startTimeOffset.nanos / 1e6).toFixed(0)}s`); - console.log(`\tEnd: ${time.endTimeOffset.seconds}.` + - `${(time.endTimeOffset.nanos / 1e6).toFixed(0)}s`); - console.log(`\tConfidence: ${segment.confidence}`); - }); - }); - }) - .catch((err) => { - console.error('ERROR:', err); - }); - // [END analyze_labels_gcs] -} - -function analyzeLabelsLocal (path) { - // [START analyze_labels_local] - // Imports the Google Cloud Video Intelligence library + Node's fs library - const Video = require('@google-cloud/video-intelligence'); - const fs = require('fs'); - - // Instantiates a client - const video = Video(); - - // The local filepath of the video to analyze - // const path = 'my-file.mp4'; - - // Reads a local video file and converts it to base64 - const file = fs.readFileSync(path); - const inputContent = file.toString('base64'); - - // Constructs request - const request = { - inputContent: inputContent, - features: ['LABEL_DETECTION'] - }; - - // Detects labels in a video - video.annotateVideo(request) - .then((results) => { - const operation = results[0]; - console.log('Waiting for operation to complete...'); - return operation.promise(); - }) - .then((results) => { - // Gets annotations for video - const annotations = results[0].annotationResults[0]; - - const labels = annotations.segmentLabelAnnotations; - labels.forEach((label) => { - console.log(`Label ${label.entity.description} occurs at:`); - label.segments.forEach((segment) => { - let time = segment.segment; - if (time.startTimeOffset.seconds === undefined) { - time.startTimeOffset.seconds = 0; - } - if (time.startTimeOffset.nanos === undefined) { - time.startTimeOffset.nanos = 0; - } - if (time.endTimeOffset.seconds === undefined) { - time.endTimeOffset.seconds = 0; - } - if (time.endTimeOffset.nanos === undefined) { - time.endTimeOffset.nanos = 0; - } - console.log(`\tStart: ${time.startTimeOffset.seconds}` + - `.${(time.startTimeOffset.nanos / 1e6).toFixed(0)}s`); - console.log(`\tEnd: ${time.endTimeOffset.seconds}.` + - `${(time.endTimeOffset.nanos / 1e6).toFixed(0)}s`); - console.log(`\tConfidence: ${segment.confidence}`); - }); - }); - }) - .catch((err) => { - console.error('ERROR:', err); - }); - // [END analyze_labels_local] -} - -function analyzeShots (gcsUri) { - // [START analyze_shots] - // Imports the Google Cloud Video Intelligence library - const Video = require('@google-cloud/video-intelligence'); - - // Instantiates a client - const video = Video(); - - // The GCS filepath of the video to analyze - // const gcsUri = 'gs://my-bucket/my-video.mp4'; - - const request = { - inputUri: gcsUri, - features: ['SHOT_CHANGE_DETECTION'] - }; - - // Detects camera shot changes - video.annotateVideo(request) - .then((results) => { - const operation = results[0]; - console.log('Waiting for operation to complete...'); - return operation.promise(); - }) - .then((results) => { - // Gets shot changes - const shotChanges = results[0].annotationResults[0].shotAnnotations; - console.log('Shot changes:'); - - if (shotChanges.length === 1) { - console.log(`The entire video is one shot.`); - } else { - shotChanges.forEach((shot, shotIdx) => { - console.log(`Scene ${shotIdx} occurs from:`); - if (shot.startTimeOffset === undefined) { - shot.startTimeOffset = {}; - } - if (shot.endTimeOffset === undefined) { - shot.endTimeOffset = {}; - } - if (shot.startTimeOffset.seconds === undefined) { - shot.startTimeOffset.seconds = 0; - } - if (shot.startTimeOffset.nanos === undefined) { - shot.startTimeOffset.nanos = 0; - } - if (shot.endTimeOffset.seconds === undefined) { - shot.endTimeOffset.seconds = 0; - } - if (shot.endTimeOffset.nanos === undefined) { - shot.endTimeOffset.nanos = 0; - } - console.log(`\tStart: ${shot.startTimeOffset.seconds}` + - `.${(shot.startTimeOffset.nanos / 1e6).toFixed(0)}s`); - console.log(`\tEnd: ${shot.endTimeOffset.seconds}.` + - `${(shot.endTimeOffset.nanos / 1e6).toFixed(0)}s`); - }); - } - }) - .catch((err) => { - console.error('ERROR:', err); - }); - // [END analyze_shots] -} - -function analyzeSafeSearch (gcsUri) { - // [START analyze_safe_search] - // Imports the Google Cloud Video Intelligence library - const Video = require('@google-cloud/video-intelligence'); - - // Instantiates a client - const video = Video(); - - // The GCS filepath of the video to analyze - // const gcsUri = 'gs://my-bucket/my-video.mp4'; - - const request = { - inputUri: gcsUri, - features: ['EXPLICIT_CONTENT_DETECTION'] - }; - - // Human-readable likelihoods - const likelihoods = ['UNKNOWN', 'VERY_UNLIKELY', 'UNLIKELY', 'POSSIBLE', 'LIKELY', 'VERY_LIKELY']; - - // Detects unsafe content - video.annotateVideo(request) - .then((results) => { - const operation = results[0]; - console.log('Waiting for operation to complete...'); - return operation.promise(); - }) - .then((results) => { - // Gets unsafe content - const explicitContentResults = results[0].annotationResults[0].explicitAnnotation; - console.log('Explicit annotation results:'); - explicitContentResults.frames.forEach((result) => { - if (result.timeOffset === undefined) { - result.timeOffset = {}; - } - if (result.timeOffset.seconds === undefined) { - result.timeOffset.seconds = 0; - } - if (result.timeOffset.nanos === undefined) { - result.timeOffset.nanos = 0; - } - console.log(`\tTime: ${result.timeOffset.seconds}` + - `.${(result.timeOffset.nanos / 1e6).toFixed(0)}s`); - console.log(`\t\tPornography liklihood: ${likelihoods[result.pornographyLikelihood]}`); - }); - }) - .catch((err) => { - console.error('ERROR:', err); - }); - // [END analyze_safe_search] -} - -require(`yargs`) // eslint-disable-line - .demand(1) - .command( - `faces `, - `Analyzes faces in a video stored in Google Cloud Storage using the Cloud Video Intelligence API.`, - {}, - (opts) => analyzeFaces(opts.gcsUri) - ) - .command( - `shots `, - `Analyzes shot angles in a video stored in Google Cloud Storage using the Cloud Video Intelligence API.`, - {}, - (opts) => analyzeShots(opts.gcsUri) - ) - .command( - `labels-gcs `, - `Labels objects in a video stored in Google Cloud Storage using the Cloud Video Intelligence API.`, - {}, - (opts) => analyzeLabelsGCS(opts.gcsUri) - ) - .command( - `labels-file `, - `Labels objects in a video stored locally using the Cloud Video Intelligence API.`, - {}, - (opts) => analyzeLabelsLocal(opts.gcsUri) - ) - .command( - `safe-search `, - `Detects explicit content in a video stored in Google Cloud Storage.`, - {}, - (opts) => analyzeSafeSearch(opts.gcsUri) - ) - .example(`node $0 faces gs://demomaker/larry_sergey_ice_bucket_short.mp4`) - .example(`node $0 shots gs://demomaker/sushi.mp4`) - .example(`node $0 labels-gcs gs://demomaker/tomatoes.mp4`) - .example(`node $0 labels-file cat.mp4`) - .example(`node $0 safe-search gs://demomaker/tomatoes.mp4`) - .wrap(120) - .recommendCommands() - .epilogue(`For more information, see https://cloud.google.com/video-intelligence/docs`) - .help() - .strict() - .argv; diff --git a/video/package.json b/video/package.json deleted file mode 100644 index e17c092aa4..0000000000 --- a/video/package.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "name": "nodejs-docs-samples-videointelligence", - "version": "0.0.1", - "private": true, - "license": "Apache-2.0", - "author": "Google Inc.", - "repository": { - "type": "git", - "url": "https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git" - }, - "engines": { - "node": ">=4.3.2" - }, - "scripts": { - "lint": "samples lint", - "pretest": "npm run lint", - "test": "samples test run --cmd ava -- -T 5m --verbose system-test/*.test.js" - }, - "dependencies": { - "@google-cloud/video-intelligence": "^0.3.2", - "long": "^3.2.0", - "safe-buffer": "5.1.1", - "yargs": "8.0.2" - }, - "devDependencies": { - "@google-cloud/nodejs-repo-tools": "1.4.17", - "ava": "0.22.0", - "proxyquire": "1.8.0" - }, - "cloud-repo-tools": { - "requiresKeyFile": true, - "requiresProjectId": true, - "product": "video", - "samples": [ - { - "id": "video", - "name": "Video Intelligence", - "file": "analyze.js", - "docs_link": "https://cloud.google.com/video-intelligence/docs", - "usage": "node analyze.js --help" - } - ] - } -} diff --git a/video/quickstart.js b/video/quickstart.js deleted file mode 100644 index bb40eafe9f..0000000000 --- a/video/quickstart.js +++ /dev/null @@ -1,73 +0,0 @@ -/** - * Copyright 2017, Google, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -'use strict'; - -// [START videointelligence_quickstart] -// Imports the Google Cloud Video Intelligence library -const Video = require('@google-cloud/video-intelligence'); - -// Instantiates a client -const video = Video(); - -// The GCS filepath of the video to analyze -const gcsUri = 'gs://nodejs-docs-samples-video/quickstart_short.mp4'; - -// Construct request -const request = { - inputUri: gcsUri, - features: ['LABEL_DETECTION'] -}; - -// Execute request -video.annotateVideo(request) - .then((results) => { - const operation = results[0]; - console.log('Waiting for operation to complete... (this may take a few minutes)'); - return operation.promise(); - }) - .then((results) => { - // Gets annotations for video - const annotations = results[0].annotationResults[0]; - - // Gets labels for video from its annotations - const labels = annotations.segmentLabelAnnotations; - labels.forEach((label) => { - console.log(`Label ${label.entity.description} occurs at:`); - label.segments.forEach((segment) => { - segment = segment.segment; - if (segment.startTimeOffset.seconds === undefined) { - segment.startTimeOffset.seconds = 0; - } - if (segment.startTimeOffset.nanos === undefined) { - segment.startTimeOffset.nanos = 0; - } - if (segment.endTimeOffset.seconds === undefined) { - segment.endTimeOffset.seconds = 0; - } - if (segment.endTimeOffset.nanos === undefined) { - segment.endTimeOffset.nanos = 0; - } - console.log(`\tStart: ${segment.startTimeOffset.seconds}` + - `.${(segment.startTimeOffset.nanos / 1e6).toFixed(0)}s`); - console.log(`\tEnd: ${segment.endTimeOffset.seconds}.` + - `${(segment.endTimeOffset.nanos / 1e6).toFixed(0)}s`); - }); - }); - }) - .catch((err) => { - console.error('ERROR:', err); - }); -// [END videointelligence_quickstart] diff --git a/video/resources/cat.mp4 b/video/resources/cat.mp4 deleted file mode 100644 index 0e071b9ec6..0000000000 Binary files a/video/resources/cat.mp4 and /dev/null differ diff --git a/video/system-test/analyze.test.js b/video/system-test/analyze.test.js deleted file mode 100644 index ce54904743..0000000000 --- a/video/system-test/analyze.test.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Copyright 2017, Google, Inc. - * Licensed under the Apache License, Version 2.0 (the `License`); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an `AS IS` BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// https://cloud.google.com/video-intelligence/docs/ - -'use strict'; - -const path = require(`path`); -const test = require(`ava`); -const tools = require(`@google-cloud/nodejs-repo-tools`); - -const cmd = `node analyze.js`; -const cwd = path.join(__dirname, `..`); - -const url = `gs://nodejs-docs-samples-video/quickstart.mp4`; -const shortUrl = `gs://nodejs-docs-samples-video/quickstart_short.mp4`; -const file = `resources/cat.mp4`; - -// analyze_faces -test.serial(`should analyze faces in a GCS file`, async (t) => { - const output = await tools.runAsync(`${cmd} faces ${url}`, cwd); - t.regex(output, /Thumbnail size: \d+/); - t.regex(output, /Start:.*\d+\.\d+s/); - t.regex(output, /End:.*\d+\.\d+s/); -}); - -// analyze_labels_gcs (one scene) -test.serial(`should analyze labels in a GCS file with one scene`, async (t) => { - const output = await tools.runAsync(`${cmd} labels-gcs ${shortUrl}`, cwd); - t.regex(output, /Label shirt occurs at:/); - t.regex(output, /Confidence: \d+\.\d+/); -}); - -// analyze_labels_gcs (multiple scenes) -test.serial(`should analyze labels in a GCS file with multiple scenes`, async (t) => { - const output = await tools.runAsync(`${cmd} labels-gcs ${url}`, cwd); - t.regex(output, /Label shirt occurs at:/); - t.regex(output, /Confidence: \d+\.\d+/); -}); - -// analyze_labels_local -test.serial(`should analyze labels in a local file`, async (t) => { - const output = await tools.runAsync(`${cmd} labels-file ${file}`, cwd); - t.regex(output, /Label whiskers occurs at:/); - t.regex(output, /Confidence: \d+\.\d+/); -}); - -// analyze_shots (multiple shots) -test.serial(`should analyze shots in a GCS file with multiple shots`, async (t) => { - const output = await tools.runAsync(`${cmd} shots ${url}`, cwd); - t.regex(output, /Scene 0 occurs from:/); -}); - -// analyze_shots (one shot) -test.serial(`should analyze shots in a GCS file with one shot`, async (t) => { - const output = await tools.runAsync(`${cmd} shots ${shortUrl}`, cwd); - t.regex(output, /The entire video is one shot./); -}); - -// analyze_safe_search -test.serial(`should analyze safe search results in a GCS file`, async (t) => { - const output = await tools.runAsync(`${cmd} safe-search ${url}`, cwd); - t.regex(output, /Time: \d+\.\d+s/); - t.regex(output, /Explicit annotation results:/); -}); diff --git a/video/system-test/quickstart.test.js b/video/system-test/quickstart.test.js deleted file mode 100644 index 20965be0c6..0000000000 --- a/video/system-test/quickstart.test.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright 2017, Google, Inc. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -'use strict'; - -const path = require(`path`); -const test = require(`ava`); -const tools = require(`@google-cloud/nodejs-repo-tools`); - -const cmd = `node quickstart.js`; -const cwd = path.join(__dirname, `..`); - -test(`should analyze a hardcoded video`, async (t) => { - const output = await tools.runAsync(cmd, cwd); - t.regex(output, /Label standing occurs at:/); -});