diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 40811b5..ade8240 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -64,6 +64,10 @@ android {
exclude(group = "org.jetbrains", module = "annotations")
}
}
+ packaging {
+ resources.excludes.add("META-INF/INDEX.LIST")
+ resources.excludes.add("META-INF/io.netty.versions.properties")
+ }
}
ksp {
@@ -84,6 +88,7 @@ dependencies {
implementation(project(":smollm"))
implementation(project(":hf-model-hub-api"))
+ implementation(project(":smollm-server"))
// Koin: dependency injection
implementation(libs.koin.android)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ea94e63..f3b75b5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -43,6 +43,10 @@
+
\ No newline at end of file
diff --git a/app/src/main/java/io/shubham0204/smollmandroid/server/LlamaServerService.kt b/app/src/main/java/io/shubham0204/smollmandroid/server/LlamaServerService.kt
new file mode 100644
index 0000000..7830eca
--- /dev/null
+++ b/app/src/main/java/io/shubham0204/smollmandroid/server/LlamaServerService.kt
@@ -0,0 +1,28 @@
+package io.shubham0204.smollmandroid.server
+
+import android.app.Service
+import android.content.Intent
+import android.os.IBinder
+import io.shubham0204.smollm_server.LlamaServer
+
+class LlamaServerService : Service() {
+ private val llamaServer = LlamaServer()
+
+ override fun onBind(intent: Intent?): IBinder? {
+ TODO("Not yet implemented")
+ }
+
+ override fun onStartCommand(
+ intent: Intent?,
+ flags: Int,
+ startId: Int,
+ ): Int {
+ llamaServer.start()
+ return START_STICKY
+ }
+
+ override fun onDestroy() {
+ llamaServer.stop()
+ super.onDestroy()
+ }
+}
diff --git a/app/src/main/java/io/shubham0204/smollmandroid/ui/screens/chat/ChatActivity.kt b/app/src/main/java/io/shubham0204/smollmandroid/ui/screens/chat/ChatActivity.kt
index 3b5d887..3807d73 100644
--- a/app/src/main/java/io/shubham0204/smollmandroid/ui/screens/chat/ChatActivity.kt
+++ b/app/src/main/java/io/shubham0204/smollmandroid/ui/screens/chat/ChatActivity.kt
@@ -100,6 +100,7 @@ import androidx.navigation.compose.rememberNavController
import io.shubham0204.smollmandroid.R
import io.shubham0204.smollmandroid.data.Chat
import io.shubham0204.smollmandroid.data.Task
+import io.shubham0204.smollmandroid.server.LlamaServerService
import io.shubham0204.smollmandroid.ui.components.AppBarTitleText
import io.shubham0204.smollmandroid.ui.components.MediumLabelText
import io.shubham0204.smollmandroid.ui.screens.manage_tasks.ManageTasksActivity
@@ -143,6 +144,9 @@ class ChatActivity : ComponentActivity() {
}
}
+
+ startService(Intent(this, LlamaServerService::class.java))
+
setContent {
val navController = rememberNavController()
NavHost(
diff --git a/build.gradle.kts b/build.gradle.kts
index 0da250c..a11f4df 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -4,7 +4,7 @@ plugins {
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.kotlin.compose) apply false
alias(libs.plugins.android.library) apply false
- id("com.google.devtools.ksp") version "2.0.0-1.0.24" apply false
+ id("com.google.devtools.ksp") version "2.0.21-1.0.28" apply false
alias(libs.plugins.jetbrains.kotlin.jvm) apply false
- kotlin("plugin.serialization") version "2.1.0" apply false
+ kotlin("plugin.serialization") version "2.1.10" apply false
}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 9a84bd5..6adab9c 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -13,6 +13,8 @@ koin = "3.5.6"
koinAnnotations = "1.3.1"
jetbrainsKotlinJvm = "2.0.0"
uiTextGoogleFonts = "1.7.7"
+appcompat = "1.7.0"
+material = "1.12.0"
[libraries]
@@ -39,6 +41,8 @@ koin-androidx-compose = { module = "io.insert-koin:koin-androidx-compose", versi
koin-annotations = { module = "io.insert-koin:koin-annotations", version.ref = "koinAnnotations" }
koin-ksp-compiler = { module = "io.insert-koin:koin-ksp-compiler", version.ref = "koinAnnotations" }
androidx-ui-text-google-fonts = { group = "androidx.compose.ui", name = "ui-text-google-fonts", version.ref = "uiTextGoogleFonts" }
+androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
+material = { group = "com.google.android.material", name = "material", version.ref = "material" }
[plugins]
diff --git a/hf-model-hub-api/build.gradle.kts b/hf-model-hub-api/build.gradle.kts
index 17f6eb8..ae26015 100644
--- a/hf-model-hub-api/build.gradle.kts
+++ b/hf-model-hub-api/build.gradle.kts
@@ -1,7 +1,7 @@
plugins {
id("java-library")
alias(libs.plugins.jetbrains.kotlin.jvm)
- kotlin("plugin.serialization") version "2.1.0"
+ kotlin("plugin.serialization") version "2.1.10"
}
val ktorVersion = "3.0.2"
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 5fecc55..13c41fd 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,5 +1,8 @@
import java.net.URI
+include(":smollm-server")
+
+
include(":hf-model-hub-api")
diff --git a/smollm-server/.gitignore b/smollm-server/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/smollm-server/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/smollm-server/build.gradle.kts b/smollm-server/build.gradle.kts
new file mode 100644
index 0000000..d2056a0
--- /dev/null
+++ b/smollm-server/build.gradle.kts
@@ -0,0 +1,59 @@
+plugins {
+ alias(libs.plugins.android.library)
+ alias(libs.plugins.kotlin.android)
+ kotlin("plugin.serialization") version "2.1.10"
+ id("com.google.devtools.ksp")
+}
+
+android {
+ namespace = "io.shubham0204.smollm_server"
+ compileSdk = 35
+
+ defaultConfig {
+ minSdk = 24
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles("consumer-rules.pro")
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro",
+ )
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_21
+ targetCompatibility = JavaVersion.VERSION_21
+ }
+ kotlinOptions {
+ jvmTarget = "21"
+ }
+}
+
+val ktorVersion = "3.0.3"
+
+dependencies {
+ implementation(libs.androidx.core.ktx)
+ implementation(libs.androidx.appcompat)
+ implementation(libs.material)
+
+ // Ktor server
+ implementation("io.ktor:ktor-server-core:$ktorVersion")
+ implementation("io.ktor:ktor-server-netty:$ktorVersion")
+
+ // kotlinx serialization (JSON) and
+ // content-negotiation
+ // docs: https://ktor.io/docs/server-serialization.html
+ implementation("io.ktor:ktor-server-content-negotiation:$ktorVersion")
+ implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion")
+
+ implementation(project(":smollm"))
+
+ testImplementation(libs.junit)
+ androidTestImplementation(libs.androidx.junit)
+ androidTestImplementation(libs.androidx.espresso.core)
+}
diff --git a/smollm-server/consumer-rules.pro b/smollm-server/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/smollm-server/proguard-rules.pro b/smollm-server/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/smollm-server/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/smollm-server/src/androidTest/java/io/shubham0204/smollm_server/ExampleInstrumentedTest.kt b/smollm-server/src/androidTest/java/io/shubham0204/smollm_server/ExampleInstrumentedTest.kt
new file mode 100644
index 0000000..c256160
--- /dev/null
+++ b/smollm-server/src/androidTest/java/io/shubham0204/smollm_server/ExampleInstrumentedTest.kt
@@ -0,0 +1,24 @@
+package io.shubham0204.smollm_server
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+ @Test
+ fun useAppContext() {
+ // Context of the app under test.
+ val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+ assertEquals("io.shubham0204.smollm_server.test", appContext.packageName)
+ }
+}
\ No newline at end of file
diff --git a/smollm-server/src/main/AndroidManifest.xml b/smollm-server/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..a5918e6
--- /dev/null
+++ b/smollm-server/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/smollm-server/src/main/java/io/shubham0204/smollm_server/LlamaServer.kt b/smollm-server/src/main/java/io/shubham0204/smollm_server/LlamaServer.kt
new file mode 100644
index 0000000..e72baf7
--- /dev/null
+++ b/smollm-server/src/main/java/io/shubham0204/smollm_server/LlamaServer.kt
@@ -0,0 +1,78 @@
+package io.shubham0204.smollm_server
+
+import io.ktor.http.HttpStatusCode
+import io.ktor.serialization.kotlinx.json.json
+import io.ktor.server.application.Application
+import io.ktor.server.application.install
+import io.ktor.server.engine.connector
+import io.ktor.server.engine.embeddedServer
+import io.ktor.server.netty.Netty
+import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
+import io.ktor.server.request.receive
+import io.ktor.server.response.respond
+import io.ktor.server.routing.get
+import io.ktor.server.routing.post
+import io.ktor.server.routing.route
+import io.ktor.server.routing.routing
+import io.shubham0204.smollm_server.models.OpenAIChatCompletionRequest
+import kotlinx.serialization.json.Json
+
+class LlamaServer {
+ private val server =
+ embeddedServer(
+ factory = Netty,
+ configure = {
+ connector {
+ port = 8080
+ }
+ },
+ ) {
+ setupPlugins()
+ setupRoutes()
+ }
+
+ fun start() {
+ server.start(wait = false)
+ }
+
+ fun stop() {
+ server.stop()
+ }
+
+ private fun Application.setupPlugins() {
+ // install content-negotiation and
+ // configure JSON serializer
+ // docs: https://ktor.io/docs/server-serialization.html#install_plugin
+ // https://ktor.io/docs/server-serialization.html#register_xml
+ install(ContentNegotiation) {
+ json(
+ Json {
+ isLenient = true
+ prettyPrint = true
+ },
+ )
+ }
+ }
+
+ private fun Application.setupRoutes() {
+ routing {
+ get {
+ call.respond(HttpStatusCode.OK, "Hello, world!")
+ }
+ route("v1") {
+ route("chat") {
+ post("completions") {
+ val request = call.receive()
+ }
+ }
+ get("/echo") {
+ val message =
+ call.queryParameters["message"] ?: call.respond(HttpStatusCode.BadRequest)
+ call.respond(HttpStatusCode.OK, message)
+ }
+ get("/models") {
+ }
+ }
+ }
+ }
+}
diff --git a/smollm-server/src/main/java/io/shubham0204/smollm_server/models/OpenAIChatCompletionRequest.kt b/smollm-server/src/main/java/io/shubham0204/smollm_server/models/OpenAIChatCompletionRequest.kt
new file mode 100644
index 0000000..7de1342
--- /dev/null
+++ b/smollm-server/src/main/java/io/shubham0204/smollm_server/models/OpenAIChatCompletionRequest.kt
@@ -0,0 +1,25 @@
+package io.shubham0204.smollm_server.models
+
+import kotlinx.serialization.Serializable
+
+/**
+ * Represents a message in the OpenAI Chat Completion API
+ * docs: https://platform.openai.com/docs/api-reference/chat/create#chat-create-messages
+ */
+@Serializable
+data class ChatCompletionMessage(
+ val role: String,
+ val content: String,
+)
+
+/**
+ * Represents the request for the OpenAI Chat Completion API
+ * docs: https://platform.openai.com/docs/api-reference/chat/create
+ */
+@Serializable
+data class OpenAIChatCompletionRequest(
+ val messages: List,
+ val model: String,
+ val topP: Float = 1.0f,
+ val temperature: Float = 1.0f,
+)
diff --git a/smollm-server/src/main/java/io/shubham0204/smollm_server/models/OpenAIModel.kt b/smollm-server/src/main/java/io/shubham0204/smollm_server/models/OpenAIModel.kt
new file mode 100644
index 0000000..2bc6992
--- /dev/null
+++ b/smollm-server/src/main/java/io/shubham0204/smollm_server/models/OpenAIModel.kt
@@ -0,0 +1,16 @@
+package io.shubham0204.smollm_server.models
+
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+
+/**
+ * OpenAI Model object, representing a LLM model available for inference
+ * docs: https://platform.openai.com/docs/api-reference/models/object
+ */
+@Serializable
+data class OpenAIModel(
+ val id: String,
+ val created: Long,
+ @SerialName("object") val object_: String = "model", // `object` is a reserved word in Kotlin
+ @SerialName("owned_by") val ownedBy: String,
+)
diff --git a/smollm-server/src/test/java/io/shubham0204/smollm_server/ExampleUnitTest.kt b/smollm-server/src/test/java/io/shubham0204/smollm_server/ExampleUnitTest.kt
new file mode 100644
index 0000000..decc876
--- /dev/null
+++ b/smollm-server/src/test/java/io/shubham0204/smollm_server/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package io.shubham0204.smollm_server
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file