Skip to content

Commit

Permalink
added :cargo-qdrant module to install/start/stop Qdrant Vector DB docker
Browse files Browse the repository at this point in the history
containers
  • Loading branch information
jlangch committed Mar 22, 2024
1 parent 6369302 commit 20e3737
Show file tree
Hide file tree
Showing 5 changed files with 295 additions and 8 deletions.
2 changes: 2 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ All notable changes to this project will be documented in this file.
- improvements to markdown to ascii text renderer to allow the Venice
Github flavoured markdown documentation to be converted to pure ascii
to feed it as embeddings to LLMs
- :cargo-qdrant module to install/start/stop Qdrant Vector DB docker
containers

### Changed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import com.github.jlangch.venice.impl.docgen.cheatsheet.modules.ModuleAsciiTableSection;
import com.github.jlangch.venice.impl.docgen.cheatsheet.modules.ModuleBenchmarkSection;
import com.github.jlangch.venice.impl.docgen.cheatsheet.modules.ModuleCargoArangoDBSection;
import com.github.jlangch.venice.impl.docgen.cheatsheet.modules.ModuleCargoQdrantDBSection;
import com.github.jlangch.venice.impl.docgen.cheatsheet.modules.ModuleCargoSection;
import com.github.jlangch.venice.impl.docgen.cheatsheet.modules.ModuleComponentSection;
import com.github.jlangch.venice.impl.docgen.cheatsheet.modules.ModuleConfigSection;
Expand Down Expand Up @@ -124,14 +125,15 @@ public DocGenerator(final boolean runExamples) {

preloadedModules
.addAll(Arrays.asList(
"app", "xml", "crypt", "gradle",
"trace", "ansi", "maven", "kira",
"java", "semver", "excel", "hexdump",
"shell", "geoip", "benchmark", "component",
"config", "parsifal", "grep", "test",
"fonts", "qrref", "jsonl", "timing",
"zipvault", "docker", "cargo", "cargo-arangodb",
"gradlew", "matrix", "ascii-table", "installer"));
"app", "xml", "crypt", "gradle",
"trace", "ansi", "maven", "kira",
"java", "semver", "excel", "hexdump",
"shell", "geoip", "benchmark", "component",
"config", "parsifal", "grep", "test",
"fonts", "qrref", "jsonl", "timing",
"zipvault", "gradlew", "matrix", "ascii-table",
"docker", "cargo", "cargo-arangodb", "cargo-qdrant",
"installer"));

final IVeniceInterpreter venice = new VeniceInterpreter(new AcceptAllInterceptor());

