@@ -8,8 +8,6 @@ import com.intellij.openapi.application.runReadAction
88import com.intellij.openapi.components.Service
99import com.intellij.openapi.components.service
1010import com.intellij.openapi.editor.Editor
11- import com.intellij.openapi.fileEditor.FileDocumentManager
12- import com.intellij.openapi.util.SystemInfo
1311import com.intellij.util.Alarm
1412import com.intellij.util.AlarmFactory
1513import kotlinx.coroutines.Job
@@ -18,20 +16,11 @@ import org.apache.commons.collections4.queue.CircularFifoQueue
1816import software.aws.toolkits.jetbrains.core.coroutines.EDT
1917import software.aws.toolkits.jetbrains.core.coroutines.applicationCoroutineScope
2018import software.aws.toolkits.jetbrains.services.amazonq.CodeWhispererFeatureConfigService
21- import software.aws.toolkits.jetbrains.services.codewhisperer.editor.CodeWhispererEditorUtil
22- import software.aws.toolkits.jetbrains.services.codewhisperer.language.languages.CodeWhispererUnknownLanguage
23- import software.aws.toolkits.jetbrains.services.codewhisperer.language.programmingLanguage
2419import software.aws.toolkits.jetbrains.services.codewhisperer.model.LatencyContext
25- import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.CodeWhispererTelemetryService
26- import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.CodeWhispererTelemetryServiceNew
27- import software.aws.toolkits.telemetry.CodewhispererAutomatedTriggerType
2820import software.aws.toolkits.telemetry.CodewhispererPreviousSuggestionState
2921import software.aws.toolkits.telemetry.CodewhispererTriggerType
3022import java.time.Duration
3123import java.time.Instant
32- import kotlin.math.exp
33-
34- data class ClassifierResult (val shouldTrigger : Boolean , val calculatedResult : Double = 0.0 )
3524
3625@Service
3726class CodeWhispererAutoTriggerService : CodeWhispererAutoTriggerHandler , Disposable {
@@ -47,38 +36,9 @@ class CodeWhispererAutoTriggerService : CodeWhispererAutoTriggerHandler, Disposa
4736 scheduleReset()
4837 }
4938
50- fun addPreviousDecision (decision : CodewhispererPreviousSuggestionState ) {
51- previousUserTriggerDecisions.add(decision)
52- }
53-
54- // a util wrapper
55- fun tryInvokeAutoTrigger (editor : Editor , triggerType : CodeWhispererAutomatedTriggerType ): Job ? {
56- // only needed for Classifier group, thus calculate it lazily
57- timeAtLastCharTyped = System .nanoTime()
58- val classifierResult: ClassifierResult by lazy { shouldTriggerClassifier(editor, triggerType.telemetryType) }
59-
60- // we need classifier result for any type of triggering for classifier group for supported languages
61- triggerType.calculationResult = classifierResult.calculatedResult
62-
63- return when (triggerType) {
64- // only invoke service if result > threshold for classifier trigger
65- is CodeWhispererAutomatedTriggerType .Classifier -> run {
66- if (classifierResult.shouldTrigger) {
67- invoke(editor, triggerType)
68- } else {
69- null
70- }
71- }
72-
73- // invoke whatever the result is for char / enter based trigger
74- else -> run {
75- invoke(editor, triggerType)
76- }
77- }
78- }
79-
8039 // real auto trigger logic
8140 fun invoke (editor : Editor , triggerType : CodeWhispererAutomatedTriggerType ): Job ? {
41+ timeAtLastCharTyped = System .nanoTime()
8242 if (! (
8343 if (CodeWhispererFeatureConfigService .getInstance().getNewAutoTriggerUX()) {
8444 CodeWhispererServiceNew .getInstance().canDoInvocation(editor, CodewhispererTriggerType .AutoTrigger )
@@ -120,203 +80,9 @@ class CodeWhispererAutoTriggerService : CodeWhispererAutoTriggerHandler, Disposa
12080 }
12181 }
12282
123- fun shouldTriggerClassifier (
124- editor : Editor ,
125- automatedTriggerType : CodewhispererAutomatedTriggerType = CodewhispererAutomatedTriggerType .Classifier , // TODO: need this?
126- ): ClassifierResult {
127- val caretContext = runReadAction { CodeWhispererEditorUtil .extractCaretContext(editor) }
128- val language = runReadAction {
129- FileDocumentManager .getInstance().getFile(editor.document)?.programmingLanguage()
130- } ? : CodeWhispererUnknownLanguage .INSTANCE
131- val caretPosition = runReadAction { CodeWhispererEditorUtil .getCaretPosition(editor) }
132-
133- val leftContextLines = caretContext.leftFileContext.split(Regex (" \r ?\n " ))
134- val leftContextLength = caretContext.leftFileContext.length
135- val leftContextAtCurrentLine = if (leftContextLines.size - 1 >= 0 ) leftContextLines[leftContextLines.size - 1 ] else " "
136- var keyword = " "
137- val lastToken = leftContextAtCurrentLine.trim().split(" " ).let { tokens ->
138- if (tokens.size - 1 >= 0 ) tokens[tokens.size - 1 ] else " "
139- }
140- if (lastToken.length > 1 ) keyword = lastToken
141-
142- val lengthOfLeftCurrent = leftContextAtCurrentLine.length
143- val lengthOfLeftPrev = if (leftContextLines.size - 2 >= 0 ) {
144- leftContextLines[leftContextLines.size - 2 ].length.toDouble()
145- } else {
146- 0.0
147- }
148-
149- val rightContext = caretContext.rightFileContext
150- val lengthOfRight = rightContext.trim().length
151-
152- val triggerTypeCoefficient = CodeWhispererClassifierConstants .triggerTypeCoefficientMap[automatedTriggerType] ? : 0.0
153-
154- val osCoefficient: Double = if (SystemInfo .isMac) {
155- CodeWhispererClassifierConstants .osMap[" Mac OS X" ] ? : 0.0
156- } else if (SystemInfo .isWindows) {
157- val osVersion = SystemInfo .OS_VERSION
158- if (osVersion.contains(" 11" , true ) || osVersion.contains(" 10" , true )) {
159- CodeWhispererClassifierConstants .osMap[" Windows 10" ]
160- } else {
161- CodeWhispererClassifierConstants .osMap[" Windows" ]
162- }
163- } else {
164- 0.0
165- } ? : 0.0
166-
167- val lastCharCoefficient = if (leftContextAtCurrentLine.length - 1 >= 0 ) {
168- CodeWhispererClassifierConstants .coefficientsMap[leftContextAtCurrentLine[leftContextAtCurrentLine.length - 1 ].toString()] ? : 0.0
169- } else {
170- 0.0
171- }
172-
173- val keywordCoefficient = CodeWhispererClassifierConstants .coefficientsMap[keyword] ? : 0.0
174- val averageLanguageCoefficient = CodeWhispererClassifierConstants .languageMap.values.average()
175- val languageCoefficient = CodeWhispererClassifierConstants .languageMap[language] ? : averageLanguageCoefficient
176- val ideCoefficient = 0.0
177-
178- var previousOneAccept: Double = 0.0
179- var previousOneReject: Double = 0.0
180- var previousOneOther: Double = 0.0
181- val previousOneDecision =
182- if (CodeWhispererFeatureConfigService .getInstance().getNewAutoTriggerUX()) {
183- CodeWhispererTelemetryServiceNew .getInstance().previousUserTriggerDecision
184- } else {
185- CodeWhispererTelemetryService .getInstance().previousUserTriggerDecision
186- }
187- if (previousOneDecision == null ) {
188- previousOneAccept = 0.0
189- previousOneReject = 0.0
190- previousOneOther = 0.0
191- } else {
192- previousOneAccept =
193- if (previousOneDecision == CodewhispererPreviousSuggestionState .Accept ) {
194- CodeWhispererClassifierConstants .prevDecisionAcceptCoefficient
195- } else {
196- 0.0
197- }
198- previousOneReject =
199- if (previousOneDecision == CodewhispererPreviousSuggestionState .Reject ) {
200- CodeWhispererClassifierConstants .prevDecisionRejectCoefficient
201- } else {
202- 0.0
203- }
204- previousOneOther =
205- if (
206- previousOneDecision != CodewhispererPreviousSuggestionState .Accept &&
207- previousOneDecision != CodewhispererPreviousSuggestionState .Reject
208- ) {
209- CodeWhispererClassifierConstants .prevDecisionOtherCoefficient
210- } else {
211- 0.0
212- }
213- }
214-
215- var leftContextLengthCoefficient: Double = 0.0
216-
217- leftContextLengthCoefficient = when (leftContextLength) {
218- in 0 .. 4 -> CodeWhispererClassifierConstants .lengthLeft0To5
219- in 5 .. 9 -> CodeWhispererClassifierConstants .lengthLeft5To10
220- in 10 .. 19 -> CodeWhispererClassifierConstants .lengthLeft10To20
221- in 20 .. 29 -> CodeWhispererClassifierConstants .lengthLeft20To30
222- in 30 .. 39 -> CodeWhispererClassifierConstants .lengthLeft30To40
223- in 40 .. 49 -> CodeWhispererClassifierConstants .lengthLeft40To50
224- else -> 0.0
225- }
226-
227- val normalizedLengthOfRight = CodeWhispererClassifierConstants .lengthofRightCoefficient * VariableTypeNeedNormalize .LenRight .normalize(
228- lengthOfRight.toDouble()
229- )
230-
231- val normalizedLengthOfLeftCurrent = CodeWhispererClassifierConstants .lengthOfLeftCurrentCoefficient * VariableTypeNeedNormalize .LenLeftCur .normalize(
232- lengthOfLeftCurrent.toDouble()
233- )
234-
235- val normalizedLengthOfPrev = CodeWhispererClassifierConstants .lengthOfLeftPrevCoefficient * VariableTypeNeedNormalize .LenLeftPrev .normalize(
236- lengthOfLeftPrev
237- )
238-
239- val normalizedLineNum = CodeWhispererClassifierConstants .lineNumCoefficient * VariableTypeNeedNormalize .LineNum .normalize(caretPosition.line.toDouble())
240-
241- val intercept = CodeWhispererClassifierConstants .intercept
242-
243- val resultBeforeSigmoid =
244- normalizedLengthOfRight +
245- normalizedLengthOfLeftCurrent +
246- normalizedLengthOfPrev +
247- normalizedLineNum +
248- languageCoefficient +
249- osCoefficient +
250- triggerTypeCoefficient +
251- lastCharCoefficient +
252- keywordCoefficient +
253- ideCoefficient +
254- previousOneAccept +
255- previousOneReject +
256- previousOneOther +
257- leftContextLengthCoefficient +
258- intercept
259-
260- val shouldTrigger = sigmoid(resultBeforeSigmoid) > getThreshold()
261-
262- return ClassifierResult (shouldTrigger, sigmoid(resultBeforeSigmoid))
263- }
264-
26583 override fun dispose () {}
26684
26785 companion object {
268- private const val triggerThreshold: Double = 0.43
269-
27086 fun getInstance (): CodeWhispererAutoTriggerService = service()
271-
272- fun getThreshold (): Double = triggerThreshold
273-
274- fun sigmoid (x : Double ): Double = 1 / (1 + exp(- x))
275- }
276- }
277-
278- private enum class VariableTypeNeedNormalize {
279- Cursor {
280- override fun normalize (value : Double ): Double = 0.0
281- },
282- LineNum {
283- override fun normalize (value : Double ): Double = (value - minn.lineNum) / (maxx.lineNum - minn.lineNum)
284- },
285- LenLeftCur {
286- override fun normalize (value : Double ): Double = (value - minn.lenLeftCur) / (maxx.lenLeftCur - minn.lenLeftCur)
287- },
288- LenLeftPrev {
289- override fun normalize (value : Double ): Double = (value - minn.lenLeftPrev) / (maxx.lenLeftPrev - minn.lenLeftPrev)
290- },
291- LenRight {
292- override fun normalize (value : Double ): Double = (value - minn.lenRight) / (maxx.lenRight - minn.lenRight)
293- },
294- LineDiff {
295- override fun normalize (value : Double ): Double = 0.0
296- }, ;
297-
298- abstract fun normalize (toDouble : Double ): Double
299-
300- data class NormalizedCoefficients (
301- val lineNum : Double ,
302- val lenLeftCur : Double ,
303- val lenLeftPrev : Double ,
304- val lenRight : Double ,
305- )
306-
307- companion object {
308- private val maxx = NormalizedCoefficients (
309- lineNum = 4631.0 ,
310- lenLeftCur = 157.0 ,
311- lenLeftPrev = 176.0 ,
312- lenRight = 10239.0 ,
313- )
314-
315- private val minn = NormalizedCoefficients (
316- lineNum = 0.0 ,
317- lenLeftCur = 0.0 ,
318- lenLeftPrev = 0.0 ,
319- lenRight = 0.0 ,
320- )
32187 }
32288}
0 commit comments