Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New api version for plugin #13

Merged
merged 1 commit into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions src/main/kotlin/OSSLLMCompletionProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,29 @@ import com.github.bzz.intellij.requests.Requester
import com.intellij.codeInsight.inline.completion.InlineCompletionElement
import com.intellij.codeInsight.inline.completion.InlineCompletionProvider
import com.intellij.codeInsight.inline.completion.InlineCompletionRequest
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.event.DocumentEvent
import org.jetbrains.annotations.ApiStatus

@ApiStatus.Experimental
class OSSLLMCompletionProvider : InlineCompletionProvider {

override suspend fun getProposals(request: InlineCompletionRequest): List<InlineCompletionElement> {
private val logger = Logger.getInstance("(when autocompleting)")

override suspend fun getProposals(request: InlineCompletionRequest): List<InlineCompletionElement> =
try {
val caretPosition = request.startOffset
val proposal = Requester.getModelSuggestions(
val proposals = Requester.getModelSuggestions(
request.document.text.substring(0, caretPosition)
).text ?: return emptyList()
return listOf(InlineCompletionElement(proposal))
)
proposals.results.map { InlineCompletionElement(it.text) }
} catch (knownException: Requester.RequesterException) {
thisLogger().warn(knownException.message)
return emptyList()
logger.warn(knownException.message)
emptyList()
} catch (exception: Exception) {
thisLogger().warn("Unknown exception. Message: ${exception.message}")
return emptyList()
logger.warn("Unknown exception. Message: ${exception.message}")
emptyList()
}
}

override fun isEnabled(event: DocumentEvent): Boolean {
return true
Expand Down
7 changes: 5 additions & 2 deletions src/main/kotlin/com/github/bzz/intellij/actions/TestAction.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ class TestAction: AnAction() {

val editor = event.getRequiredData(CommonDataKeys.EDITOR)
val caretPosition = editor.caretModel.primaryCaret.selectionStart
logger.warn(Requester.getModelSuggestions(editor.document.text).text?.substring(0, caretPosition))
logger.warn(
Requester.getModelSuggestions(editor.document.text.substring(0, caretPosition)).
results.firstOrNull()?.text ?: "---"
)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,30 @@
package com.github.bzz.intellij.com.github.bzz.intellij.models

import com.github.bzz.intellij.requests.Requester
import com.intellij.openapi.diagnostic.Logger
import java.util.concurrent.atomic.AtomicInteger


object AvailableModels {

val currentModelIndex = AtomicInteger(0)

val modelsList: List<String> = listOf("proxy-model", "other proxy-model")
private val logger = Logger.getInstance("(getting available models)")

private fun getAvailableModels(): List<String> =
try {
Requester.getAvailableModels().models.map { it.modelName }
} catch (knownException: Requester.RequesterException) {
logger.warn(knownException.message)
emptyList()
} catch (otherException: Requester.RequesterException) {
logger.warn("Unknown exception. Message: ${otherException.message}")
emptyList()
}

val modelsList: List<String> = getAvailableModels()

fun currentModel() : String? {
return modelsList.getOrNull(currentModelIndex.get())
}
}
34 changes: 34 additions & 0 deletions src/main/kotlin/com/github/bzz/intellij/requests/JsonData.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.github.bzz.intellij.com.github.bzz.intellij.requests

import com.google.gson.annotations.SerializedName
import kotlinx.serialization.Serializable


@Serializable
data class ServerProposal (
val text: String
)

@Serializable
data class ProposalsResponse (
val results: List<ServerProposal>
)

@Serializable
data class LLMModel (
@SerializedName("model_name")
val modelName: String
)

@Serializable
data class ModelsResponse(
val models: List<LLMModel>
)

@Serializable
data class ProposalsQuery(
val model: String,
val prompt: String,
@SerializedName("max_new_tokens")
val maxNewTokens: Int
)
55 changes: 41 additions & 14 deletions src/main/kotlin/com/github/bzz/intellij/requests/Requester.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package com.github.bzz.intellij.requests

import com.github.bzz.intellij.com.github.bzz.intellij.requests.ServerResponse
import com.github.bzz.intellij.com.github.bzz.intellij.models.AvailableModels
import com.github.bzz.intellij.com.github.bzz.intellij.requests.ModelsResponse
import com.github.bzz.intellij.com.github.bzz.intellij.requests.ProposalsQuery
import com.github.bzz.intellij.com.github.bzz.intellij.requests.ProposalsResponse
import com.google.gson.Gson
import com.google.gson.JsonSyntaxException
import java.io.IOException
import java.net.URI
import java.net.http.HttpClient
Expand All @@ -11,30 +15,56 @@ import java.net.http.HttpTimeoutException


object Requester {

const val MAX_TOKEN_LENGTH = 10
open class RequesterException(message: String): RuntimeException("RequesterException: $message")

private class NoListenerRequesterException(ip: String, port: Int):
RequesterException("Probable cause: server $ip is not running or listening at port $port.")

private class TimeoutRequesterException():
RequesterException("Probable cause: new model is being downloaded currently.")
private class TimeoutRequesterException:
RequesterException("Probable cause: poor connection.")

private class GeneralRequesterException(ip: String, port: Int, httpStatus: Int):
RequesterException("HTTP Request to $ip:$port failed. Failure status code: $httpStatus")

private class LocationMissingException(ip: String):
RequesterException("Redirect response from $ip is missing Location header")
private class JsonRequesterException(ip: String, port: Int, answer: String?):
RequesterException("Response from $ip:$port has incompatible json: $answer")

private class NoLoadedLLMException:
RequesterException("No LLM is chosen due to the absence of any.")


private val client = HttpClient.newBuilder().build()

fun getModelSuggestions(context: String, ip: String = "localhost", port: Int = 8000): ServerResponse {
fun getAvailableModels(ip: String = "localhost", port: Int = 8000): ModelsResponse {
val request = HttpRequest.newBuilder()
.uri(URI.create("http://$ip:$port"))
.GET()
.timeout(java.time.Duration.ofSeconds(10))
.build()

return serverQuery(ip, port, request, ModelsResponse::class.java)
}

fun getModelSuggestions(context: String, ip: String = "localhost", port: Int = 8000): ProposalsResponse {
val queryParams = ProposalsQuery(
model = AvailableModels.currentModel() ?: throw NoLoadedLLMException(),
prompt = context,
maxNewTokens = MAX_TOKEN_LENGTH
)
val json = Gson().toJson(queryParams)
val request = HttpRequest.newBuilder()
.uri(URI.create("http://$ip:$port"))
.POST(HttpRequest.BodyPublishers.ofString(context))
.POST(HttpRequest.BodyPublishers.ofString(json))
.header("Content-type", "application/json")
.timeout(java.time.Duration.ofSeconds(10))
.build()

return serverQuery(ip, port, request, ProposalsResponse::class.java)
}

private fun <T> serverQuery(ip: String, port: Int, request: HttpRequest, serializableClass: Class<T>): T {
val response = try {
client.send(request, HttpResponse.BodyHandlers.ofString())
} catch(toe: HttpTimeoutException) {
Expand All @@ -44,13 +74,10 @@ object Requester {
}

return when (response.statusCode()) {
200 -> Gson().fromJson(response.body(), ServerResponse::class.java)
301, 302, 303, 307 -> {
val newLocation = response.headers().firstValue("Location")
.orElseThrow {
LocationMissingException(ip)
}
getModelSuggestions(context, newLocation)
200 -> try {
Gson().fromJson(response.body(), serializableClass)
} catch(jsonException: JsonSyntaxException) {
throw JsonRequesterException(ip, port, response.body())
}
else -> throw GeneralRequesterException(ip, port, response.statusCode())
}
Expand Down

This file was deleted.

Loading