diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 9cdec10..9b66e48 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -8,6 +8,7 @@
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 5461fe0..d76fc77 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -4,16 +4,17 @@
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
@@ -40,6 +41,9 @@
+
+
+
@@ -47,6 +51,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -72,6 +94,7 @@
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+ true
+ false
+ true
+
+
@@ -149,6 +225,8 @@
+
+
@@ -157,6 +235,7 @@
+
@@ -170,7 +249,7 @@
1711789328334
-
+
@@ -188,7 +267,15 @@
1711790617285
-
+
+
+ 1711791812195
+
+
+
+ 1711791812195
+
+
@@ -197,7 +284,8 @@
-
+
+
diff --git a/img-ai/.gitignore b/img-ai/.gitignore
new file mode 100644
index 0000000..1cbcb90
--- /dev/null
+++ b/img-ai/.gitignore
@@ -0,0 +1,2 @@
+# Deep learning models
+src/main/resources/dev/nuculabs/imagetagger/ai/*.onnx
\ No newline at end of file
diff --git a/img-ai/build.gradle.kts b/img-ai/build.gradle.kts
new file mode 100644
index 0000000..b7efe2b
--- /dev/null
+++ b/img-ai/build.gradle.kts
@@ -0,0 +1,22 @@
+plugins {
+ kotlin("jvm") version "1.8.22"
+}
+
+group = "dev.nuculabs.imagetagger.ai"
+version = "1.1"
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ implementation("com.microsoft.onnxruntime:onnxruntime:1.17.1")
+ testImplementation("org.jetbrains.kotlin:kotlin-test")
+}
+
+tasks.test {
+ useJUnitPlatform()
+}
+kotlin {
+ jvmToolchain(17)
+}
\ No newline at end of file
diff --git a/img-ai/src/main/kotlin/ImageTagsPrediction.kt b/img-ai/src/main/kotlin/ImageTagsPrediction.kt
new file mode 100644
index 0000000..383c103
--- /dev/null
+++ b/img-ai/src/main/kotlin/ImageTagsPrediction.kt
@@ -0,0 +1,173 @@
+package dev.nuculabs.imagetagger.ai
+
+import ai.onnxruntime.OnnxTensor
+import ai.onnxruntime.OrtEnvironment
+import ai.onnxruntime.OrtSession
+import java.awt.image.BufferedImage
+import java.io.IOException
+import java.io.InputStream
+import java.util.logging.Logger
+import javax.imageio.ImageIO
+
+/**
+ * ImageTagsPrediction is a specialized class that predicts an Image's tags
+ */
+class ImageTagsPrediction {
+ private val logger: Logger = Logger.getLogger("InfoLogging")
+ private var ortEnv: OrtEnvironment = OrtEnvironment.getEnvironment()
+ private var ortSession: OrtSession
+ private var modelClasses: MutableList = mutableListOf()
+
+ init {
+ try {
+ logger.info("Loading ML model. Please wait.")
+ ImageTagsPrediction::class.java.getResourceAsStream("/dev/nuculabs/imagetagger/ai/prediction.onnx").let { modelFile ->
+ ortSession = ortEnv.createSession(
+ modelFile!!.readBytes(),
+ OrtSession.SessionOptions()
+ )
+ }
+ ImageTagsPrediction::class.java.getResourceAsStream("/dev/nuculabs/imagetagger/ai/prediction_categories.txt")
+ .let { classesFile ->
+ modelClasses.addAll(0, classesFile!!.bufferedReader().readLines())
+ }
+ logger.info("Loaded ${modelClasses.size} model classes.")
+ } catch (e: NullPointerException) {
+ logger.severe(
+ "Failed to load model file or categories file. If you're building the project from " +
+ "source, please follow the instructions from the README.md: " +
+ "https://github.com/dnutiu/ImageTagger." +
+ "Exception ${e.message}"
+ )
+ throw e
+ }
+ }
+
+ /**
+ * Processes an image into an ONNX Tensor.
+ */
+ private fun processImage(bufferedImage: BufferedImage): Array>> {
+ try {
+ val tensorData = Array(1) {
+ Array(3) {
+ Array(224) {
+ FloatArray(224)
+ }
+ }
+ }
+ val mean = floatArrayOf(0.485f, 0.456f, 0.406f)
+ val standardDeviation = floatArrayOf(0.229f, 0.224f, 0.225f)
+
+ // crop image to 224x224
+ var width: Int = bufferedImage.width
+ var height: Int = bufferedImage.height
+ var startX = 0
+ var startY = 0
+ if (width > height) {
+ startX = (width - height) / 2
+ width = height
+ } else {
+ startY = (height - width) / 2
+ height = width
+ }
+
+ val image = bufferedImage.getSubimage(startX, startY, width, height)
+ val resizedImage = image.getScaledInstance(224, 224, 4)
+ val scaledImage = BufferedImage(224, 224, BufferedImage.TYPE_4BYTE_ABGR)
+ scaledImage.graphics.drawImage(resizedImage, 0, 0, null)
+
+
+ // Process image
+ for (y in 0 until scaledImage.height) {
+ for (x in 0 until scaledImage.width) {
+ val pixel: Int = scaledImage.getRGB(x, y)
+
+ // Get RGB values
+ tensorData[0][0][y][x] =
+ ((pixel shr 16 and 0xFF) / 255f - mean[0]) / standardDeviation[0]
+ tensorData[0][1][y][x] =
+ ((pixel shr 16 and 0xFF) / 255f - mean[1]) / standardDeviation[1]
+ tensorData[0][2][y][x] =
+ ((pixel shr 16 and 0xFF) / 255f - mean[2]) / standardDeviation[2]
+ }
+ }
+ return tensorData
+ } catch (e: IOException) {
+ throw RuntimeException(e)
+ }
+ }
+
+ /**
+ * Uses the ML model to predict tags for a given bitmap.
+ */
+ @Suppress("UNCHECKED_CAST")
+ private fun predictTagsInternal(bufferedImage: BufferedImage): List {
+ // 1. Get input and output names
+ val inputName: String = ortSession.inputNames.iterator().next()
+ val outputName: String = ortSession.outputNames.iterator().next()
+
+ // 2. Create input tensor
+ val inputTensor = OnnxTensor.createTensor(ortEnv, processImage(bufferedImage))
+
+ // 3. Run the model.
+ val inputs = mapOf(inputName to inputTensor)
+ val results = ortSession.run(inputs)
+
+ // 4. Get output tensor
+ val outputTensor = results.get(outputName)
+ if (outputTensor.isPresent) {
+ // 5. Get prediction results
+ val floatBuffer = outputTensor.get().value as Array
+ val predictions = ArrayList()
+
+ // filter buffer by threshold
+ for (i in floatBuffer[0].indices) {
+ if (floatBuffer[0][i] > -0.5) {
+ predictions.add(modelClasses[i])
+ }
+ }
+
+ return predictions
+ } else {
+ return ArrayList()
+ }
+ }
+
+ /**
+ * Predicts tags for a Bitmap.
+ */
+ fun predictTags(image: BufferedImage): List {
+ return predictTagsInternal(image)
+ }
+
+ /**
+ * Predicts tags for a given image input stream.
+ */
+ fun predictTags(input: InputStream?): List {
+ if (input == null) {
+ return ArrayList()
+ }
+
+ return predictTagsInternal(ImageIO.read(input))
+ }
+
+ /**
+ * Close the session and environment.
+ */
+ fun close() {
+ ortSession.close()
+ ortEnv.close()
+ modelClasses.clear()
+ }
+
+ // Singleton Pattern
+ companion object {
+ @Volatile
+ private var instance: ImageTagsPrediction? = null
+
+ fun getInstance() =
+ instance ?: synchronized(this) {
+ instance ?: ImageTagsPrediction().also { instance = it }
+ }
+ }
+}
\ No newline at end of file
diff --git a/img-ai/src/main/resources/dev/nuculabs/imagetagger/ai/prediction_categories.txt b/img-ai/src/main/resources/dev/nuculabs/imagetagger/ai/prediction_categories.txt
new file mode 100644
index 0000000..612ac9f
--- /dev/null
+++ b/img-ai/src/main/resources/dev/nuculabs/imagetagger/ai/prediction_categories.txt
@@ -0,0 +1,1708 @@
+abandoned
+abdomen
+above
+abs
+abstract
+abundance
+action
+active
+activity
+actor
+adult
+adventure
+aerial
+aerial view
+aerospace industry
+africa
+african
+african american ethnicity
+aging process
+agricultural field
+agriculture
+air
+air show
+air vehicle
+aircraft
+aircraft wing
+airplane
+airport
+airport runway
+airshow
+alcohol
+alcoholic
+alertness
+alley
+alone
+alpha
+alpine
+alps
+altar
+alternative energy
+amazing
+america
+american
+amersfoort
+amphibian
+amsterdam
+analog
+anatomy
+ancient
+angel
+anibalfoto
+animal
+antique
+antler
+antwerp
+aperitif
+appetizer
+appetizing
+apple
+aquatic organism
+arachnid
+archaeology
+architecture
+arid climate
+arizona
+arm
+armed forces
+arms
+arms raised
+aroma
+art
+asia
+asian
+asian ethnicity
+ass
+assortment
+astronomy
+astrophotography
+athlete
+athletic
+atlantic
+atmosphere
+atmospheric
+atmospheric mood
+attitude
+attraction
+attractive
+aurora borealis
+aurora polaris
+australia
+austria
+auto racing
+autumn
+available light
+aves
+aviation
+avocado
+awe
+b&w
+b/w
+baby
+back
+background
+backgrounds
+backlight
+baked
+baked pastry item
+bakery
+baking
+balance
+bale
+ballet
+balloon
+banff
+bar
+barbecue
+barcelona
+bare tree
+baroque style
+basilica
+basket
+bathroom
+bathtub
+bavaria
+bay
+bayern
+beach
+bear
+beard
+bearded
+beautiful
+beautiful people
+beauty
+bed
+bedroom
+bee
+beef
+beetle
+belgium
+bench
+berries
+berry
+berry fruit
+beverage
+biceps
+bicycle
+big cat
+bike
+bikini
+bird
+bishop
+bitter
+black
+black & white
+black and white
+black background
+black color
+black man
+blackandwhite
+blank
+blinds
+blond
+blonde
+bloom
+blooming
+blossom
+blue
+blue eyes
+blue hour
+blue jeans
+blue sky
+blueberry
+blur
+blurred motion
+bnw
+board
+boat
+boats
+body
+body building
+bodybuilder
+bodybuilding
+bokeh
+bokehlicious
+bonding
+boobs
+book
+bookshelf
+border collie
+botanical
+botany
+bottle
+boudoir
+bouquet
+bowl
+boy
+boys
+bra
+braies lake
+bread
+breakfast
+breast
+breasts
+brick
+bride
+bridge
+bright
+brown
+brown bear
+brown hair
+brunette
+brutal
+bubble
+bud
+buddhism
+building
+building exterior
+buildings
+built structure
+bumblebee
+bumper
+bun
+burger
+burning
+bus
+bush
+business
+business finance and industry
+businessman
+butterfly
+cable
+cable car
+cafe
+cake
+california
+calm
+camel
+camera
+camping
+canada
+canal
+candid
+candle
+candy
+canine
+canon
+canyon
+cappuccino
+car
+car interior
+car show
+care
+carefree
+cargo container
+carnivora
+castle
+casual
+casual clothing
+cat
+cathedral
+catholicism
+caucasian
+cave
+ceiling
+celebration
+cellphone
+ceramics
+cereal plant
+chair
+challenge
+chapel
+charming
+cheerful
+cheese
+cherry
+chest
+child
+children
+chinese
+chocolate
+christianity
+christmas
+christmas background
+christmas tree
+chrome
+church
+cigar
+cigarette
+cinematic
+circle
+citrus
+citrus fruit
+city
+city life
+cityscape
+classic
+clean
+clear sky
+cliff
+cliffs
+climbing
+close
+close up
+closeup
+clothes
+clothing
+cloud
+clouds
+cloudscape
+cloudy
+coast
+coastal
+coastline
+coat
+cocktail
+coffee
+coffee cup
+collector's car
+college
+color
+color image
+colorful
+colors
+colour
+colourful
+colours
+comfortable
+commercial
+commercial airplane
+commercial dock
+common blue butterfly
+common kingfisher
+communication
+commuter
+competition
+composition
+computer
+concept
+concepts
+conceptual
+concert
+concrete
+confidence
+confident
+connection
+consideration
+constellation
+construction industry
+container
+container ship
+contemplation
+contemporary
+contrast
+convertible
+cook
+cooked
+cookie
+cooking
+cool
+cool attitude
+copy
+copy space
+coral
+coral reef
+corporate
+corporate business
+corridor
+costume
+cottage
+country
+countryside
+couple
+covering
+cow
+cozy
+crane
+crash helmet
+cream
+creative
+creativity
+crop
+cub
+cuisine
+culinary
+culture
+cultures
+cup
+curly
+curly hair
+curtain
+curve
+cut
+cut out
+cute
+cute men
+cycle
+cycling
+dahlia
+daisy
+damaged
+damselfly
+dance
+dancer
+dancing
+dandelion
+danger
+daniel laan
+dark
+darkness
+dawn
+day
+daylight
+daytime
+decay
+december
+decoration
+deep
+deer
+delicious
+denim
+denmark
+desert
+design
+desire
+desk
+dessert
+destination
+detail
+details
+determination
+deutschland
+dew
+diet
+dieting
+digital
+diminishing perspective
+dinner
+direction
+directly above
+dirt
+dirt road
+discovery
+dish
+display
+diverse
+diversity
+diving
+dji
+dog
+dolomites
+dolomiti
+domestic bathroom
+domestic cat
+domestic life
+domestic room
+door
+downtown district
+dragonfly
+dramatic
+dramatic sky
+dream
+dreamy
+dress
+drink
+drinking
+drinking glass
+driving
+drone
+drone point of view
+drop
+drops
+dry
+dubai
+dunes
+dusk
+dutch
+dynamic
+eat
+eating
+ecology
+editorial
+education
+effort
+egret
+electric guitar
+electricity
+elegance
+elegant
+elephant
+embracing
+emotion
+emotional
+emotions
+empty
+endangered species
+energy
+engine
+engineering
+england
+enjoy
+enjoyment
+entrance
+entrepreneur
+environment
+environmental conservation
+epic
+equipment
+eroded
+erotic
+erupting
+escalator
+espresso
+europa
+europe
+european
+european bee
+evening
+evening gown
+event
+executive
+exercise
+exercising
+exhibition
+exotic
+exploding
+exploration
+expression
+exterior
+extreme
+extreme close
+extreme terrain
+eye
+eye contact
+eyes
+facade
+face
+factory
+fairy tale
+fall
+falling
+family
+famous place
+fantasy
+farm
+fashion
+fashion model
+fashion photography
+fashionable
+fast
+favorites
+feather
+february
+feeding
+feline
+female
+female identifying
+female model
+feminine
+femininity
+fence
+fender
+ferris wheel
+festival
+field
+fields
+fighter
+fighter plane
+film
+finch
+fine
+fire
+firework
+firework display
+fish
+fishing
+fishing boat
+fishing industry
+fit
+fitness
+fitness model
+five people
+flag
+flame
+flamingo
+flapping wings
+flash
+flat lay
+flexibility
+flight
+flooring
+flora
+floral
+flow
+flower
+flowing
+fluffy
+fly
+flying
+focus
+focus on foreground
+fog
+foggy
+food
+food and drink
+football
+footpath
+forest
+forest trees
+fork
+formal
+formalwear
+fort
+fountain
+four people
+fox
+fragility
+france
+freckles
+free spirited
+freedom
+french
+french alps
+french culture
+french food
+fresh
+freshness
+fried
+friends
+friendship
+frog
+front view
+frozen
+fruit
+fruits
+fuel and power generation
+fuji
+fujifilm
+full frame
+full length
+full moon
+fun
+fungi
+fungus
+funny
+fur
+furniture
+furry
+futuristic
+galaxy
+garden
+gardening
+garlic
+gastronomy
+geology
+gerbera daisy
+german culture
+germany
+gin
+ginger
+girl
+girls
+glacier
+glamour
+glass
+glasses
+glendor
+glow
+glowing
+good looking
+gorgeous
+gothic style
+gourmet
+grace
+grain
+grape
+grass
+grassland
+gray
+grazing
+great blue heron
+great egret
+greece
+green
+green color
+grey
+grilled
+groom
+group
+growth
+guidance
+guitar
+guy
+gym
+gymnastics
+hafen
+hair
+haircut
+hairstyle
+half moon
+hamburg
+hamburger
+hand
+hands
+hands in pockets
+handsome
+handsome people
+hanging
+happiness
+happy
+harbor
+harbour
+harvest
+harvesting
+hat
+hawaii
+hay
+hdr
+head
+head and shoulders
+headlight
+headshot
+headwear
+health
+healthy
+healthy eating
+healthy food
+healthy lifestyle
+heat
+helicopter
+herb
+herbal
+heron
+high
+high angle view
+high heels
+high up
+highway
+hijab
+hike
+hiking
+hill
+hills
+hipster
+hispanic
+historic
+historical
+history
+hobbies
+holiday
+holland
+home
+home interior
+homemade
+homme
+honey
+hood
+horizon
+horizon over land
+horned
+horror
+horse
+hot
+hot air balloon
+hot guy
+hot rod car
+hotel
+house
+hovering
+human
+hunk
+hut
+hygiene
+ice
+ice cream
+iceberg
+iceland
+idea
+idyllic
+illuminated
+illustration
+image
+image focus technique
+in a row
+in bloom
+inclusive
+india
+indian
+indian culture
+individuality
+indonesia
+indoor
+indoors
+indulgence
+industrial
+industry
+inflorescence
+ingredient
+inked
+innocence
+insect
+inside
+inspiration
+interesting
+interior
+invertebrate
+ireland
+islam
+island
+isolated
+istanbul
+italia
+italian
+italian culture
+italian food
+italian girl
+italian photographer
+italian woman
+italy
+jacket
+january
+japan
+japanese
+japanese culture
+jeans
+jewelry
+journey
+joy
+joyful
+jug
+juice
+juicy
+jumping
+june
+jungle
+kicking
+kid
+kids
+kingfisher
+kiss
+kitchen
+kitten
+laanscapes
+lace
+lady
+ladybug
+lagoon
+lake
+land
+land vehicle
+landing
+landmark
+landscape
+large
+large group of objects
+latina
+latinx
+latte
+laughing
+lava
+lavender
+leader
+leaf
+learning
+leather
+leaves
+legs
+leisure
+leisure activity
+lemon
+lepidoptera
+libellulidae
+library
+life
+life events
+lifestyle
+lifestyle photography
+lifestyles
+light
+light painting
+light trail
+lighthouse
+lighting
+lighting equipment
+lightning
+lights
+lily
+lime
+lines
+lingerie
+lion
+lips
+lipstick
+liqueur
+liquid
+liquor
+lithuania
+livestock
+living organism
+locomotive
+lofoten
+lofoten islands
+london
+london lighthouse studio
+loneliness
+lonely
+long
+long exposure
+long hair
+longexposure
+look
+looking
+looking at camera
+looking away
+looking through window
+love
+love couple
+love story
+lovely
+low angle view
+low key
+low light
+low section
+low shutter
+lowkey
+loyalty
+luca foscili
+lunch
+lush foliage
+luxury
+lying down
+lying on back
+machinery
+macho
+macro
+madeira
+magazine
+magic
+magical
+majestic
+make
+make up
+makeup
+male
+male beauty
+male model
+malemodel
+mallard duck
+mammal
+man
+manager
+manhattan
+marina
+market
+market stall
+marsh
+masculine
+masculinity
+mast
+mature
+mature adult
+mature men
+meadow
+meal
+meat
+medieval
+mediterranean
+medium group of people
+melbourne
+men
+metal
+metro
+mexican
+mexican ethnicity
+mexican woman
+mexico
+miami
+mid
+mid adult
+mid adult man
+mid adult men
+midsection
+military
+military airplane
+milk
+milky way
+minimal
+minimalism
+minimalistic
+mint
+mirror
+mist
+misty
+mixed
+mobile
+moda
+model
+modeling
+modelo
+models
+modern
+mollusk
+moment
+monastery
+mono
+monochrome
+monument
+mood
+moody
+moon
+moon surface
+moonlight
+moored
+morning
+moscow
+mosque
+moss
+motion
+motor racing track
+motor vehicle
+motorcycle
+mountain
+mug
+multi colored
+munich
+muscle
+muscles
+muscular
+museum
+mushroom
+mushrooms
+music
+musical instrument
+musician
+mustache
+mysterious
+mystery
+naked
+national landmark
+national park
+natur
+natural
+natural landmark
+natural light
+natural parkland
+natural phenomenon
+natural world
+nature
+naughty
+nautical vessel
+nebula
+necklace
+nederland
+neon
+netherlands
+new
+new life
+new york
+new york city
+new zealand
+nice
+niedersachsen
+night
+nightlife
+nightscape
+nikkor
+nipple
+no people
+no person
+nobody
+non
+north
+northern lights
+norway
+nostalgia
+nu
+nude
+nudity
+nutrition
+nyc
+object
+obsolete
+ocean
+odonata
+off
+office
+office building exterior
+oil
+old
+on the move
+one
+one adult only
+one man only
+one mid adult man only
+one mid adult only
+one person
+one woman only
+onion
+orange
+orange color
+orchid
+organic
+ornate
+orthodox church
+outdoor
+outdoors
+outer space
+outerwear
+outfit
+outside
+overcast
+owl
+paesaggio
+painting
+palace
+palm
+palm tree
+panorama
+panoramic
+panties
+pantyhose
+paradise
+paris
+park
+park bench
+parks
+parrot
+passenger craft
+passenger train
+passion
+pastel
+pastry
+pasture
+path
+pattern
+peaceful
+peak
+pensive
+pentax
+people
+pepper
+perching
+perfection
+performance
+person
+perspective
+pet
+petal
+petals
+petapixel
+pets
+phone
+photo
+photo shoot
+photographer
+photographie
+photography themes
+photoshoot
+physical geography
+physique
+pick
+picnic
+picturesque
+piece
+pier
+piercing
+pigeon
+pillow
+pilot
+pinaceae
+pine tree
+pink
+pink color
+place
+place of worship
+plain
+plane
+planespotter
+planespotting
+planet
+planetary moon
+plant
+plant stem
+plants
+plate
+play
+player
+playful
+playing
+plucking an instrument
+poisonous
+poland
+polar climate
+pollen
+pollination
+pomegranate
+pond
+pool
+poppy
+popular
+popular tags
+portrait
+portugal
+pose
+posing
+positive
+positive emotion
+power
+pregnant
+preparation
+prepared potato
+presents
+pretty
+primate
+professional
+profile
+propeller
+protection
+provocative
+public park
+puddle
+puppy
+purebred dog
+purple
+race
+racecar
+racing
+railing
+railroad
+railway
+rain
+rainbow
+rainforest
+rainy
+raspberry
+raw
+raw food
+reading
+ready
+real
+real people
+rear view
+recipe
+recreation
+recreational pursuit
+red
+red fox
+redhead
+reef
+reflection
+reflections
+refreshing
+refreshment
+relationship
+relax
+relaxation
+relaxed
+relaxing
+religion
+religious cross
+remote location
+residential
+restaurant
+resting
+retail
+retouch
+retrato
+retro
+retro style
+rh
+rice
+riding
+ripe
+rippled
+risk
+river
+road
+road trip
+roasted
+roasted coffee bean
+rock
+rodent
+romance
+romantic
+rooftop
+room
+rose
+rosseblanc
+round
+ruined
+rum
+run
+running
+rural
+rural scene
+russia
+russian
+rustic
+rusty
+sad
+sadness
+safari
+safety
+sail
+sailboat
+sailing
+sailing ship
+salad
+sand
+sand dune
+satisfaction
+sauce
+saucer
+savory food
+scandinavia
+scarf
+scene
+scenery
+scenic
+scenics
+scented
+schweiz
+science
+scotland
+scuba diving
+sculpture
+sea
+security
+seduction
+seductive
+seed
+selective focus
+selfie
+semi
+senior men
+sensual
+sensuality
+serious
+serving size
+sexual
+sexual issues
+sexy
+sexy man
+shadow
+shadows
+shape
+sheet
+shiny
+ship
+shipping
+shipwreck
+shirt
+shirtless
+shoe
+shooting
+shopping
+shore
+shot
+shredded
+side view
+sidewalk
+sierras
+sigma
+sign
+silhouette
+simple
+simplicity
+singapore
+singer
+single
+sitting
+six pack
+sixpacks
+skating
+skiing
+skill
+skin
+skirt
+sky
+skyline
+skyscraper
+sleeping
+slice
+slice of food
+slim
+slovenia
+slovenija
+small
+smile
+smiling
+smoke
+snack
+snow
+snowfall
+snowflakes
+soccer
+soccer ball
+social issues
+sofa
+soft
+softness
+sokarieu
+solid
+solitude
+space
+space and astronomy
+space exploration
+spain
+sparkling
+speed
+sphere
+spice
+spicy
+spider
+spiral
+spiral staircase
+spirituality
+splash
+splashing
+spooky
+spoon
+sport
+spotted
+spotter
+spread wings
+spring
+springtime
+square
+squirrel
+stadium
+stag
+staircase
+stairs
+stamen
+standing
+star
+star field
+star trail
+stars
+station
+stationary
+statue
+steam
+steam train
+steel
+steering wheel
+steps
+steps and staircases
+still life
+stockings
+stone
+store
+storm
+storm cloud
+story
+storytelling
+stranger
+strawberry
+stream
+street
+strength
+stretching
+string instrument
+striped
+strong
+structure
+stubble
+student
+studio
+studio shot
+stunning
+stunt
+style
+stylish
+success
+successful
+sugar
+suit
+summer
+summertime
+sun
+sun hat
+sunbathing
+sunbeam
+sundown
+sunglasses
+sunlight
+sunny
+sunrise
+sunset
+sunshine
+surf
+surfboard
+surfing
+suspension bridge
+swamp
+swan
+sweater
+sweet
+sweet food
+swimming
+swimming pool
+swimsuit
+swimwear
+switzerland
+symbiotic relationship
+symbol
+symmetry
+syrup
+t
+table
+taking a bath
+taking off
+tall
+tan
+tasty
+tattoo
+tattooed
+tattoos
+tea
+tea cup
+teamwork
+technology
+teen
+teenage
+teenage boys
+teenage girls
+teenager
+temple
+temptation
+tequila
+texture
+textured
+textures
+thai
+thailand
+the netherlands
+the past
+the way forward
+thinking
+thomas ruppel
+three people
+thunderstorm
+tie
+tiger
+tits
+toadstool
+together
+togetherness
+tokyo
+tomato
+tonic
+top
+top view
+topless
+torso
+touching
+tourism
+tourist
+tourist attraction
+tourist resort
+towel
+tower
+town
+town square
+toy
+tractor
+traditional
+traffic
+train
+training
+tramway
+tranquil
+transparent
+travel
+travel destinations
+traveler
+tray
+tree
+tree trunk
+trees
+trekking
+trendy
+trip
+tropical
+truck
+tulip
+tulips
+tunnel
+turkey
+turquoise
+turquoise colored
+turtle
+tutu
+twig
+twilight
+two
+two people
+uk
+ukraine
+umbrella
+uncultivated
+underground
+underwear
+undomesticated cat
+unhealthy eating
+unique
+united kingdom
+united states
+up
+urban
+urban photography
+urban skyline
+urbex
+usa
+vacation
+vacations
+valentine
+valley
+variation
+vase
+vector
+vegan
+vegetable
+vegetables
+vegetarian
+vegetarian food
+vehicle
+vehicle grille
+vehicle interior
+venice
+versatile
+vertebrate
+vibrant
+vietnamese
+view
+view from above
+village
+vilnius
+vintage
+vintage car
+vitality
+vitamin
+vitamins
+vodka
+vogue
+vulnerability
+waist up
+walk
+walking
+wall
+wallpaper
+war
+warm
+warm clothing
+wasp
+wasser
+watch
+water
+wave
+waves
+wealth
+weapon
+wear
+wearing a towel
+weather
+wedding
+wedding ceremony
+wedding day
+wedding dress
+well
+wellbeing
+wet
+wheat
+wheel
+whiskey
+white
+white background
+white color
+wild
+wilderness
+wildlife
+wind
+wind power
+wind turbine
+windmill
+window
+windows
+wine
+wineglass
+winter
+winter activity
+winter clothes
+winter time
+woman
+wood
+wooden
+woodland
+woods
+work
+work tool
+working
+workout
+xmas
+yacht
+yellow
+yoga
+young
+youth
diff --git a/img-ai/src/test/kotlin/ImageTagsPredictionTests.kt b/img-ai/src/test/kotlin/ImageTagsPredictionTests.kt
new file mode 100644
index 0000000..240581d
--- /dev/null
+++ b/img-ai/src/test/kotlin/ImageTagsPredictionTests.kt
@@ -0,0 +1,121 @@
+package dev.nuculabs.imagetagger.ai
+
+import org.junit.jupiter.api.AfterAll
+import org.junit.jupiter.api.Assertions.assertEquals
+import org.junit.jupiter.api.BeforeAll
+import org.junit.jupiter.api.Test
+import java.io.File
+import javax.imageio.ImageIO
+
+class ImageTagsPredictionTests {
+
+ @Test
+ fun testPredictTagsForBufferedImage_TimisoaraBega() {
+ val timisoaraBega = ImageTagsPredictionTests::class.java.getResource("timisoara-bega.jpg")
+ val tags = imageTagsPrediction.predictTags(ImageIO.read(timisoaraBega))
+ assertEquals(
+ listOf(
+ "lake",
+ "nature",
+ "no people",
+ "outdoors",
+ "reflection",
+ "river",
+ "sky",
+ "tranquil",
+ "tree",
+ "water"
+ ), tags
+ )
+ }
+
+ @Test
+ fun testPredictTagsForBufferedImage_TimisoaraThrees() {
+ val timisoaraBega = ImageTagsPredictionTests::class.java.getResource("timisoara-threes.jpg")
+ val tags = imageTagsPrediction.predictTags(ImageIO.read(timisoaraBega))
+ assertEquals(
+ listOf("day", "forest", "growth", "nature", "no people", "outdoors", "plant", "tree"), tags
+ )
+ }
+
+ @Test
+ fun testPredictTagsForBufferedImage_TimisoaraWaterTower() {
+ val timisoaraBega = ImageTagsPredictionTests::class.java.getResource("timisoara-water-tower.jpg")
+ val tags = imageTagsPrediction.predictTags(ImageIO.read(timisoaraBega))
+ assertEquals(
+ listOf(
+ "architecture",
+ "building exterior",
+ "built structure",
+ "day",
+ "history",
+ "no people",
+ "outdoors",
+ "travel destinations"
+ ), tags
+ )
+ }
+
+ @Test
+ fun testPredictTagsForInputStream_TimisoaraBega() {
+ val image = ImageTagsPredictionTests::class.java.getResource("timisoara-bega.jpg")
+ val tags = imageTagsPrediction.predictTags(File(image!!.toURI()).inputStream())
+ assertEquals(
+ listOf(
+ "lake",
+ "nature",
+ "no people",
+ "outdoors",
+ "reflection",
+ "river",
+ "sky",
+ "tranquil",
+ "tree",
+ "water"
+ ), tags
+ )
+ }
+
+ @Test
+ fun testPredictTagsForInputStream__TimisoaraThrees() {
+ val image = ImageTagsPredictionTests::class.java.getResource("timisoara-threes.jpg")
+ val tags = imageTagsPrediction.predictTags(File(image!!.toURI()).inputStream())
+ assertEquals(
+ listOf("day", "forest", "growth", "nature", "no people", "outdoors", "plant", "tree"), tags
+ )
+ }
+
+ @Test
+ fun testPredictTagsForInputStream_TimisoaraWaterTower() {
+ val image = ImageTagsPredictionTests::class.java.getResource("timisoara-water-tower.jpg")
+ val tags = imageTagsPrediction.predictTags(File(image!!.toURI()).inputStream())
+ assertEquals(
+ listOf(
+ "architecture",
+ "building exterior",
+ "built structure",
+ "day",
+ "history",
+ "no people",
+ "outdoors",
+ "travel destinations"
+ ), tags
+ )
+ }
+
+ companion object {
+ private lateinit var imageTagsPrediction: ImageTagsPrediction
+ @JvmStatic
+ @BeforeAll
+ fun setUp() {
+ imageTagsPrediction = ImageTagsPrediction()
+ }
+
+ @JvmStatic
+ @AfterAll
+ fun tearDown() {
+ imageTagsPrediction.close()
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/img-ai/src/test/resources/dev/nuculabs/imagetagger/ai/timisoara-bega.jpg b/img-ai/src/test/resources/dev/nuculabs/imagetagger/ai/timisoara-bega.jpg
new file mode 100644
index 0000000..daf59ac
Binary files /dev/null and b/img-ai/src/test/resources/dev/nuculabs/imagetagger/ai/timisoara-bega.jpg differ
diff --git a/img-ai/src/test/resources/dev/nuculabs/imagetagger/ai/timisoara-threes.jpg b/img-ai/src/test/resources/dev/nuculabs/imagetagger/ai/timisoara-threes.jpg
new file mode 100644
index 0000000..b18dbf7
Binary files /dev/null and b/img-ai/src/test/resources/dev/nuculabs/imagetagger/ai/timisoara-threes.jpg differ
diff --git a/img-ai/src/test/resources/dev/nuculabs/imagetagger/ai/timisoara-water-tower.jpg b/img-ai/src/test/resources/dev/nuculabs/imagetagger/ai/timisoara-water-tower.jpg
new file mode 100644
index 0000000..b4777ab
Binary files /dev/null and b/img-ai/src/test/resources/dev/nuculabs/imagetagger/ai/timisoara-water-tower.jpg differ
diff --git a/img-ui/build.gradle b/img-ui/build.gradle
index 8281d8c..6f56c42 100644
--- a/img-ui/build.gradle
+++ b/img-ui/build.gradle
@@ -46,7 +46,7 @@ dependencies {
}
implementation('org.kordamp.ikonli:ikonli-javafx:12.3.1')
implementation('org.kordamp.ikonli:ikonli-fontawesome5-pack:12.3.1')
- implementation('com.microsoft.onnxruntime:onnxruntime:1.17.1')
+ implementation('com.microsoft.onnxruntime:onnxruntime:1.17.1') // delete
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1-Beta")
testImplementation("org.junit.jupiter:junit-jupiter-api:${junitVersion}")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${junitVersion}")
diff --git a/settings.gradle b/settings.gradle
index 15106fa..dad1195 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,2 +1,7 @@
+plugins {
+ id 'org.gradle.toolchains.foojay-resolver-convention' version '0.5.0'
+}
rootProject.name = "ImageTagger-Solution"
-include("img-ui")
\ No newline at end of file
+include("img-ui")
+include 'img-ai'
+