diff --git a/.github/workflows/publish-development-version.yml b/.github/workflows/publish-development-version.yml index d373c3827..36fa1407a 100644 --- a/.github/workflows/publish-development-version.yml +++ b/.github/workflows/publish-development-version.yml @@ -34,7 +34,7 @@ jobs: - name: Assemble uses: gradle/gradle-build-action@v2 with: - arguments: assemble -x:xef-java-examples:assemble -x:xef-scala:assemble -x:xef-scala-examples:assemble + arguments: assemble - name: Upload reports if: failure() @@ -46,36 +46,4 @@ jobs: - name: Publish development version uses: gradle/gradle-build-action@v2 with: - arguments: publishToSonatype -x:xef-scala:publishToSonatype closeAndReleaseSonatypeStagingRepository - - publish-modules-with-loom: - timeout-minutes: 30 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - ref: ${{ github.ref_name }} - - - name: Set up Java - uses: actions/setup-java@v3 - with: - distribution: 'zulu' - java-version: 20 - - - name: assemble - uses: gradle/gradle-build-action@v2 - with: - arguments: :xef-scala:assemble :xef-java-examples:assemble - - - name: Upload reports - if: failure() - uses: actions/upload-artifact@v3 - with: - name: 'reports-${{ matrix.os }}' - path: '**/build/reports/**' - - - name: Publish development version - uses: gradle/gradle-build-action@v2 - with: - arguments: :xef-scala:publishToSonatype closeAndReleaseSonatypeStagingRepository + arguments: publishToSonatype closeAndReleaseSonatypeStagingRepository diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index f6523d87c..10b5e15a4 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -32,7 +32,7 @@ jobs: - name: Assemble uses: gradle/gradle-build-action@v2 with: - arguments: assemble -x:xef-java-examples:assemble -x:xef-scala:assemble -x:xef-scala-examples:assemble + arguments: assemble - name: Upload reports if: failure() @@ -44,36 +44,4 @@ jobs: - name: Publish final version uses: gradle/gradle-build-action@v2 with: - arguments: publishToSonatype -x:xef-scala:publishToSonatype closeSonatypeStagingRepository - - publish-modules-with-loom: - timeout-minutes: 30 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - ref: ${{ github.ref_name }} - - - name: Set up Java - uses: actions/setup-java@v3 - with: - distribution: 'zulu' - java-version: 20 - - - name: assemble - uses: gradle/gradle-build-action@v2 - with: - arguments: :xef-scala:assemble :xef-java-examples:assemble - - - name: Upload reports - if: failure() - uses: actions/upload-artifact@v3 - with: - name: 'reports-${{ matrix.os }}' - path: '**/build/reports/**' - - - name: Publish final version - uses: gradle/gradle-build-action@v2 - with: - arguments: :xef-scala:publishToSonatype closeSonatypeStagingRepository + arguments: publishToSonatype closeSonatypeStagingRepository diff --git a/README.md b/README.md index dccf15acd..ca77c7c77 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Our goal is to make the move to this new world as simple as possible for the dev xef.ai is packaged in two layers: 1. Core libraries bringing integration with the basic services in an AI application. These libraries expose an _idiomatic_ interface, so there's one per programming language. - At this moment we support Kotlin and Scala. + At this moment we support Kotlin. 2. Integrations with other libraries which complement the core mission of xef.ai. xef.ai draws inspiration from libraries like [LangChain](https://docs.langchain.com/docs/) @@ -47,11 +47,9 @@ strategies. Libraries are published in Maven Central, under the `com.xebia` group. -1. `xef-kotlin` for Kotlin support, `xef-scala` for Scala, `xef-java` for Java. +1. `xef-kotlin` for Kotlin support. 2. The name of a library we provide integration for, like `xef-lucene`. -
-Kotlin logo Gradle (Kotlin DSL) Libraries are published in Maven Central. You may need to add that repository explicitly in your build, if you haven't done it before. @@ -73,51 +71,10 @@ We publish all libraries at once under the same version, so [version catalogs](https://docs.gradle.org/current/userguide/platforms.html#sec:sharing-catalogs) could be useful. -
- -
-Scala logo SBT - -```sbt -libraryDependencies += "com.xebia" %% "xef-scala" % "" -``` - -> **Warning** -> `xef-scala` is currently only available for Scala 3, and depends on project [Loom](https://openjdk.org/projects/loom/), -> so you will need at least Java 20 to use the library. - -
- -
-Maven logo Maven - -Libraries are published in Maven Central. You may need to add that repository explicitly -in your build, if you haven't done it before. - -```xml - - com.xebia - xef-java - x.x.x - pom - runtime - -``` - -
- ## 📖 Quick Introduction -In this small introduction we look at the main features of xef, including the `conversation` function. - -- [Kotlin logo Kotlin version](https://github.com/xebia-functional/xef/blob/main/docs/intro/kotlin.md) -- [Scala logo Scala version](https://github.com/xebia-functional/xef/blob/main/docs/intro/scala.md) -- [Java logo Java version](https://github.com/xebia-functional/xef/blob/main/docs/intro/java.md) +In [this](https://github.com/xebia-functional/xef/blob/main/docs/intro.md) small introduction we look at the main features of xef, including the `conversation` function. ## 🚀 Examples -You can also have a look at the examples to have a feeling of how using the library looks like. - -- [Kotlin logo Examples in Kotlin](https://github.com/xebia-functional/xef/tree/main/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation) -- [Scala logo Examples in Scala](https://github.com/xebia-functional/xef/tree/main/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala) -- [Java logo Examples in Java](https://github.com/xebia-functional/xef/tree/main/examples/java/src/main/java/com/xebia/functional/xef/java/auto) +You can also have a look at the [examples](https://github.com/xebia-functional/xef/tree/main/examples/src/main/kotlin/com/xebia/functional/xef/conversation) to have a feeling of how using the library looks like. diff --git a/buildSrc/src/main/kotlin/ScalaPublishingConventionsPlugin.kt b/buildSrc/src/main/kotlin/ScalaPublishingConventionsPlugin.kt deleted file mode 100644 index 400817204..000000000 --- a/buildSrc/src/main/kotlin/ScalaPublishingConventionsPlugin.kt +++ /dev/null @@ -1,60 +0,0 @@ -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.plugins.BasePlugin -import org.gradle.api.plugins.BasePluginExtension -import org.gradle.api.publish.PublishingExtension -import org.gradle.api.publish.maven.MavenPublication -import org.gradle.api.tasks.TaskProvider -import org.gradle.api.tasks.bundling.Jar -import org.gradle.kotlin.dsl.findByType -import org.gradle.kotlin.dsl.get -import org.gradle.kotlin.dsl.register -import org.gradle.plugins.signing.SigningExtension - -class ScalaPublishingConventionsPlugin : Plugin { - - override fun apply(project: Project): Unit = project.run { - val scaladocJarTask: TaskProvider = tasks.register("scaladocJar") { - group = BasePlugin.BUILD_GROUP - tasks.findByName("scaladoc")?.let { dependsOn(it) } - ?: errorMessage("The scaladoc task was not found. The Javadoc jar file won't contain any documentation") - archiveClassifier.set("javadoc") - from("${layout.buildDirectory.get()}/docs/scaladoc") - } - - val publishingExtension: PublishingExtension = - extensions.findByType() - ?: throw IllegalStateException("The Maven Publish plugin is required to publish the build artifacts") - - val signingExtension: SigningExtension = - extensions.findByType() - ?: throw IllegalStateException("The Signing plugin is required to digitally sign the built artifacts") - - val basePluginExtension: BasePluginExtension = - extensions.findByType() - ?: throw IllegalStateException("The Base plugin is required to configure the name of artifacts") - - publishingExtension.run { - publications { - register("maven") { - val scala3Suffix = "_3" - artifactId = basePluginExtension.archivesName.get() + scala3Suffix - from(components["java"]) - artifact(scaladocJarTask) - pomConfiguration(project) - } - } - } - - signingExtension.run { - val isLocal = gradle.startParameter.taskNames.any { it.contains("publishToMavenLocal", ignoreCase = true) } - val signingKeyId: String? = configValue("signing.keyId", "SIGNING_KEY_ID") - val signingKey: String? = configValue("signing.key", "SIGNING_KEY") - val signingPassphrase: String? = configValue("signing.passphrase", "SIGNING_KEY_PASSPHRASE") - isRequired = !isLocal - useGpgCmd() - useInMemoryPgpKeys(signingKeyId, signingKey, signingPassphrase) - sign(publishingExtension.publications) - } - } -} diff --git a/buildSrc/src/main/kotlin/xef-scala-publishing-conventions.gradle.kts b/buildSrc/src/main/kotlin/xef-scala-publishing-conventions.gradle.kts deleted file mode 100644 index 97fa1cfd8..000000000 --- a/buildSrc/src/main/kotlin/xef-scala-publishing-conventions.gradle.kts +++ /dev/null @@ -1 +0,0 @@ -apply() diff --git a/core/TECHNICAL.MD b/core/TECHNICAL.MD index 22b88ceb0..70969ee8e 100644 --- a/core/TECHNICAL.MD +++ b/core/TECHNICAL.MD @@ -14,11 +14,9 @@ The breakdown is only in terms of JVM, since that's where we _mostly_ care about We include the following dependencies in our _core_ module to implement a _common_ layer to interact with LLMs. The dependency on Kotlin Stdlib is unavoidable, since we use Kotlin as our main language. -We also require KotlinX Coroutines such that we can leverage the `suspend` keyword in our API and expose `Future` to the -Java/Scala API. -Additionally, we also have a need for a HTTP client, and a serialization framework. Here we use Ktor and KotlinX -Serialization respectively, -and Xef relies on the CIO engine for Ktor, which avoids any additional dependencies. +We also require KotlinX Coroutines such that we can leverage the `suspend` keyword in our API. +Additionally, we also have a need for an HTTP client, and a serialization framework. Here we use Ktor and KotlinX +Serialization respectively, and Xef relies on the CIO engine for Ktor, which avoids any additional dependencies. - kotlin-stdlib (1810 Kb = 1598 Kb + 212 Kb) - kotlinx-coroutines-core (1608 Kb = 1442 Kb + 166 Kb) diff --git a/core/src/jvmMain/kotlin/com/xebia/functional/xef/conversation/futures/ExecutionContext.kt b/core/src/jvmMain/kotlin/com/xebia/functional/xef/conversation/futures/ExecutionContext.kt deleted file mode 100644 index c9fad09f4..000000000 --- a/core/src/jvmMain/kotlin/com/xebia/functional/xef/conversation/futures/ExecutionContext.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.xebia.functional.xef.conversation.futures - -import java.util.concurrent.CompletableFuture -import java.util.concurrent.ExecutorService -import java.util.concurrent.Executors -import java.util.concurrent.ThreadFactory -import java.util.concurrent.atomic.AtomicInteger -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.CoroutineStart -import kotlinx.coroutines.asCoroutineDispatcher -import kotlinx.coroutines.cancel -import kotlinx.coroutines.future.future - -interface ExecutionContext : AutoCloseable { - - val executorService: ExecutorService - val coroutineScope: CoroutineScope - - fun future(block: suspend CoroutineScope.() -> A): CompletableFuture = - coroutineScope.future(coroutineScope.coroutineContext, CoroutineStart.DEFAULT, block) - - override fun close() { - coroutineScope.cancel() - executorService.shutdown() - } - - private class AIScopeThreadFactory : ThreadFactory { - private val counter = AtomicInteger() - - override fun newThread(r: Runnable): Thread { - val t = Thread(r) - t.name = "xef-ai-scope-worker-${counter.getAndIncrement()}" - t.isDaemon = true - return t - } - } - - companion object { - @JvmField val DEFAULT = from(Executors.newCachedThreadPool(AIScopeThreadFactory())) - - @JvmStatic - fun from(executorService: ExecutorService): ExecutionContext = - object : ExecutionContext { - override val executorService: ExecutorService = executorService - override val coroutineScope: CoroutineScope = - CoroutineScope(executorService.asCoroutineDispatcher()) - } - } -} diff --git a/docs/intro/kotlin.md b/docs/intro.md similarity index 100% rename from docs/intro/kotlin.md rename to docs/intro.md diff --git a/docs/intro/java.md b/docs/intro/java.md deleted file mode 100644 index 2d16ccdc7..000000000 --- a/docs/intro/java.md +++ /dev/null @@ -1,193 +0,0 @@ -# Quick introduction to xef.ai (Java version) - -After adding the library to your project -(see the [main README](https://github.com/xebia-functional/xef/blob/main/README.md) for instructions), -you get access to the `AIScope` class, which is your port of entry to the modern AI world. -Using it, you can _prompt_ for information, which means posing the question to an LLM -(Large Language Model). The easiest way is to just get the information back as a string. - -```java -package my.example; - -import com.xebia.functional.xef.java.auto.AIScope; - -import java.util.concurrent.ExecutionException; - -public class Example { - public static void main(String[] args) throws ExecutionException, InterruptedException { - try (AIScope scope = new AIScope()) { - String topic = "artificial intelligence"; - scope.promptMessage("Give me a selection of books about " + topic) - .thenAccept(System.out::println) - .get(); - } - } -} -``` - -> **Note** -> By default the `AIScope` connects to [OpenAI](https://platform.openai.com/). -> To use their services you should provide the corresponding API key in the `OPENAI_TOKEN` -> environment variable, and have enough credits. - -In the example above we create an `AIScope` using the `try-with-resources` syntax, -which ensures that the scope is closed at the end of the block. -The `AIScope` gives us access to the `promptMessage` & co functions, which allow us to interact with the LLM. - -All the functions of `AIScope` are returned as a `Future` for maximum backward compatibility until JDK8, -but you can inject `Executors.newVirtualThreadPerTaskExecutor()` to have the `Future`s work on virtual threads. - -Remember that exceptions in `Future`are wrapped in `ExecutionException`, -so to inspect the actual exception you need to call `getCause()` on it. -_Structured Concurrency_ is implemented under the hood by Kotlin's `CoroutineScope`, -and all futures are cancelled when the `AIScope` is closed and `Future#get` will throw `CancellationException`. - -In the next examples we'll write functions that rely on `AIScope`'s DSL functionality - -## Structure - - -The output from the `books` function above may be hard to parse back from the -strings we obtain. Fortunately, you can also ask xef.ai to give you back the information -using a _custom type_. The library takes care of instructing the LLM on building such -a structure, and deserialize the result back for you. - -We can thus define a `Book` class that describes the desired response we want to receive from the LLM. -Relying on [Jakarta validation](https://beanvalidation.org) we can also specify which fields are mandatory using `NotNull`, -or include additional constraints in the [Json Schema](https://json-schema.org). - -xef.ai reuses [Jackson](https://github.com/FasterXML/jackson-databind), -and [JsonSchema generator](https://github.com/victools/jsonschema-generator) to parse and generate the Json Schema V7 for you. - -```java -package my.example; - -import jakarta.validation.constraints.NotNull; - -public class Book { - @NotNull public String title; - @NotNull public String author; - @NotNull public int year; - @NotNull public String genre; - - @Override - public String toString() { - return "Book{" + - "title='" + title + '\'' + - ", author='" + author + '\'' + - ", year=" + year + - ", genre='" + genre + '\'' + - '}'; - } -} -``` - -Using the definition of `Book`, we can rewrite our previous example as: - -```java -package my.example; - -import com.xebia.functional.xef.java.auto.AIScope; -import jakarta.validation.constraints.NotNull; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - -public class Example { - - private final AIScope scope; - - public Example(AIScope scope) { - this.scope = scope; - } - - public CompletableFuture bookSelection(String topic) { - return scope.prompt("Give me a selection of books about " + topic, Example.Book.class); - } - - public static void main(String[] args) throws ExecutionException, InterruptedException { - try (AIScope scope = new AIScope()) { - Example example = new Example(scope); - example.bookSelection("artificial intelligence") - .thenAccept(System.out::println) - .get(); - } - } -} -``` - -Here we also show how you can easily capture the `AIScope` in a class, -and build and compose additional functionality on top. -If you're using any dependency injection framework, you can also construct `AIScope` and inject it as usual. -Make sure that the dependency injection framework properly closes the `AIScope` when the application shuts down. - -## Context - -LLMs have knowledge about a broad variety of topics. But by construction they are not able -to respond to questions about information not available in their training set. However, you -often want to supplement the LLM with more data: -- Transient information referring to the current moment, like the current weather, or - the trends in the stock market in the past 10 days. -- Non-public information, for example for summarizing a piece of text you're creating - within you organization. - -These additional pieces of information are called the _contextScope_ in xef.ai, and are attached -to every question to the LLM. Although you can add arbitrary strings to the context at any -point, the most common mode of usage is using an _agent_ to consult an external service, -and make its response part of the context. One such agent is `search`, which uses a web -search service to enrich that context. - -```java -package my.example; - -import java.util.concurrent.CompletableFuture; - -public class Weather { - private final AIScope scope; - - public Weather(AIScope scope) { - this.scope = scope; - } - - public CompletableFuture recommendation() { - return scope.contextScope(scope.search("Weather in $place"), () -> - scope.promptMessage("Knowing this forecast, what clothes do you recommend I should wear?") - ); - } -} -``` - -> **Note** -> The underlying mechanism of the context is a _vector store_, a data structure which -> saves a set of strings, and is able to find those similar to another given one. -> By default xef.ai uses an _in-memory_ vector store, since it provides maximum -> compatibility across platforms. However, if you foresee your context growing above -> the hundreds of elements, you may consider switching to another alternative, like -> Lucene or PostgreSQL. -> -> ```java -> package my.example; -> -> import com.xebia.functional.xef.store.LuceneKt; -> -> import java.nio.file.Path; -> import java.util.concurrent.CompletableFuture; -> -> public class VectorStore { -> -> private final AIScope scope; -> -> public VectorStore(AIScope scope) { -> this.scope = scope; -> } -> -> public void example() { -> Path LUCENE_PATH = Path.of("lucene"); -> scope.contextScope( -> LuceneKt.InMemoryLuceneBuilder(LUCENE_PATH), -> () -> CompletableFuture.completedFuture("do stuff") -> ); -> } -> -> } -> ``` diff --git a/docs/intro/scala.md b/docs/intro/scala.md deleted file mode 100644 index a40fca0d5..000000000 --- a/docs/intro/scala.md +++ /dev/null @@ -1,146 +0,0 @@ -# Quick introduction to xef.ai (Scala version) - -After adding the library to your project (see the -[main README](https://github.com/xebia-functional/xef/blob/main/README.md) for instructions), -you get access to the `conversation` function, which is your port of entry to the modern AI world. -Inside of it, you can _prompt_ for information, which means posing the question to an LLM -(Large Language Model). The easiest way is to just get the information back as a string or list of strings. - -```scala 3 -import com.xebia.functional.xef.scala.conversation.* - -def books(topic: String): Unit = conversation: - val topBook: String = promptMessage(s"Give me the top-selling book about $topic") - println(topBook) - val selectedBooks: List[String] = promptMessages(s"Give me a selection of books about $topic") - println(selectedBooks.mkString("\n")) -``` - -## Additional setup - -If the code above fails, you may need to perform some additional setup. - -### OpenAI - -By default, the `conversation` block connects to [OpenAI](https://platform.openai.com/). -To use their services you should provide the corresponding API key in the `OPENAI_TOKEN` -environment variable, and have enough credits. - -
-SBT - -```shell -env OPENAI_TOKEN= sbt -``` -
- -
-IntelliJ - -Set the environment variable `OPENAI_TOKEN=xxx` - -
- -### Project Loom - -The Scala module depends on project [Loom](https://openjdk.org/projects/loom/), -so you will need at least Java 20 to use the library. Furthermore, if using Java 20 specifically, -you need to pass the `--enable-preview` flag. - -
-SBT - -```shell -env OPENAI_TOKEN= sbt -J--enable-preview -``` -
- -
-IntelliJ - -- Set the Java version to at least 20 -- If using Java 20 specifically, set VM options to `--enable-preview` - -
- -## Structure - -The output from the `books` function above may be hard to parse back from the -strings we obtain. Fortunately, you can also ask xef.ai to give you back the information -using a _custom type_. The library takes care of instructing the LLM on building such -a structure, and deserialize the result back for you. - -This can be done by declaring a case class that `derives SerialDescriptor, Decoder`: - -```scala 3 -import com.xebia.functional.xef.scala.conversation.* -import com.xebia.functional.xef.scala.serialization.* -import io.circe.Decoder - -case class Book(name: String, author: String, pages: Int) derives SerialDescriptor, Decoder -``` - -The `conversation` block can then be written in this way: - -```scala 3 -def bookExample(topic: String): Unit = conversation: - val Book(title, author, pages) = prompt[Book](s"Give me the best-selling book about $topic") - println(s"The book $title is by $author and has $pages pages.") -``` - -xef.ai for Scala uses xef.ai core, which is based on the Kotlin implementation. Hence, the core -reuses [Kotlin's common serialization](https://kotlinlang.org/docs/serialization.html), and -Scala uses [circe](https://github.com/circe/circe) to derive the required serializable instance. -The LLM is usually able to detect which kind of information should go in each field based on its name -(like `title` and `author` above). - -## Context - -LLMs have knowledge about a broad variety of topics. But by construction they are not able -to respond to questions about information not available in their training set. However, you -often want to supplement the LLM with more data: -- Transient information referring to the current moment, like the current weather, or - the trends in the stock market in the past 10 days. -- Non-public information, for example for summarizing a piece of text you're creating - within your organization. - -These additional pieces of information are called the _context_ in xef.ai, and are attached -to every question to the LLM. Although you can add arbitrary strings to the context at any -point, the most common mode of usage is using an _agent_ to consult an external service, -and make its response part of the context. One such agent is `search`, which uses the -[Google Search API (SerpApi)](https://serpapi.com/) to enrich that context. - -(Note that a SerpApi token may be required to run this example.) - -```scala 3 -import com.xebia.functional.xef.conversation.llm.openai.* -import com.xebia.functional.xef.reasoning.serpapi.* -import com.xebia.functional.xef.scala.conversation.* -import com.xebia.functional.xef.scala.serialization.* -import io.circe.Decoder - -val openAI: OpenAI = OpenAI.fromEnvironment() - -def setContext(query: String)(using conversation: ScalaConversation): Unit = - addContext(Search(openAI.DEFAULT_CHAT, conversation, 3).search(query).get) - -@main def runWeather(): Unit = conversation: - setContext("Weather in Cádiz, Spain") - val question = "Knowing this forecast, what clothes do you recommend I should wear if I live in Cádiz?" - val answer = promptMessage(question) - println(answer) -``` - -> **Note** -> The underlying mechanism of the context is a _vector store_, a data structure which -> saves a set of strings, and is able to find those similar to another given one. -> By default xef.ai uses an _in-memory_ vector store, since this provides maximum -> compatibility across platforms. However, if you foresee your context growing above -> the hundreds of elements, you may consider switching to another alternative, like -> Lucene or PostgreSQL. - -## Examples - -Check out the -[examples folder](https://github.com/xebia-functional/xef/blob/main/examples/scala/src/main/scala/com/xebia/functional/xef/examples) -for a complete list of different use cases. diff --git a/examples/kotlin/build.gradle.kts b/examples/build.gradle.kts similarity index 86% rename from examples/kotlin/build.gradle.kts rename to examples/build.gradle.kts index b3e74135a..a3751ab09 100644 --- a/examples/kotlin/build.gradle.kts +++ b/examples/build.gradle.kts @@ -15,14 +15,13 @@ java { } dependencies { - implementation(projects.xefKotlin) + implementation(projects.xefCore) + implementation(projects.xefOpenai) implementation(projects.xefFilesystem) implementation(projects.xefPdf) implementation(projects.xefSql) implementation(projects.xefTokenizer) - implementation(projects.xefGpt4all) implementation(projects.xefGcp) - implementation(projects.xefOpenai) implementation(projects.xefReasoning) implementation(projects.xefOpentelemetry) implementation(projects.xefMlflow) @@ -43,12 +42,6 @@ spotless { } } -tasks.getByName("processResources") { - dependsOn(projects.xefGpt4all.dependencyProject.tasks.getByName("jvmProcessResources")) - from("${projects.xefGpt4all.dependencyProject.layout.buildDirectory}/processedResources/jvm/main") - into("${layout.buildDirectory}/resources/main") -} - @Suppress("MaxLineLength") tasks.create("docker-sql-example-up") { diff --git a/examples/java/build.gradle.kts b/examples/java/build.gradle.kts deleted file mode 100644 index aded6cd45..000000000 --- a/examples/java/build.gradle.kts +++ /dev/null @@ -1,16 +0,0 @@ -@file:Suppress("DSL_SCOPE_VIOLATION") - -plugins { - java - alias(libs.plugins.spotless) -} - -dependencies { - implementation(projects.xefJava) - implementation(projects.xefReasoning) - implementation(projects.xefGpt4all) -} - -tasks.test { - useJUnitPlatform() -} diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/BreakingNews.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/BreakingNews.java deleted file mode 100644 index f4c56619e..000000000 --- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/BreakingNews.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.xebia.functional.xef.java.auto.jdk21.contexts; - -import com.xebia.functional.xef.conversation.PlatformConversation; -import com.xebia.functional.xef.conversation.llm.openai.OpenAI; -import com.xebia.functional.xef.prompt.Prompt; -import com.xebia.functional.xef.reasoning.serpapi.Search; - -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - -public class BreakingNews { - - static DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd/M/yyyy"); - static LocalDateTime now = LocalDateTime.now(); - - public record BreakingNew(String summary) { - } - - private static CompletableFuture writeParagraph(PlatformConversation scope) { - var currentDate = dtf.format(now); - - return scope.prompt(OpenAI.fromEnvironment().DEFAULT_SERIALIZATION, new Prompt("write a paragraph of about 300 words about: " + currentDate + " Covid News"), BreakingNews.BreakingNew.class) - .thenAccept(breakingNews -> System.out.println(currentDate + " Covid news summary:\n" + breakingNews)); - } - - public static void main(String[] args) throws ExecutionException, InterruptedException { - try (PlatformConversation scope = OpenAI.conversation()) { - var currentDate = dtf.format(now); - var search = new Search(OpenAI.fromEnvironment().DEFAULT_CHAT, scope, 3); - scope.addContextFromArray(search.search(currentDate + " Covid News").get()); - writeParagraph(scope).get(); - } - } -} diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/DivergentTasks.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/DivergentTasks.java deleted file mode 100644 index 80790b2d5..000000000 --- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/DivergentTasks.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.xebia.functional.xef.java.auto.jdk21.contexts; - -import com.xebia.functional.xef.conversation.PlatformConversation; -import com.xebia.functional.xef.conversation.llm.openai.OpenAI; -import com.xebia.functional.xef.prompt.Prompt; -import com.xebia.functional.xef.reasoning.serpapi.Search; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - -public class DivergentTasks { - - public Long numberOfMedicalNeedlesInWorld; - - private static CompletableFuture numberOfMedical(PlatformConversation scope) { - return scope.prompt(OpenAI.fromEnvironment().DEFAULT_SERIALIZATION, new Prompt("Provide the number of medical needles in the world"), DivergentTasks.class) - .thenAccept(numberOfNeedles -> System.out.println("Needles in world:\n" + numberOfNeedles.numberOfMedicalNeedlesInWorld)); - } - - public static void main(String[] args) throws ExecutionException, InterruptedException { - try (PlatformConversation scope = OpenAI.conversation()) { - Search search = new Search(OpenAI.fromEnvironment().DEFAULT_CHAT, scope, 3); - scope.addContextFromArray(search.search("Estimate amount of medical needles in the world").get()); - numberOfMedical(scope).get(); - } - } - -} diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/Markets.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/Markets.java deleted file mode 100644 index 9f09bd86d..000000000 --- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/Markets.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.xebia.functional.xef.java.auto.jdk21.contexts; - -import com.xebia.functional.xef.conversation.PlatformConversation; -import com.xebia.functional.xef.conversation.llm.openai.OpenAI; -import com.xebia.functional.xef.prompt.Prompt; -import com.xebia.functional.xef.reasoning.serpapi.Search; - -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - -public class Markets { - - public record Market(String news, List raisingStockSymbols, List decreasingStockSymbols) { - } - - private static CompletableFuture stockMarketSummary(PlatformConversation scope) { - var news = new Prompt("Write a short summary of the stock market results given the provided context."); - - return scope.prompt(OpenAI.fromEnvironment().DEFAULT_SERIALIZATION, news, Market.class) - .thenAccept(markets -> System.out.println(markets)); - } - - public static void main(String[] args) throws ExecutionException, InterruptedException { - try (PlatformConversation scope = OpenAI.conversation()) { - var dtf = DateTimeFormatter.ofPattern("dd/M/yyyy"); - var now = LocalDateTime.now(); - var currentDate = dtf.format(now); - var search = new Search(OpenAI.fromEnvironment().DEFAULT_CHAT, scope, 3); - scope.addContextFromArray(search.search(currentDate + "Stock market results, raising stocks, decreasing stocks").get()); - stockMarketSummary(scope).get(); - } - } -} diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/PDFDocument.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/PDFDocument.java deleted file mode 100644 index 6640d3613..000000000 --- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/PDFDocument.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.xebia.functional.xef.java.auto.jdk21.contexts; - -import com.xebia.functional.xef.conversation.PlatformConversation; -import com.xebia.functional.xef.conversation.llm.openai.OpenAI; -import com.xebia.functional.xef.java.auto.jdk21.util.ConsoleUtil; -import com.xebia.functional.xef.prompt.Prompt; -import com.xebia.functional.xef.reasoning.pdf.PDF; - -import java.util.List; -import java.util.concurrent.CompletableFuture; - -public class PDFDocument { - - private static ConsoleUtil util = new ConsoleUtil(); - - public record AIResponse(String answer, String source){} - - private static final String PDF_URL = "https://people.cs.ksu.edu/~schmidt/705a/Scala/Programming-in-Scala.pdf"; - - private static CompletableFuture askQuestion(PlatformConversation scope) { - System.out.println("Enter your question ( to exit): "); - - - var line = util.readLine(); - if (line == null || line.isBlank()) { - return CompletableFuture.completedFuture(null); - } else { - scope.prompt(OpenAI.fromEnvironment().DEFAULT_SERIALIZATION, new Prompt(line), AIResponse.class) - .thenAccept(aiRes -> System.out.println(aiRes.answer + "\n---\n" + - aiRes.source + "\n---\n")); - - return askQuestion(scope); - } - } - - public static void main(String[] args) throws Exception { - try (PlatformConversation scope = OpenAI.conversation()) { - PDF pdf = new PDF(OpenAI.fromEnvironment().DEFAULT_CHAT, - OpenAI.fromEnvironment().DEFAULT_SERIALIZATION, scope); - scope.addContext(List.of(pdf.readPDFFromUrl.readPDFFromUrl(PDF_URL).get())); - askQuestion(scope).get(); - } - finally { - util.close(); - } - } - -} diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/Weather.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/Weather.java deleted file mode 100644 index d596eb734..000000000 --- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/contexts/Weather.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.xebia.functional.xef.java.auto.jdk21.contexts; - -import com.xebia.functional.xef.conversation.PlatformConversation; -import com.xebia.functional.xef.conversation.llm.openai.OpenAI; -import com.xebia.functional.xef.prompt.Prompt; -import com.xebia.functional.xef.reasoning.serpapi.Search; - -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - -public class Weather { - public List answer; - - private static CompletableFuture clothesRecommend(PlatformConversation scope) { - return scope.prompt(OpenAI.fromEnvironment().DEFAULT_SERIALIZATION, new Prompt("Knowing this forecast, what clothes do you recommend I should wear?"), Weather.class) - .thenAccept(weather -> - System.out.println(weather.answer) - ); - } - - public static void main(String[] args) throws ExecutionException, InterruptedException { - try (PlatformConversation scope = OpenAI.conversation()) { - Search search = new Search(OpenAI.fromEnvironment().DEFAULT_CHAT, scope, 3); - scope.addContextFromArray(search.search("Weather in Cádiz, Spain").get()); - clothesRecommend(scope).get(); - } - } - -} diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/conversations/Animals.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/conversations/Animals.java deleted file mode 100644 index 49d4b3c9d..000000000 --- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/conversations/Animals.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.xebia.functional.xef.java.auto.jdk21.conversations; - -import com.xebia.functional.xef.conversation.PlatformConversation; -import com.xebia.functional.xef.conversation.llm.openai.OpenAI; -import com.xebia.functional.xef.prompt.JvmPromptBuilder; -import com.xebia.functional.xef.prompt.Prompt; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - -public class Animals { - - private final PlatformConversation scope; - - public Animals(PlatformConversation scope) { - this.scope = scope; - } - - public CompletableFuture uniqueAnimal() { - return scope.prompt(OpenAI.fromEnvironment().DEFAULT_SERIALIZATION, new Prompt("A unique animal species."), Animal.class); - } - - public CompletableFuture groundbreakingInvention() { - return scope.prompt(OpenAI.fromEnvironment().DEFAULT_SERIALIZATION, new Prompt("A groundbreaking invention from the 20th century."), Invention.class); - } - - public CompletableFuture story(Animal animal, Invention invention) { - Prompt storyPrompt = new JvmPromptBuilder() - .addSystemMessage("You are a writer for a science fiction magazine.") - .addUserMessage("Write a short story of 200 words that involves the animal and the invention") - .build(); - return scope.promptMessage(OpenAI.fromEnvironment().DEFAULT_CHAT, storyPrompt); - } - - public record Animal(String name, String habitat, String diet){} - public record Invention(String name, String inventor, int year, String purpose){} - - public static void main(String[] args) throws ExecutionException, InterruptedException { - try (PlatformConversation scope = OpenAI.conversation()) { - Animals animals = new Animals(scope); - animals.uniqueAnimal() - .thenCompose(animal -> - animals.groundbreakingInvention() - .thenCompose(invention -> - animals.story(animal, invention) - .thenAccept(System.out::println) - )).get(); - } - } -} diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/gpt4all/Chat.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/gpt4all/Chat.java deleted file mode 100644 index 6c16baded..000000000 --- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/gpt4all/Chat.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.xebia.functional.xef.java.auto.jdk21.gpt4all; - -import com.xebia.functional.gpt4all.GPT4All; -import com.xebia.functional.gpt4all.Gpt4AllModel; -import com.xebia.functional.xef.conversation.llm.openai.OpenAI; -import com.xebia.functional.xef.prompt.Prompt; -import org.reactivestreams.Subscriber; -import org.reactivestreams.Subscription; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.file.Path; -import java.util.Objects; -import java.util.concurrent.ExecutionException; - -public class Chat { - public static void main(String[] args) throws ExecutionException, InterruptedException, IOException { - var userDir = System.getProperty("user.dir"); - var path = userDir + "/models/gpt4all/ggml-replit-code-v1-3b.bin"; - - var supportedModels = Gpt4AllModel.Companion.getSupportedModels(); - - supportedModels.forEach(it -> { - var url = (Objects.nonNull(it.getUrl())) ? " - " + it.getUrl() : ""; - System.out.println("🤖 " + it.getName() + url); - }); - - var url = "https://huggingface.co/nomic-ai/ggml-replit-code-v1-3b/resolve/main/ggml-replit-code-v1-3b.bin"; - var modelPath = Path.of(path); - var gpt4all = GPT4All.Companion.invoke(url, modelPath); - - System.out.println("🤖 GPT4All loaded: " + gpt4all); - /** - * Uses internally [HuggingFaceLocalEmbeddings] default of "sentence-transformers", "msmarco-distilbert-dot-v5" - * to provide embeddings for docs in contextScope. - */ - - try (var scope = OpenAI.conversation(); - var br = new BufferedReader(new InputStreamReader(System.in))) { - - System.out.println("\n🤖 Enter your question: "); - - while(true){ - String line = br.readLine(); - if (line.equals("exit")) break; - - var answer = scope.promptStreamingToPublisher(gpt4all, new Prompt(line)); - - answer.subscribe(new Subscriber() { - StringBuilder answer = new StringBuilder(); - - @Override - public void onSubscribe(Subscription s) { - System.out.print("\n🤖 --> " + s); - s.request(Long.MAX_VALUE); - } - - @Override - public void onNext(String s) { - answer.append(s); - } - - @Override - public void onError(Throwable t) { - System.out.println(t); - } - - @Override - public void onComplete() { - System.out.println("\n🤖 --> " + answer.toString()); - System.out.println("\n🤖 --> Done"); - System.out.println("\n🤖 Enter your question: "); - } - }); - } - } - } -} diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/ASCIIArt.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/ASCIIArt.java deleted file mode 100644 index f30e8b1ef..000000000 --- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/ASCIIArt.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.xebia.functional.xef.java.auto.jdk21.serialization; - -import com.xebia.functional.xef.conversation.PlatformConversation; -import com.xebia.functional.xef.conversation.llm.openai.OpenAI; -import com.xebia.functional.xef.prompt.Prompt; - -import java.util.concurrent.ExecutionException; - -public class ASCIIArt { - public String art; - - public static void main(String[] args) throws ExecutionException, InterruptedException { - try (PlatformConversation scope = OpenAI.conversation()) { - scope.prompt(OpenAI.fromEnvironment().DEFAULT_SERIALIZATION, new Prompt("ASCII art of a cat dancing"), ASCIIArt.class) - .thenAccept(art -> System.out.println(art.art)) - .get(); - } - } -} diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/Book.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/Book.java deleted file mode 100644 index 157606044..000000000 --- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/Book.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.xebia.functional.xef.java.auto.jdk21.serialization; - -import com.xebia.functional.xef.conversation.PlatformConversation; -import com.xebia.functional.xef.conversation.llm.openai.OpenAI; -import com.xebia.functional.xef.prompt.Prompt; - -import java.util.concurrent.ExecutionException; - -public class Book { - - public String title; - public String author; - public String summary; - - public static void main(String[] args) throws ExecutionException, InterruptedException { - try (PlatformConversation scope = OpenAI.conversation()) { - scope.prompt(OpenAI.fromEnvironment().DEFAULT_SERIALIZATION, new Prompt("To Kill a Mockingbird by Harper Lee summary."), Book.class) - .thenAccept(book -> System.out.println("To Kill a Mockingbird summary:\n" + book.summary)) - .get(); - } - } - -} diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/Books.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/Books.java deleted file mode 100644 index b3c492a69..000000000 --- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/Books.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.xebia.functional.xef.java.auto.jdk21.serialization; - -import com.xebia.functional.xef.conversation.PlatformConversation; -import com.xebia.functional.xef.conversation.llm.openai.OpenAI; -import com.xebia.functional.xef.prompt.Prompt; -import jakarta.validation.constraints.NotNull; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - -public class Books { - - private final PlatformConversation scope; - - public Books(PlatformConversation scope) { - this.scope = scope; - } - - public record Book(@NotNull String title, @NotNull String author, @NotNull int year, @NotNull String genre){} - - public CompletableFuture bookSelection(String topic) { - return scope.prompt(OpenAI.fromEnvironment().DEFAULT_SERIALIZATION, new Prompt("Give me a selection of books about " + topic), Books.Book.class); - } - - public static void main(String[] args) throws ExecutionException, InterruptedException { - try (PlatformConversation scope = OpenAI.conversation()) { - Books books = new Books(scope); - books.bookSelection("artificial intelligence") - .thenAccept(System.out::println) - .get(); - } - } -} diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/ChessAI.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/ChessAI.java deleted file mode 100644 index 5112d56dd..000000000 --- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/ChessAI.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.xebia.functional.xef.java.auto.jdk21.serialization; - -import com.xebia.functional.xef.conversation.PlatformConversation; -import com.xebia.functional.xef.conversation.llm.openai.OpenAI; -import com.xebia.functional.xef.prompt.Prompt; - -import java.util.ArrayList; -import java.util.concurrent.ExecutionException; -import java.util.stream.Collectors; - -public class ChessAI { - - public record ChessMove(String player, String move){} - public record ChessBoard(String board){} - public record GameState(Boolean ended, String winner){} - - public static void main(String[] args) throws ExecutionException, InterruptedException { - try (PlatformConversation scope = OpenAI.conversation()) { - var moves = new ArrayList(); - var gameEnded = false; - var winner = ""; - - while (!gameEnded) { - var currentPlayer = ((moves.size() % 2) == 0) ? "Player 1 (White)" : "Player 2 (Black)"; - - var prompt = String.format(""" - |%s, it's your turn. - |Previous moves: %s - |Make your next move:""", - currentPlayer, - moves.stream().map(ChessMove::toString).collect(Collectors.joining(", "))); - - ChessMove move = scope.prompt(OpenAI.fromEnvironment().DEFAULT_SERIALIZATION, new Prompt(prompt), ChessMove.class).get(); - moves.add(move); - - // Update boardState according to move.move - // ... - - var boardPrompt = String.format(""" - Given the following chess moves: %s, - generate a chess board on a table with appropriate emoji representations for each move and piece. - Add a brief description of the move and it's implications""", - moves.stream().map(it -> it.player + ":" + it.move).collect(Collectors.joining(", "))); - - ChessBoard chessBoard= scope.prompt(OpenAI.fromEnvironment().DEFAULT_SERIALIZATION, new Prompt(boardPrompt), ChessBoard.class).get(); - System.out.println("Current board:\n" + chessBoard.board); - - var gameStatePrompt = String.format(""" - Given the following chess moves: %s, - has the game ended (win, draw, or stalemate)?""", - moves.stream().map(ChessMove::toString).collect(Collectors.joining(", "))); - - GameState gameState = scope.prompt(OpenAI.fromEnvironment().DEFAULT_SERIALIZATION, new Prompt(gameStatePrompt), GameState.class).get(); - - gameEnded = gameState.ended; - winner = gameState.winner; - } - - System.out.println("Game over. Final move: " + moves.get(moves.size() - 1) + ", Winner: " + winner); - } - } -} diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/Movies.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/Movies.java deleted file mode 100644 index f399de71b..000000000 --- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/Movies.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.xebia.functional.xef.java.auto.jdk21.serialization; - -import com.xebia.functional.xef.conversation.PlatformConversation; -import com.xebia.functional.xef.conversation.llm.openai.OpenAI; -import com.xebia.functional.xef.prompt.Prompt; - -import java.util.concurrent.ExecutionException; - -public class Movies { - - public record Movie(String title, String genre, String director){} - - public static void main(String[] args) throws ExecutionException, InterruptedException { - try (PlatformConversation scope = OpenAI.conversation()) { - scope.prompt(OpenAI.fromEnvironment().DEFAULT_SERIALIZATION, new Prompt("Please provide a movie title, genre and director for the Inception movie"), Movie.class) - .thenAccept(movie -> System.out.println(movie)) - .get(); - } - } -} diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/Recipes.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/Recipes.java deleted file mode 100644 index 879a293e0..000000000 --- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/serialization/Recipes.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.xebia.functional.xef.java.auto.jdk21.serialization; - -import com.xebia.functional.xef.conversation.PlatformConversation; -import com.xebia.functional.xef.conversation.llm.openai.OpenAI; -import com.xebia.functional.xef.prompt.Prompt; - -import java.util.List; -import java.util.concurrent.ExecutionException; - -public class Recipes { - - public record Recipe(String name, List ingredients){} - - public static void main(String[] args) throws ExecutionException, InterruptedException { - try (PlatformConversation scope = OpenAI.conversation()) { - var recipe = scope.prompt(OpenAI.fromEnvironment().DEFAULT_SERIALIZATION, new Prompt("Recipe for chocolate chip cookies."), Recipe.class).get(); - System.out.println("The recipe for " + recipe.name + " is " + recipe.ingredients ); - } - } -} diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Checker.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Checker.java deleted file mode 100644 index 59a53b3a8..000000000 --- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Checker.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.xebia.functional.xef.java.auto.jdk21.tot; - -public class Checker { - - public static
Solutions.Solution checkSolution(Solutions.Solution response){ - System.out.println("✅ Validating solution: " + Rendering.truncateText(response.answer) + "..."); - return response.isValid ? response : - Solutions.makeSolution(response.answer, false, "Invalid solution", null); - } -} diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/ControlSignals.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/ControlSignals.java deleted file mode 100644 index ecc0309a6..000000000 --- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/ControlSignals.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.xebia.functional.xef.java.auto.jdk21.tot; - -import com.xebia.functional.xef.conversation.llm.openai.OpenAI; -import com.xebia.functional.xef.prompt.Prompt; - -import static com.xebia.functional.xef.java.auto.jdk21.tot.Rendering.renderHistory; -import static com.xebia.functional.xef.java.auto.jdk21.tot.Rendering.truncateText; - -import java.util.concurrent.CompletableFuture; - -public class ControlSignals { - - static class ControlSignal { - public String value = ""; - } - - public static CompletableFuture controlSignal(Problems.Memory memory){ - System.out.println("\uD83E\uDDE0 Generating control signal for problem:" + truncateText(memory.problem.description) + "..."); - var guidancePrompt = new Prompt(Rendering.trimMargin( - " You are an expert advisor on information extraction.\n" + - " You generate guidance for a problem.\n" + - " " + renderHistory(memory) + "\n" + - " You are given the following problem:\n" + - " " + memory.problem.description + "\n" + - " Instructions:\n" + - " 1. Generate 1 guidance to get the best results for this problem.\n" + - " 2. Ensure the guidance is relevant to the problem.\n" + - " 3. Ensure the guidance is accurate, complete, and unambiguous.\n" + - " 4. Ensure the guidance is actionable.\n" + - " 5. Ensure the guidance accounts for previous answers in the `history`.\n" + - " \n")); - - return Problems.Memory.getAiScope().prompt(OpenAI.fromEnvironment().DEFAULT_SERIALIZATION, guidancePrompt, ControlSignal.class); - } - -} diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Critiques.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Critiques.java deleted file mode 100644 index 49ad2f22d..000000000 --- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Critiques.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.xebia.functional.xef.java.auto.jdk21.tot; - -import com.xebia.functional.xef.conversation.llm.openai.OpenAI; -import com.xebia.functional.xef.prompt.Prompt; - -import static com.xebia.functional.xef.java.auto.jdk21.tot.Rendering.truncateText; - -import java.util.concurrent.CompletableFuture; - -public class Critiques { - - static class Critique { - public String answer; - public String reasoning; - public boolean answerTrulyAccomplishesTheGoal; - } - - public static CompletableFuture critique(Problems.Memory memory, Solutions.Solution currentSolution){ - System.out.println("🕵️ Critiquing solution: " + truncateText(currentSolution.answer) + "..."); - - var prompt = new Prompt(Rendering.trimMargin( - " You are an expert advisor critiquing a solution.\n" + - " \n" + - " Previous history:\n" + - " " + Rendering.renderHistory(memory) + "\n" + - " \n" + - " You are given the following problem:\n" + - " " + memory.problem.description + "\n" + - " \n" + - " You are given the following solution:\n" + - " " + currentSolution.answer + "\n" + - " \n" + - " Instructions:\n" + - " 1. Provide a critique and determine if the answer truly accomplishes the goal.\n" + - " \n")); - - return Problems.Memory.getAiScope().prompt(OpenAI.fromEnvironment().DEFAULT_SERIALIZATION, prompt, Critique.class); - } -} diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Main.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Main.java deleted file mode 100644 index 67cae5025..000000000 --- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Main.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.xebia.functional.xef.java.auto.jdk21.tot; - -public class Main { - - private static final int MAX_ROUNDS = 5; - - public static void main(String[] args) { - Problems.Problem problem = new Problems.Problem(); - problem.description = Rendering.trimMargin( - " You are an expert functional programmer.\n" + - " 1. You never throw exceptions.\n" + - " 2. You never use null.\n" + - " 3. You never use `for` `while` or loops in general, prefer tail recursion.\n" + - " 4. You never use mutable state.\n" + - " \n" + - " This code is unsafe. Find the problems in this code and provide a Github suggestion code fence with the `diff` to fix it.\n" + - " \n" + - " ```kotlin\n" + - " fun access(list: List, index: Int): Int {\n" + - " return list[index]\n" + - " }\n" + - " ```\n" + - " \n" + - " Return a concise solution that fixes the problems in the code."); - - - var solve = Problems.solve(problem, MAX_ROUNDS); - - System.out.println("✅ Final solution: " + solve.answer); - System.out.println("✅ Solution validity: " + solve.isValid); - System.out.println("✅ Solution reasoning: " + solve.reasoning); - System.out.println("✅ Solution code: " + solve.value); - } - - static class FinalSolution { - public String solution; - } - -} diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Problems.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Problems.java deleted file mode 100644 index 167225f00..000000000 --- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Problems.java +++ /dev/null @@ -1,116 +0,0 @@ -package com.xebia.functional.xef.java.auto.jdk21.tot; - -import com.xebia.functional.xef.conversation.PlatformConversation; -import com.xebia.functional.xef.conversation.llm.openai.OpenAI; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Stream; - -import static com.xebia.functional.xef.java.auto.jdk21.tot.Rendering.truncateText; - -public class Problems { - - static class Problem{ - public String description; - } - - public static Solutions.Solution solve(Problem problem, int maxRounds) { - try(Memory initialMemory = new Memory<>(problem, new ArrayList<>())) { - return solveRec(maxRounds, initialMemory); - } - } - - private static Solutions.Solution solveRec(int remainingRounds, Memory sMemory) { - if(remainingRounds <= 0){ - System.out.println("❌ Maximum rounds reached. Unable to find a solution."); - return Solutions.makeSolution("", false, "No Response", null); - } else{ - System.out.println("🌱 Solving problem: " + - truncateText(sMemory.problem.description, 100) + - " (Remaining rounds: " + remainingRounds + "..."); - - ControlSignals.ControlSignal controlSignal = getControlSignal(sMemory); - Solutions.Solution response = Solutions.solution(sMemory, controlSignal); - Solutions.Solution result = Checker.checkSolution(response); - Memory updatedMemory = sMemory.addResult(result); - if(result.isValid){ - System.out.println("✅ Solution found: " + truncateText(result.answer) + "!"); - Critiques.Critique critique = getCritique(result, updatedMemory); - if(critique != null && critique.answerTrulyAccomplishesTheGoal){ - System.out.println("❌ Solution does not accomplish the goal: " + truncateText(result.answer) + "!"); - System.out.println("⏪ Backtracking..."); - return solveRec(remainingRounds - 1, updatedMemory); - } - else { - return result; - } - } - else{ - System.out.println("⏪ Backtracking..."); - return solveRec(remainingRounds - 1, updatedMemory); - } - } - } - - private static ControlSignals.ControlSignal getControlSignal(Memory sMemory) { - try { - ControlSignals.ControlSignal controlSignal = ControlSignals.controlSignal(sMemory).get(); - System.out.println("\uD83E\uDDE0 Generated control signal: " + truncateText(controlSignal.value)); - return controlSignal; - } catch (Exception e) { - System.err.printf("ControlSignals.controlSignal prompt threw exception: %s - %s\n", - e.getClass().getName(), e.getMessage()); - return new ControlSignals.ControlSignal(); - } - } - - @Nullable - private static Critiques.Critique getCritique(Solutions.Solution result, Memory updatedMemory) { - try { - return Critiques.critique(updatedMemory, result).get(); - } catch (Exception e) { - System.err.printf("Critiques.critique prompt threw exception: %s - %s\n", - e.getClass().getName(), e.getMessage()); - return null; - } - } - - static class Memory implements AutoCloseable { - - public Problem problem; - public List> history; - - private static PlatformConversation aiScope = null; - - public Memory(Problem problem, List> history) { - this.problem = problem; - this.history = history; - checkPlatformConversation(); - } - - public Memory addResult(Solutions.Solution result) { - List> historyUpdate = Stream.concat(this.history.stream(), Stream.of(result)).toList(); - checkPlatformConversation(); - return new Memory<>(this.problem, historyUpdate); - } - - private static void checkPlatformConversation() { - if(aiScope == null){ - aiScope = OpenAI.conversation(); - } - } - - public static PlatformConversation getAiScope() { - return aiScope; - } - - public void close(){ - if(aiScope != null) { - aiScope.close(); - aiScope = null; - } - } - } -} diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Rendering.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Rendering.java deleted file mode 100644 index b1fdda157..000000000 --- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Rendering.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.xebia.functional.xef.java.auto.jdk21.tot; - -import java.util.Arrays; -import java.util.stream.Collectors; - -public class Rendering { - - public static String trimMargin(String input){ - return Arrays.stream(input.split("\n")).map(String::trim).collect(Collectors.joining("\n")); - } - - public static String truncateText(String answer) { - return truncateText(answer, 150); - } - - public static String truncateText(String answer, int limit) { - if(answer == null) - return ""; - if(answer.length() > limit) { - answer = answer.substring(0, limit - 3) + "..."; - } - return answer.replace("\n", " "); - } - - public static String renderHistory(Problems.Memory memory){ - return trimMargin(" ```history \n\n" + - memory.history.stream() - .map(Rendering::renderHistoryItem) - .collect(Collectors.joining("\n")) + - "```"); - } - - private static String renderHistoryItem(Solutions.Solution solution){ - return trimMargin(solution.answer + "\n" + - solution.reasoning + "\n" + - (solution.isValid ? "✅" : "❌") + "\n"); - } -} diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Solutions.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Solutions.java deleted file mode 100644 index 5fbf8062c..000000000 --- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/tot/Solutions.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.xebia.functional.xef.java.auto.jdk21.tot; - -import com.xebia.functional.xef.conversation.llm.openai.OpenAI; -import com.xebia.functional.xef.prompt.Prompt; - -import static com.xebia.functional.xef.java.auto.jdk21.tot.Rendering.renderHistory; -import static com.xebia.functional.xef.java.auto.jdk21.tot.Rendering.truncateText; - -public class Solutions{ - - static class Solution{ - public String answer; - public boolean isValid; - public String reasoning; - - public A value; - } - - public static Solution makeSolution(String answer, boolean isValid, String reasoning, B value) { - Solution solution = new Solution<>(); - solution.isValid = isValid; - solution.answer = answer; - solution.reasoning = reasoning; - solution.value = value; - return solution; - } - - public static Solution solution(Problems.Memory memory, - ControlSignals.ControlSignal controlSignal){ - //ai emoji - System.out.println("\uD83E\uDD16 Generating solution for problem: " + truncateText(memory.problem.description) + "..."); - - Prompt enhancedPrompt = new Prompt( - " Given previous history:\n" + - " " + renderHistory(memory) + "\n" + - " Given the goal: \n" + - " ```goal\n" + - " " + memory.problem.description + " \n" + - " ```\n" + - " and considering the guidance: \n" + - " ```guidance\n" + - " " + controlSignal.value + "\n" + - " ```\n" + - " \n" + - " Instructions:\n" + - " \n" + - " 1. Please provide a comprehensive solution. \n" + - " 2. Consider all possible scenarios and edge cases. \n" + - " 3. Ensure your solution is accurate, complete, and unambiguous. \n" + - " 4. If you are unable to provide a solution, please provide a reason why and set `isValid` to false.\n" + - " 5. Include citations, references and links at the end to support your solution based on your sources.\n" + - " 6. Do not provide recommendations, only provide a solution.\n" + - " 7. when `isValid` is true Include in the `value` field the value of the solution according to the `value` json schema.\n" + - " 8. If no solution is found set the `value` field to `null`.\n" + - " 9. If the solution is not valid set the `isValid` field to `false` and the `value` field to `null`.\n" + - " 10. If the solution is valid set the `isValid` field to `true` and the `value` field to the value of the solution.\n" + - " \n"); - - try { - return Problems.Memory.getAiScope().prompt(OpenAI.fromEnvironment().DEFAULT_SERIALIZATION, enhancedPrompt, Solution.class).get(); - } catch (Exception e) { - System.err.printf("Solutions.solution enhancedPrompt threw exception: %s - %s\n", - e.getClass().getName(), e.getMessage()); - return null; - } - } - -} diff --git a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/util/ConsoleUtil.java b/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/util/ConsoleUtil.java deleted file mode 100644 index a06678b28..000000000 --- a/examples/java/src/main/java/com/xebia/functional/xef/java/auto/jdk21/util/ConsoleUtil.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.xebia.functional.xef.java.auto.jdk21.util; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; - -public class ConsoleUtil implements AutoCloseable{ - - private final BufferedReader sysin; - - public ConsoleUtil(){ - sysin = new BufferedReader(new InputStreamReader(System.in)); - } - - /** - * Read line from the console (IDE friendly) - * @return line from console input - */ - public String readLine() { - try { - return sysin.readLine(); - } catch (IOException e) { - return null; - } - } - - @Override - public void close() throws Exception { - sysin.close(); - } -} diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/gpc/Pipelines.kt b/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/gpc/Pipelines.kt deleted file mode 100644 index e494e0b22..000000000 --- a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/gpc/Pipelines.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.xebia.functional.xef.conversation.gpc - -import com.xebia.functional.gpt4all.conversation -import com.xebia.functional.xef.env.getenv -import com.xebia.functional.xef.gcp.GcpConfig -import com.xebia.functional.xef.gcp.VertexAIRegion -import com.xebia.functional.xef.gcp.pipelines.GcpPipelinesClient - -suspend fun main() { - conversation { - val token = getenv("GCP_TOKEN") ?: error("missing gcp token") - val pipelineClient = - autoClose(GcpPipelinesClient(GcpConfig(token, "xefdemo", VertexAIRegion.US_CENTRAL1))) - val answer = pipelineClient.list() - println("\n🤖 $answer") - } -} diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/gpt4all/Chat.kt b/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/gpt4all/Chat.kt deleted file mode 100644 index c316b5fd3..000000000 --- a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/gpt4all/Chat.kt +++ /dev/null @@ -1,40 +0,0 @@ -package com.xebia.functional.xef.conversation.gpt4all - -import com.xebia.functional.gpt4all.GPT4All -import com.xebia.functional.gpt4all.Gpt4AllModel -import com.xebia.functional.xef.prompt.Prompt -import java.nio.file.Path -import kotlinx.coroutines.flow.onCompletion - -suspend fun main() { - val userDir = System.getProperty("user.dir") - val path = "$userDir/models/gpt4all/ggml-replit-code-v1-3b.bin" - - Gpt4AllModel.supportedModels.forEach { println("🤖 ${it.name} ${it.url?.let { "- $it" }}") } - - val url = - "https://huggingface.co/nomic-ai/ggml-replit-code-v1-3b/resolve/main/ggml-replit-code-v1-3b.bin" - val modelPath: Path = Path.of(path) - val model = GPT4All(url, modelPath) - - println("🤖 GPT4All loaded: $GPT4All") - /** - * Uses internally [HuggingFaceLocalEmbeddings] default of "sentence-transformers", - * "msmarco-distilbert-dot-v5" to provide embeddings for docs in contextScope. - */ - GPT4All.conversation { - println("🤖 Context loaded: $store") - // hack until https://github.com/nomic-ai/gpt4all/pull/1126 is accepted or merged - val out = System.out - model.use { gpT4All: GPT4All -> - while (true) { - print("\n🤖 Enter your question: ") - val userInput = readlnOrNull() ?: break - gpT4All - .promptStreaming(Prompt(userInput), this) - .onCompletion { println("\n🤖 Done") } - .collect { out.print(it) } - } - } - } -} diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/manual/NoAI.kt b/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/manual/NoAI.kt deleted file mode 100644 index 5d2403806..000000000 --- a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/manual/NoAI.kt +++ /dev/null @@ -1,45 +0,0 @@ -package com.xebia.functional.xef.conversation.manual - -import com.xebia.functional.gpt4all.GPT4All -import com.xebia.functional.gpt4all.HuggingFaceLocalEmbeddings -import com.xebia.functional.gpt4all.huggingFaceUrl -import com.xebia.functional.xef.conversation.Conversation -import com.xebia.functional.xef.metrics.LogsMetric -import com.xebia.functional.xef.pdf.pdf -import com.xebia.functional.xef.prompt.Prompt -import com.xebia.functional.xef.store.LocalVectorStore -import java.nio.file.Path - -suspend fun main() { - // Choose your base folder for downloaded models - val userDir = System.getProperty("user.dir") - - // Specify the local model path - val modelPath: Path = Path.of("$userDir/models/gpt4all/ggml-gpt4all-j-v1.3-groovy.bin") - - // Specify the Hugging Face URL for the model - val url = huggingFaceUrl("orel12", "ggml-gpt4all-j-v1.3-groovy", "bin") - - // Create an instance of GPT4All with the local model - val gpt4All = GPT4All(url, modelPath) - - // Create an instance of the embeddings - val embeddings = HuggingFaceLocalEmbeddings.DEFAULT - val scope = Conversation(LocalVectorStore(embeddings), LogsMetric()) - - // Fetch and add texts from a PDF document to the vector store - val results = pdf("https://arxiv.org/pdf/2305.10601.pdf") - scope.store.addTexts(results) - - // Prompt the GPT4All model with a question and provide the vector store for context - val result: String = - gpt4All.use { - it.promptMessage( - prompt = Prompt("What is the Tree of Thoughts framework about?"), - scope = scope - ) - } - - // Print the response - println(result) -} diff --git a/examples/kotlin/src/main/resources/logback.xml b/examples/kotlin/src/main/resources/logback.xml deleted file mode 100644 index dfb690eb2..000000000 --- a/examples/kotlin/src/main/resources/logback.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%kvp- %msg%n - - - - - - - - - - - - - - - - - - - diff --git a/examples/scala/.scalafmt.conf b/examples/scala/.scalafmt.conf deleted file mode 100644 index 038d0ede0..000000000 --- a/examples/scala/.scalafmt.conf +++ /dev/null @@ -1,36 +0,0 @@ -# tune this file as appropriate to your style! see: https://olafurpg.github.io/scalafmt/#Configuration - -version = "3.7.15" - -runner.dialect = "scala3" - -maxColumn = 150 - -continuationIndent.callSite = 2 - -newlines { - sometimesBeforeColonInMethodReturnType = false -} - -align { - arrowEnumeratorGenerator = false - ifWhileOpenParen = false - openParenCallSite = false - openParenDefnSite = false - tokens = ["%", "%%"] -} - -docstrings.style = Asterisk - -rewrite { - rules = [SortImports, RedundantBraces] - redundantBraces.maxLines = 1 -} - -optIn { - breaksInsideChains = true -} - -project.excludeFilters = [ - "metals.sbt" -] diff --git a/examples/scala/build.gradle.kts b/examples/scala/build.gradle.kts deleted file mode 100644 index 615adf2a5..000000000 --- a/examples/scala/build.gradle.kts +++ /dev/null @@ -1,30 +0,0 @@ -@file:Suppress("DSL_SCOPE_VIOLATION") - -plugins { - scala - alias(libs.plugins.spotless) -} - -java { - sourceCompatibility = JavaVersion.VERSION_21 - targetCompatibility = JavaVersion.VERSION_21 - toolchain { languageVersion = JavaLanguageVersion.of(21) } -} - -dependencies { - implementation(projects.xefCore) - implementation(projects.xefScala) - implementation(projects.xefReasoning) - implementation(projects.xefOpenai) - implementation(libs.circe.parser) - implementation(libs.scala.lang) - implementation(libs.logback) -} - -tasks.withType().configureEach { useJUnit() } - -tasks.withType { - scalaCompileOptions.additionalParameters = listOf("-Wunused:all", "-Wvalue-discard") -} - -spotless { scala { scalafmt("3.7.15").configFile(".scalafmt.conf") } } diff --git a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/Simple.scala b/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/Simple.scala deleted file mode 100644 index c9f4b17d1..000000000 --- a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/Simple.scala +++ /dev/null @@ -1,10 +0,0 @@ -package com.xebia.functional.xef.examples.scala - -import com.xebia.functional.xef.scala.conversation.* - -@main def runBooks(): Unit = conversation: - val topic = "functional programming" - val topBook: String = promptMessage(s"Give me the top-selling book about $topic") - println(topBook) - val selectedBooks: List[String] = promptMessages(s"Give me a selection of books about $topic") - println(selectedBooks.mkString("\n")) diff --git a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/context/serpapi/Simple.scala b/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/context/serpapi/Simple.scala deleted file mode 100644 index 68ee8a49a..000000000 --- a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/context/serpapi/Simple.scala +++ /dev/null @@ -1,45 +0,0 @@ -package com.xebia.functional.xef.examples.scala.context.serpapi - -import com.xebia.functional.xef.conversation.llm.openai.* -import com.xebia.functional.xef.reasoning.serpapi.* -import com.xebia.functional.xef.scala.conversation.* -import com.xebia.functional.xef.scala.serialization.* -import io.circe.Decoder - -import java.text.SimpleDateFormat -import java.util.Date - -val openAI: OpenAI = OpenAI.fromEnvironment() - -val sdf = SimpleDateFormat("dd/M/yyyy") -def currentDate: String = sdf.format(new Date) - -def setContext(query: String)(using conversation: ScalaConversation): Unit = - addContext(Search(openAI.DEFAULT_CHAT, conversation, 3).search(query).get) - -case class BreakingNews(summary: String) derives SerialDescriptor, Decoder - -case class MarketNews(news: String, risingStockSymbols: List[String], fallingStockSymbols: List[String]) derives SerialDescriptor, Decoder - -case class Estimate(number: Long) derives SerialDescriptor, Decoder - -@main def runWeather(): Unit = conversation: - setContext("Weather in Cádiz, Spain") - val question = "Knowing this forecast, what clothes do you recommend I should wear if I live in Cádiz?" - val answer = promptMessage(question) - println(answer) - -@main def runBreakingNews(): Unit = conversation: - setContext(s"$currentDate COVID News") - val BreakingNews(summary) = prompt[BreakingNews](s"Write a summary of about 300 words given the provided context.") - println(summary) - -@main def runMarketNews(): Unit = conversation: - setContext(s"$currentDate Stock market results, rising stocks, falling stocks") - val news = prompt[MarketNews]("Write a short summary of the stock market results given the provided context.") - println(news) - -@main def runFermiEstimate(): Unit = conversation: - setContext("Estimate the number of medical needles in the world") - val Estimate(needlesInWorld) = prompt[Estimate]("Answer the question with an integer number given the provided context.") - println(s"Needles in world: $needlesInWorld") diff --git a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/context/serpapi/UserQueries.scala b/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/context/serpapi/UserQueries.scala deleted file mode 100644 index 711db19da..000000000 --- a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/context/serpapi/UserQueries.scala +++ /dev/null @@ -1,20 +0,0 @@ -package com.xebia.functional.xef.examples.scala.context.serpapi - -import com.xebia.functional.xef.reasoning.pdf.PDF -import com.xebia.functional.xef.scala.conversation.* -import com.xebia.functional.xef.scala.serialization.* -import io.circe.Decoder - -import scala.io.StdIn.readLine - -case class AIResponse(answer: String) derives SerialDescriptor, Decoder - -val PdfUrl = "https://people.cs.ksu.edu/~schmidt/705a/Scala/Programming-in-Scala.pdf" - -@main def runUserQueries(): Unit = conversation: - val pdf = PDF(openAI.DEFAULT_CHAT, openAI.DEFAULT_SERIALIZATION, summon[ScalaConversation]) - addContext(Array(pdf.readPDFFromUrl.readPDFFromUrl(PdfUrl).get)) - while (true) - println("Enter your question: ") - val AIResponse(answer) = prompt[AIResponse](readLine()) - println(s"$answer\n---\n") diff --git a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/images/HybridCity.scala b/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/images/HybridCity.scala deleted file mode 100644 index 1c9a3b4a9..000000000 --- a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/images/HybridCity.scala +++ /dev/null @@ -1,10 +0,0 @@ -package com.xebia.functional.xef.examples.scala.images - -import com.xebia.functional.xef.prompt.Prompt -import com.xebia.functional.xef.scala.conversation.* -import com.xebia.functional.xef.scala.serialization.* -import io.circe.Decoder - -@main def runHybridCity(): Unit = conversation: - val imageUrls = images(Prompt("A hybrid city of Cádiz, Spain and Seattle, US.")) - println(imageUrls) diff --git a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/iteration/AnimalStory.scala b/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/iteration/AnimalStory.scala deleted file mode 100644 index 19e6d433e..000000000 --- a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/iteration/AnimalStory.scala +++ /dev/null @@ -1,20 +0,0 @@ -package com.xebia.functional.xef.examples.scala.iteration - -import com.xebia.functional.xef.prompt.JvmPromptBuilder -import com.xebia.functional.xef.scala.conversation.* -import com.xebia.functional.xef.scala.serialization.* -import io.circe.Decoder - -case class Animal(name: String, habitat: String, diet: String) derives SerialDescriptor, Decoder -case class Invention(name: String, inventor: String, year: Int, purpose: String) derives SerialDescriptor, Decoder - -@main def runAnimalStory(): Unit = conversation: - val animal = prompt[Animal]("A unique animal species") - val invention = prompt[Invention]("A groundbreaking invention from the 20th century.") - println(s"Animal: $animal") - println(s"Invention: $invention") - val builder = new JvmPromptBuilder() - .addSystemMessage("You are a writer for a science fiction magazine.") - .addUserMessage("Write a short story of 200 words that involves the animal and the invention.") - val story = promptMessage(builder.build) - println(story) diff --git a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/iteration/ChessGame.scala b/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/iteration/ChessGame.scala deleted file mode 100644 index 42472e1a0..000000000 --- a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/iteration/ChessGame.scala +++ /dev/null @@ -1,52 +0,0 @@ -package com.xebia.functional.xef.examples.scala.iteration - -import com.xebia.functional.xef.prompt.Prompt -import com.xebia.functional.xef.scala.conversation.* -import com.xebia.functional.xef.scala.serialization.* -import io.circe.Decoder - -import scala.annotation.tailrec - -case class ChessMove(player: String, move: String) derives SerialDescriptor, Decoder -case class ChessBoard(board: String) derives SerialDescriptor, Decoder -case class GameState(ended: Boolean = false, winner: Option[String] = None) derives SerialDescriptor, Decoder - -@tailrec -private def chessGame(moves: List[ChessMove] = Nil, gameState: GameState = new GameState)(using ScalaConversation): (String, ChessMove) = - if !gameState.ended then - val currentPlayer = if moves.size % 2 == 0 then "Player 1 (White)" else "Player 2 (Black)" - val previousMoves = moves.map(m => m.player + ":" + m.move).mkString(", ") - val movePrompt = moves match { - case Nil => s""" - |$currentPlayer, you are playing chess and it's your turn. - |Make your first move: - """.stripMargin - case l => s""" - |$currentPlayer, you are playing chess and it's your turn. - |Here are the previous moves: $previousMoves - |Make your next move: - """.stripMargin - } - println(movePrompt) - val move = prompt[ChessMove](movePrompt) - println(s"Move is: $move") - val boardPrompt = - s""" - |Given the following chess moves: $previousMoves, - |generate a chess board on a table with appropriate emoji representations for each move and piece. - |Add a brief description of the move and its implications. - """.stripMargin - val chessBoard = prompt[ChessBoard](boardPrompt) - println(s"Current board:\n${chessBoard.board}") - val gameStatePrompt = - s""" - |Given the following chess moves: ${moves.mkString(", ")}, - |has the game ended (win, draw, or stalemate)? - """.stripMargin - val gameState = prompt[GameState](gameStatePrompt) - chessGame(moves :+ move, gameState) - else (gameState.winner.getOrElse("Something went wrong"), moves.last) - -@main def runChessGame(): Unit = conversation: - val (winner, fMove) = chessGame() - println(s"Game over. Final move: $fMove, Winner: $winner") diff --git a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/serialization/Annotated.scala b/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/serialization/Annotated.scala deleted file mode 100644 index 168599987..000000000 --- a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/serialization/Annotated.scala +++ /dev/null @@ -1,18 +0,0 @@ -package com.xebia.functional.xef.examples.scala.serialization - -import com.xebia.functional.xef.prompt.Prompt -import com.xebia.functional.xef.scala.conversation.* -import com.xebia.functional.xef.scala.serialization.* -import io.circe.Decoder - -@Description("A book") -case class AnnotatedBook( - @Description("The name of the book") name: String, - @Description("The author of the book") author: String, - @Description("A 50 word paragraph with a summary of this book") summary: String -) derives SerialDescriptor, - Decoder - -@main def runAnnotatedBook(): Unit = conversation: - val book = prompt[AnnotatedBook]("To Kill a Mockingbird") - println(book) diff --git a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/serialization/Simple.scala b/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/serialization/Simple.scala deleted file mode 100644 index 2652fd8a3..000000000 --- a/examples/scala/src/main/scala/com/xebia/functional/xef/examples/scala/serialization/Simple.scala +++ /dev/null @@ -1,37 +0,0 @@ -package com.xebia.functional.xef.examples.scala.serialization - -import com.xebia.functional.xef.scala.conversation.* -import com.xebia.functional.xef.scala.serialization.* -import io.circe.Decoder - -case class AsciiArt(art: String) derives SerialDescriptor, Decoder - -case class Book(title: String, author: String, pages: Int) derives SerialDescriptor, Decoder - -case class City(population: Int, description: String) derives SerialDescriptor, Decoder - -case class Movie(title: String, genre: String, director: String) derives SerialDescriptor, Decoder - -case class Recipe(name: String, ingredients: List[String]) derives SerialDescriptor, Decoder - -@main def runAsciiArt(): Unit = conversation: - val AsciiArt(art) = prompt[AsciiArt]("ASCII art of a cat dancing") - println(art) - -@main def runBook(): Unit = conversation: - val topic = "functional programming" - val Book(title, author, pages) = prompt[Book](s"Give me the best-selling book about $topic") - println(s"The book $title is by $author and has $pages pages.") - -@main def runMovie(): Unit = conversation: - val Movie(title, genre, director) = prompt[Movie]("Inception movie genre and director.") - println(s"The movie $title is a $genre film directed by $director.") - -@main def runCities(): Unit = conversation: - val cadiz = prompt[City]("Cádiz, Spain") - val seattle = prompt[City]("Seattle, WA") - println(s"The population of Cádiz is ${cadiz.population} and the population of Seattle is ${seattle.population}.") - -@main def runRecipe(): Unit = conversation: - val Recipe(name, ingredients) = prompt[Recipe]("Recipe for chocolate chip cookies.") - println(s"The recipe for $name is $ingredients.") diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/contexts/BreakingNews.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/contexts/BreakingNews.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/contexts/BreakingNews.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/contexts/BreakingNews.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/contexts/DivergentTasks.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/contexts/DivergentTasks.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/contexts/DivergentTasks.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/contexts/DivergentTasks.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/contexts/PDFDocument.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/contexts/PDFDocument.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/contexts/PDFDocument.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/contexts/PDFDocument.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/contexts/Weather.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/contexts/Weather.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/contexts/Weather.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/contexts/Weather.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/conversations/Animal.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/conversations/Animal.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/conversations/Animal.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/conversations/Animal.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/conversations/Simple.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/conversations/Simple.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/conversations/Simple.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/conversations/Simple.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/expressions/DigitalDetoxPlanner.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/expressions/DigitalDetoxPlanner.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/expressions/DigitalDetoxPlanner.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/expressions/DigitalDetoxPlanner.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/expressions/PromptCrafter.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/expressions/PromptCrafter.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/expressions/PromptCrafter.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/expressions/PromptCrafter.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/expressions/RecipeGenerator.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/expressions/RecipeGenerator.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/expressions/RecipeGenerator.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/expressions/RecipeGenerator.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/expressions/TravelItinerary.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/expressions/TravelItinerary.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/expressions/TravelItinerary.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/expressions/TravelItinerary.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/expressions/WorkoutPlanProgram.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/expressions/WorkoutPlanProgram.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/expressions/WorkoutPlanProgram.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/expressions/WorkoutPlanProgram.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/fields/Book.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/fields/Book.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/fields/Book.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/fields/Book.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/fields/NewsSummary.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/fields/NewsSummary.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/fields/NewsSummary.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/fields/NewsSummary.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/finetuning/FineTunedModelChat.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/finetuning/FineTunedModelChat.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/finetuning/FineTunedModelChat.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/finetuning/FineTunedModelChat.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/gpc/Chat.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/gpc/Chat.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/gpc/Chat.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/gpc/Chat.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/memory/ChatWithMemory.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/memory/ChatWithMemory.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/memory/ChatWithMemory.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/memory/ChatWithMemory.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/mlflow/Example.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/mlflow/Example.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/mlflow/Example.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/mlflow/Example.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/prompts/ExpertSystemExample.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/prompts/ExpertSystemExample.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/prompts/ExpertSystemExample.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/prompts/ExpertSystemExample.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/prompts/PromptEvaluationExample.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/prompts/PromptEvaluationExample.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/prompts/PromptEvaluationExample.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/prompts/PromptEvaluationExample.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/prompts/StructuredInput.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/prompts/StructuredInput.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/prompts/StructuredInput.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/prompts/StructuredInput.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/CodeExample.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/CodeExample.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/CodeExample.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/CodeExample.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/CreatePRDescription.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/CreatePRDescription.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/CreatePRDescription.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/CreatePRDescription.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/ReActExample.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/ReActExample.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/ReActExample.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/ReActExample.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/ReActWikipediaExample.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/ReActWikipediaExample.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/ReActWikipediaExample.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/ReActWikipediaExample.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/SerpApiExample.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/SerpApiExample.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/SerpApiExample.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/SerpApiExample.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/TextExample.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/TextExample.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/TextExample.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/TextExample.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/ToolSelectionExample.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/ToolSelectionExample.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/ToolSelectionExample.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/ToolSelectionExample.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/WikipediaSearchByParamsExample.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/WikipediaSearchByParamsExample.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/WikipediaSearchByParamsExample.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/WikipediaSearchByParamsExample.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/WikipediaSearchExample.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/WikipediaSearchExample.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/WikipediaSearchExample.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/reasoning/WikipediaSearchExample.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/serialization/ChessAI.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/serialization/ChessAI.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/serialization/ChessAI.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/serialization/ChessAI.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/serialization/Movie.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/serialization/Movie.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/serialization/Movie.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/serialization/Movie.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/serialization/Recipe.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/serialization/Recipe.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/serialization/Recipe.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/serialization/Recipe.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/sql/MysqlExample.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/sql/MysqlExample.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/sql/MysqlExample.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/sql/MysqlExample.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/sql/README.md b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/sql/README.md similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/sql/README.md rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/sql/README.md diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/streaming/OpenAIStreamingExample.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/streaming/OpenAIStreamingExample.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/streaming/OpenAIStreamingExample.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/streaming/OpenAIStreamingExample.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/streaming/SpaceCraft.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/streaming/SpaceCraft.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/streaming/SpaceCraft.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/streaming/SpaceCraft.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/streaming/StreamingFunctionsExample.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/streaming/StreamingFunctionsExample.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/streaming/StreamingFunctionsExample.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/streaming/StreamingFunctionsExample.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/tot/Checker.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/tot/Checker.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/tot/Checker.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/tot/Checker.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/tot/ControlSignal.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/tot/ControlSignal.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/tot/ControlSignal.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/tot/ControlSignal.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/tot/Critique.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/tot/Critique.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/tot/Critique.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/tot/Critique.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/tot/Main.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/tot/Main.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/tot/Main.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/tot/Main.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/tot/Problem.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/tot/Problem.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/tot/Problem.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/tot/Problem.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/tot/Rendering.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/tot/Rendering.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/tot/Rendering.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/tot/Rendering.kt diff --git a/examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/tot/Solution.kt b/examples/src/main/kotlin/com/xebia/functional/xef/conversation/tot/Solution.kt similarity index 100% rename from examples/kotlin/src/main/kotlin/com/xebia/functional/xef/conversation/tot/Solution.kt rename to examples/src/main/kotlin/com/xebia/functional/xef/conversation/tot/Solution.kt diff --git a/examples/kotlin/src/main/resources/documents/weather.csv b/examples/src/main/resources/documents/weather.csv similarity index 100% rename from examples/kotlin/src/main/resources/documents/weather.csv rename to examples/src/main/resources/documents/weather.csv diff --git a/examples/scala/src/main/resources/logback.xml b/examples/src/main/resources/logback.xml similarity index 100% rename from examples/scala/src/main/resources/logback.xml rename to examples/src/main/resources/logback.xml diff --git a/examples/kotlin/src/main/resources/sql/data/mysql_diagram.png b/examples/src/main/resources/sql/data/mysql_diagram.png similarity index 100% rename from examples/kotlin/src/main/resources/sql/data/mysql_diagram.png rename to examples/src/main/resources/sql/data/mysql_diagram.png diff --git a/examples/kotlin/src/main/resources/sql/data/mysql_dump.sql b/examples/src/main/resources/sql/data/mysql_dump.sql similarity index 100% rename from examples/kotlin/src/main/resources/sql/data/mysql_dump.sql rename to examples/src/main/resources/sql/data/mysql_dump.sql diff --git a/examples/kotlin/src/main/resources/sql/stack.yml b/examples/src/main/resources/sql/stack.yml similarity index 100% rename from examples/kotlin/src/main/resources/sql/stack.yml rename to examples/src/main/resources/sql/stack.yml diff --git a/gpt4all-kotlin/README.MD b/gpt4all-kotlin/README.MD deleted file mode 100644 index 8f937af29..000000000 --- a/gpt4all-kotlin/README.MD +++ /dev/null @@ -1,24 +0,0 @@ -# gpt4all-kotlin - -Kotlin multiplatform bindings for GP4All. - -Right now, only `Kotlin/JVM` platform is supported via JNA. - -# Configuration - -By default, the library is using last model backend built from: [c5de9634c90bba5b528a6fceebc9a48a7f2e2597](https://github.com/nomic-ai/gpt4all/tree/c5de9634c90bba5b528a6fceebc9a48a7f2e2597/gpt4all-backend), which is included inside `src/commonMain/resources` folder. - -Right now, only `darwin-aarch64`, `darwin-x86-64` and `linux-x86-64` platforms are included. - -It is also possible to use a GPT4All local installation by setting the `jna.library.path` system property to the path where the model backend is located: `/lib` - -# How to use - -In order to use the library, apart from the previous configuration, you must have downloaded some GPT4All model in your local, and pass both the model path and the model type: - -```kotlin -GPT4All(Path.of("models/gpt4all/ggml-gpt4all-j-v1.3-groovy.bin"), GPT4AllModel.Type.GPTJ).use { gpt4All -> - val promptMessage = Message(Message.Role.USER, "Some prompt goes here") - gpt4All.chatCompletion(listOf(promptMessage)) -} -``` diff --git a/gpt4all-kotlin/build.gradle.kts b/gpt4all-kotlin/build.gradle.kts deleted file mode 100644 index f81c495e6..000000000 --- a/gpt4all-kotlin/build.gradle.kts +++ /dev/null @@ -1,89 +0,0 @@ -plugins { - alias(libs.plugins.kotlin.multiplatform) - alias(libs.plugins.kotest.multiplatform) - alias(libs.plugins.spotless) - alias(libs.plugins.arrow.gradle.publish) - alias(libs.plugins.semver.gradle) - alias(libs.plugins.kotlinx.serialization) - alias(libs.plugins.detekt) -} - -dependencies { detektPlugins(project(":detekt-rules")) } - -repositories { mavenCentral() } - -java { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 - toolchain { languageVersion = JavaLanguageVersion.of(11) } -} - -detekt { - toolVersion = "1.23.1" - source.setFrom(files("src/commonMain/kotlin", "src/jvmMain/kotlin")) - config.setFrom("../config/detekt/detekt.yml") - autoCorrect = true -} - -kotlin { - jvm { - compilations { - val integrationTest by compilations.creating { - // Create a test task to run the tests produced by this compilation: - tasks.register("integrationTest") { - description = "Run the integration tests" - group = "verification" - classpath = compileDependencyFiles + runtimeDependencyFiles + output.allOutputs - testClassesDirs = output.classesDirs - testLogging { events("passed") } - } - } - val test by compilations.getting - integrationTest.associateWith(test) - } - } - js(IR) { browser() } - sourceSets { - val commonMain by getting { dependencies { implementation(projects.xefCore) } } - commonTest { - dependencies { - implementation(kotlin("test")) - implementation(libs.kotest.property) - implementation(libs.kotest.framework) - implementation(libs.kotest.assertions) - } - } - val jvmMain by getting { - dependencies { - implementation(libs.gpt4all.java.bindings) - implementation(libs.ai.djl.huggingface.tokenizers) - } - } - val jsMain by getting {} - val jvmTest by getting { dependencies { implementation(libs.kotest.junit5) } } - } -} - -tasks { - withType().configureEach { - dependsOn(":detekt-rules:assemble") - autoCorrect = true - } - named("detektJvmMain") { - dependsOn(":detekt-rules:assemble") - getByName("build").dependsOn(this) - } - named("detekt") { - dependsOn(":detekt-rules:assemble") - getByName("build").dependsOn(this) - } - withType().configureEach { - maxParallelForks = Runtime.getRuntime().availableProcessors() - useJUnitPlatform() - testLogging { - setExceptionFormat("full") - setEvents(listOf("passed", "skipped", "failed", "standardOut", "standardError")) - } - } - withType { dependsOn(withType()) } -} diff --git a/gpt4all-kotlin/src/commonMain/kotlin/com/xebia/functional/gpt4all/models.kt b/gpt4all-kotlin/src/commonMain/kotlin/com/xebia/functional/gpt4all/models.kt deleted file mode 100644 index 33be8d3f8..000000000 --- a/gpt4all-kotlin/src/commonMain/kotlin/com/xebia/functional/gpt4all/models.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.xebia.functional.gpt4all - -data class GenerationConfig( - val logitsSize: Int = 0, - val tokensSize: Int = 0, - val nPast: Int = 0, - val nCtx: Int = 4096, - val nPredict: Int = 128, - val topK: Int = 40, - val topP: Double = 0.95, - val temp: Double = 0.28, - val nBatch: Int = 8, - val repeatPenalty: Double = 1.1, - val repeatLastN: Int = 64, - val contextErase: Double = 0.5 -) diff --git a/gpt4all-kotlin/src/jvmMain/kotlin/com/xebia/functional/gpt4all/Conversation.kt b/gpt4all-kotlin/src/jvmMain/kotlin/com/xebia/functional/gpt4all/Conversation.kt deleted file mode 100644 index fc9b74165..000000000 --- a/gpt4all-kotlin/src/jvmMain/kotlin/com/xebia/functional/gpt4all/Conversation.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.xebia.functional.gpt4all - -import com.xebia.functional.xef.conversation.Conversation -import com.xebia.functional.xef.metrics.LogsMetric -import com.xebia.functional.xef.metrics.Metric -import com.xebia.functional.xef.store.LocalVectorStore -import com.xebia.functional.xef.store.VectorStore - -suspend inline fun conversation( - store: VectorStore = LocalVectorStore(HuggingFaceLocalEmbeddings.DEFAULT), - metric: Metric = Metric.EMPTY, - noinline block: suspend Conversation.() -> A -): A = block(Conversation(store, metric)) diff --git a/gpt4all-kotlin/src/jvmMain/kotlin/com/xebia/functional/gpt4all/GPT4All.kt b/gpt4all-kotlin/src/jvmMain/kotlin/com/xebia/functional/gpt4all/GPT4All.kt deleted file mode 100644 index 84e97316f..000000000 --- a/gpt4all-kotlin/src/jvmMain/kotlin/com/xebia/functional/gpt4all/GPT4All.kt +++ /dev/null @@ -1,197 +0,0 @@ -package com.xebia.functional.gpt4all - -import ai.djl.training.util.DownloadUtils -import ai.djl.training.util.ProgressBar -import com.hexadevlabs.gpt4all.LLModel -import com.xebia.functional.tokenizer.EncodingType -import com.xebia.functional.tokenizer.ModelType -import com.xebia.functional.xef.conversation.Conversation -import com.xebia.functional.xef.conversation.PlatformConversation -import com.xebia.functional.xef.llm.Chat -import com.xebia.functional.xef.llm.Completion -import com.xebia.functional.xef.llm.models.chat.* -import com.xebia.functional.xef.llm.models.text.CompletionChoice -import com.xebia.functional.xef.llm.models.text.CompletionRequest -import com.xebia.functional.xef.llm.models.text.CompletionResult -import com.xebia.functional.xef.llm.models.usage.Usage -import com.xebia.functional.xef.metrics.LogsMetric -import com.xebia.functional.xef.metrics.Metric -import com.xebia.functional.xef.store.LocalVectorStore -import com.xebia.functional.xef.store.VectorStore -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED -import kotlinx.coroutines.flow.* -import java.io.OutputStream -import java.io.PrintStream -import java.nio.charset.StandardCharsets -import java.nio.file.Files -import java.nio.file.Path -import java.util.* -import kotlin.io.path.name - - -interface GPT4All : AutoCloseable, Chat, Completion { - - override fun close() { - } - - companion object { - - @JvmSynthetic - suspend inline fun conversation( - store: VectorStore = LocalVectorStore(HuggingFaceLocalEmbeddings.DEFAULT), - metric: Metric = Metric.EMPTY, - noinline block: suspend Conversation.() -> A - ): A = block(conversation(store)) - - @JvmSynthetic - suspend fun conversation( - block: suspend Conversation.() -> A - ): A = block(conversation()) - - @JvmStatic - @JvmOverloads - fun conversation( - store: VectorStore = LocalVectorStore(HuggingFaceLocalEmbeddings.DEFAULT), - metric: Metric = Metric.EMPTY - ): PlatformConversation = Conversation(store, metric) - - operator fun invoke( - url: String, - path: Path - ): GPT4All = object : GPT4All { - - init { - if (!Files.exists(path)) { - DownloadUtils.download(url, path.toFile().absolutePath, ProgressBar()) - } - } - - val llModel = LLModel(path) - - override fun copy(modelType: ModelType) = - GPT4All(url, path) - - override suspend fun createCompletion(request: CompletionRequest): CompletionResult = - with(request) { - val config = LLModel.config() - .withTopP(request.topP?.toFloat() ?: 0.4f) - .withTemp(request.temperature?.toFloat() ?: 0f) - .withRepeatPenalty(request.frequencyPenalty.toFloat()) - .build() - val response: String = generateCompletion(prompt, config, request.streamToStandardOut) - return CompletionResult( - UUID.randomUUID().toString(), - path.name, - System.currentTimeMillis(), - path.name, - listOf(CompletionChoice(response, 0, null, null)), - Usage.ZERO - ) - } - - override suspend fun createChatCompletion(request: ChatCompletionRequest): ChatCompletionResponse = - with(request) { - val prompt: String = messages.buildPrompt() - val config = LLModel.config() - .withTopP(request.topP.toFloat()) - .withTemp(request.temperature.toFloat()) - .withRepeatPenalty(request.frequencyPenalty.toFloat()) - .build() - val response: String = generateCompletion(prompt, config, request.streamToStandardOut) - return ChatCompletionResponse( - UUID.randomUUID().toString(), - path.name, - System.currentTimeMillis().toInt(), - path.name, - Usage.ZERO, - listOf(Choice(Message(Role.ASSISTANT, response, Role.ASSISTANT.name), null, 0)), - ) - } - - /** - * Creates chat completions based on the given ChatCompletionRequest. - * - * hacks the System.out until https://github.com/nomic-ai/gpt4all/pull/1126 is accepted or merged - * - * @param request The ChatCompletionRequest containing the necessary information for creating completions. - * @return A Flow of ChatCompletionChunk objects representing the generated chat completions. - */ - override suspend fun createChatCompletions(request: ChatCompletionRequest): Flow { - val prompt: String = request.messages.buildPrompt() - val config = with(request) { - LLModel.config() - .withTopP(topP.toFloat()) - .withTemp(temperature.toFloat()) - .withRepeatPenalty(frequencyPenalty.toFloat()) - .build() - } - - val channel = Channel(capacity = UNLIMITED) - val outputStream = object : OutputStream() { - override fun write(b: Int) { - val c = b.toChar() - channel.trySend(c.toString()) - } - } - - val originalOut = System.out // Save the original standard output - - fun toChunk(text: String?): ChatCompletionChunk = ChatCompletionChunk( - UUID.randomUUID().toString(), - System.currentTimeMillis().toInt(), - path.name, - listOf(ChatChunk(delta = ChatDelta(Role.ASSISTANT, text))), - Usage.ZERO, - ) - - return merge( - emptyFlow() - .onStart { - val printStream = PrintStream(outputStream, true, StandardCharsets.UTF_8) - System.setOut(printStream) // Set the standard output to the print stream - generateCompletion(prompt, config, request.streamToStandardOut) - channel.close() - System.setOut(originalOut) // Restore the original standard output - } - .flowOn(Dispatchers.IO), - channel - .consumeAsFlow() - .map(::toChunk) - ) - } - - override fun tokensFromMessages(messages: List): Int { - return 0 - } - - override val name: String = path.name - - override fun close(): Unit = llModel.close() - - override val modelType: ModelType = ModelType.LocalModel(name, EncodingType.CL100K_BASE, 4096) - - private fun List.buildPrompt(): String { - val messages: String = joinToString("") { message -> - when (message.role) { - Role.SYSTEM -> message.content - Role.USER -> "\n### Human: ${message.content}" - Role.ASSISTANT -> "\n### Response: ${message.content}" - } - } - return "$messages\n### Response:" - } - - private fun generateCompletion( - prompt: String, - config: LLModel.GenerationConfig, - stream: Boolean, - ): String { - return llModel.generate(prompt, config, stream) - } - } - - } - -} diff --git a/gpt4all-kotlin/src/jvmMain/kotlin/com/xebia/functional/gpt4all/HuggingFaceLocalEmbeddings.kt b/gpt4all-kotlin/src/jvmMain/kotlin/com/xebia/functional/gpt4all/HuggingFaceLocalEmbeddings.kt deleted file mode 100644 index 679294158..000000000 --- a/gpt4all-kotlin/src/jvmMain/kotlin/com/xebia/functional/gpt4all/HuggingFaceLocalEmbeddings.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.xebia.functional.gpt4all - -import ai.djl.huggingface.tokenizers.HuggingFaceTokenizer -import com.xebia.functional.tokenizer.ModelType -import com.xebia.functional.xef.llm.Embeddings -import com.xebia.functional.xef.llm.models.embeddings.Embedding -import com.xebia.functional.xef.llm.models.embeddings.EmbeddingRequest -import com.xebia.functional.xef.llm.models.embeddings.EmbeddingResult -import com.xebia.functional.xef.llm.models.embeddings.RequestConfig -import com.xebia.functional.xef.llm.models.usage.Usage - -class HuggingFaceLocalEmbeddings( - override val modelType: ModelType, - private val artifact: String, -) : Embeddings { - - private val tokenizer = HuggingFaceTokenizer.newInstance("${modelType.name}/$artifact") - - override val name: String = HuggingFaceLocalEmbeddings::class.java.canonicalName - - override fun copy(modelType: ModelType) = - HuggingFaceLocalEmbeddings(modelType, artifact) - - override suspend fun createEmbeddings(request: EmbeddingRequest): EmbeddingResult { - val embedings = tokenizer.batchEncode(request.input) - return EmbeddingResult( - data = embedings.map { Embedding(it.ids.map { it.toFloat() }) }, - usage = Usage.ZERO - ) - } - - override suspend fun embedDocuments( - texts: List, - requestConfig: RequestConfig, - chunkSize: Int? - ): List = - tokenizer.batchEncode(texts).map { em -> Embedding(em.ids.map { it.toFloat() }) } // TODO we need to remove the index - - companion object { - @JvmField - val DEFAULT = HuggingFaceLocalEmbeddings(ModelType.TODO("sentence-transformers"), artifact = "msmarco-distilbert-dot-v5") - } -} diff --git a/gpt4all-kotlin/src/jvmMain/kotlin/com/xebia/functional/gpt4all/HuggingFaceUtils.kt b/gpt4all-kotlin/src/jvmMain/kotlin/com/xebia/functional/gpt4all/HuggingFaceUtils.kt deleted file mode 100644 index ac2f1f4fb..000000000 --- a/gpt4all-kotlin/src/jvmMain/kotlin/com/xebia/functional/gpt4all/HuggingFaceUtils.kt +++ /dev/null @@ -1,4 +0,0 @@ -package com.xebia.functional.gpt4all - -fun huggingFaceUrl(name: String, artifact:String, extension: String): String = - "https://huggingface.co/$name/$artifact/resolve/main/$artifact.$extension" diff --git a/gpt4all-kotlin/src/jvmMain/kotlin/com/xebia/functional/gpt4all/Models.kt b/gpt4all-kotlin/src/jvmMain/kotlin/com/xebia/functional/gpt4all/Models.kt deleted file mode 100644 index 392a29bf8..000000000 --- a/gpt4all-kotlin/src/jvmMain/kotlin/com/xebia/functional/gpt4all/Models.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.xebia.functional.gpt4all - -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import java.net.URL - -@Serializable -data class Gpt4AllModel( - val order: String, - val md5sum: String, - val name: String, - val filename: String, - val filesize: String, - val requires: String? = null, - val ramrequired: String, - val parameters: String, - val quant: String, - val type: String, - val description: String, - val disableGUI: String? = null, - val url: String? = null, - val promptTemplate: String? = null, - val systemPrompt: String? = null, -) { - companion object { - private val url = "https://raw.githubusercontent.com/nomic-ai/gpt4all/main/gpt4all-chat/metadata/models.json" - val supportedModels : List by lazy { - // fetch the content as string from https://raw.githubusercontent.com/nomic-ai/gpt4all/main/gpt4all-chat/metadata/models.json - val json = URL(url).readText() - // parse the json string into a list of Model objects - Json.decodeFromString>(json) - } - } -} diff --git a/gpt4all-kotlin/src/jvmTest/kotlin/com/xebia/functional/xef/tests/GPT4ALLModelSpec.kt b/gpt4all-kotlin/src/jvmTest/kotlin/com/xebia/functional/xef/tests/GPT4ALLModelSpec.kt deleted file mode 100644 index 50d8c3ede..000000000 --- a/gpt4all-kotlin/src/jvmTest/kotlin/com/xebia/functional/xef/tests/GPT4ALLModelSpec.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.xebia.functional.xef.tests - -import com.xebia.functional.gpt4all.Gpt4AllModel -import io.kotest.core.spec.style.StringSpec -import io.kotest.matchers.ints.shouldBeGreaterThan - -class GPT4ALLModelSpec : - StringSpec({ - "should return a list of supported models by GPT4ALL" { - Gpt4AllModel.supportedModels.size shouldBeGreaterThan 0 - } - }) diff --git a/gradle.properties b/gradle.properties index a0979c287..e42fb3212 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ kotlin.native.cacheKind=none project.group=com.xebia pom.name=xef -pom.description=Building applications with LLMs through composability, in Kotlin and Scala +pom.description=Building applications with LLMs through composability in Kotlin pom.url=https://github.com/xebia-functional/xef pom.license.name=The Apache Software License, Version 2.0 pom.license.url=https://www.apache.org/licenses/LICENSE-2.0.txt @@ -21,5 +21,3 @@ systemProp.org.gradle.unsafe.kotlin.assignment=true # Workaround to disable Dokka setup from Arrow Gradle Config dokkaEnabled=false - -scalaVersion=3.3.1 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8c36b5552..b9b0801e8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -20,23 +20,14 @@ dokka = "1.9.10" logback = "1.4.11" node-gradle = "7.0.1" kotlinx-coroutines = "1.7.3" -scalaMultiversion = "2.0.6" -circe = "0.14.6" -catsEffect = "3.6-0142603" -munit = "0.7.29" -munitCatsEffect = "1.0.7" scrapeit = "1.1.5" rssreader = "3.5.0" lucene = "9.8.0" -assertj = "3.24.2" junit = "5.10.0" pdfbox = "3.0.0" mysql = "8.0.33" semverGradle = "0.5.0-rc.5" -scala = "3.3.1" openai-client-version = "3.5.1" -gpt4all-java = "1.1.5" -ai-djl = "0.24.0" jackson = "2.15.3" jsonschema = "4.32.0" jakarta = "3.0.2" @@ -65,7 +56,6 @@ kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serializa kotlinx-serialization-hocon = { module = "org.jetbrains.kotlinx:kotlinx-serialization-hocon", version.ref = "kotlinx-json" } kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref="kotlinx-coroutines" } kotlinx-coroutines-reactive = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-reactive", version.ref="kotlinx-coroutines" } -kotlinx-coroutines-jdk8 = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8", version.ref="kotlinx-coroutines" } kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinx-datetime" } ktor-utils = { module = "io.ktor:ktor-utils", version.ref = "ktor" } ktor-http = { module = "io.ktor:ktor-http", version.ref = "ktor" } @@ -104,24 +94,15 @@ hikari = { module = "com.zaxxer:HikariCP", version.ref = "hikari" } postgresql = { module = "org.postgresql:postgresql", version.ref = "postgresql" } testcontainers-postgresql = { module = "org.testcontainers:postgresql", version.ref = "testcontainers" } logback = { module = "ch.qos.logback:logback-classic", version.ref = "logback" } -circe = { module = "io.circe:circe-generic_3", version.ref = "circe" } -circe-parser = { module = "io.circe:circe-parser_3", version.ref = "circe" } -cats-effect = { module = "org.typelevel:cats-effect_3", version.ref = "catsEffect" } -munit-core = { module = "org.scalameta:munit_3", version.ref = "munit" } -munit-cats-effect = { module = "org.typelevel:munit-cats-effect-3_3", version.ref = "munitCatsEffect" } skrape = { module = "it.skrape:skrapeit", version.ref = "scrapeit" } skrape-browser-fetcher = { module = "it.skrape:skrapeit-browser-fetcher", version.ref = "scrapeit" } skrape-async-fetcher = { module = "it.skrape:skrapeit-asyn-fetcher", version.ref = "scrapeit" } rss-reader = { module = "com.apptasticsoftware:rssreader", version.ref = "rssreader" } lucene-core = { module = "org.apache.lucene:lucene-core", version.ref = "lucene" } lucene-queries = { module = "org.apache.lucene:lucene-queries", version.ref = "lucene" } -assertj = { module = "org.assertj:assertj-core", version.ref = "assertj" } apache-pdf-box = { module = "org.apache.pdfbox:pdfbox", version.ref = "pdfbox" } jdbc-mysql-connector = { module = "mysql:mysql-connector-java", version.ref = "mysql" } -scala-lang = { module = "org.scala-lang:scala3-library_3", version.ref = "scala" } openai-client = { module = "com.aallam.openai:openai-client", version.ref = "openai-client-version" } -gpt4all-java-bindings = { module = "com.hexadevlabs:gpt4all-java-binding", version.ref = "gpt4all-java" } -ai-djl-huggingface-tokenizers = { module = "ai.djl.huggingface:tokenizers", version.ref = "ai-djl" } jackson = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref = "jackson" } jackson-schema = { module = "com.github.victools:jsonschema-generator", version.ref = "jsonschema" } jackson-schema-jakarta = { module = "com.github.victools:jsonschema-module-jakarta-validation", version.ref = "jsonschema" } @@ -155,10 +136,8 @@ spotless = { id = "com.diffplug.spotless", version.ref = "spotless" } dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } arrow-gradle-nexus = { id = "io.arrow-kt.arrow-gradle-config-nexus", version.ref = "arrowGradle" } arrow-gradle-publish = { id = "io.arrow-kt.arrow-gradle-config-publish", version.ref = "arrowGradle" } -scala-multiversion = { id = "com.adtran.scala-multiversion-plugin", version.ref = "scalaMultiversion" } kotest-multiplatform = { id = "io.kotest.multiplatform", version.ref = "kotest" } semver-gradle = { id="com.javiersc.semver", version.ref="semverGradle" } -suspend-transform-plugin = { id="love.forte.plugin.suspend-transform", version.ref="suspend-transform" } resources = { id="com.goncalossilva.resources", version.ref="resources-kmp" } detekt = { id="io.gitlab.arturbosch.detekt", version.ref="detekt"} node-gradle = { id = "com.github.node-gradle.node", version.ref = "node-gradle" } diff --git a/java/README.md b/java/README.md deleted file mode 100644 index 380f6937b..000000000 --- a/java/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# xef.ai for Java - -Build the project locally, from the project root: - -```shell -./gradlew build -``` - -## Java Spotless - -The Java module uses the [spotless](https://github.com/diffplug/spotless/tree/main/plugin-gradle#java) plugin. -Therefore, the previous command (`./gradlew build`) will fail in case there is any formatting issue. To apply format, you can run the following command: - -```shell -./gradlew spotlessApply -``` - -## Examples - -Check out some use case at the [Java examples](../examples/java) folder. - -### Running the Examples - -How to run the examples (from IntelliJ IDEA): - -* Set Env variable: `OPENAI_TOKEN=xxx` diff --git a/java/build.gradle.kts b/java/build.gradle.kts deleted file mode 100644 index 99ba21ab2..000000000 --- a/java/build.gradle.kts +++ /dev/null @@ -1,32 +0,0 @@ -@file:Suppress("DSL_SCOPE_VIOLATION") - -plugins { - `java-library` - `maven-publish` - signing - `xef-java-publishing-conventions` - alias(libs.plugins.semver.gradle) - alias(libs.plugins.spotless) -} - -dependencies { - api(projects.xefCore) - api(projects.xefOpenai) - api(projects.xefPdf) - api(projects.xefSql) - api(libs.jdbc.mysql.connector) - api(libs.jackson) - api(libs.jackson.schema) - api(libs.jackson.schema.jakarta) - api(libs.jakarta.validation) - api(libs.kotlinx.coroutines.reactive) -} - -java { - withJavadocJar() - withSourcesJar() -} - -tasks.withType().configureEach { useJUnit() } - -tasks.withType { dependsOn(tasks.withType()) } diff --git a/java/src/main/java/com/xebia/functional/xef/java/auto/Empty.java b/java/src/main/java/com/xebia/functional/xef/java/auto/Empty.java deleted file mode 100644 index 82c339a6b..000000000 --- a/java/src/main/java/com/xebia/functional/xef/java/auto/Empty.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.xebia.functional.xef.java.auto; - -/** - * Module placeholder - */ -public class Empty { -} diff --git a/kotlin/build.gradle.kts b/kotlin/build.gradle.kts deleted file mode 100644 index 42afef530..000000000 --- a/kotlin/build.gradle.kts +++ /dev/null @@ -1,102 +0,0 @@ -import org.jetbrains.dokka.gradle.DokkaTask - -repositories { mavenCentral() } - -plugins { - base - alias(libs.plugins.kotlin.multiplatform) - alias(libs.plugins.kotest.multiplatform) - alias(libs.plugins.kotlinx.serialization) - alias(libs.plugins.spotless) - alias(libs.plugins.dokka) - alias(libs.plugins.arrow.gradle.publish) - alias(libs.plugins.semver.gradle) - alias(libs.plugins.detekt) -} - -dependencies { detektPlugins(project(":detekt-rules")) } - -detekt { - toolVersion = "1.23.1" - source.setFrom(files("src/commonMain/kotlin", "src/jvmMain/kotlin")) - config.setFrom("../config/detekt/detekt.yml") - autoCorrect = true -} - -java { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 - toolchain { languageVersion = JavaLanguageVersion.of(11) } -} - -kotlin { - jvm() - js(IR) { - browser() - nodejs() - } - linuxX64() - macosX64() - macosArm64() - mingwX64() - sourceSets { - val commonMain by getting { - dependencies { - api(projects.xefCore) - api(projects.xefOpenai) - } - } - } -} - -spotless { - kotlin { - target("**/*.kt") - ktfmt().googleStyle() - } -} - -tasks { - withType().configureEach { - dependsOn(":detekt-rules:assemble") - autoCorrect = true - } - named("detektJvmMain") { - dependsOn(":detekt-rules:assemble") - getByName("build").dependsOn(this) - } - named("detekt") { - dependsOn(":detekt-rules:assemble") - getByName("build").dependsOn(this) - } - withType().configureEach { - maxParallelForks = Runtime.getRuntime().availableProcessors() - useJUnitPlatform() - testLogging { - setExceptionFormat("full") - setEvents(listOf("passed", "skipped", "failed", "standardOut", "standardError")) - } - } - withType().configureEach { - kotlin.sourceSets.forEach { kotlinSourceSet -> - dokkaSourceSets.named(kotlinSourceSet.name) { - perPackageOption { - matchingRegex.set(".*\\.internal.*") - suppress.set(true) - } - skipDeprecated.set(true) - reportUndocumented.set(false) - val baseUrl = checkNotNull(project.properties["pom.smc.url"]?.toString()) - kotlinSourceSet.kotlin.srcDirs.filter { it.exists() }.forEach { srcDir -> - sourceLink { - localDirectory.set(srcDir) - remoteUrl.set(uri("$baseUrl/blob/main/${srcDir.relativeTo(rootProject.rootDir)}").toURL()) - remoteLineSuffix.set("#L") - } - } - } - } - } -} - -tasks.withType { dependsOn(tasks.withType()) } diff --git a/kotlin/src/commonMain/kotlin/com/xebia/functional/xef/conversation/DSLExtensions.kt b/kotlin/src/commonMain/kotlin/com/xebia/functional/xef/conversation/DSLExtensions.kt deleted file mode 100644 index d0a8ebcc0..000000000 --- a/kotlin/src/commonMain/kotlin/com/xebia/functional/xef/conversation/DSLExtensions.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.xebia.functional.xef.conversation - -import com.xebia.functional.xef.llm.Embeddings -import com.xebia.functional.xef.metrics.Metric -import com.xebia.functional.xef.store.LocalVectorStore -import com.xebia.functional.xef.store.VectorStore - -/** - * Executes a conversation with the given embeddings and vector store. - * - * @param embeddings The embeddings used for the conversation. - * @param store The vector store used for the conversation. Defaults to a local vector store. - * @param block The block of code representing the conversation logic. - * @return The result of the conversation execution. - */ -suspend inline fun conversation( - embeddings: Embeddings, - store: VectorStore = LocalVectorStore(embeddings), - metric: Metric = Metric.EMPTY, - noinline block: suspend Conversation.() -> A -): A = block(Conversation(store, metric)) diff --git a/models/gpt4all/get-models.sh b/models/gpt4all/get-models.sh deleted file mode 100755 index 32afa866d..000000000 --- a/models/gpt4all/get-models.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -curl --url https://gpt4all.io/models/ggml-gpt4all-j-v1.3-groovy.bin --output ./ggml-gpt4all-j-v1.3-groovy.bin diff --git a/scala/.scalafmt.conf b/scala/.scalafmt.conf deleted file mode 100644 index 038d0ede0..000000000 --- a/scala/.scalafmt.conf +++ /dev/null @@ -1,36 +0,0 @@ -# tune this file as appropriate to your style! see: https://olafurpg.github.io/scalafmt/#Configuration - -version = "3.7.15" - -runner.dialect = "scala3" - -maxColumn = 150 - -continuationIndent.callSite = 2 - -newlines { - sometimesBeforeColonInMethodReturnType = false -} - -align { - arrowEnumeratorGenerator = false - ifWhileOpenParen = false - openParenCallSite = false - openParenDefnSite = false - tokens = ["%", "%%"] -} - -docstrings.style = Asterisk - -rewrite { - rules = [SortImports, RedundantBraces] - redundantBraces.maxLines = 1 -} - -optIn { - breaksInsideChains = true -} - -project.excludeFilters = [ - "metals.sbt" -] diff --git a/scala/README.md b/scala/README.md deleted file mode 100644 index e74c18873..000000000 --- a/scala/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# xef.ai for Scala - -Build the project locally, from the project root: - -```shell -./gradlew build -``` - -## Scalafmt - -The Scala module uses the [spotless](https://github.com/diffplug/spotless/tree/main/plugin-gradle#scala) plugin. -Therefore, the previous command (`./gradlew build`) will fail if there are any formatting issues. -To apply formatting, you can run the following command: - -```shell -./gradlew spotlessApply -``` - -## Examples - -Check out some use case at the [Scala examples](../examples/scala) folder. - -### Running the Examples - -How to run the examples (from IntelliJ IDEA): - -* Set Java version 20 or above -* Set VM options: `--enable-preview` (if using Java 20 specifically) -* Set Env variable: `OPENAI_TOKEN=xxx` diff --git a/scala/build.gradle.kts b/scala/build.gradle.kts deleted file mode 100644 index e17e0c4c4..000000000 --- a/scala/build.gradle.kts +++ /dev/null @@ -1,38 +0,0 @@ -@file:Suppress("DSL_SCOPE_VIOLATION") - -plugins { - scala - `maven-publish` - signing - alias(libs.plugins.semver.gradle) - alias(libs.plugins.spotless) - `xef-scala-publishing-conventions` -} - -dependencies { - implementation(projects.xefCore) - implementation(projects.xefOpenai) - implementation(libs.kotlinx.coroutines.reactive) - // TODO split to separate Scala library - implementation(projects.xefPdf) - implementation(libs.circe.parser) - implementation(libs.circe) - implementation(libs.scala.lang) - implementation(libs.logback) - testImplementation(libs.munit.core) -} - -java { - sourceCompatibility = JavaVersion.VERSION_21 - targetCompatibility = JavaVersion.VERSION_21 - toolchain { languageVersion = JavaLanguageVersion.of(21) } - withSourcesJar() -} - -tasks.withType().configureEach { useJUnit() } - -tasks.withType { - scalaCompileOptions.additionalParameters = listOf("-Wunused:all", "-Wvalue-discard") -} - -spotless { scala { scalafmt("3.7.15").configFile(".scalafmt.conf") } } diff --git a/scala/src/main/resources/logback.xml b/scala/src/main/resources/logback.xml deleted file mode 100644 index 8b62c8b02..000000000 --- a/scala/src/main/resources/logback.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%kvp- %msg%n - - - - - - - - - - - - - - - diff --git a/scala/src/main/scala/com/xebia/functional/xef/scala/conversation/package.scala b/scala/src/main/scala/com/xebia/functional/xef/scala/conversation/package.scala deleted file mode 100644 index c30cc9396..000000000 --- a/scala/src/main/scala/com/xebia/functional/xef/scala/conversation/package.scala +++ /dev/null @@ -1,66 +0,0 @@ -package com.xebia.functional.xef.scala.conversation - -import com.xebia.functional.xef.conversation.* -import com.xebia.functional.xef.conversation.llm.openai.* -import com.xebia.functional.xef.llm.* -import com.xebia.functional.xef.llm.models.images.* -import com.xebia.functional.xef.metrics.* -import com.xebia.functional.xef.prompt.Prompt -import com.xebia.functional.xef.scala.serialization.* -import com.xebia.functional.xef.store.* -import io.circe.Decoder -import io.circe.parser.parse -import org.reactivestreams.* - -import java.util.UUID.* -import java.util.concurrent.LinkedBlockingQueue -import scala.jdk.CollectionConverters.* - -class ScalaConversation(store: VectorStore, metric: Metric, conversationId: ConversationId) extends JVMConversation(store, metric, conversationId) - -def addContext(context: Array[String])(using conversation: ScalaConversation): Unit = - conversation.addContextFromArray(context).join() - -def prompt[A: Decoder: SerialDescriptor](prompt: Prompt, chat: ChatWithFunctions = OpenAI.fromEnvironment().DEFAULT_SERIALIZATION)(using - conversation: ScalaConversation -): A = - conversation.prompt(chat, prompt, chat.chatFunction(SerialDescriptor[A].serialDescriptor), fromJson).join() - -def promptMessage(prompt: Prompt, chat: Chat = OpenAI.fromEnvironment().DEFAULT_CHAT)(using conversation: ScalaConversation): String = - conversation.promptMessage(chat, prompt).join() - -def promptMessages(prompt: Prompt, chat: Chat = OpenAI.fromEnvironment().DEFAULT_CHAT)(using conversation: ScalaConversation): List[String] = - conversation.promptMessages(chat, prompt).join().asScala.toList - -def promptStreaming(prompt: Prompt, chat: Chat = OpenAI.fromEnvironment().DEFAULT_CHAT)(using conversation: ScalaConversation): LazyList[String] = - val publisher = conversation.promptStreamingToPublisher(chat, prompt) - val queue = new LinkedBlockingQueue[String]() - publisher.subscribe(new Subscriber[String]: // TODO change to fs2 or similar - def onSubscribe(s: Subscription): Unit = s.request(Long.MaxValue) - def onNext(t: String): Unit = queue.add(t); () - def onError(t: Throwable): Unit = throw t - def onComplete(): Unit = () - ) - LazyList.continually(queue.take) - -def prompt[A: Decoder: SerialDescriptor](message: String)(using ScalaConversation): A = - prompt(Prompt(message)) - -def promptMessage(message: String)(using ScalaConversation): String = - promptMessage(Prompt(message)) - -def promptMessages(message: String)(using ScalaConversation): List[String] = - promptMessages(Prompt(message)) - -def promptStreaming(message: String)(using ScalaConversation): LazyList[String] = - promptStreaming(Prompt(message)) - -def images(prompt: Prompt, images: Images = OpenAI.fromEnvironment().DEFAULT_IMAGES, numberImages: Int = 1, size: String = "1024x1024")(using - conversation: ScalaConversation -): ImagesGenerationResponse = - conversation.images(images, prompt, numberImages, size).join() - -def conversation[A](block: ScalaConversation ?=> A, id: ConversationId = ConversationId(randomUUID.toString)): A = - block(using ScalaConversation(LocalVectorStore(OpenAI.fromEnvironment().DEFAULT_EMBEDDING), LogsMetric(), id)) - -private def fromJson[A: Decoder]: FromJson[A] = json => parse(json).flatMap(Decoder[A].decodeJson(_)).fold(throw _, identity) diff --git a/scala/src/main/scala/com/xebia/functional/xef/scala/serialization/KotlinXSerializers.scala b/scala/src/main/scala/com/xebia/functional/xef/scala/serialization/KotlinXSerializers.scala deleted file mode 100644 index 30aa05e4a..000000000 --- a/scala/src/main/scala/com/xebia/functional/xef/scala/serialization/KotlinXSerializers.scala +++ /dev/null @@ -1,18 +0,0 @@ -package com.xebia.functional.xef.scala.serialization - -import kotlin.jvm.internal.* -import kotlinx.serialization.KSerializer -import kotlinx.serialization.builtins.BuiltinSerializersKt -import kotlinx.serialization.builtins.BuiltinSerializersKt.serializer - -object KotlinXSerializers: - val int: KSerializer[java.lang.Integer] = serializer(IntCompanionObject.INSTANCE) - val string: KSerializer[String] = serializer(StringCompanionObject.INSTANCE) - val boolean: KSerializer[java.lang.Boolean] = serializer(BooleanCompanionObject.INSTANCE) - val double: KSerializer[java.lang.Double] = serializer(DoubleCompanionObject.INSTANCE) - val float: KSerializer[java.lang.Float] = serializer(FloatCompanionObject.INSTANCE) - val long: KSerializer[java.lang.Long] = serializer(LongCompanionObject.INSTANCE) - val short: KSerializer[java.lang.Short] = serializer(ShortCompanionObject.INSTANCE) - val byte: KSerializer[java.lang.Byte] = serializer(ByteCompanionObject.INSTANCE) - val char: KSerializer[Character] = serializer(CharCompanionObject.INSTANCE) - val unit: KSerializer[kotlin.Unit] = serializer(kotlin.Unit.INSTANCE) diff --git a/scala/src/main/scala/com/xebia/functional/xef/scala/serialization/SerialDescriptor.scala b/scala/src/main/scala/com/xebia/functional/xef/scala/serialization/SerialDescriptor.scala deleted file mode 100644 index 9b574065a..000000000 --- a/scala/src/main/scala/com/xebia/functional/xef/scala/serialization/SerialDescriptor.scala +++ /dev/null @@ -1,116 +0,0 @@ -package com.xebia.functional.xef.scala.serialization - -import com.xebia.functional.xef.conversation.jvm.Description as JvmDescription -import kotlinx.serialization.KSerializer -import kotlinx.serialization.descriptors.{SerialDescriptor as KtSerialDescriptor, SerialKind, StructureKind} -import kotlinx.serialization.encoding.{Decoder as KtDecoder, Encoder as KtEncoder} - -import java.lang.annotation.Annotation -import java.util -import scala.annotation.meta.* -import scala.compiletime.* -import scala.deriving.* -import scala.jdk.CollectionConverters.* -import scala.quoted.* -import scala.reflect.ClassTag - -trait SerialDescriptor[A]: - def serialDescriptor: KtSerialDescriptor - def kserializer: KSerializer[A] = new KSerializer[A]: - override def getDescriptor: KtSerialDescriptor = serialDescriptor - override def serialize(encoder: KtEncoder, t: A): Unit = ??? // TODO should we implement this? - override def deserialize(decoder: KtDecoder): A = ??? // TODO should we implement this? - -object SerialDescriptor extends SerialDescriptorInstances: - def apply[A](using ev: SerialDescriptor[A]): SerialDescriptor[A] = ev - - private inline def getElemsLabel[T <: Tuple]: List[String] = inline erasedValue[T] match - case _: EmptyTuple => Nil - case _: (h *: t) => erasedValue[h].toString :: getElemsLabel[t] - - private inline def getSerialDescriptor[T <: Tuple]: List[KtSerialDescriptor] = inline erasedValue[T] match - case _: EmptyTuple => Nil - case _: (String *: t) => KotlinXSerializers.string.getDescriptor :: getSerialDescriptor[t] - case _: (Boolean *: t) => KotlinXSerializers.boolean.getDescriptor :: getSerialDescriptor[t] - case _: (Byte *: t) => KotlinXSerializers.byte.getDescriptor :: getSerialDescriptor[t] - case _: (Char *: t) => KotlinXSerializers.char.getDescriptor :: getSerialDescriptor[t] - case _: (Double *: t) => KotlinXSerializers.double.getDescriptor :: getSerialDescriptor[t] - case _: (Float *: t) => KotlinXSerializers.float.getDescriptor :: getSerialDescriptor[t] - case _: (Int *: t) => KotlinXSerializers.int.getDescriptor :: getSerialDescriptor[t] - case _: (Long *: t) => KotlinXSerializers.long.getDescriptor :: getSerialDescriptor[t] - case _: (Short *: t) => KotlinXSerializers.short.getDescriptor :: getSerialDescriptor[t] - case _: (Unit *: t) => KotlinXSerializers.unit.getDescriptor :: getSerialDescriptor[t] - case _: (h *: t) => summonInline[SerialDescriptor[h]].serialDescriptor :: getSerialDescriptor[t] - - inline final def derived[A](using m: Mirror.Of[A]): SerialDescriptor[A] = - val fieldAnnotationMap = getFieldAnnotationsMap[A] - new SerialDescriptor[A]: - val serialDescriptorImpl: KtSerialDescriptor = new KtSerialDescriptor: - val labels = getElemsLabel[m.MirroredElemLabels] - val serialDescriptors = getSerialDescriptor[m.MirroredElemTypes] - - override def getElementIndex(name: String): Int = labels.indexOf(name) - - // We're going to ignore annotations for now, it's not relevant for JsonSchema - override def getElementAnnotations(index: Int): util.List[Annotation] = - val fieldName = labels(index) - val annotations = fieldAnnotationMap(fieldName) - annotations.filter(_.isInstanceOf[Description]).asJava.asInstanceOf[util.List[Annotation]] - - override def getElementDescriptor(index: Int): KtSerialDescriptor = serialDescriptors(index) - - // We're going to ignore annotations for now, it's not relevant for JsonSchema - override def getAnnotations: util.List[Annotation] = - val annotations = getStaticAnnotations[A] - annotations.filter(_.isInstanceOf[Description]).asJava.asInstanceOf[util.List[Annotation]] - - override def getElementsCount: Int = labels.size - - override def isInline: Boolean = false - - // Is the element wrapped in `Option`, or is a union with `Null`? - override def isNullable: Boolean = false - - override def getKind: SerialKind = StructureKind.CLASS.INSTANCE - - override def getSerialName: String = constValue[m.MirroredLabel] - - override def getElementName(i: Int): String = labels(i) - - // Does the element at the given index have a default value, or is it wrapped in `Option`, or is a union with `Null`? - override def isElementOptional(index: Int): Boolean = false - - def serialDescriptor: KtSerialDescriptor = serialDescriptorImpl - -inline def getStaticAnnotations[A]: List[Any] = ${ getAnnotationsImpl[A] } - -def getAnnotationsImpl[A: Type](using Quotes): Expr[List[Any]] = - import quotes.reflect.* - val annotations = TypeRepr.of[A].typeSymbol.annotations.map(_.asExpr) - Expr.ofList(annotations) - -inline def getFieldAnnotationsMap[A]: Map[String, List[Any]] = - ${ getFieldAnnotationsMapImpl[A] } - -def getFieldAnnotationsMapImpl[A: Type](using Quotes): Expr[Map[String, List[Any]]] = - import quotes.reflect.* - // Extract the fields from the type - val fields = TypeRepr.of[A].typeSymbol.primaryConstructor.paramSymss.flatten - // For each field, extract its name and annotations - val fieldAnnotationsMap: List[Expr[(String, List[Any])]] = fields.map: field => - val fieldName = Expr(field.name) - val annotations = Expr.ofList(field.annotations.map(_.asExpr)) - '{ ($fieldName, $annotations) } - // Convert list of (String, List[Any]) tuples to a map - fieldAnnotationsMap match - case Nil => '{ Map.empty[String, List[Any]] } - case _ => - val mapExpr = Expr.ofList(fieldAnnotationsMap) - '{ $mapExpr.toMap } - -/** - * A scala annotation that maps to the jvm description annotation - */ -class Description(description: String) extends JvmDescription with scala.annotation.StaticAnnotation: - override def value(): String = description - override def annotationType(): Class[_ <: Annotation] = classOf[JvmDescription] diff --git a/scala/src/main/scala/com/xebia/functional/xef/scala/serialization/SerialDescriptorInstances.scala b/scala/src/main/scala/com/xebia/functional/xef/scala/serialization/SerialDescriptorInstances.scala deleted file mode 100644 index ee761f27c..000000000 --- a/scala/src/main/scala/com/xebia/functional/xef/scala/serialization/SerialDescriptorInstances.scala +++ /dev/null @@ -1,64 +0,0 @@ -package com.xebia.functional.xef.scala.serialization - -import kotlin.jvm.internal.Reflection -import kotlin.reflect.KClass -import kotlinx.serialization.builtins.BuiltinSerializersKt - -import scala.compiletime.summonInline -import scala.reflect.ClassTag - -class SerialDescriptorInstances: - - given [T: SerialDescriptor]: SerialDescriptor[Option[T]] = new SerialDescriptor[Option[T]]: - def serialDescriptor = BuiltinSerializersKt.getNullable(SerialDescriptor[T].kserializer).getDescriptor - - given [T: ClassTag: SerialDescriptor]: SerialDescriptor[Array[T]] = new SerialDescriptor[Array[T]]: - def serialDescriptor = - val kClass = Reflection.createKotlinClass(summonInline[ClassTag[T]].runtimeClass).asInstanceOf[KClass[T]] - BuiltinSerializersKt.ArraySerializer(kClass, SerialDescriptor[T].kserializer).getDescriptor - - given [T: SerialDescriptor]: SerialDescriptor[List[T]] = new SerialDescriptor[List[T]]: - def serialDescriptor = BuiltinSerializersKt.ListSerializer(SerialDescriptor[T].kserializer).getDescriptor - - given [T: SerialDescriptor]: SerialDescriptor[Seq[T]] = new SerialDescriptor[Seq[T]]: - def serialDescriptor = BuiltinSerializersKt.ListSerializer(SerialDescriptor[T].kserializer).getDescriptor - - given [T: SerialDescriptor]: SerialDescriptor[Vector[T]] = new SerialDescriptor[Vector[T]]: - def serialDescriptor = BuiltinSerializersKt.ListSerializer(SerialDescriptor[T].kserializer).getDescriptor - - given [T: SerialDescriptor]: SerialDescriptor[Set[T]] = new SerialDescriptor[Set[T]]: - def serialDescriptor = BuiltinSerializersKt.SetSerializer(SerialDescriptor[T].kserializer).getDescriptor - - given [K: SerialDescriptor, V: SerialDescriptor]: SerialDescriptor[Map[K, V]] = new SerialDescriptor[Map[K, V]]: - def serialDescriptor = - BuiltinSerializersKt.MapSerializer(SerialDescriptor[K].kserializer, SerialDescriptor[V].kserializer).getDescriptor - - given SerialDescriptor[Boolean] = new SerialDescriptor[Boolean]: - def serialDescriptor = KotlinXSerializers.boolean.getDescriptor - - given SerialDescriptor[Byte] = new SerialDescriptor[Byte]: - def serialDescriptor = KotlinXSerializers.byte.getDescriptor - - given SerialDescriptor[Char] = new SerialDescriptor[Char]: - def serialDescriptor = KotlinXSerializers.char.getDescriptor - - given SerialDescriptor[Double] = new SerialDescriptor[Double]: - def serialDescriptor = KotlinXSerializers.double.getDescriptor - - given SerialDescriptor[Float] = new SerialDescriptor[Float]: - def serialDescriptor = KotlinXSerializers.float.getDescriptor - - given SerialDescriptor[Int] = new SerialDescriptor[Int]: - def serialDescriptor = KotlinXSerializers.int.getDescriptor - - given SerialDescriptor[Long] = new SerialDescriptor[Long]: - def serialDescriptor = KotlinXSerializers.long.getDescriptor - - given SerialDescriptor[Short] = new SerialDescriptor[Short]: - def serialDescriptor = KotlinXSerializers.short.getDescriptor - - given SerialDescriptor[String] = new SerialDescriptor[String]: - def serialDescriptor = KotlinXSerializers.string.getDescriptor - - given SerialDescriptor[Unit] = new SerialDescriptor[Unit]: - def serialDescriptor = KotlinXSerializers.unit.getDescriptor diff --git a/scala/src/test/scala/com/xebia/functional/xef/scala/serialization/SerialDescriptorSpec.scala b/scala/src/test/scala/com/xebia/functional/xef/scala/serialization/SerialDescriptorSpec.scala deleted file mode 100644 index 4c103b6e1..000000000 --- a/scala/src/test/scala/com/xebia/functional/xef/scala/serialization/SerialDescriptorSpec.scala +++ /dev/null @@ -1,68 +0,0 @@ -package com.xebia.functional.xef.scala.serialization - -import cats.syntax.either.* -import kotlinx.serialization.builtins.BuiltinSerializersKt -import munit.FunSuite - -import scala.collection.immutable.HashSet -import scala.compiletime.summonInline -import scala.reflect.ClassTag - -class SerialDescriptorSpec extends FunSuite: - - test("Should create a SerialDescriptor for a simple case class") { - final case class Person(age: Int, name: String) derives SerialDescriptor - assert(Either.catchNonFatal(SerialDescriptor[Person].serialDescriptor).isRight) - } - - test("Should create a SerialDescriptor for a simple case class with optional fields") { - final case class Person(age: Int, name: String, id: Option[Long]) derives SerialDescriptor - assert(Either.catchNonFatal(SerialDescriptor[Person].serialDescriptor).isRight) - } - - test("Should create a SerialDescriptor for a simple case class with set and list fields") { - final case class Person(age: Int, name: String, siblingNames: Set[String], nationality: List[String]) derives SerialDescriptor - assert(Either.catchNonFatal(SerialDescriptor[Person].serialDescriptor).isRight) - } - - test("Should create a SerialDescriptor for a simple case class with a list case class") { - final case class Pet(age: Int, name: String) derives SerialDescriptor - final case class Person(age: Int, name: String, pets: List[Pet]) derives SerialDescriptor - - assert(Either.catchNonFatal(SerialDescriptor[Person].serialDescriptor).isRight) - } - - test("Should create a SerialDescriptor for a simple case class with seq and vector fields") { - final case class Person(age: Int, name: String, other1: Seq[Byte], other2: Vector[Short]) derives SerialDescriptor - assert(Either.catchNonFatal(SerialDescriptor[Person].serialDescriptor).isRight) - } - - test("Should create a SerialDescriptor for a simple case class with an array field") { - final case class Person(other: Array[Double]) derives SerialDescriptor - assert(Either.catchNonFatal(SerialDescriptor[Person].serialDescriptor).isRight) - } - - test("Should create a SerialDescriptor for a simple case class with map fields") { - final case class Person(age: Int, name: String, alias: Map[String, String]) derives SerialDescriptor - assert(Either.catchNonFatal(SerialDescriptor[Person].serialDescriptor).isRight) - } - - test("Should create a SerialDescriptor for a simple case class with HashSet field, providing a custom given") { - given [T: SerialDescriptor]: SerialDescriptor[HashSet[T]] = new SerialDescriptor[HashSet[T]]: - def serialDescriptor = BuiltinSerializersKt.SetSerializer(SerialDescriptor[T].kserializer).getDescriptor - final case class Person(age: Int, name: String, alias: HashSet[String]) derives SerialDescriptor - assert(Either.catchNonFatal(SerialDescriptor[Person].serialDescriptor).isRight) - } - - test("Should create a SerialDescriptor for a composite case class") { - final case class Person(age: Int, name: PersonName) derives SerialDescriptor - final case class PersonName(firstName: String, lastName: String) derives SerialDescriptor - assert(Either.catchNonFatal(SerialDescriptor[Person].serialDescriptor).isRight) - } - - test("Should create a SerialDescriptor for a composite (level 2) case class") { - final case class Person(age: Int, placeOfBirth: PlaceOfBirth) derives SerialDescriptor - final case class PlaceOfBirth(city: String, country: Country) derives SerialDescriptor - final case class Country(country: String) derives SerialDescriptor - assert(Either.catchNonFatal(SerialDescriptor[Person].serialDescriptor).isRight) - } diff --git a/server/build.gradle.kts b/server/build.gradle.kts index d7d360436..57c8f6c87 100644 --- a/server/build.gradle.kts +++ b/server/build.gradle.kts @@ -48,7 +48,7 @@ dependencies { implementation(libs.suspendApp.core) implementation(libs.suspendApp.ktor) implementation(libs.uuid) - implementation(projects.xefKotlin) + implementation(projects.xefOpenai) implementation(projects.xefCore) implementation(projects.xefLucene) implementation(projects.xefPostgresql) @@ -69,12 +69,6 @@ spotless { } } -tasks.getByName("processResources") { - dependsOn(projects.xefGpt4all.dependencyProject.tasks.getByName("jvmProcessResources")) - from("${projects.xefGpt4all.dependencyProject.buildDir}/processedResources/jvm/main") - into("$buildDir/resources/main") -} - task("web-app") { dependsOn("npm_run_build") group = "Execution" diff --git a/settings.gradle.kts b/settings.gradle.kts index 8f598cd6f..713130d35 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -35,9 +35,7 @@ project(":xef-tokenizer").projectDir = file("tokenizer") include("xef-openai") project(":xef-openai").projectDir = file("openai") - -include("xef-gpt4all") -project(":xef-gpt4all").projectDir = file("gpt4all-kotlin") +// // include("xef-lucene") @@ -61,40 +59,13 @@ project(":xef-opentelemetry").projectDir = file("integrations/opentelemetry") include("xef-mlflow") project(":xef-mlflow").projectDir = file("integrations/mlflow") // -// - -// -include("xef-kotlin") -project(":xef-kotlin").projectDir = file("kotlin") - -include("xef-kotlin-examples") -project(":xef-kotlin-examples").projectDir = file("examples/kotlin") -// -// -include("xef-scala-examples") -project(":xef-scala-examples").projectDir = file("examples/scala") +include("xef-examples") +project(":xef-examples").projectDir = file("examples") -include("xef-scala") -project(":xef-scala").projectDir = file("scala") -// - -// -include("xef-java") -project(":xef-java").projectDir = file("java") - -include("xef-java-examples") -project(":xef-java-examples").projectDir = file("examples/java") -// - -// include("xef-reasoning") project(":xef-reasoning").projectDir = file("reasoning") -include("xef-java-examples") -project(":xef-java-examples").projectDir = file("examples/java") -// - // include("xef-server") project(":xef-server").projectDir = file("server")