Expand Down Expand Up @@ -357,6 +359,7 @@ private List<DocSection> getTOC() {
extmod.addSection(new DocSection("Docker", "modules.docker"));
extmod.addSection(new DocSection("Cargo", "modules.cargo"));
extmod.addSection(new DocSection("Cargo/ArangoDB", "modules.cargo-arangodb"));
extmod.addSection(new DocSection("Cargo/Qdrant", "modules.cargo-qdrant"));
extmod.addSection(new DocSection("Test", "modules.test"));
extmod.addSection(new DocSection("Tracing", "modules.tracing"));
extmod.addSection(new DocSection("Benchmark", "modules.benchmark"));
Expand Down Expand Up @@ -460,6 +463,7 @@ private List<DocSection> getModulesLeftSections() {
new ModuleDockerSection(diBuilder).section(),
new ModuleCargoSection(diBuilder).section(),
new ModuleCargoArangoDBSection(diBuilder).section(),
new ModuleCargoQdrantDBSection(diBuilder).section(),
new ModuleTracingSection(diBuilder).section(),
new ModuleShellSection(diBuilder).section(),
new ModuleAnsiSection(diBuilder).section(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/* __ __ _
* \ \ / /__ _ __ (_) ___ ___
* \ \/ / _ \ '_ \| |/ __/ _ \
* \ / __/ | | | | (_| __/
* \/ \___|_| |_|_|\___\___|
*
*
* Copyright 2017-2024 Venice
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.jlangch.venice.impl.docgen.cheatsheet.modules;

import com.github.jlangch.venice.impl.docgen.cheatsheet.DocItemBuilder;
import com.github.jlangch.venice.impl.docgen.cheatsheet.DocSection;
import com.github.jlangch.venice.impl.docgen.cheatsheet.ISectionBuilder;


public class ModuleCargoQdrantDBSection implements ISectionBuilder {

public ModuleCargoQdrantDBSection(final DocItemBuilder diBuilder) {
this.diBuilder = diBuilder;
}

@Override
public DocSection section() {
final DocSection section = new DocSection(
"Cargo Qdrant Vector DB",
"Qdrant Testcontainers",
"modules.cargo-qdrant");

final DocSection all = new DocSection("(load-module :cargo-qdrant)", id());
section.addSection(all);

final DocSection docker = new DocSection("Lifecycle", id());
all.addSection(docker);
docker.addItem(diBuilder.getDocItem("cargo-qdrant/start", false));
docker.addItem(diBuilder.getDocItem("cargo-qdrant/stop", false));
docker.addItem(diBuilder.getDocItem("cargo-qdrant/running?", false));

return section;
}

private String id() {
return diBuilder.id();
}

private final DocItemBuilder diBuilder;
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public static boolean isValidModule(final VncKeyword module) {
"benchmark",
"cargo",
"cargo-arangodb",
"cargo-qdrant",
"chatgpt",
"cli",
"clipboard",
Expand Down
221 changes: 221 additions & 0 deletions src/main/resources/com/github/jlangch/venice/cargo-qdrant.venice
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
;;;; __ __ _
;;;; \ \ / /__ _ __ (_) ___ ___
;;;; \ \/ / _ \ '_ \| |/ __/ _ \
;;;; \ / __/ | | | | (_| __/
;;;; \/ \___|_| |_|_|\___\___|
;;;;
;;;;
;;;; Copyright 2017-2024 Venice
;;;;
;;;; Licensed under the Apache License, Version 2.0 (the "License");
;;;; you may not use this file except in compliance with the License.
;;;; You may obtain a copy of the License at
;;;;
;;;; http://www.apache.org/licenses/LICENSE-2.0
;;;;
;;;; Unless required by applicable law or agreed to in writing, software
;;;; distributed under the License is distributed on an "AS IS" BASIS,
;;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;;;; See the License for the specific language governing permissions and
;;;; limitations under the License.

;;;; Docker Qdrant cargo testcontainer

;;;; This is just a configuration wrapper on top of the :cargo module to
;;;; simplify using Qdrant testcontainers

(ns cargo-qdrant)

(load-module :docker)
(load-module :cargo)

(import :com.github.jlangch.venice.ShellException)

;; Qdrant is now accessible through these APIs
;; REST API: localhost:6333
;; Web UI: localhost:6333/dashboard
;; GRPC API: localhost:6334
(defonce internal-rest-port 6333)
(defonce internal-grpc-port 6334)


;; ---------------------------------------------------------------------------
;; Qdrant start & stop container
;; ---------------------------------------------------------------------------

(defn
^{ :arglists '(
"(cargo-qdrant/start cname version storage-dir)")
:doc """
Starts a Qdrant container.

Qdrant is vector database often used for LLM embeddings.

Start rules:

* If a container with another version exists for the container
name remove the container and the image
* Pull the image if not yet locally available
* If the container already runs - use it
* If the container is available but does not run - start it `(docker/start ...)`
* If the container is not available - run it `(docker/run ...)`
* Finally check for a successful startup. The container log must
contain the string ".*is ready for business. Have fun.*" on the
last line.

Args:

| [![width: 20%]] | [![width: 85%]] |
| cname | A unique container name |
| version | The Qdrant version to use. E.g.: 1.8.3 |
| mapped-rest-port | The published (mapped) Qdrant REST port on the \
host. Defaults to 6333 |
| mapped-grpc-port | The published (mapped) Qdrant GRPC port on the \
host. Defaults to 6334 |
| storage-dir | Directory where Qdrant persists all the data. |
| config-file | An optional custom configuration yaml file |
| log | A log function, may be *nil*. \
E.g: `(fn [s] (println "Qdrant:" s))`|
"""
:examples '(
"""
(do
(load-module :cargo-qdrant ['cargo-qdrant :as 'cq])

;; Run a Qdrant container labeled as "qdrant"
(cq/start "qdrant" "1.8.3" "./qdrant-storage"))
""")
:see-also '(
"cargo-qdrant/stop"
"cargo-qdrant/running?") }

start

([cname version storage-dir config-file log]
(start cname
version
internal-rest-port ;; default REST port
internal-grpc-port ;; default GRPC port
storage-dir
config-file
log))

([cname version mapped-rest-port mapped-grpc-port storage-dir config-file log]
{ :pre [(string? cname)
(string? version)
(or (int? mapped-rest-port) (long? mapped-rest-port))
(< 0 mapped-rest-port 65536)
(or (int? mapped-grpc-port) (long? mapped-grpc-port))
(< 0 mapped-grpc-port 65536)
(or (string? storage-dir)
(io/file? storage-dir))
(or (nil? config-file)
(string? config-file)
(io/file? config-file))] }
(when-not (io/exists-dir? storage-dir)
(throw :VncException
"The Qdrant storage directory \"~{storage-dir}\" does not exist!"))
(when-not (and (some? config-file) (io/exists-file? config-file))
(throw :VncException
"The Qdrant config file \"~{config-file}\" does not exist!"))
(let [publish ["~{mapped-rest-port}:~{internal-rest-port}"
"~{mapped-grpc-port}:~{internal-grpc-port}"]
envs []
volumes (if (nil? config-file)
["~{storage-dir}:/qdrant/storage"]
["~{storage-dir}:/qdrant/storage"
"~{config-file}:/qdrant/config/production.yaml"])
args []
log (or log default-log)
wait-after-start-secs 3
ready-check-max-secs 30]
(log "starting ~{version} as \"~{cname}\" @ port ~{publish} ...")
(cargo/start cname "qdrant/qdrant" version
publish
envs
volumes
args
qdrant-ready?
log
wait-after-start-secs
ready-check-max-secs))))


(defn
^{ :arglists '("(cargo-qdrant/stop cname log)")
:doc """
Stops an Qdrant container

Args:

| cname | A unique container name |
"""
:examples '(
"""
(do
(load-module :cargo-qdrant ['cargo-qdrant :as 'cq])

;; Stop the Qdrant container labeled as "qdrant"
(cq/stop "qdrant"))
""")
:see-also '(
"cargo-qdrant/start"
"cargo-qdrant/running?") }

stop [cname log]

{ :pre [(string? cname)] }

(let [log (or log default-log)]
(cargo/stop cname log)))


(defn
^{ :arglists '("(cargo-qdrant/running? cname)")
:doc """
Returns true if a container with the specified name is running.

Args:

| cname | A unique container name |
"""
:examples '(
"""
;; Test if Qdrant container is running
(do
(load-module :cargo-qdrant ['cargo-qdrant :as 'cq])
(cq/running? "qdrant"))
""")
:see-also '(
"cargo-qdrant/start",
"cargo-qdrant/stop") }

running? [cname]

{ :pre [(string? cname)] }

(docker/container-running-with-name? cname))



;; ---------------------------------------------------------------------------
;; utils
;; ---------------------------------------------------------------------------

(defn default-log [s]
(println "Qdrant:" s))

(defn qdrant-ready? [cname]
(-> (docker/container-logs cname :tail 1)
(str/trim)
(match? #".*is ready for business. Have fun.*")))

(defn dir-empty? [dir]
(zero? (count (io/list-files dir))))

(defn dir-not-empty? [dir]
(pos? (count (io/list-files dir))))


(defn admin-url [port]
"http://localhost:6333/dashboard")

0 comments on commit 20e3737

Please sign in to comment.