Simple Intelligence showcases the capabilities of Couchbase Capella for data search and synchronization. It provides a comprehensive view of search using AI, vectors, full-text, SQL, indexing, and syncing data with the Capella Cloud.
The app provides real-time search using the devices camera coupled with AI and Capella's search and sync capabilities, making it an excellent utility for experiencing their unique ability to turbocharge the speed and reliability of business critical applications.
Download Simple Intelligence from the App Store today and experience the power of Couchbase Capella's AI, search, and sync capabilities right from the palm of your hand.
The app includes a demo that enables experiencing the features and functionality of the app without any setup. Follow these steps to see the AI powered visual search in action:
- Download the Simple Intelligence app from the Apple App Store
- Download the demo images PDF and open it on your computer
- Open the app
- On the splash screen, press the "Try Now" button
- Grant camera access when prompted
- Aim the back-facing camera at one of demo images displayed on your computer
- See the corresponding item instantly appear on the screen in the app
The code is divided into the following areas demonstrating AI search, vector search, SQL queries, full-text search, indexing, and data sync with the cloud:
The Database.search(image: UIImage)
function demonstrates AI search capabilities. It uses the SQL and Vector Search functions below to find database results base on AI predictions from an image.
func search(image: UIImage) -> [Product] {
// Search with barcode
if let barcode = AI.barcode(from: image), let product = search(barcode: barcode) {
return [product]
}
// Search with embedding
if let embedding = AI.embedding(for: image) {
let products = search(vector: embedding)
return products
}
return []
}
The Database.search(vector: [Float])
function demonstrates the vector search capabilities.
func search(vector: [Float]) -> [Product] {
// SQL
let sql = """
SELECT name, price, location, image, APPROX_VECTOR_DISTANCE(image, $embedding) AS distance
FROM products
WHERE distance BETWEEN 0 AND 0.25
ORDER BY distance, name
LIMIT 10
"""
// Create the query.
let query = database.createQuery(sql)
query.parameters = Parameters()
.setArray(vector, forName: "embedding")
// Execute the query and get the results.
var products = [Product]()
for result in query.execute() {
if let name = result["name"].string,
let price = result["price"].number,
let location = result["location"].string,
let imageData = result["image"].blob?.content,
let image = UIImage(data: imageData)
{
let product = Product(name: name, price: price.doubleValue, location: location, image: image)
products.append(product)
}
}
return products
}
The Database.search(barcode: String)
function demonstrates SQL query capabilities.
private func search(barcode: String) -> Product? {
// SQL
let sql = """
SELECT name, price, location, image
FROM products
WHERE barcode = $barcode
LIMIT 1
"""
// Create the query
let query = database.createQuery(sql)
query.parameters = Parameters()
.setString(barcode, forName: "barcode")
// Return the first search result
if let result = query.execute().next(),
let name = result["name"].string,
let price = result["price"].number,
let location = result["location"].string,
let imageData = result["image"].blob?.content,
let image = UIImage(data: imageData)
{
let product = Product(name: name, price: price.doubleValue, location: location, image: image)
return product
}
return nil
}
The Database.search(search: String)
function demonstrates full-text search capabilities.
func search(string: String) -> [Product] {
// SQL
let sql = """
SELECT name, price, location, image
FROM products
WHERE MATCH(NameAndCategoryFullTextIndex, $search)
ORDER BY RANK(NameAndCategoryFullTextIndex), name
"""
// Create the query.
let query = database.createQuery(sql)
query.parameters = Parameters()
.setString(searchString, forName: "search")
// Enumerate through the query results.
var products = [Product]()
for result in query.execute() {
if let name = result["name"].string,
let price = result["price"].number,
let location = result["location"].string,
let imageData = result["image"].blob?.content,
let image = UIImage(data: imageData)
{
let product = Product(name: name, price: price.doubleValue, location: location, image: image)
products.append(product)
}
}
return products
}
The Database
class demonstrates creating indexes for fast searches.
// Initialize the value index on the "name" field for fast sorting.
let nameIndex = ValueIndexConfiguration(["name"])
collection.createIndex(withName: "NameIndex", config: nameIndex)
// Initialize the value index on the "barcode" field for fast searching.
let barcodeIndex = ValueIndexConfiguration(["barcode"])
collection.createIndex(withName: "BarcodeIndex", config: barcodeIndex)
// Initialize the vector index on the "embedding" field for image search.
var vectorIndex = VectorIndexConfiguration(expression: "embedding", dimensions: 768, centroids: 100)
vectorIndex.metric = .cosine
collection.createIndex(withName: "EmbeddingVectorIndex", config: vectorIndex)
// Initialize the full-text search index on the "name" and "category" fields.
let ftsIndex = FullTextIndexConfiguration(["name", "category"])
collection.createIndex(withName: "NameAndCategoryFullTextIndex", config: ftsIndex)
The Database.startSync()
function demonstrates how to sync with a Couchbase Capella cloud endpoint.
private func startSync() {
// Set up the sync endpoint.
let target = URLEndpoint(url: endpoint.url)
var config = ReplicatorConfiguration(target: target)
config.addCollection(collection)
config.replicatorType = .pull
config.authenticator = BasicAuthenticator(username: endpoint.username, password: endpoint.password)
// Create and start the replicator.
let replicator = Replicator(config: config)
replicator.start()
}
The app is designed to be run on an iPhone or iPad in the following configurations:
The iPad setups work well for stationary kiosks and wall displays. Use cases include point-of-sale, self checkout, self check-in, price lookup, ticket validation, and more.
This is the stand that I'm using for my iPad Pro (12.9-inch, 3rd generation). You can find it here on Amazon.
The iPhone setups work well for mobile use. Use cases include inventory, personal shopping, self checkout, order collection, package delivery, ticket validation, and more.
The demo is trained to recognize the products in it's catalog using the camera. To help demonstrating these capabilities, download the demo cards, display them from your computer or print them out, and scan the cards to find the corresponding products in the app. Here are a few examples of cards from the set:
- Clone or download this repository
- Download the latest
CouchbaseLiteSwift.xcframework
andCouchbaseLiteVectorSearch.xcframework
, and copy them to the project'sFrameworks
directory. - Open the project in Xcode.
- Run the app on a phone or tablet.
To explore the code, start with the following source files:
Database.swift
: Manages the search and sync features.AI.swift
: Provides the AI features.Camera.swift
: Manages the camera.Settings.swift
: Manages the settings.
You can customize the app by syncing with a Couchbase backend. Here are the steps for setting up Capella:
- Create a Database
- Create an App Service
- Create an App Service Endpoint
- Update the function in
Access Control
:function (doc, oldDoc, meta) { requireRole("admin"); if (doc.type !== "product") { throw({forbidden: "Document type must be 'product'"}); } channel(doc.type); }
- Configure CORS in
Settings > Advansed
- Origin: *
- Login Origin: *
- Max Age: 86400
- Headers: Content-Type, Authorization
- Create an admin user
- Create a role named
admin
- Create a user with the role
admin
- Create a role named
- Create non-admin user
- Create a user with channel
product
- Create a user with channel
- Copy the endpoint URL from
Connections
- Update the function in
- Use the
admin
user to add products to the backend using the Simple Intelligence Admin tool - In the Simple Intelligence app setting, configure the Sync Endpoint using the
non-admin
user.