Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
pse-trapp-public
IntentFinder
Commits
439f439a
Commit
439f439a
authored
May 05, 2021
by
Patrick Schlindwein
Browse files
Feat/
#8
implement ktor business logic
parent
22bc4d53
Changes
11
Hide whitespace changes
Inline
Side-by-side
.gitignore
View file @
439f439a
...
@@ -7,3 +7,5 @@ src/ktor-server/.idea/compiler.xml
...
@@ -7,3 +7,5 @@ src/ktor-server/.idea/compiler.xml
src/ktor-server/.idea/gradle.xml
src/ktor-server/.idea/gradle.xml
src/ktor-server/.idea/ktor-server.iml
src/ktor-server/.idea/ktor-server.iml
src/ktor-server/.idea/misc.xml
src/ktor-server/.idea/misc.xml
.idea/
.gradle/
\ No newline at end of file
src/ktor-server/.gitignore
View file @
439f439a
...
@@ -5,4 +5,5 @@
...
@@ -5,4 +5,5 @@
.idea/**/usage.statistics.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/dictionaries
.idea/**/shelf
.idea/**/shelf
.idea
build
build
src/ktor-server/build.gradle
View file @
439f439a
...
@@ -17,11 +17,16 @@ repositories {
...
@@ -17,11 +17,16 @@ repositories {
}
}
dependencies
{
dependencies
{
implementation
"io.ktor:ktor-gson:$ktor_version"
implementation
"io.ktor:ktor-server-core:$ktor_version"
implementation
"io.ktor:ktor-server-core:$ktor_version"
implementation
"io.ktor:ktor-server-netty:$ktor_version"
implementation
"io.ktor:ktor-server-netty:$ktor_version"
implementation
"io.ktor:ktor-serialization:$ktor_version"
implementation
"io.ktor:ktor-serialization:$ktor_version"
implementation
"org.jetbrains.kotlinx:kotlinx-serialization-core:$kotlin_serialization"
implementation
"org.jetbrains.kotlinx:kotlinx-serialization-core:$kotlin_serialization"
implementation
'com.squareup.retrofit2:retrofit:2.7.0'
implementation
'com.squareup.retrofit2:converter-gson:2.7.0'
implementation
'com.squareup.okhttp3:okhttp:4.3.1'
// tests
// tests
testImplementation
(
platform
(
'org.junit:junit-bom:5.7.1'
))
testImplementation
(
platform
(
'org.junit:junit-bom:5.7.1'
))
testImplementation
(
'org.junit.jupiter:junit-jupiter'
)
testImplementation
(
'org.junit.jupiter:junit-jupiter'
)
...
@@ -51,6 +56,10 @@ dependencies {
...
@@ -51,6 +56,10 @@ dependencies {
// for html parsing or scraping
// for html parsing or scraping
// https://mvnrepository.com/artifact/org.jsoup/jsoup
// https://mvnrepository.com/artifact/org.jsoup/jsoup
implementation
group:
'org.jsoup'
,
name:
'jsoup'
,
version:
'1.13.1'
implementation
group:
'org.jsoup'
,
name:
'jsoup'
,
version:
'1.13.1'
testImplementation
'com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0'
//Mockito-Kotlin
testImplementation
'org.mockito:mockito-inline:2.21.0'
testImplementation
'org.hamcrest:hamcrest:2.2'
}
}
compileKotlin
{
compileKotlin
{
...
...
src/ktor-server/src/main/kotlin/de/h_da/fbi/smebt/intentfinder/server/Application.kt
View file @
439f439a
...
@@ -7,6 +7,7 @@ import io.ktor.features.*
...
@@ -7,6 +7,7 @@ import io.ktor.features.*
import
io.ktor.response.*
import
io.ktor.response.*
import
io.ktor.routing.*
import
io.ktor.routing.*
import
io.ktor.serialization.*
import
io.ktor.serialization.*
import
kotlinx.serialization.json.Json
import
registerUploadRoutes
import
registerUploadRoutes
...
@@ -14,12 +15,15 @@ fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args)
...
@@ -14,12 +15,15 @@ fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args)
fun
Application
.
module
()
{
fun
Application
.
module
()
{
install
(
ContentNegotiation
)
{
install
(
ContentNegotiation
)
{
json
()
json
(
Json
{
prettyPrint
=
true
})
}
}
routing
{
routing
{
get
(
"/summary"
)
{
get
(
"/summary"
)
{
val
response
=
PythonBridge
().
getSummary
(
"test bridge"
)
val
response
=
PythonBridge
().
getSummary
(
"test bridge"
)
call
.
respond
Text
(
response
)
call
.
respond
(
response
)
}
}
get
(
"/"
)
{
get
(
"/"
)
{
call
.
respondText
(
"IntentFinder is available"
)
call
.
respondText
(
"IntentFinder is available"
)
...
...
src/ktor-server/src/main/kotlin/de/h_da/fbi/smebt/intentfinder/server/nlp/PythonBridge.kt
View file @
439f439a
package
de.h_da.fbi.smebt.intentfinder.server.nlp
package
de.h_da.fbi.smebt.intentfinder.server.nlp
import
io.ktor.client.*
import
de.h_da.fbi.smebt.intentfinder.server.nlp.client.RetrofitClient
import
io.ktor.client.engine.cio.*
import
de.h_da.fbi.smebt.intentfinder.server.nlp.dto.Summary
import
io.ktor.client.request.*
import
java.util.*
import
io.ktor.client.request.forms.*
import
java.util.concurrent.ExecutionException
import
io.ktor.client.statement.*
import
java.util.concurrent.ExecutorCompletionService
import
io.ktor.http.*
import
java.util.concurrent.Executors
import
io.ktor.http.content.*
import
kotlin.collections.ArrayList
class
PythonBridge
:
AutoCloseable
{
class
PythonBridge
(
private
val
client
:
RetrofitClient
=
RetrofitClient
())
{
private
val
httpClient
=
HttpClient
(
CIO
)
companion
object
{
private
fun
getAllSummaries
(
text
:
String
):
List
<
Summary
>
{
const
val
NLP_ENDPOINT
=
"http://127.0.0.1:8000"
val
strategies
=
client
.
getStrategies
()
}
val
executor
=
Executors
.
newFixedThreadPool
(
strategies
.
size
)
val
completionService
=
ExecutorCompletionService
<
Summary
>(
executor
)
strategies
.
forEach
{
completionService
.
submit
{
client
.
getSummary
(
it
.
name
,
text
)
}
}
val
summaries
=
ArrayList
<
Summary
>()
repeat
(
strategies
.
size
)
{
try
{
val
result
=
completionService
.
take
()
summaries
.
add
(
result
.
get
())
}
catch
(
ex
:
ExecutionException
)
{
// TODO handle ExecutionException
}
}
suspend
fun
getSummary
(
text
:
String
):
String
{
return
summaries
// options see https://ktor.io/docs/response.html#receive and https://kotlinlang.org/docs/mobile/use-ktor-for-networking.html
val
response
=
httpClient
.
post
<
HttpResponse
>
(
NLP_ENDPOINT
+
"/summarize-text?text=$text"
)
return
response
.
readText
()
}
}
suspend
fun
getIntentId
(
text
:
String
):
String
{
fun
getSummary
(
text
:
String
):
List
<
Summary
>
{
val
response
=
httpClient
.
post
<
HttpResponse
>
(
NLP_ENDPOINT
+
"/intentid?text=$text"
)
return
getAllSummaries
(
text
).
sortedWith
(
compareByDescending
{
it
.
quality
})
return
response
.
readText
()
}
}
override
fun
close
()
{
fun
getIntentId
(
text
:
String
):
String
{
httpClient
.
close
(
)
return
client
.
getIntentId
(
text
)
}
}
}
}
\ No newline at end of file
src/ktor-server/src/main/kotlin/de/h_da/fbi/smebt/intentfinder/server/nlp/client/RetrofitClient.kt
0 → 100644
View file @
439f439a
package
de.h_da.fbi.smebt.intentfinder.server.nlp.client
import
com.google.gson.JsonObject
import
de.h_da.fbi.smebt.intentfinder.server.nlp.dto.Strategy
import
de.h_da.fbi.smebt.intentfinder.server.nlp.dto.Summary
import
okhttp3.OkHttpClient
import
retrofit2.Retrofit
import
retrofit2.converter.gson.GsonConverterFactory
class
RetrofitClient
{
companion
object
{
private
const
val
BASE_URL
=
"http://127.0.0.1:8000"
}
private
var
client
:
SummarizationAPI
=
buildRetrofitClient
()
private
fun
buildRetrofitClient
():
SummarizationAPI
{
val
retrofit
=
Retrofit
.
Builder
()
.
baseUrl
(
BASE_URL
)
.
addConverterFactory
(
GsonConverterFactory
.
create
())
.
client
(
OkHttpClient
.
Builder
().
build
())
.
build
()
return
retrofit
.
create
(
SummarizationAPI
::
class
.
java
)
}
fun
root
()
:
JsonObject
{
return
RetrofitExecutor
().
execute
(
client
.
root
())
}
fun
getStrategies
()
:
List
<
Strategy
>
{
return
RetrofitExecutor
().
execute
(
client
.
getStrategies
())
}
fun
getSummary
(
strategy
:
String
,
text
:
String
)
:
Summary
{
return
RetrofitExecutor
().
execute
(
client
.
getSummary
(
strategy
,
text
))
}
fun
getIntentId
(
text
:
String
)
:
String
{
return
RetrofitExecutor
().
execute
(
client
.
getIntentId
(
text
))
}
}
\ No newline at end of file
src/ktor-server/src/main/kotlin/de/h_da/fbi/smebt/intentfinder/server/nlp/client/RetrofitExecutor.kt
0 → 100644
View file @
439f439a
package
de.h_da.fbi.smebt.intentfinder.server.nlp.client
import
retrofit2.Call
class
RetrofitExecutor
{
fun
<
T
>
execute
(
call
:
Call
<
T
>):
T
{
try
{
val
response
=
call
.
execute
()
if
(
response
.
isSuccessful
)
{
return
response
.
body
()
!!
}
else
{
throw
NullPointerException
(
"call was not successful"
)
}
}
catch
(
e
:
NullPointerException
)
{
// TODO Body null but response successful? better handling
throw
e
}
}
}
\ No newline at end of file
src/ktor-server/src/main/kotlin/de/h_da/fbi/smebt/intentfinder/server/nlp/client/SummarizationAPI.kt
0 → 100644
View file @
439f439a
package
de.h_da.fbi.smebt.intentfinder.server.nlp.client
import
com.google.gson.JsonObject
import
de.h_da.fbi.smebt.intentfinder.server.nlp.dto.Strategy
import
de.h_da.fbi.smebt.intentfinder.server.nlp.dto.Summary
import
retrofit2.Call
import
retrofit2.http.Body
import
retrofit2.http.GET
import
retrofit2.http.POST
import
retrofit2.http.Path
interface
SummarizationAPI
{
@GET
(
"/"
)
fun
root
()
:
Call
<
JsonObject
>
@GET
(
"/strategies"
)
fun
getStrategies
():
Call
<
List
<
Strategy
>>
@POST
(
"/summarize/{strategy}"
)
fun
getSummary
(
@Path
(
"strategy"
)
strategy
:
String
,
@Body
text
:
String
):
Call
<
Summary
>
@POST
(
"/intentid"
)
fun
getIntentId
(
@Body
text
:
String
)
:
Call
<
String
>
}
\ No newline at end of file
src/ktor-server/src/main/kotlin/de/h_da/fbi/smebt/intentfinder/server/nlp/dto/Strategy.kt
0 → 100644
View file @
439f439a
package
de.h_da.fbi.smebt.intentfinder.server.nlp.dto
import
kotlinx.serialization.Serializable
@Serializable
data class
Strategy
(
val
name
:
String
)
src/ktor-server/src/main/kotlin/de/h_da/fbi/smebt/intentfinder/server/nlp/dto/Summary.kt
0 → 100644
View file @
439f439a
package
de.h_da.fbi.smebt.intentfinder.server.nlp.dto
import
kotlinx.serialization.Serializable
@Serializable
data class
Summary
(
val
strategy
:
String
,
val
quality
:
Double
,
val
result
:
String
,
)
src/ktor-server/src/test/kotlin/de/h_da/fbi/smebt/intentfinder/server/sources/PythonBridgeTest.kt
0 → 100644
View file @
439f439a
package
de.h_da.fbi.smebt.intentfinder.server.sources
import
de.h_da.fbi.smebt.intentfinder.server.nlp.PythonBridge
import
de.h_da.fbi.smebt.intentfinder.server.nlp.client.RetrofitClient
import
de.h_da.fbi.smebt.intentfinder.server.nlp.dto.Strategy
import
de.h_da.fbi.smebt.intentfinder.server.nlp.dto.Summary
import
org.hamcrest.CoreMatchers
import
org.hamcrest.MatcherAssert.assertThat
import
org.hamcrest.collection.IsIterableContainingInAnyOrder
import
org.hamcrest.collection.IsIterableContainingInOrder
import
org.junit.jupiter.api.BeforeAll
import
org.junit.jupiter.api.Test
import
org.junit.jupiter.api.TestInstance
import
org.mockito.Mockito.*
import
kotlin.test.assertEquals
@TestInstance
(
TestInstance
.
Lifecycle
.
PER_CLASS
)
class
PythonBridgeTest
{
lateinit
var
retrofitClient
:
RetrofitClient
lateinit
var
bridge
:
PythonBridge
@BeforeAll
fun
setup
()
{
retrofitClient
=
mock
(
RetrofitClient
::
class
.
java
)
bridge
=
PythonBridge
(
retrofitClient
)
}
@Test
fun
`returns
strategy
with
the
highest
quality`
()
{
val
strategyNameOne
=
"first"
val
strategyNameTwo
=
"second"
val
strategies
=
listOf
(
Strategy
(
strategyNameOne
),
Strategy
(
strategyNameTwo
)
)
val
summaryOne
=
Summary
(
strategyNameOne
,
0.7
,
""
)
val
summaryTwo
=
Summary
(
strategyNameTwo
,
0.8
,
""
)
`when`
(
retrofitClient
.
getStrategies
()).
thenReturn
(
strategies
)
`when`
(
retrofitClient
.
getSummary
(
strategyNameOne
,
""
)).
thenReturn
(
summaryOne
)
`when`
(
retrofitClient
.
getSummary
(
strategyNameTwo
,
""
)).
thenReturn
(
summaryTwo
)
val
result
=
bridge
.
getSummary
(
""
)
verify
(
retrofitClient
,
times
(
1
)).
getStrategies
()
verify
(
retrofitClient
,
times
(
2
)).
getSummary
(
anyString
(),
anyString
())
assertEquals
(
2
,
result
.
size
)
assertThat
(
result
,
CoreMatchers
.
`is`
(
listOf
(
summaryTwo
,
summaryOne
)))
}
}
\ No newline at end of file
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment