Build an AI-enhanced image
processing enterprise workflow:
Image archive, analysis & report generation,
or "How to spice up file backups"🥱
Seattle:: Fall 2025
Wesley Chun
AI TPgM, Red Hat and
Principal, CyberWeb
@wescpy@
AI TPM, Red Hat and Principal, CyberWeb
● Mission: enable developer success
with Google tools, platforms & APIs,
using OSS AI projects in GCP projects;
and train accelerated Python users
● Focus: OSS AI tools, Google Cloud
(GCP) & Workspace (GWS) APIs; GAE
migrations; Google X-product sol'ns
● Services: technical consulting,
training, engineering, speaking, code
samples, hands-on tutorials, public
technical content (blogs, social, etc.)
About the speaker (and Red Hat AI)
Previous experience / background
● Software Engineer & Developer Advocate
○ Google, Sun, HP, Cisco, EMC, Xilinx &
○ Original Yahoo!Mail engineer/SWE
● Technical trainer, teacher, instructor
○ Teaching Math, Linux, Python since '83
○ Adjunct CS Faculty at local SV colleges
● Python community member
○ Popular Core Python series author
○ Python Software Foundation Fellow
● AB (Math/CS) & CMP (Music/Piano), UC
Berkeley and MSCS, UC Santa Barbara
● Adjunct Computer Science Faculty, Foothill
College (Silicon Valley)
GWS Dev Show
goo.gl/JpBQ40
GAE migration
bit.ly/3xk2Swi
Why and Agenda
● Organizations have real-life business problems seeking solutions
● Google Cloud/GCP and Google Workspace/GWS: most Google APIs
○ May know GCP for compute, storage, data, and AI/ML services
○ GWS known for its apps (Gmail, Drive,...); also for developers(!)
● Many other APIs from Google AI, Maps, YouTube, Firebase, etc.
● Use all of them to build novel solutions to unique business problems
1
Using Google APIs
2
Google APIs
sampler
3
AI-enhanced image
processing workflow
4
Wrap-up
464!
(2024)
01
Using Google APIs
Getting started & the nuts-n-bolts
General steps
1. Go to Cloud Console
2. Login to Google/Gmail account
(Workspace domain may require admin approval)
3. Create project (per application)
4. Enable APIs to use
5. Enable billing (CC, Free Trial, etc.)
6. Download client library(ies)
7. Create & download credentials
8. Write code*
9. Run code (may need to authorize)
Google APIs: how to use
*In your code
1. Import API client library
2. Create API client object
3. Use client to make API Calls
Costs & pricing
● GCP & GMP: pay-per-use (CC req'd)
● GWS: "subscription" (incl. $0USD/mo.)
● GMP: $200/mo. free usage
● GCP Free Trial: $300/1Q
● GCP "Always Free" tier
○ Some products have free tier
○ Daily or monthly quota
○ Must exceed to incur billing
● More on both programs at
cloud.google.com/free
Cloud/GCP console
console.cloud.google.com
● Hub of all developer activity
● Applications == projects
○ New project for new apps
○ Projects have a billing acct
● Manage billing accounts
○ Financial instrument required
○ Personal or corporate credit cards,
Free Trial, and education grants
● Access GCP product settings
● Manage users & security
● Manage APIs in devconsole
● View application statistics
● En-/disable Google APIs
● Obtain application credentials
Using Google APIs
goo.gl/RbyTFD
API manager aka Developers Console (devconsole)
console.developers.google.com
Three different credentials types
● Simple: API keys (to access public data)
○ Simplest form of authorization: an API key; tied to a project
○ Allows access to public data
○ Do not put in code, lose, or upload to GitHub! (can be restricted however)
○ Supported by: Google Maps, (some) YouTube, (some) GCP, etc.
● Authorized: OAuth client IDs (to access data owned by [human] user)
○ Provides additional layer of security via OAuth2 (RFC 6749)
○ Owner must grant permission for your app to access their data
○ Access granularity determined by requested permissions (user scopes)
○ Supported by: Google Workspace, (some) YouTube, (some) GCP, etc.
● Authorized: service accounts (to access data owned by an app/robot user)
○ Provides additional layer of security via OAuth2 or JWT (RFC 7519)
○ Project owning data grants permission implicitly; requires public-private key-pair
○ Access granularity determined by Cloud IAM permissions granted to service account key-pair
○ Supported by: GCP, (some) Google Workspace, etc.
Blog series:
dev.to/wescpy
Two different client library "styles"
● "Platform" client libraries (lower-level)
○ Supports multiple products as a "lowest-common denominator"
○ Manage API service endpoints (setup & use)
○ Manage authorization (API keys, OAuth client IDs, service accounts)
○ Google Workspace, Cloud/GCP, Google Analytics, YouTube, Google Ads APIs, etc.
○ developers.google.com/api-client-library
● "Product" client libraries (higher-level)
○ Custom client libraries made specifically for each product
○ Managing API service endpoints & security mostly taken care of
○ Only need to create a "client" to use API services
○ Cloud/GCP: cloud.google.com/apis/docs/cloud-client-libraries, Firebase,
Maps: developers.google.com/maps/web-services/client-library
● Some Google APIs families support both, e.g., Cloud/GCP
Google APIs client
libraries for common
languages; demos in
developers.google.com/api-
client-library
cloud.google.com/apis/docs
/cloud-client-libraries
(User-)authorized API access(lower-level, older, generic)
OAuth boilerplate
goo.gl/KMfbeK
from googleapiclient import discovery
from httplib2 import Http
from oauth2client import file, client, tools
SCOPES = ... # at least one (string or array of strings)
# 'storage.json' - where to store OAuth2 tokens from API
# 'client_secret.json' - OAuth2 client ID & secret (download from DevConsole)
store = file.Storage('storage.json')
creds = store.get()
if not creds or creds.invalid:
flow = client.flow_from_clientsecrets('client_secret.json', SCOPES)
creds = tools.run_flow(flow, store)
# create API service endpoint; for example: API='sheets', VERSION='v4'
SERVICE = discovery.build(API, VERSION, http=creds.authorize(Http()))
(User-)authorized API access(lower-level, newer, generic)
from googleapiclient import discovery
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from google.oauth2 import credentials
SCOPES = ... # at least one (string or array of strings)
# 'storage.json' - where to store OAuth2 tokens from API
# 'client_secret.json' - OAuth2 client ID & secret (download from DevConsole)
TOKENS = 'storage.json' # OAuth2 token storage
if os.path.exists(TOKENS):
creds = credentials.Credentials.from_authorized_user_file(TOKENS)
if not (creds and creds.valid):
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file('client_secret.json', SCOPES)
creds = flow.run_local_server()
with open(TOKENS, 'w') as token:
token.write(creds.to_json())
# create API service endpoint; for example: API='sheets', VERSION='v4'
SERVICE = discovery.build(API, VERSION, http=creds.authorize(Http()))
OAuth2 or
API key
HTTP-based REST APIs 1
HTTP
2
Google APIs request-response workflow
● Application makes request
● Request received by service
● Process data, return response
● Results sent to application
(typical client-server model)
02
Google APIs
Sampler of GCP & GWS APIs
formerly
( )
● GWS developer home: developers.google.com/gsuite
● GWS developer intro: youtu.be/NqumcYgj5LI
● GWS REST APIs: youtu.be/2VpvWhDdXsI
● GWS Apps Script: youtu.be/xDovB0pu4OU
● Comprehensive overview: youtu.be/kkp0aNGlynw
Google Workspace
(formerly G Suite and Google Apps)
(GWS) APIs
Google Compute Engine, Cloud Storage
AWS EC2 & S3; Rackspace; Joyent
SaaS
Software as a Service
PaaS
Platform as a Service
IaaS
Infrastructure as a Service
Google Apps Script
Salesforce1/force.com
Google Workspace (was G Suite/Google Apps)
Yahoo!Mail, Hotmail, Salesforce, Netsuite, Office 365
Google App Engine, Cloud Functions
Heroku, Cloud Foundry, Engine Yard, AWS Lambda
Google BigQuery, Cloud SQL, Vertex AI,
Cloud Firestore, NL, Vision, Pub/Sub
AWS Kinesis, RDS; Windows Azure SQL, Docker
Google Cloud Platform vs. Google Workspace
GWS
APIs
GCP
APIs
List (first 100) files/folders in Drive (older, OAuth2)
from __future__ import print_function
from googleapiclient import discovery
from httplib2 import Http
from oauth2client import file, client, tools
SCOPES = 'https://www.googleapis.com/auth/drive.metadata.readonly'
store = file.Storage('storage.json')
creds = store.get()
if not creds or creds.invalid:
flow = client.flow_from_clientsecrets('client_secret.json', SCOPES)
creds = tools.run_flow(flow, store)
DRIVE = discovery.build('drive', 'v3', http=creds.authorize(Http()))
files = DRIVE.files().list().execute().get('files', [])
for f in files:
print(f['name'], f['mimeType'])
Listing your files
goo.gl/ZIgf8k
github.com/wescpy/gsuite-apis-intro
Migrate SQL data to a Sheet
# read SQL data then create new spreadsheet & add rows into it
FIELDS = ('ID', 'Customer Name', 'Product Code',
'Units Ordered', 'Unit Price', 'Status')
cxn = sqlite3.connect('db.sqlite')
cur = cxn.cursor()
rows = cur.execute('SELECT * FROM orders').fetchall()
cxn.close()
rows.insert(0, FIELDS)
DATA = {'properties': {'title': 'Customer orders'}}
SHEET_ID = SHEETS.spreadsheets().create(body=DATA,
fields='spreadsheetId').execute().get('spreadsheetId')
SHEETS.spreadsheets().values().update(spreadsheetId=SHEET_ID, range='A1',
body={'values': rows}, valueInputOption='RAW').execute()
Migrate SQL data
to Sheets
goo.gl/N1RPwC
Storage: listing buckets
from __future__ import print_function
from googleapiclient import discovery
GCS = discovery.build('storage', 'v1')
BUCKET = YOUR_BUCKET
# send bucket name & return fields to API, display results
print('n** Objects in bucket %r...' % BUCKET)
FIELDS = 'items(name,size)'
files = GCS.objects().list(bucket=BUCKET, fields=FIELDS
).execute().get('items') or [{'name': '(none)', 'size': 'NaN'}]
for f in files:
print(' %s (%s)' % (f['name'], f['size']))
IMG = 'gs://cloud-samples-data/vision/using_curl/shanghai.jpeg'
body = {'requests': [{
'image': {'source': {'imageUri': IMG}},
'features': [{'type': 'LABEL_DETECTION'}],
}]}
VISION = discovery.build('vision', 'v1', developerKey=API_KEY)
labeling = VISION.images().annotate(body=body).execute().get('responses')
for labels in labeling:
if 'labelAnnotations' in labels:
print('** Labels detected (and confidence score):')
for label in labels['labelAnnotations']:
print(label['description'], '(%.2f%%)' % (label['score']*100.))
Vision: label annotation/object detection
$ python3 label-detect.py
Labels (and confidence score):
==============================
People (95.05%)
Street (89.12%)
Mode of transport (89.09%)
Transport (85.13%)
Vehicle (84.69%)
Snapshot (84.11%)
Urban area (80.29%)
Infrastructure (73.14%)
Road (72.74%)
Pedestrian (68.90%)
Vision: label annotation/object detection
g.co/codelabs/vision-python
Image: Google
03
AI/ML-driven image
processing workflow
Archive and analyze GWS images with GCP
mfg: licensed from iStockPhoto
arch: public domain from Piqsels
media: by RAEng Pubs from Pixabay
advert: by Free-Photos from Pixabay
Image licensed from Adobe
Image licensed from iStockPhoto
Image: Gerd Altmann from Pixabay
Image: CC BY 2.0 Mike MacKenzie from VPNSRUS
Image: CC0 PD from RawPixel
Cloud
Vision
Google Workspace Google Cloud
Image processing application architecture
Cloud
Storage
Drive
Sheets
Archive
image
Categorize
image
Record
results
Google Maps Google AI
Maps
(Static)
Geolocate
image & map
LLM image
analysis
Application initialization and API setup
from __future__ import print_function
import argparse, base64, io, os, sys, time, webbrowser
from googleapiclient import discovery, http
from httplib2 import Http
from oauth2client import file, client, tools
from PIL import Image
from google import genai
from settings import API_KEY
k_ize = lambda b: '%6.2fK' % (b/1000.) # bytes to kBs
FILE = 'YOUR_IMG_ON_DRIVE'
BUCKET = 'YOUR_BUCKET_NAME'
SHEET = 'YOUR_SHEET_ID'
TOP = 5 # get top Vision API labels
DEBUG = False
# create Gemini API client object plus constants
PROMPT = 'Describe this image in 2-3 sentences'
MODEL = 'gemini-2.5-flash'
GENAI = genai.Client(api_key=API_KEY)
# process credentials for OAuth2 tokens
SCOPES = (
'https://www.googleapis.com/auth/drive.readonly',
'https://www.googleapis.com/auth/devstorage',
'https://www.googleapis.com/auth/cloud-vision',
'https://www.googleapis.com/auth/spreadsheets',
)
store = file.Storage('storage.json')
creds = store.get()
if not creds or creds.invalid:
flow = client.flow_from_clientsecrets(
'client_secret.json', SCOPES)
creds = tools.run_flow(flow, store)
# create Google API client objects
HTTP = creds.authorize(Http())
DRIVE = discovery.build('drive', 'v3', http=HTTP)
GCS = discovery.build('storage', 'v1', http=HTTP)
VISION = discovery.build('vision', 'v1', http=HTTP)
SHEETS = discovery.build('sheets', 'v4', http=HTTP)
def drive_get_file(fname):
rsp = DRIVE.files().list(q="name='%s'" % fname).execute().get['files'][0]
fileId, fname, mtype = rsp['id'], rsp['name'], rsp['mimeType']
blob = DRIVE.files().get_media(fileId).execute()
return fname, mtype, rsp['modifiedTime'], blob, drive_geoloc_maps(fileId)
Individual API components
def drive_geoloc_maps(file_id):
imd = DRIVE.files().get(fileId=file_id).execute().get('imageMediaMetadata')
return 'https://maps.googleapis.com/maps/api/staticmap?size=480x480&markers=%s,%s&key=%s' % (
imd['location']['latitude'], imd['location']['longitude'], API_KEY)
def genai_analyze_img(media):
image = Image.open(io.BytesIO(media))
return GENAI.models.generate_content(
model=MODEL, contents=(PROMPT, image)).text.strip()
def sheet_append_row(sheet, row):
rsp = SHEETS.spreadsheets().values().append(
spreadsheetId=sheet, range='Sheet1',
body={'values': rows}).execute()
return rsp.get('updates').get('updatedCells')
def vision_label_img(img, top):
body = {'requests': [{'image': {'content': img}, 'features':
[{'type': 'LABEL_DETECTION', 'maxResults': top}]}]}
rsp = VISION.images().annotate(
body=body).execute().get('responses', [{}])[0]
return ', '.join('%s (%.2f%%)' % (label['description'],
label['score']*100.) for label in rsp['labelAnnotations'])
def gcs_blob_upload(fname, bucket, blob, mimetype):
body = {'name': fname, 'uploadType': 'multipart',
'contentType': mimetype}
return GCS.objects().insert(bucket, body, blob).execute()
Acquire file info from Drive; Maps geolocation
def drive_get_file(fname):
rsp = DRIVE.files().list(
q="name='%s'" % fname).execute().get['files'][0]
fileId, fname, mtype = rsp['id'], rsp['name'], rsp['mimeType']
blob = DRIVE.files().get_media(fileId).execute()
return mtype, rsp['modifiedTime'], blob, drive_geoloc_maps(fileId)
Upload file media/binary/blob to Google Cloud Storage
def gcs_blob_upload(fname, bucket, blob, mimetype):
body = {
'name': fname,
'uploadType': 'multipart',
'contentType': mimetype
}
return GCS.objects().insert(
bucket, body, blob).execute()
Cloud Vision label annotation (image contents)
def vision_label_img(img, top):
body = [{'image': {'content': img},
'features': [{
'type': 'LABEL_DETECTION',
'maxResults': top,
}]
}]
rsp = VISION.images().annotate(
body={'requests': body}).execute()['responses'][0]
return ', '.join('%s (%.2f%%)' % (
label['description'], label['score']*100.)
for label in rsp['labelAnnotations'])
Analyze & describe image contents with LLM
from PIL import Image
from google import genai
from settings import API_KEY
# gen AI setup
PROMPT = 'Describe this image in 2-3 sentences'
MODEL = 'gemini-2.5-flash'
GENAI = genai.Client(api_key=API_KEY)
def genai_analyze_img(media):
'analyze image with genAI LLM and return analysis'
image = Image.open(io.BytesIO(media))
return GENAI.models.generate_content(
model=MODEL, contents=(PROMPT, image)).text.strip()
Create Google Maps map if image geolocated
MAPS_URL = 'https://maps.googleapis.com/maps/api/staticmap?size=480x480&markers='
def drive_geoloc_maps(file_id):
imd = DRIVE.files().get(fileId=file_id,
fields='imageMediaMetadata').execute().get('imageMediaMetadata')
if not imd or 'location' not in imd:
return ''
return '%s%s,%s&key=%s' % (MAPS_URL, imd['location']['latitude'],
imd['location']['longitude'], API_KEY)
Store all results in one row to Google Sheets
def sheet_append_row(sheet, row):
rsp = SHEETS.spreadsheets().values().append(
spreadsheetId=sheet, range='Sheet1',
body={'values': row}).execute()
return rsp.get('updates').get('updatedCells')
Complete image processing workflow
def main(fname, bucket, sheet_id, top):
fname, mtype, ftime, data, maps = drive_get_img(fname)
gcs_blob_upload(fname, bucket, data, mtype)
viz = vision_label_img(data, top)
gem = genai_analyze_img(data)
sheet_append_row(sheet_id,
[fname, mtype, ftime, len(data), viz, gem, maps])
● Project goal: Imagining an actual enterprise use case and solve it!
● Specific goals: free-up highly-utilized resource, archive data to colder/cheaper
storage, analyze images, generate report for mgmt
● Download image binary from Google Drive
● If image geolocated use Google Maps to create static map
● Upload object to Cloud Storage bucket
● Process image label/object detection by Cloud Vision
● GenAI request for Gemini to summarize image contents
● Write back-up location & analysis results into Google Sheets
● Blog post: goo.gle/3nPxmlc (original post); Cloud X-post
● Codelab: free, online, self-paced, hands-on tutorial
● g.co/codelabs/drive-gcs-vision-sheets
● Application source code (Gemini & Maps version in /alt)
● github.com/wescpy/analyze_gsimg
App summary
04
Wrap-up
Summary & resources
Session Summary
● File backup: "boring" ... while AI/ML: "exciting"
● Merge together for possible business scenario solvable with APIs
● Google provides more than just apps
○ More than search, YouTube, Android, Chrome, and Gmail/Docs
○ "Much" Google technology available to developers via APIs
● Google APIs do vary
○ Alas, developer experience differs between product families
○ Some products have higher-level product client libraries
○ Others require use of lower-level client libraries (or none at all!)
■ Lower-level may be useful as lowest common denominator
● Interesting possibilities using multiple Google product APIs
Other Google APIs & platforms
● Firebase (mobile development platform + RT DB; ML Kit)
○ firebase.google.com & firebase.google.com/docs/ml-kit
● Google Looker/Data Studio (data visualization, dashboards, etc.)
○ datastudio.google.com/overview
○ goo.gle/datastudio-course
● Actions on Google/Assistant/DialogFlow (voice apps)
○ developers.google.com/actions
● YouTube (Data, Analytics, and Livestreaming APIs)
○ developers.google.com/youtube
● Google Maps (Maps, Routes, and Places APIs)
○ developers.google.com/maps
● Flutter (native apps [Android, iOS, web] w/1 code base[!])
○ flutter.dev
● Documentation
○ GCP: cloud.google.com/{docs,vision,automl,storage,language,speech,translate,firestore,sql,
video-intelligence,bigquery,filestore,identity-platform,vertex-ai,kubernetes,compute,gpu,tpu}
○ GWS & other non-GCP: developers.google.com/{gsuite,gmail,drive,calendar,docs,sheets,
slides,forms,classroom,chat,apps-script,maps,youtube,analytics,cast,actions,people,ar,books}
● Introductory "codelabs" ([free] self-paced, hands-on tutorials)
○ GWS APIs: g.co/codelabs/gsuite-apis-intro (featuring Drive API)
○ Cloud Vision API: g.co/codelabs/vision-python (or C#)
○ All other codelabs: g.co/codelabs (all Google APIs, all levels)
● Videos
○ GWS: goo.gl/JpBQ40, Drive: developers.google.com/drive/web/videos, Sheets:
developers.google.com/sheets/api/videos, GCP: youtube.com/GoogleCloudPlatform
● Code: github.com/GoogleCloudPlatform & github.com/googleworkspace
● GCP Free Trial (new users) and Always Free tier: cloud.google.com/free
● Compare GCP to AWS and Azure: cloud.google.com/docs/compare/aws
Online resources
Bring me to your organization
... it is my job to help you!
● Engineering consulting
● Software development
● Technical seminars/tech talks
● Hands-on workshops
● Technical training courses
● Migration strategy & planning
● cyberwebconsulting.com
● appenginemigrations.com
Images: author
Slides
you're looking
at them now
Work:
cyberwebconsulting.com
Books
corepython.com
Blog
dev.to/wescpy
App blog post
goo.gle/3nPxmlc
GCP+GWS 101 (2019)
youtu.be/ri8Bfptgo9Q
...& 102 talks (2023)
youtu.be/3IQ4Yv80lJg
Progress bars
goo.gl/69EJVw
Thank you! Questions?
Wesley Chun
AI TPM, Red Hat & Principal, CyberWeb
AI OSS, Python, GCP & GWS specialist
@wescpy (Tw/X, BS, SO, GH, IG, LI)

Build an AI/ML-driven image archive processing workflow: Image archive, analysis & report generation

  • 1.
    Build an AI-enhancedimage processing enterprise workflow: Image archive, analysis & report generation, or "How to spice up file backups"🥱 Seattle:: Fall 2025 Wesley Chun AI TPgM, Red Hat and Principal, CyberWeb @wescpy@ AI TPM, Red Hat and Principal, CyberWeb ● Mission: enable developer success with Google tools, platforms & APIs, using OSS AI projects in GCP projects; and train accelerated Python users ● Focus: OSS AI tools, Google Cloud (GCP) & Workspace (GWS) APIs; GAE migrations; Google X-product sol'ns ● Services: technical consulting, training, engineering, speaking, code samples, hands-on tutorials, public technical content (blogs, social, etc.) About the speaker (and Red Hat AI) Previous experience / background ● Software Engineer & Developer Advocate ○ Google, Sun, HP, Cisco, EMC, Xilinx & ○ Original Yahoo!Mail engineer/SWE ● Technical trainer, teacher, instructor ○ Teaching Math, Linux, Python since '83 ○ Adjunct CS Faculty at local SV colleges ● Python community member ○ Popular Core Python series author ○ Python Software Foundation Fellow ● AB (Math/CS) & CMP (Music/Piano), UC Berkeley and MSCS, UC Santa Barbara ● Adjunct Computer Science Faculty, Foothill College (Silicon Valley) GWS Dev Show goo.gl/JpBQ40 GAE migration bit.ly/3xk2Swi
  • 2.
    Why and Agenda ●Organizations have real-life business problems seeking solutions ● Google Cloud/GCP and Google Workspace/GWS: most Google APIs ○ May know GCP for compute, storage, data, and AI/ML services ○ GWS known for its apps (Gmail, Drive,...); also for developers(!) ● Many other APIs from Google AI, Maps, YouTube, Firebase, etc. ● Use all of them to build novel solutions to unique business problems 1 Using Google APIs 2 Google APIs sampler 3 AI-enhanced image processing workflow 4 Wrap-up 464! (2024) 01 Using Google APIs Getting started & the nuts-n-bolts
  • 4.
    General steps 1. Goto Cloud Console 2. Login to Google/Gmail account (Workspace domain may require admin approval) 3. Create project (per application) 4. Enable APIs to use 5. Enable billing (CC, Free Trial, etc.) 6. Download client library(ies) 7. Create & download credentials 8. Write code* 9. Run code (may need to authorize) Google APIs: how to use *In your code 1. Import API client library 2. Create API client object 3. Use client to make API Calls Costs & pricing ● GCP & GMP: pay-per-use (CC req'd) ● GWS: "subscription" (incl. $0USD/mo.) ● GMP: $200/mo. free usage ● GCP Free Trial: $300/1Q ● GCP "Always Free" tier ○ Some products have free tier ○ Daily or monthly quota ○ Must exceed to incur billing ● More on both programs at cloud.google.com/free Cloud/GCP console console.cloud.google.com ● Hub of all developer activity ● Applications == projects ○ New project for new apps ○ Projects have a billing acct ● Manage billing accounts ○ Financial instrument required ○ Personal or corporate credit cards, Free Trial, and education grants ● Access GCP product settings ● Manage users & security ● Manage APIs in devconsole
  • 5.
    ● View applicationstatistics ● En-/disable Google APIs ● Obtain application credentials Using Google APIs goo.gl/RbyTFD API manager aka Developers Console (devconsole) console.developers.google.com Three different credentials types ● Simple: API keys (to access public data) ○ Simplest form of authorization: an API key; tied to a project ○ Allows access to public data ○ Do not put in code, lose, or upload to GitHub! (can be restricted however) ○ Supported by: Google Maps, (some) YouTube, (some) GCP, etc. ● Authorized: OAuth client IDs (to access data owned by [human] user) ○ Provides additional layer of security via OAuth2 (RFC 6749) ○ Owner must grant permission for your app to access their data ○ Access granularity determined by requested permissions (user scopes) ○ Supported by: Google Workspace, (some) YouTube, (some) GCP, etc. ● Authorized: service accounts (to access data owned by an app/robot user) ○ Provides additional layer of security via OAuth2 or JWT (RFC 7519) ○ Project owning data grants permission implicitly; requires public-private key-pair ○ Access granularity determined by Cloud IAM permissions granted to service account key-pair ○ Supported by: GCP, (some) Google Workspace, etc. Blog series: dev.to/wescpy
  • 6.
    Two different clientlibrary "styles" ● "Platform" client libraries (lower-level) ○ Supports multiple products as a "lowest-common denominator" ○ Manage API service endpoints (setup & use) ○ Manage authorization (API keys, OAuth client IDs, service accounts) ○ Google Workspace, Cloud/GCP, Google Analytics, YouTube, Google Ads APIs, etc. ○ developers.google.com/api-client-library ● "Product" client libraries (higher-level) ○ Custom client libraries made specifically for each product ○ Managing API service endpoints & security mostly taken care of ○ Only need to create a "client" to use API services ○ Cloud/GCP: cloud.google.com/apis/docs/cloud-client-libraries, Firebase, Maps: developers.google.com/maps/web-services/client-library ● Some Google APIs families support both, e.g., Cloud/GCP Google APIs client libraries for common languages; demos in developers.google.com/api- client-library cloud.google.com/apis/docs /cloud-client-libraries
  • 7.
    (User-)authorized API access(lower-level,older, generic) OAuth boilerplate goo.gl/KMfbeK from googleapiclient import discovery from httplib2 import Http from oauth2client import file, client, tools SCOPES = ... # at least one (string or array of strings) # 'storage.json' - where to store OAuth2 tokens from API # 'client_secret.json' - OAuth2 client ID & secret (download from DevConsole) store = file.Storage('storage.json') creds = store.get() if not creds or creds.invalid: flow = client.flow_from_clientsecrets('client_secret.json', SCOPES) creds = tools.run_flow(flow, store) # create API service endpoint; for example: API='sheets', VERSION='v4' SERVICE = discovery.build(API, VERSION, http=creds.authorize(Http())) (User-)authorized API access(lower-level, newer, generic) from googleapiclient import discovery from google_auth_oauthlib.flow import InstalledAppFlow from google.auth.transport.requests import Request from google.oauth2 import credentials SCOPES = ... # at least one (string or array of strings) # 'storage.json' - where to store OAuth2 tokens from API # 'client_secret.json' - OAuth2 client ID & secret (download from DevConsole) TOKENS = 'storage.json' # OAuth2 token storage if os.path.exists(TOKENS): creds = credentials.Credentials.from_authorized_user_file(TOKENS) if not (creds and creds.valid): if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) else: flow = InstalledAppFlow.from_client_secrets_file('client_secret.json', SCOPES) creds = flow.run_local_server() with open(TOKENS, 'w') as token: token.write(creds.to_json()) # create API service endpoint; for example: API='sheets', VERSION='v4' SERVICE = discovery.build(API, VERSION, http=creds.authorize(Http()))
  • 8.
    OAuth2 or API key HTTP-basedREST APIs 1 HTTP 2 Google APIs request-response workflow ● Application makes request ● Request received by service ● Process data, return response ● Results sent to application (typical client-server model) 02 Google APIs Sampler of GCP & GWS APIs
  • 9.
  • 10.
    ● GWS developerhome: developers.google.com/gsuite ● GWS developer intro: youtu.be/NqumcYgj5LI ● GWS REST APIs: youtu.be/2VpvWhDdXsI ● GWS Apps Script: youtu.be/xDovB0pu4OU ● Comprehensive overview: youtu.be/kkp0aNGlynw Google Workspace (formerly G Suite and Google Apps) (GWS) APIs Google Compute Engine, Cloud Storage AWS EC2 & S3; Rackspace; Joyent SaaS Software as a Service PaaS Platform as a Service IaaS Infrastructure as a Service Google Apps Script Salesforce1/force.com Google Workspace (was G Suite/Google Apps) Yahoo!Mail, Hotmail, Salesforce, Netsuite, Office 365 Google App Engine, Cloud Functions Heroku, Cloud Foundry, Engine Yard, AWS Lambda Google BigQuery, Cloud SQL, Vertex AI, Cloud Firestore, NL, Vision, Pub/Sub AWS Kinesis, RDS; Windows Azure SQL, Docker Google Cloud Platform vs. Google Workspace GWS APIs GCP APIs
  • 11.
    List (first 100)files/folders in Drive (older, OAuth2) from __future__ import print_function from googleapiclient import discovery from httplib2 import Http from oauth2client import file, client, tools SCOPES = 'https://www.googleapis.com/auth/drive.metadata.readonly' store = file.Storage('storage.json') creds = store.get() if not creds or creds.invalid: flow = client.flow_from_clientsecrets('client_secret.json', SCOPES) creds = tools.run_flow(flow, store) DRIVE = discovery.build('drive', 'v3', http=creds.authorize(Http())) files = DRIVE.files().list().execute().get('files', []) for f in files: print(f['name'], f['mimeType']) Listing your files goo.gl/ZIgf8k github.com/wescpy/gsuite-apis-intro Migrate SQL data to a Sheet # read SQL data then create new spreadsheet & add rows into it FIELDS = ('ID', 'Customer Name', 'Product Code', 'Units Ordered', 'Unit Price', 'Status') cxn = sqlite3.connect('db.sqlite') cur = cxn.cursor() rows = cur.execute('SELECT * FROM orders').fetchall() cxn.close() rows.insert(0, FIELDS) DATA = {'properties': {'title': 'Customer orders'}} SHEET_ID = SHEETS.spreadsheets().create(body=DATA, fields='spreadsheetId').execute().get('spreadsheetId') SHEETS.spreadsheets().values().update(spreadsheetId=SHEET_ID, range='A1', body={'values': rows}, valueInputOption='RAW').execute() Migrate SQL data to Sheets goo.gl/N1RPwC
  • 12.
    Storage: listing buckets from__future__ import print_function from googleapiclient import discovery GCS = discovery.build('storage', 'v1') BUCKET = YOUR_BUCKET # send bucket name & return fields to API, display results print('n** Objects in bucket %r...' % BUCKET) FIELDS = 'items(name,size)' files = GCS.objects().list(bucket=BUCKET, fields=FIELDS ).execute().get('items') or [{'name': '(none)', 'size': 'NaN'}] for f in files: print(' %s (%s)' % (f['name'], f['size'])) IMG = 'gs://cloud-samples-data/vision/using_curl/shanghai.jpeg' body = {'requests': [{ 'image': {'source': {'imageUri': IMG}}, 'features': [{'type': 'LABEL_DETECTION'}], }]} VISION = discovery.build('vision', 'v1', developerKey=API_KEY) labeling = VISION.images().annotate(body=body).execute().get('responses') for labels in labeling: if 'labelAnnotations' in labels: print('** Labels detected (and confidence score):') for label in labels['labelAnnotations']: print(label['description'], '(%.2f%%)' % (label['score']*100.)) Vision: label annotation/object detection
  • 13.
    $ python3 label-detect.py Labels(and confidence score): ============================== People (95.05%) Street (89.12%) Mode of transport (89.09%) Transport (85.13%) Vehicle (84.69%) Snapshot (84.11%) Urban area (80.29%) Infrastructure (73.14%) Road (72.74%) Pedestrian (68.90%) Vision: label annotation/object detection g.co/codelabs/vision-python Image: Google 03 AI/ML-driven image processing workflow Archive and analyze GWS images with GCP
  • 14.
    mfg: licensed fromiStockPhoto arch: public domain from Piqsels media: by RAEng Pubs from Pixabay advert: by Free-Photos from Pixabay Image licensed from Adobe
  • 15.
    Image licensed fromiStockPhoto Image: Gerd Altmann from Pixabay
  • 16.
    Image: CC BY2.0 Mike MacKenzie from VPNSRUS Image: CC0 PD from RawPixel
  • 17.
    Cloud Vision Google Workspace GoogleCloud Image processing application architecture Cloud Storage Drive Sheets Archive image Categorize image Record results Google Maps Google AI Maps (Static) Geolocate image & map LLM image analysis
  • 18.
    Application initialization andAPI setup from __future__ import print_function import argparse, base64, io, os, sys, time, webbrowser from googleapiclient import discovery, http from httplib2 import Http from oauth2client import file, client, tools from PIL import Image from google import genai from settings import API_KEY k_ize = lambda b: '%6.2fK' % (b/1000.) # bytes to kBs FILE = 'YOUR_IMG_ON_DRIVE' BUCKET = 'YOUR_BUCKET_NAME' SHEET = 'YOUR_SHEET_ID' TOP = 5 # get top Vision API labels DEBUG = False # create Gemini API client object plus constants PROMPT = 'Describe this image in 2-3 sentences' MODEL = 'gemini-2.5-flash' GENAI = genai.Client(api_key=API_KEY) # process credentials for OAuth2 tokens SCOPES = ( 'https://www.googleapis.com/auth/drive.readonly', 'https://www.googleapis.com/auth/devstorage', 'https://www.googleapis.com/auth/cloud-vision', 'https://www.googleapis.com/auth/spreadsheets', ) store = file.Storage('storage.json') creds = store.get() if not creds or creds.invalid: flow = client.flow_from_clientsecrets( 'client_secret.json', SCOPES) creds = tools.run_flow(flow, store) # create Google API client objects HTTP = creds.authorize(Http()) DRIVE = discovery.build('drive', 'v3', http=HTTP) GCS = discovery.build('storage', 'v1', http=HTTP) VISION = discovery.build('vision', 'v1', http=HTTP) SHEETS = discovery.build('sheets', 'v4', http=HTTP) def drive_get_file(fname): rsp = DRIVE.files().list(q="name='%s'" % fname).execute().get['files'][0] fileId, fname, mtype = rsp['id'], rsp['name'], rsp['mimeType'] blob = DRIVE.files().get_media(fileId).execute() return fname, mtype, rsp['modifiedTime'], blob, drive_geoloc_maps(fileId) Individual API components def drive_geoloc_maps(file_id): imd = DRIVE.files().get(fileId=file_id).execute().get('imageMediaMetadata') return 'https://maps.googleapis.com/maps/api/staticmap?size=480x480&markers=%s,%s&key=%s' % ( imd['location']['latitude'], imd['location']['longitude'], API_KEY) def genai_analyze_img(media): image = Image.open(io.BytesIO(media)) return GENAI.models.generate_content( model=MODEL, contents=(PROMPT, image)).text.strip() def sheet_append_row(sheet, row): rsp = SHEETS.spreadsheets().values().append( spreadsheetId=sheet, range='Sheet1', body={'values': rows}).execute() return rsp.get('updates').get('updatedCells') def vision_label_img(img, top): body = {'requests': [{'image': {'content': img}, 'features': [{'type': 'LABEL_DETECTION', 'maxResults': top}]}]} rsp = VISION.images().annotate( body=body).execute().get('responses', [{}])[0] return ', '.join('%s (%.2f%%)' % (label['description'], label['score']*100.) for label in rsp['labelAnnotations']) def gcs_blob_upload(fname, bucket, blob, mimetype): body = {'name': fname, 'uploadType': 'multipart', 'contentType': mimetype} return GCS.objects().insert(bucket, body, blob).execute()
  • 19.
    Acquire file infofrom Drive; Maps geolocation def drive_get_file(fname): rsp = DRIVE.files().list( q="name='%s'" % fname).execute().get['files'][0] fileId, fname, mtype = rsp['id'], rsp['name'], rsp['mimeType'] blob = DRIVE.files().get_media(fileId).execute() return mtype, rsp['modifiedTime'], blob, drive_geoloc_maps(fileId) Upload file media/binary/blob to Google Cloud Storage def gcs_blob_upload(fname, bucket, blob, mimetype): body = { 'name': fname, 'uploadType': 'multipart', 'contentType': mimetype } return GCS.objects().insert( bucket, body, blob).execute()
  • 20.
    Cloud Vision labelannotation (image contents) def vision_label_img(img, top): body = [{'image': {'content': img}, 'features': [{ 'type': 'LABEL_DETECTION', 'maxResults': top, }] }] rsp = VISION.images().annotate( body={'requests': body}).execute()['responses'][0] return ', '.join('%s (%.2f%%)' % ( label['description'], label['score']*100.) for label in rsp['labelAnnotations']) Analyze & describe image contents with LLM from PIL import Image from google import genai from settings import API_KEY # gen AI setup PROMPT = 'Describe this image in 2-3 sentences' MODEL = 'gemini-2.5-flash' GENAI = genai.Client(api_key=API_KEY) def genai_analyze_img(media): 'analyze image with genAI LLM and return analysis' image = Image.open(io.BytesIO(media)) return GENAI.models.generate_content( model=MODEL, contents=(PROMPT, image)).text.strip()
  • 21.
    Create Google Mapsmap if image geolocated MAPS_URL = 'https://maps.googleapis.com/maps/api/staticmap?size=480x480&markers=' def drive_geoloc_maps(file_id): imd = DRIVE.files().get(fileId=file_id, fields='imageMediaMetadata').execute().get('imageMediaMetadata') if not imd or 'location' not in imd: return '' return '%s%s,%s&key=%s' % (MAPS_URL, imd['location']['latitude'], imd['location']['longitude'], API_KEY) Store all results in one row to Google Sheets def sheet_append_row(sheet, row): rsp = SHEETS.spreadsheets().values().append( spreadsheetId=sheet, range='Sheet1', body={'values': row}).execute() return rsp.get('updates').get('updatedCells')
  • 22.
    Complete image processingworkflow def main(fname, bucket, sheet_id, top): fname, mtype, ftime, data, maps = drive_get_img(fname) gcs_blob_upload(fname, bucket, data, mtype) viz = vision_label_img(data, top) gem = genai_analyze_img(data) sheet_append_row(sheet_id, [fname, mtype, ftime, len(data), viz, gem, maps]) ● Project goal: Imagining an actual enterprise use case and solve it! ● Specific goals: free-up highly-utilized resource, archive data to colder/cheaper storage, analyze images, generate report for mgmt ● Download image binary from Google Drive ● If image geolocated use Google Maps to create static map ● Upload object to Cloud Storage bucket ● Process image label/object detection by Cloud Vision ● GenAI request for Gemini to summarize image contents ● Write back-up location & analysis results into Google Sheets ● Blog post: goo.gle/3nPxmlc (original post); Cloud X-post ● Codelab: free, online, self-paced, hands-on tutorial ● g.co/codelabs/drive-gcs-vision-sheets ● Application source code (Gemini & Maps version in /alt) ● github.com/wescpy/analyze_gsimg App summary
  • 23.
    04 Wrap-up Summary & resources SessionSummary ● File backup: "boring" ... while AI/ML: "exciting" ● Merge together for possible business scenario solvable with APIs ● Google provides more than just apps ○ More than search, YouTube, Android, Chrome, and Gmail/Docs ○ "Much" Google technology available to developers via APIs ● Google APIs do vary ○ Alas, developer experience differs between product families ○ Some products have higher-level product client libraries ○ Others require use of lower-level client libraries (or none at all!) ■ Lower-level may be useful as lowest common denominator ● Interesting possibilities using multiple Google product APIs
  • 24.
    Other Google APIs& platforms ● Firebase (mobile development platform + RT DB; ML Kit) ○ firebase.google.com & firebase.google.com/docs/ml-kit ● Google Looker/Data Studio (data visualization, dashboards, etc.) ○ datastudio.google.com/overview ○ goo.gle/datastudio-course ● Actions on Google/Assistant/DialogFlow (voice apps) ○ developers.google.com/actions ● YouTube (Data, Analytics, and Livestreaming APIs) ○ developers.google.com/youtube ● Google Maps (Maps, Routes, and Places APIs) ○ developers.google.com/maps ● Flutter (native apps [Android, iOS, web] w/1 code base[!]) ○ flutter.dev ● Documentation ○ GCP: cloud.google.com/{docs,vision,automl,storage,language,speech,translate,firestore,sql, video-intelligence,bigquery,filestore,identity-platform,vertex-ai,kubernetes,compute,gpu,tpu} ○ GWS & other non-GCP: developers.google.com/{gsuite,gmail,drive,calendar,docs,sheets, slides,forms,classroom,chat,apps-script,maps,youtube,analytics,cast,actions,people,ar,books} ● Introductory "codelabs" ([free] self-paced, hands-on tutorials) ○ GWS APIs: g.co/codelabs/gsuite-apis-intro (featuring Drive API) ○ Cloud Vision API: g.co/codelabs/vision-python (or C#) ○ All other codelabs: g.co/codelabs (all Google APIs, all levels) ● Videos ○ GWS: goo.gl/JpBQ40, Drive: developers.google.com/drive/web/videos, Sheets: developers.google.com/sheets/api/videos, GCP: youtube.com/GoogleCloudPlatform ● Code: github.com/GoogleCloudPlatform & github.com/googleworkspace ● GCP Free Trial (new users) and Always Free tier: cloud.google.com/free ● Compare GCP to AWS and Azure: cloud.google.com/docs/compare/aws Online resources
  • 25.
    Bring me toyour organization ... it is my job to help you! ● Engineering consulting ● Software development ● Technical seminars/tech talks ● Hands-on workshops ● Technical training courses ● Migration strategy & planning ● cyberwebconsulting.com ● appenginemigrations.com Images: author Slides you're looking at them now Work: cyberwebconsulting.com Books corepython.com Blog dev.to/wescpy App blog post goo.gle/3nPxmlc GCP+GWS 101 (2019) youtu.be/ri8Bfptgo9Q ...& 102 talks (2023) youtu.be/3IQ4Yv80lJg Progress bars goo.gl/69EJVw Thank you! Questions? Wesley Chun AI TPM, Red Hat & Principal, CyberWeb AI OSS, Python, GCP & GWS specialist @wescpy (Tw/X, BS, SO, GH, IG, LI)