-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
eb1ed14
commit 538cc94
Showing
19 changed files
with
1,709 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
444 changes: 444 additions & 0 deletions
444
examples/EmbeddingSearch/EmbeddingSearch.xcodeproj/project.pbxproj
Large diffs are not rendered by default.
Oops, something went wrong.
7 changes: 7 additions & 0 deletions
7
...es/EmbeddingSearch/EmbeddingSearch.xcodeproj/project.xcworkspace/contents.xcworkspacedata
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
8 changes: 8 additions & 0 deletions
8
...earch/EmbeddingSearch.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||
<plist version="1.0"> | ||
<dict> | ||
<key>IDEDidComputeMac32BitWarning</key> | ||
<true/> | ||
</dict> | ||
</plist> |
69 changes: 69 additions & 0 deletions
69
...earch/EmbeddingSearch.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
{ | ||
"originHash" : "aaf6a678a26d0e2261ac5404e010320978efb780c0bb1e84e11066f69b467c28", | ||
"pins" : [ | ||
{ | ||
"identity" : "combine-schedulers", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/pointfreeco/combine-schedulers", | ||
"state" : { | ||
"revision" : "9fa31f4403da54855f1e2aeaeff478f4f0e40b13", | ||
"version" : "1.0.2" | ||
} | ||
}, | ||
{ | ||
"identity" : "sqlitevec", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/jkrukowski/SQLiteVec", | ||
"state" : { | ||
"revision" : "eb1ed1476bd0b3e6a25a9aea0e68eec4180861eb", | ||
"version" : "0.0.7" | ||
} | ||
}, | ||
{ | ||
"identity" : "swift-clocks", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/pointfreeco/swift-clocks", | ||
"state" : { | ||
"revision" : "b9b24b69e2adda099a1fa381cda1eeec272d5b53", | ||
"version" : "1.0.5" | ||
} | ||
}, | ||
{ | ||
"identity" : "swift-concurrency-extras", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/pointfreeco/swift-concurrency-extras", | ||
"state" : { | ||
"revision" : "bb5059bde9022d69ac516803f4f227d8ac967f71", | ||
"version" : "1.1.0" | ||
} | ||
}, | ||
{ | ||
"identity" : "swift-dependencies", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/pointfreeco/swift-dependencies", | ||
"state" : { | ||
"revision" : "21660b042cd8fd0bdd45cc39050cacd4e91a63a4", | ||
"version" : "1.3.8" | ||
} | ||
}, | ||
{ | ||
"identity" : "swift-syntax", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/swiftlang/swift-syntax", | ||
"state" : { | ||
"revision" : "515f79b522918f83483068d99c68daeb5116342d", | ||
"version" : "600.0.0-prerelease-2024-08-20" | ||
} | ||
}, | ||
{ | ||
"identity" : "xctest-dynamic-overlay", | ||
"kind" : "remoteSourceControl", | ||
"location" : "https://github.com/pointfreeco/xctest-dynamic-overlay", | ||
"state" : { | ||
"revision" : "96beb108a57f24c8476ae1f309239270772b2940", | ||
"version" : "1.2.5" | ||
} | ||
} | ||
], | ||
"version" : 3 | ||
} |
11 changes: 11 additions & 0 deletions
11
examples/EmbeddingSearch/EmbeddingSearch/Assets.xcassets/AccentColor.colorset/Contents.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"colors" : [ | ||
{ | ||
"idiom" : "universal" | ||
} | ||
], | ||
"info" : { | ||
"author" : "xcode", | ||
"version" : 1 | ||
} | ||
} |
63 changes: 63 additions & 0 deletions
63
examples/EmbeddingSearch/EmbeddingSearch/Assets.xcassets/AppIcon.appiconset/Contents.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
{ | ||
"images" : [ | ||
{ | ||
"idiom" : "universal", | ||
"platform" : "ios", | ||
"size" : "1024x1024" | ||
}, | ||
{ | ||
"idiom" : "mac", | ||
"scale" : "1x", | ||
"size" : "16x16" | ||
}, | ||
{ | ||
"idiom" : "mac", | ||
"scale" : "2x", | ||
"size" : "16x16" | ||
}, | ||
{ | ||
"idiom" : "mac", | ||
"scale" : "1x", | ||
"size" : "32x32" | ||
}, | ||
{ | ||
"idiom" : "mac", | ||
"scale" : "2x", | ||
"size" : "32x32" | ||
}, | ||
{ | ||
"idiom" : "mac", | ||
"scale" : "1x", | ||
"size" : "128x128" | ||
}, | ||
{ | ||
"idiom" : "mac", | ||
"scale" : "2x", | ||
"size" : "128x128" | ||
}, | ||
{ | ||
"idiom" : "mac", | ||
"scale" : "1x", | ||
"size" : "256x256" | ||
}, | ||
{ | ||
"idiom" : "mac", | ||
"scale" : "2x", | ||
"size" : "256x256" | ||
}, | ||
{ | ||
"idiom" : "mac", | ||
"scale" : "1x", | ||
"size" : "512x512" | ||
}, | ||
{ | ||
"idiom" : "mac", | ||
"scale" : "2x", | ||
"size" : "512x512" | ||
} | ||
], | ||
"info" : { | ||
"author" : "xcode", | ||
"version" : 1 | ||
} | ||
} |
6 changes: 6 additions & 0 deletions
6
examples/EmbeddingSearch/EmbeddingSearch/Assets.xcassets/Contents.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"info" : { | ||
"author" : "xcode", | ||
"version" : 1 | ||
} | ||
} |
65 changes: 65 additions & 0 deletions
65
examples/EmbeddingSearch/EmbeddingSearch/ContentView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
// | ||
// ContentView.swift | ||
// EmbeddingSearch | ||
// | ||
// Created by Jan Krukowski on 8/22/24. | ||
// | ||
|
||
import Dependencies | ||
import SwiftUI | ||
|
||
@MainActor | ||
struct ContentView: View { | ||
@State private var searchText = "" | ||
@StateObject private var viewModel = ContentViewModel() | ||
|
||
var body: some View { | ||
VStack { | ||
switch viewModel.dataState { | ||
case .initial: | ||
Button("Load data") { | ||
Task { | ||
await viewModel.populateDatabase() | ||
} | ||
} | ||
case .loading: | ||
ProgressView() | ||
case .loaded: | ||
NavigationStack { | ||
VStack { | ||
if searchText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { | ||
Text("Search to see the results") | ||
} else { | ||
ScrollView { | ||
LazyVStack(alignment: .leading) { | ||
ForEach(viewModel.searchResult) { item in | ||
VStack(alignment: .leading) { | ||
Text(item.text) | ||
Text(item.distance, format: .number.precision(.fractionLength(2))) | ||
.font(.footnote) | ||
.foregroundStyle(.gray) | ||
} | ||
.padding([.top, .leading, .trailing]) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
.navigationTitle("Search") | ||
.searchable(text: $searchText) | ||
.onChange(of: searchText) { _, _ in | ||
Task { | ||
await viewModel.search(by: searchText) | ||
} | ||
} | ||
} | ||
case let .error(error): | ||
Text("Error \(error)") | ||
} | ||
} | ||
} | ||
} | ||
|
||
#Preview { | ||
ContentView() | ||
} |
109 changes: 109 additions & 0 deletions
109
examples/EmbeddingSearch/EmbeddingSearch/ContentViewModel.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
// | ||
// ContentViewModel.swift | ||
// EmbeddingSearch | ||
// | ||
// Created by Jan Krukowski on 8/22/24. | ||
// | ||
|
||
import Dependencies | ||
import Foundation | ||
import Observation | ||
import OSLog | ||
import SwiftUI | ||
|
||
let logger = Logger() | ||
|
||
@MainActor | ||
final class ContentViewModel: ObservableObject { | ||
@Published var searchResult = [QueryResult]() | ||
@Published var dataState = DataState.initial | ||
@Dependency(\.embeddingDatabase) private var embeddingDatabase | ||
private var searchTask: Task<Void, any Error>? | ||
|
||
func populateDatabase() async { | ||
if dataState.isLoading { | ||
return | ||
} | ||
do { | ||
dataState = .loading | ||
try await embeddingDatabase.initializeDatabase() | ||
let texts = try await loadTexts() | ||
try await embeddingDatabase.store(texts: texts) | ||
dataState = .loaded | ||
} catch { | ||
logger.error("Error: \(error)") | ||
dataState = .error(error.localizedDescription) | ||
} | ||
} | ||
|
||
func search(by text: String) async { | ||
searchTask?.cancel() | ||
searchTask = Task { | ||
do { | ||
let query = text.trimmingCharacters(in: .whitespacesAndNewlines) | ||
if query.isEmpty { | ||
searchResult = [] | ||
return | ||
} | ||
if Task.isCancelled { | ||
return | ||
} | ||
let result = try await embeddingDatabase.querySimilar(to: query) | ||
searchResult = result.compactMap(QueryResult.init) | ||
} catch { | ||
logger.error("Error: \(error)") | ||
} | ||
} | ||
} | ||
|
||
private func loadTexts() async throws -> [String] { | ||
guard let url = Bundle.main.url(forResource: "sentences", withExtension: "txt") else { | ||
fatalError("Missing required file in main bundle") | ||
} | ||
let task = Task.detached { | ||
try String(contentsOf: url) | ||
.components(separatedBy: "\n") | ||
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) } | ||
} | ||
return try await task.value | ||
} | ||
} | ||
|
||
extension ContentViewModel { | ||
enum DataState { | ||
case initial | ||
case loading | ||
case loaded | ||
case error(String) | ||
|
||
var isLoading: Bool { | ||
switch self { | ||
case .loading: | ||
true | ||
default: | ||
false | ||
} | ||
} | ||
} | ||
} | ||
|
||
struct QueryResult: Hashable, Identifiable { | ||
let id: Int | ||
let text: String | ||
let distance: Double | ||
} | ||
|
||
extension QueryResult { | ||
init?(_ result: [String: Any]) { | ||
guard let id = result["id"] as? Int else { | ||
return nil | ||
} | ||
guard let text = result["text"] as? String else { | ||
return nil | ||
} | ||
guard let distance = result["distance"] as? Double else { | ||
return nil | ||
} | ||
self.init(id: id, text: text, distance: distance) | ||
} | ||
} |
Oops, something went wrong.