Skip to content

Commit

Permalink
achieved the mvp
Browse files Browse the repository at this point in the history
  • Loading branch information
itishermann committed Jun 25, 2024
1 parent 8a3a919 commit 8503fff
Show file tree
Hide file tree
Showing 18 changed files with 294 additions and 183 deletions.
6 changes: 2 additions & 4 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,8 @@ repositories {

// Dependencies are managed with Gradle version catalog - read more: https://docs.gradle.org/current/userguide/platforms.html#sub:version-catalog
dependencies {
// implementation(libs.exampleLibrary)
val ollama4jVersion = "1.0.73"

implementation("io.github.amithkoujalgi:ollama4j:$ollama4jVersion")
implementation(libs.ollama4j)
implementation(libs.javaDiffUtils)
}

// Set the JVM language level used to build the project.
Expand Down
7 changes: 5 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[versions]
# libraries
exampleLibrary = "24.1.0"
ollama4j = "1.0.73"
javaDiffUtils = "4.12"

# plugins
kotlin = "1.9.24"
Expand All @@ -10,7 +11,9 @@ qodana = "2024.1.5"
kover = "0.8.1"

[libraries]
exampleLibrary = { group = "com.example", name = "exampleLibrary", version.ref = "exampleLibrary" }
ollama4j = { group = "io.github.amithkoujalgi", name = "ollama4j", version.ref = "ollama4j" }
javaDiffUtils = { group = "io.github.java-diff-utils", name = "java-diff-utils", version.ref = "javaDiffUtils" }


[plugins]
changelog = { id = "org.jetbrains.changelog", version.ref = "changelog" }
Expand Down
20 changes: 0 additions & 20 deletions src/main/kotlin/me/itishermann/ollamacommitsummarizer/MyBundle.kt

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package me.itishermann.ollamacommitsummarizer.actions

import com.github.difflib.DiffUtils
import com.github.difflib.UnifiedDiffUtils
import com.github.difflib.patch.Patch
import com.github.weisj.jsvg.e

Check warning on line 6 in src/main/kotlin/me/itishermann/ollamacommitsummarizer/actions/GenerateCommitAction.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Unused import directive

Unused import directive
import com.intellij.notification.Notification
import com.intellij.notification.NotificationType
import com.intellij.notification.Notifications
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.service
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.progress.Task
import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.vcs.CommitMessageI
import com.intellij.openapi.vcs.VcsDataKeys
import com.intellij.openapi.vcs.VcsException
import com.intellij.openapi.vcs.changes.Change
import com.intellij.openapi.vcs.ui.Refreshable
import com.intellij.vcs.commit.AbstractCommitWorkflowHandler
import io.github.amithkoujalgi.ollama4j.core.OllamaStreamHandler
import io.github.amithkoujalgi.ollama4j.core.utils.OptionsBuilder
import me.itishermann.ollamacommitsummarizer.exceptions.NoChangeToCommitException
import me.itishermann.ollamacommitsummarizer.services.OllamaService
import me.itishermann.ollamacommitsummarizer.settings.OllamaSettingsState
import org.jetbrains.annotations.NotNull
import java.util.*


class GenerateCommitAction: AnAction(), DumbAware {
private var processing: Boolean = false

override fun actionPerformed(event: AnActionEvent) {
val commitPanel: CommitMessageI? = getVcsPanel(event)
if (commitPanel == null || processing) {
return
}
ProgressManager.getInstance().run(object : Task.Backgroundable(event.project, "Generating commit", false) {
override fun run(@NotNull indicator: ProgressIndicator) {
indicator.text = "Generating commit message"
processing = true
handleEvent(event, commitPanel, indicator)
}
})
}

private fun handleEvent(e: AnActionEvent, commitPanel: CommitMessageI, indicator: ProgressIndicator) {
val project = checkNotNull(e.project)
// get included changes
val abstractCommitWorkflowHandler =
e.dataContext.getData(VcsDataKeys.COMMIT_WORKFLOW_HANDLER) as AbstractCommitWorkflowHandler<*, *>?
?: return
val includedChanges = abstractCommitWorkflowHandler.ui.getIncludedChanges()
val baseDir = project.basePath
try {
val prompt = buildPrompt(includedChanges, baseDir!!)
generateCommitMessage(prompt, commitPanel, indicator)
} catch (e: NoChangeToCommitException) {
Notifications.Bus.notify(
Notification(
"me.itishermann.ollamacommitsummarizer.default",
"No changes to commit",
"There are no changes to commit, please include some changes to commit", NotificationType.INFORMATION
)
)
}
}

private fun generateCommitMessage(prompt: String, commitPanel: CommitMessageI, indicator: ProgressIndicator) {
val client = service<OllamaService>().getOllamaClient()
val modelName = OllamaSettingsState.instance.state.modelName
val streamHandler = OllamaStreamHandler { s: String? ->
ApplicationManager.getApplication().invokeLater {
indicator.fraction += 0.05
commitPanel.setCommitMessage(s)
}
}
val options = OptionsBuilder().setTemperature(1.5f).setTopP(0.9f).setTopK(40).build()
try {
client.generate(modelName, prompt, options, streamHandler)
processing = false
Notifications.Bus.notify(
Notification(
"me.itishermann.ollamacommitsummarizer.default",
"Commit message generated",
"The commit message has been generated successfully", NotificationType.INFORMATION
)
)
} catch (e: Exception) {
e.printStackTrace()
Notifications.Bus.notify(
Notification(
"me.itishermann.ollamacommitsummarizer.default",
"Ollama API error",
"An error occured while generating your commit message: ${e.localizedMessage ?: e.message}", NotificationType.ERROR
)
)
} finally {
processing = false
}
}

private fun buildPrompt(includedChanges: List<Change>, baseDir: String): String {
val totalUnifiedDiffs: MutableList<String> = ArrayList()
if(includedChanges.isEmpty()) {
throw NoChangeToCommitException("No changes to commit")
}
for (change in includedChanges) {
val beforeRevision = change.beforeRevision
val afterRevision = change.afterRevision
var beforeContent: String? = ""
var afterContent: String? = ""
try {
beforeContent = if (beforeRevision != null) beforeRevision.content else ""
afterContent = if (afterRevision != null) afterRevision.content else ""
} catch (e: VcsException) {
e.printStackTrace()
}
val original = Arrays.stream(beforeContent!!.split("\n".toRegex()).dropLastWhile { it.isEmpty() }
.toTypedArray()).toList()
val revised = Arrays.stream(afterContent!!.split("\n".toRegex()).dropLastWhile { it.isEmpty() }
.toTypedArray()).toList()
val patch: Patch<String> = DiffUtils.diff(original, revised)
val relativePath = change.virtualFile!!.path.replace(baseDir, "")
val unifiedDiff: List<String> =
UnifiedDiffUtils.generateUnifiedDiff(relativePath, relativePath, original, patch, 3)
totalUnifiedDiffs.addAll(unifiedDiff)
}
var prompt = OllamaSettingsState.instance.state.prompt ?: throw IllegalStateException("Prompt is null")
prompt = prompt.replace("{{gitDiff}}", java.lang.String.join("\n", totalUnifiedDiffs))
prompt = prompt.replace("{{fileCount}}", includedChanges.size.toString())
return prompt
}

private fun getVcsPanel(e: AnActionEvent?): CommitMessageI? {
if (e == null) {
return null
}
val data = Refreshable.PANEL_KEY.getData(e.dataContext)
if (data is CommitMessageI) {
return data
}
return VcsDataKeys.COMMIT_MESSAGE_CONTROL.getData(e.dataContext)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package me.itishermann.ollamacommitsummarizer.exceptions

class AiServiceUninitializedException(message: String) : Exception(message)

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package me.itishermann.ollamacommitsummarizer.exceptions

class NoChangeToCommitException(message: String) : Exception(message)

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package me.itishermann.ollamacommitsummarizer.interfaces

interface AiServiceInterface {

fun isServerReachable(): Boolean

fun ask(prompt: String, model: String, temperature: Float = 1.5f, topP: Float = 0.9f, topK: Int = 40): String
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package me.itishermann.ollamacommitsummarizer.listeners

import com.intellij.openapi.application.ApplicationActivationListener
import com.intellij.openapi.components.service
import com.intellij.openapi.diagnostic.thisLogger
import com.intellij.openapi.wm.IdeFrame
import io.github.amithkoujalgi.ollama4j.core.OllamaAPI
import me.itishermann.ollamacommitsummarizer.exceptions.AiServiceUninitializedException
import me.itishermann.ollamacommitsummarizer.services.OllamaService
import me.itishermann.ollamacommitsummarizer.settings.OllamaSettingsState

internal class ActivationListener : ApplicationActivationListener {

override fun applicationActivated(ideFrame: IdeFrame) {
try {
val client = service<OllamaService>().getOllamaClient()
client.ping()
thisLogger().info("API is reachable")
} catch (e: AiServiceUninitializedException) {
// initialize the service
val serverUrl = OllamaSettingsState.instance.state.serverUrl
val userName = OllamaSettingsState.instance.state.userName
val password = OllamaSettingsState.instance.state.password
val ollamaAPI = OllamaAPI(serverUrl)
ollamaAPI.setRequestTimeoutSeconds(60*60) // 1 hour
if(!userName.isNullOrEmpty() && !password.isNullOrEmpty()) {
ollamaAPI.setBasicAuth(userName, password)
}
// Comment before deploying
// ollamaAPI.setVerbose(true)
val ollamaService = service<OllamaService>()
ollamaService.setOllamaClient(ollamaAPI)
val isOllamaServerReachable = ollamaAPI.ping()
if(isOllamaServerReachable) {
thisLogger().info("API is reachable and initialized successfully")
} else {
thisLogger().warn("API is not reachable")
}
} catch (e: Exception) {
thisLogger().error("An error occurred: ${e.message}")
}
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package me.itishermann.ollamacommitsummarizer.services

import com.intellij.openapi.components.Service
import io.github.amithkoujalgi.ollama4j.core.OllamaAPI
import io.github.amithkoujalgi.ollama4j.core.utils.Options
import io.github.amithkoujalgi.ollama4j.core.utils.OptionsBuilder
import me.itishermann.ollamacommitsummarizer.exceptions.AiServiceUninitializedException
import me.itishermann.ollamacommitsummarizer.interfaces.AiServiceInterface

@Service
internal class OllamaService: AiServiceInterface {
private lateinit var client: OllamaAPI

fun getOllamaClient(): OllamaAPI {
if(!::client.isInitialized) {
throw AiServiceUninitializedException("Ollama client is not initialized")
}
return client
}

fun setOllamaClient(newClient: OllamaAPI) {
client = newClient
}

override fun isServerReachable(): Boolean {
if(!::client.isInitialized) {
throw AiServiceUninitializedException("Ollama client is not initialized")
}
return client.ping()
}

override fun ask(prompt: String, model: String, temperature: Float, topP: Float, topK: Int,): String {

Check notice on line 32 in src/main/kotlin/me/itishermann/ollamacommitsummarizer/services/OllamaService.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Trailing comma recommendations

Useless trailing comma
val options: Options =
OptionsBuilder()
.setNumGpu(2)
.setTemperature(temperature)
.setTopK(topK)
.setTopP(topP)
.build()
val result = client.generate(prompt, model, options)
return result.response
}
}
Loading

0 comments on commit 8503fff

Please sign in to comment.