Skip to content

Commit

Permalink
cherrypicked from branch #441-fine-tuning-oai
Browse files Browse the repository at this point in the history
  • Loading branch information
Intex32 committed Sep 29, 2023
1 parent a2fe05a commit a9c1ad1
Show file tree
Hide file tree
Showing 11 changed files with 295 additions and 110 deletions.
9 changes: 5 additions & 4 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[versions]
arrow = "1.2.1"
arrowGradle = "0.12.0-rc.5"
exposed = "0.43.0"
exposed = "0.44.0"
kotlin = "1.9.10"
kotlinx-json = "1.6.0"
kotlinx-datetime = "0.4.1"
Expand All @@ -10,7 +10,7 @@ spotless = "6.21.0"
okio = "3.5.0"
kotest = "5.7.2"
kotest-testcontainers = "2.0.2"
kotest-arrow = "1.3.3"
kotest-arrow = "1.4.0"
klogging = "5.1.0"
uuid = "0.0.21"
postgresql = "42.6.0"
Expand All @@ -33,7 +33,7 @@ junit = "5.10.0"
pdfbox = "3.0.0"
mysql = "8.0.33"
semverGradle = "0.5.0-rc.5"
scala = "3.3.0"
scala = "3.3.1"
openai-client-version = "3.4.1"
gpt4all-java = "1.1.5"
ai-djl = "0.23.0"
Expand All @@ -42,7 +42,7 @@ jsonschema = "4.31.1"
jakarta = "3.0.2"
suspend-transform = "0.5.1"
suspendApp = "0.4.0"
flyway = "9.22.1"
flyway = "9.22.2"
resources-kmp = "0.4.0"
detekt = "1.23.1"

