201 lines
5.8 KiB
Ruby
201 lines
5.8 KiB
Ruby
|
#!/usr/bin/env ruby -W0
|
||
|
|
||
|
# aprox. running time
|
||
|
# ./deck-neural.rb 144.08s user 10.49s system 28% cpu 8:55.15 total
|
||
|
# ./deck-neural.rb 155.95s user 10.38s system 30% cpu 9:00.29 total
|
||
|
# cards-36.csv
|
||
|
# ./deck-neural.rb 30.74s user 2.63s system 105% cpu 31.507 total
|
||
|
# 50 cards
|
||
|
# ./deck-neural.rb 76.23s user 6.31s system 132% cpu 1:02.50 total
|
||
|
|
||
|
require 'squib'
|
||
|
require 'rest-client'
|
||
|
require 'open-uri'
|
||
|
require 'json'
|
||
|
require 'digest'
|
||
|
require 'mini_magick'
|
||
|
require 'unsplash'
|
||
|
require 'pexels'
|
||
|
|
||
|
# cards from local csv and images vis text2image GAN
|
||
|
# https://deepai.org/machine-learning-model/text2img
|
||
|
$deepai_api_key = "59b70a3d-d42a-42be-979d-d09ec08ec7e0"
|
||
|
|
||
|
$pexels_api_key = "563492ad6f917000010000016e741b30a565426c90e5b65b6b34063b"
|
||
|
|
||
|
# prod the GAN in a potentially relevant direction with a keyword or phrase prefix
|
||
|
$keyword = ""
|
||
|
|
||
|
# where to get images? try "t2i" or "unsplash" or "pexels"
|
||
|
$img_source = "unsplash"
|
||
|
|
||
|
# cards descriptions
|
||
|
#$cards_csv = 'cards-p50-1.csv' # 23:02
|
||
|
#$cards_csv = 'cards-p50-2.csv' # 21:24
|
||
|
#$cards_csv = 'cards-p50-3.csv' # 22:52
|
||
|
|
||
|
# unsplash config
|
||
|
Unsplash.configure do |config|
|
||
|
config.application_access_key = "FWIsA-zAhsj3biPbVH3-H6qoeB30EVazjQpIjlrnaoE"
|
||
|
config.application_secret = "Qcr0ETekpsPVMsGBRSmHSsF7NvAnqWkiZmKw9KP9Ros"
|
||
|
config.application_redirect_uri = "urn:ietf:wg:oauth:2.0:oob"
|
||
|
config.utm_source = "pandemic"
|
||
|
end
|
||
|
|
||
|
# cards descriptions input from csv
|
||
|
data = Squib.csv file: $cards_csv
|
||
|
|
||
|
# text2image slurp
|
||
|
|
||
|
def get_img_t2i (phrase)
|
||
|
puts "test2img> #{$keyword} #{phrase}"
|
||
|
d0 = Digest::RMD160.hexdigest phrase
|
||
|
r0 = RestClient::Request.execute(method: :post, url: 'https://api.deepai.org/api/text2img', timeout: 600,
|
||
|
headers: {'api-key' => $deepai_api_key },
|
||
|
payload: { 'text' => "#{$keyword} #{$phrase}" } )
|
||
|
f0 = "img/#{d0}.png"
|
||
|
t0 = MiniMagick::Image.open(JSON.parse(r0)['output_url'])
|
||
|
t0.format('png').write(f0)
|
||
|
puts "wrote: " + f0
|
||
|
return f0
|
||
|
end
|
||
|
|
||
|
# unsplash
|
||
|
# - https://github.com/unsplash/unsplash_rb
|
||
|
# - https://www.rubydoc.info/github/unsplash/unsplash_rb/
|
||
|
|
||
|
def get_img_unsplash (phrase)
|
||
|
puts "unsplash> #{$keyword} #{phrase}"
|
||
|
d0 = Digest::RMD160.hexdigest phrase
|
||
|
r0 = Unsplash::Photo.random(query: "#{$keyword} #{phrase}", orientation: "squarish")
|
||
|
|
||
|
if true
|
||
|
f0 = "img/#{d0}.png"
|
||
|
t0 = MiniMagick::Image.open(r0.urls.regular)
|
||
|
t0.format('png').write(f0)
|
||
|
puts "wrote: " + f0
|
||
|
return f0
|
||
|
else
|
||
|
p "couldn't find an image for #{$keyword} #{phrase}..."
|
||
|
return "img/blank.png"
|
||
|
end
|
||
|
rescue
|
||
|
p "wonk? err..."
|
||
|
return "img/blank.png"
|
||
|
end
|
||
|
|
||
|
# pexels
|
||
|
$pxl = Pexels::Client.new($pexels_api_key)
|
||
|
|
||
|
def get_img_pexels (phrase)
|
||
|
puts "pexels> #{$keyword} #{phrase}"
|
||
|
d0 = Digest::RMD160.hexdigest phrase
|
||
|
r0 = $pxl.photos.search("#{$keyword} #{phrase}", per_page: 1)
|
||
|
f0 = "img/#{d0}.png"
|
||
|
if !r0.photos.empty?
|
||
|
r1 = r0.photos[0].src["portrait"]
|
||
|
t0 = MiniMagick::Image.open(r1)
|
||
|
t0.format('png').write(f0)
|
||
|
p "wrote: " + f0
|
||
|
return f0
|
||
|
else
|
||
|
p "couldn't find an image for #{$keyword} #{phrase}..."
|
||
|
return "img/blank.png"
|
||
|
end
|
||
|
end
|
||
|
|
||
|
# other options for automated image collation
|
||
|
# - https://pixabay.com/api/docs/#api_search_images
|
||
|
# - https://github.com/public-apis/public-apis#photography
|
||
|
# - https://en.wikipedia.org/wiki/Wikipedia:Public_domain_image_resources
|
||
|
# - https://commons.wikimedia.org/wiki/Category:Images
|
||
|
# - https://rapidapi.com/collection/image-apis
|
||
|
|
||
|
#layouts = ['economy.yml', 'space-layout-1.yml']
|
||
|
layouts = ['space-layout-3.yml']
|
||
|
|
||
|
c1 = '#9f68ed'
|
||
|
c2 = '#ed9f68'
|
||
|
c3 = '#b5ed68'
|
||
|
c4 = '#eeeeee'
|
||
|
|
||
|
# conditional coloring
|
||
|
# https://squib.readthedocs.io/en/v0.15.0/colors.html?highlight=color#samples
|
||
|
|
||
|
color = c1
|
||
|
|
||
|
Squib::Deck.new cards: data['name'].size, width: '38mm', height: '60mm', layout: layouts do
|
||
|
|
||
|
# set background colour per card type
|
||
|
bg = data['type'].map do |t|
|
||
|
if (t.eql? 'O')
|
||
|
c1
|
||
|
elsif (t.eql? 'Q')
|
||
|
c2
|
||
|
elsif (t.eql? 'Q')
|
||
|
c3
|
||
|
else
|
||
|
c4
|
||
|
end
|
||
|
end
|
||
|
|
||
|
# set fill colour per card type
|
||
|
fg = data['type'].map do |t|
|
||
|
if (t.eql? 'O')
|
||
|
c2
|
||
|
elsif (t.eql? 'Q')
|
||
|
c1
|
||
|
elsif (t.eql? 'Q')
|
||
|
c4
|
||
|
else
|
||
|
c4
|
||
|
end
|
||
|
end
|
||
|
|
||
|
# associative image search and/or generation
|
||
|
# https://experiments.runwayml.com/generative_engine/
|
||
|
# https://deepai.org/machine-learning-model/text2img
|
||
|
|
||
|
# generate & collect images
|
||
|
case $img_source
|
||
|
when "t2i"
|
||
|
dlimages = data['name'].map { |i| get_img_t2i i}
|
||
|
when "unsplash"
|
||
|
dlimages = data['name'].map { |i| get_img_unsplash i}
|
||
|
when "pexels"
|
||
|
dlimages = data['name'].map { |i| get_img_pexels i}
|
||
|
else
|
||
|
puts "unknown image source " + $img_source
|
||
|
end
|
||
|
|
||
|
# sharing & colours
|
||
|
background color: bg
|
||
|
rect fill_color: fg , x: '3mm', y: '3mm', width: '32mm', height: '54mm', radius: 32
|
||
|
|
||
|
#rect layout: 'cut' # cut line as defined by TheGameCrafter in economy.yml
|
||
|
#rect layout: 'safe' # safe zone as defined by TheGameCrafter in economy.yml
|
||
|
|
||
|
# in z-order low->high
|
||
|
text str: data['text'], layout: 'description'
|
||
|
png file: dlimages, layout: 'illustration'
|
||
|
png file: dlimages, layout: 'overlay'
|
||
|
text str: data['type'], layout: 'type'
|
||
|
text str: data['name'], layout: 'title'
|
||
|
|
||
|
# output a png of each card
|
||
|
tag = Time.now.strftime('%Y%m%d_%H%M')
|
||
|
|
||
|
save format: :png, prefix: "cards_#{$keyword}_#{tag}_#{$img_source}_", count_format: '%d'
|
||
|
|
||
|
#.. and pdf of the deck on A4
|
||
|
# see also https://squib.readthedocs.io/en/v0.15.0/sprues.html#list-of-sprues
|
||
|
save format: :pdf, file: "deck_#{$keyword}_#{tag}_#{$img_source}.pdf",
|
||
|
width: '297mm', height: '210mm', margin: '20mm',
|
||
|
crop_marks: true,
|
||
|
crop_stroke_width: 0.5
|
||
|
|
||
|
#save_png
|
||
|
#save_pdf
|
||
|
|
||
|
end
|