Expand Down Expand Up @@ -83,6 +83,7 @@ ktor-server-contentNegotiation = { module = "io.ktor:ktor-server-content-negotia
ktor-server-resources = { module = "io.ktor:ktor-server-resources", version.ref = "ktor" }
ktor-server-cors = { module = "io.ktor:ktor-server-cors", version.ref = "ktor" }
ktor-server-request-validation = { module = "io.ktor:ktor-server-request-validation", version.ref = "ktor" }
ktor-server-double-receive = { module = "io.ktor:ktor-server-double-receive", version.ref = "ktor" }
ktor-server-status-pages = { module = "io.ktor:ktor-server-status-pages", version.ref = "ktor" }
okio = { module = "com.squareup.okio:okio", version.ref = "okio" }
okio-fakefilesystem = { module = "com.squareup.okio:okio-fakefilesystem", version.ref = "okio" }
Expand Down
3 changes: 3 additions & 0 deletions server/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ dependencies {
implementation(libs.ktor.server.cors)
implementation(libs.ktor.server.request.validation)
implementation(libs.ktor.server.status.pages)
implementation(libs.ktor.server.double.receive)
implementation(libs.logback)
implementation(libs.openai.client)
implementation(libs.suspendApp.core)
Expand All @@ -57,6 +58,8 @@ dependencies {
implementation(projects.xefCore)
implementation(projects.xefLucene)
implementation(projects.xefPostgresql)
implementation("io.ktor:ktor-server-core-jvm:2.3.4")
implementation("io.ktor:ktor-server-double-receive-jvm:2.3.4")

testImplementation(libs.junit.jupiter.api)
testImplementation(libs.junit.jupiter.engine)
Expand Down
17 changes: 6 additions & 11 deletions server/src/main/kotlin/com/xebia/functional/xef/server/Server.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,9 @@ import com.xebia.functional.xef.server.db.psql.XefDatabaseConfig
import com.xebia.functional.xef.server.db.psql.XefVectorStoreConfig
import com.xebia.functional.xef.server.db.psql.XefVectorStoreConfig.Companion.getVectorStoreService
import com.xebia.functional.xef.server.exceptions.exceptionsHandler
import com.xebia.functional.xef.server.http.routes.genAIRoutes
import com.xebia.functional.xef.server.http.routes.organizationRoutes
import com.xebia.functional.xef.server.http.routes.projectsRoutes
import com.xebia.functional.xef.server.http.routes.userRoutes
import com.xebia.functional.xef.server.services.OrganizationRepositoryService
import com.xebia.functional.xef.server.services.ProjectRepositoryService
import com.xebia.functional.xef.server.http.routes.*
import com.xebia.functional.xef.server.http.routes.providers.oaiRoutes
import com.xebia.functional.xef.server.services.RepositoryService
import com.xebia.functional.xef.server.services.UserRepositoryService
import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.plugins.auth.*
Expand All @@ -28,6 +23,7 @@ import io.ktor.server.auth.*
import io.ktor.server.netty.*
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.server.plugins.cors.routing.*
import io.ktor.server.plugins.doublereceive.*
import io.ktor.server.resources.*
import io.ktor.server.routing.*
import kotlinx.coroutines.awaitCancellation
Expand Down Expand Up @@ -75,6 +71,7 @@ object Server {
anyHost()
}
install(ContentNegotiation) { json() }
install(DoubleReceive)
install(Resources)
install(Authentication) {
bearer("auth-bearer") {
Expand All @@ -85,10 +82,8 @@ object Server {
}
exceptionsHandler()
routing {
genAIRoutes(ktorClient, vectorStoreService)
userRoutes(UserRepositoryService(logger))
organizationRoutes(OrganizationRepositoryService(logger))
projectsRoutes(ProjectRepositoryService(logger))
aiRoutes(ktorClient)
oaiRoutes(ktorClient)
}
}
awaitCancellation()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,19 @@
package com.xebia.functional.xef.server.db.tables

import com.xebia.functional.xef.server.models.ProvidersConfig
import kotlinx.datetime.Instant
import kotlinx.serialization.SerialName
import kotlinx.serialization.json.Json
import org.jetbrains.exposed.dao.IntEntity
import org.jetbrains.exposed.dao.IntEntityClass
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.dao.id.IntIdTable
import org.jetbrains.exposed.sql.ReferenceOption
import org.jetbrains.exposed.sql.ResultRow
import org.jetbrains.exposed.sql.Table
import org.jetbrains.exposed.sql.json.jsonb
import org.jetbrains.exposed.sql.kotlin.datetime.CurrentTimestamp
import org.jetbrains.exposed.sql.kotlin.datetime.timestamp

val format = Json { prettyPrint = true }

data class XefTokens(
@SerialName("user_id") val userId: Int,
@SerialName("project_id") val projectId: Int,
@SerialName("name") val name: String,
@SerialName("created_at") val createdAt: Instant,
@SerialName("updated_at") val updatedAt: Instant,
@SerialName("token") val token: String,
@SerialName("providers_config") val providersConfig: ProvidersConfig
)

object XefTokensTable : Table("xef_tokens") {
object XefTokensTable : IntIdTable("xef_tokens") {
val userId = reference(
name = "user_id",
foreign = UsersTable,
Expand All @@ -40,17 +30,16 @@ object XefTokensTable : Table("xef_tokens") {
val token = varchar("token", 128).uniqueIndex()
val providersConfig = jsonb<ProvidersConfig>("providers_config", format)

override val primaryKey = PrimaryKey(userId, projectId, name)
}

fun ResultRow.toXefTokens(): XefTokens {
return XefTokens(
userId = this[XefTokensTable.userId].value,
projectId = this[XefTokensTable.projectId].value,
name = this[XefTokensTable.name],
createdAt = this[XefTokensTable.createdAt],
updatedAt = this[XefTokensTable.updatedAt],
token = this[XefTokensTable.token],
providersConfig = this[XefTokensTable.providersConfig]
)
class XefTokens(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<XefTokens>(XefTokensTable)

var userId by XefTokensTable.userId
var projectId by XefTokensTable.projectId
var name by XefTokensTable.name
var createdAt by XefTokensTable.createdAt
var updatedAt by XefTokensTable.updatedAt
var token by XefTokensTable.token
var providersConfig by XefTokensTable.providersConfig
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
package com.xebia.functional.xef.server.http.routes

import com.aallam.openai.api.BetaOpenAI
import com.xebia.functional.xef.server.http.routes.providers.forwardToProvider
import com.xebia.functional.xef.server.http.routes.providers.makeRequest
import com.xebia.functional.xef.server.http.routes.providers.makeStreaming
import com.xebia.functional.xef.server.models.Token
import com.xebia.functional.xef.server.models.exceptions.XefExceptions
import com.xebia.functional.xef.server.services.VectorStoreService
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
import io.ktor.server.application.*
import io.ktor.server.auth.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import io.ktor.utils.io.jvm.javaio.*
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.boolean
Expand All @@ -32,9 +28,8 @@ fun String.toProvider(): Provider? = when (this) {
}

@OptIn(BetaOpenAI::class)
fun Routing.genAIRoutes(
client: HttpClient,
vectorStoreService: VectorStoreService
fun Routing.aiRoutes(
client: HttpClient
) {
val openAiUrl = "https://api.openai.com/v1"

Expand All @@ -51,64 +46,20 @@ fun Routing.genAIRoutes(
} else {
client.makeStreaming(call, "$openAiUrl/chat/completions", body, token)
}

//forwardToProvider(client, stream = isStream) //TODO
}

post("/embeddings") {
val token = call.getToken()
val context = call.receive<String>()
client.makeRequest(call, "$openAiUrl/embeddings", context, token)
}
}
}

private suspend fun HttpClient.makeRequest(
call: ApplicationCall,
url: String,
body: String,
token: Token
) {
val response = this.request(url) {
headers {
bearerAuth(token.value)
//forwardToProvider(client, stream = isStream) //TODO
}
contentType(ContentType.Application.Json)
method = HttpMethod.Post
setBody(body)
}
call.response.headers.copyFrom(response.headers)
call.respond(response.status, response.body<String>())
}

private suspend fun HttpClient.makeStreaming(
call: ApplicationCall,
url: String,
body: String,
token: Token
) {
this.preparePost(url) {
headers {
bearerAuth(token.value)
}
contentType(ContentType.Application.Json)
method = HttpMethod.Post
setBody(body)
}.execute { httpResponse ->
call.response.headers.copyFrom(httpResponse.headers)
call.respondOutputStream {
httpResponse
.bodyAsChannel()
.copyTo(this@respondOutputStream)
}
}
}

private fun ResponseHeaders.copyFrom(headers: Headers) = headers
.entries()
.filter { (key, _) -> !HttpHeaders.isUnsafe(key) } // setting unsafe headers results in exception
.forEach { (key, values) ->
values.forEach { value -> this.appendIfAbsent(key, value) }
}

private fun ApplicationCall.getProvider(): Provider =
request.headers["xef-provider"]?.toProvider()
?: Provider.OPENAI
Expand Down
Loading

0 comments on commit a9c1ad1

Please sign in to comment.