.....
This commit is contained in:
parent
15b2c63e95
commit
c85996e453
@ -27,6 +27,9 @@ configurations {
|
|||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
|
||||||
|
maven { url = uri("https://repo.spring.io/milestone") }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@ -56,6 +59,13 @@ dependencies {
|
|||||||
// implementation(platform("com.google.cloud:libraries-bom: 26.55.0"))
|
// implementation(platform("com.google.cloud:libraries-bom: 26.55.0"))
|
||||||
// implementation("com.google.cloud:google-cloud-apikeys")
|
// implementation("com.google.cloud:google-cloud-apikeys")
|
||||||
implementation ("com.google.maps:google-maps-services:2.2.0")
|
implementation ("com.google.maps:google-maps-services:2.2.0")
|
||||||
|
// implementation ("org.springframework.ai:spring-ai-openai-spring-boot-starter:1.0.0-SNAPSHOT")
|
||||||
|
// implementation ("org.springframework.ai:spring-ai-vertex-ai-gemini-spring-boot-starter:1.0.0-SNAPSHOT")
|
||||||
|
// implementation("org.springframework.ai:spring-ai-ollama-spring-boot-starter:1.0.0-SNAPSHOT")
|
||||||
|
implementation(platform("org.springframework.ai:spring-ai-bom:1.0.0-M6"))
|
||||||
|
implementation("org.springframework.ai:spring-ai-ollama-spring-boot-starter:1.0.0-M6")
|
||||||
|
implementation("org.springframework.ai:spring-ai-redis-store")
|
||||||
|
|
||||||
implementation ("org.slf4j:slf4j-simple:1.7.25")
|
implementation ("org.slf4j:slf4j-simple:1.7.25")
|
||||||
|
|
||||||
implementation("io.jsonwebtoken:jjwt-api:0.11.5")
|
implementation("io.jsonwebtoken:jjwt-api:0.11.5")
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
package kr.lunaticbum.back.lun.configs
|
package kr.lunaticbum.back.lun.configs
|
||||||
|
|
||||||
|
import org.springframework.ai.ollama.api.OllamaApi
|
||||||
|
import org.springframework.ai.ollama.api.OllamaOptions
|
||||||
import org.springframework.beans.factory.annotation.Value
|
import org.springframework.beans.factory.annotation.Value
|
||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.context.annotation.Configuration
|
import org.springframework.context.annotation.Configuration
|
||||||
@ -27,6 +29,17 @@ class AppConfig : WebMvcConfigurer {
|
|||||||
registry.addInterceptor(authInterceptor())
|
registry.addInterceptor(authInterceptor())
|
||||||
super.addInterceptors(registry)
|
super.addInterceptors(registry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
fun chatClient(): OllamaApi {
|
||||||
|
return OllamaApi("https://lama.lunaticbum.kr")
|
||||||
|
// .withDefaultOptions(
|
||||||
|
// OllamaOptions.create()
|
||||||
|
// .withModel("phi4:14b")
|
||||||
|
// .withNumThread(5)
|
||||||
|
// .withSeed(5)
|
||||||
|
// .withTemperature(0.9f))
|
||||||
|
}
|
||||||
// @Bean
|
// @Bean
|
||||||
// fun getProperty() : Map<String,String>{
|
// fun getProperty() : Map<String,String>{
|
||||||
// println("telegramBotKey >>>> $telegramBotKey")
|
// println("telegramBotKey >>>> $telegramBotKey")
|
||||||
|
|||||||
@ -15,9 +15,14 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kr.lunaticbum.back.lun.configs.GlobalEnvironment
|
import kr.lunaticbum.back.lun.configs.GlobalEnvironment
|
||||||
import kr.lunaticbum.back.lun.model.*
|
import kr.lunaticbum.back.lun.model.*
|
||||||
|
import kr.lunaticbum.back.lun.service.Lama
|
||||||
import kr.lunaticbum.back.lun.utils.LogService
|
import kr.lunaticbum.back.lun.utils.LogService
|
||||||
import org.jsoup.Jsoup
|
import org.springframework.ai.chat.messages.UserMessage
|
||||||
|
import org.springframework.ai.chat.prompt.Prompt
|
||||||
|
import org.springframework.ai.ollama.api.OllamaApi
|
||||||
|
import org.springframework.ai.ollama.api.OllamaOptions
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier
|
||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.http.MediaType
|
import org.springframework.http.MediaType
|
||||||
import org.springframework.scheduling.annotation.Scheduled
|
import org.springframework.scheduling.annotation.Scheduled
|
||||||
@ -25,6 +30,7 @@ import org.springframework.ui.ModelMap
|
|||||||
import org.springframework.web.bind.annotation.*
|
import org.springframework.web.bind.annotation.*
|
||||||
import org.springframework.web.reactive.function.BodyInserters
|
import org.springframework.web.reactive.function.BodyInserters
|
||||||
import org.springframework.web.reactive.function.client.WebClient
|
import org.springframework.web.reactive.function.client.WebClient
|
||||||
|
import reactor.core.publisher.Mono
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.math.RoundingMode
|
import java.math.RoundingMode
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
@ -37,6 +43,7 @@ import java.util.prefs.Preferences
|
|||||||
@RequestMapping("/tlg")
|
@RequestMapping("/tlg")
|
||||||
class Telegram {
|
class Telegram {
|
||||||
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
lateinit var globalEvv : GlobalEnvironment
|
lateinit var globalEvv : GlobalEnvironment
|
||||||
|
|
||||||
@ -89,6 +96,7 @@ class Telegram {
|
|||||||
comp = (word).plus(comp)
|
comp = (word).plus(comp)
|
||||||
return comp
|
return comp
|
||||||
}
|
}
|
||||||
|
|
||||||
fun trimWithDecompString(comp : String) : String {
|
fun trimWithDecompString(comp : String) : String {
|
||||||
var doubleIpmt = false
|
var doubleIpmt = false
|
||||||
var compressed : String? = comp
|
var compressed : String? = comp
|
||||||
@ -322,32 +330,32 @@ class Telegram {
|
|||||||
|
|
||||||
} else if (req.reqMsg?.contains("검색") == true) {
|
} else if (req.reqMsg?.contains("검색") == true) {
|
||||||
var originalQuery = req.reqMsg
|
var originalQuery = req.reqMsg
|
||||||
val gSearch = "https://www.googleapis.com/customsearch/v1?key=AIzaSyARLXyvmr_554tOy3UCh3naFlZQS3-qQQM&cx=207f328d3ad7242f2&q=${originalQuery?.replace("오늘", SimpleDateFormat("yyyMMdd").format(Date()))}&num=5&lr=kr"
|
val gSearch = "https://www.google.com/search?q=${originalQuery?.replace("오늘", SimpleDateFormat("yyyMMdd").format(Date()))}&tbs=qdr%3Am"
|
||||||
println("gSearch >>> ${gSearch}")
|
println("gSearch >>> ${gSearch}")
|
||||||
WebClient.create().get()
|
WebClient.create().get()
|
||||||
.uri(gSearch)
|
.uri(gSearch)
|
||||||
.retrieve()
|
.retrieve()
|
||||||
.bodyToMono(GoogleSearchResult::class.java).timeout(Duration.ofMinutes(20L)).block()?.let { gsResult ->
|
.bodyToMono(String::class.java).timeout(Duration.ofMinutes(20L)).block()?.let { gsResult ->
|
||||||
println("gsearch result ==> ${Gson().toJson(gsResult)}")
|
println("gsearch result ==> ${Gson().toJson(gsResult)}")
|
||||||
var additionalInfo = StringBuffer()
|
var additionalInfo = StringBuffer()
|
||||||
gsResult.items?.forEach {
|
// gsResult.items?.forEach {
|
||||||
additionalInfo.append("- 정보 출처 :").append(it.link).append("\n")
|
// additionalInfo.append("- 정보 출처 :").append(it.link).append("\n")
|
||||||
try {
|
// try {
|
||||||
Jsoup.connect(it.link).get().body().text().let {
|
// Jsoup.connect(it.link).get().body().text().let {
|
||||||
if (it.length > 1000) {
|
// if (it.length > 1000) {
|
||||||
additionalInfo.append("- 정보 내용 :").append(it.chunked(500).first()).append("\n")
|
// additionalInfo.append("- 정보 내용 :").append(it.chunked(500).first()).append("\n")
|
||||||
} else {
|
// } else {
|
||||||
additionalInfo.append("- 정보 내용 :").append(it).append("\n")
|
// additionalInfo.append("- 정보 내용 :").append(it).append("\n")
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
} catch (e : Exception) {
|
// } catch (e : Exception) {
|
||||||
additionalInfo.append("- 정보 타이틀 : ").append(it.title).append("\n")
|
// additionalInfo.append("- 정보 타이틀 : ").append(it.title).append("\n")
|
||||||
additionalInfo.append("- 정보 요약 :").append(it.snippet).append("\n")
|
// additionalInfo.append("- 정보 요약 :").append(it.snippet).append("\n")
|
||||||
println(it.link)
|
// println(it.link)
|
||||||
e.printStackTrace()
|
// e.printStackTrace()
|
||||||
}
|
// }
|
||||||
additionalInfo.append("\n")
|
// additionalInfo.append("\n")
|
||||||
}
|
// }
|
||||||
println("additionalInfo >>> ${additionalInfo.toString()}")
|
println("additionalInfo >>> ${additionalInfo.toString()}")
|
||||||
req.reqMsg = "질문 : " + originalQuery + "\n\n추가정보:" + "\n${additionalInfo.toString()} 위의 질문과 추가 정보를 고려하여 답변해주세요."
|
req.reqMsg = "질문 : " + originalQuery + "\n\n추가정보:" + "\n${additionalInfo.toString()} 위의 질문과 추가 정보를 고려하여 답변해주세요."
|
||||||
|
|
||||||
@ -415,6 +423,47 @@ class Telegram {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// fun chatClient(): ChatClient {
|
||||||
|
// return OllamaChatClient(OllamaApi("https://lama.lunaticbum.kr"))
|
||||||
|
// .withDefaultOptions(
|
||||||
|
// OllamaOptions.create()
|
||||||
|
// .withModel("phi4:14b")
|
||||||
|
// .withNumThread(5)
|
||||||
|
// .withSeed(5)
|
||||||
|
// .withTemperature(0.9f)
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
@Autowired
|
||||||
|
lateinit var lama : Lama
|
||||||
|
|
||||||
|
@ResponseBody
|
||||||
|
@GetMapping("query/{path}")
|
||||||
|
fun googleQueryTest(@PathVariable path: String): String {
|
||||||
|
var originalQuery = path
|
||||||
|
val gSearch = "https://psn.lunaticbum.kr/search?q=${originalQuery?.replace("오늘", SimpleDateFormat("yyyMMdd").format(Date()))}&language=auto&time_range=month&safesearch=0&categories=general&format=json"
|
||||||
|
println("gSearch >>> ${gSearch}")
|
||||||
|
var additionalInfo = StringBuffer()
|
||||||
|
additionalInfo.append("참고자료")
|
||||||
|
var idx = 0
|
||||||
|
WebClient.create().get()
|
||||||
|
.uri(gSearch)
|
||||||
|
.retrieve()
|
||||||
|
.bodyToMono(SearXng::class.java).timeout(Duration.ofMinutes(20L)).block()?.let { gsResult ->
|
||||||
|
gsResult.results?.filter { it.score > 0.5}?.forEach {
|
||||||
|
additionalInfo.append(idx).append(":").append(Gson().toJson(it))
|
||||||
|
idx += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lama.generateResponse(query = originalQuery)
|
||||||
|
return "TEST"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
enum class LamaQueryType(val keywords : ArrayList<String>) {
|
enum class LamaQueryType(val keywords : ArrayList<String>) {
|
||||||
None(arrayListOf()),
|
None(arrayListOf()),
|
||||||
Search(arrayListOf("검색")),
|
Search(arrayListOf("검색")),
|
||||||
|
|||||||
26
src/main/kotlin/kr/lunaticbum/back/lun/model/SearXng.kt
Normal file
26
src/main/kotlin/kr/lunaticbum/back/lun/model/SearXng.kt
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package kr.lunaticbum.back.lun.model
|
||||||
|
|
||||||
|
|
||||||
|
class SearXng {
|
||||||
|
var query: String? = null
|
||||||
|
var number_of_results: Int = 0
|
||||||
|
var results: ArrayList<SearXngResult>? = null
|
||||||
|
var answers: ArrayList<Any>? = null
|
||||||
|
var corrections: ArrayList<Any>? = null
|
||||||
|
var infoboxes: ArrayList<Any>? = null
|
||||||
|
var suggestions: ArrayList<Any>? = null
|
||||||
|
var unresponsive_engines: ArrayList<ArrayList<String>>? = null
|
||||||
|
}
|
||||||
|
class SearXngResult {
|
||||||
|
var url: String? = null
|
||||||
|
var title: String? = null
|
||||||
|
var content: String? = null
|
||||||
|
var thumbnail: Any? = null
|
||||||
|
var engine: String? = null
|
||||||
|
var template: String? = null
|
||||||
|
var parsed_url: ArrayList<String>? = null
|
||||||
|
var engines: ArrayList<String>? = null
|
||||||
|
var positions: ArrayList<Int>? = null
|
||||||
|
var score: Double = 0.0
|
||||||
|
var category: String? = null
|
||||||
|
}
|
||||||
61
src/main/kotlin/kr/lunaticbum/back/lun/service/Lama.kt
Normal file
61
src/main/kotlin/kr/lunaticbum/back/lun/service/Lama.kt
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package kr.lunaticbum.back.lun.service
|
||||||
|
|
||||||
|
|
||||||
|
import org.springframework.ai.chat.messages.UserMessage
|
||||||
|
import org.springframework.ai.chat.prompt.Prompt
|
||||||
|
import org.springframework.ai.document.Document
|
||||||
|
import org.springframework.ai.ollama.OllamaChatModel
|
||||||
|
import org.springframework.ai.ollama.api.OllamaApi
|
||||||
|
import org.springframework.ai.vectorstore.SearchRequest
|
||||||
|
import org.springframework.ai.vectorstore.VectorStore
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
import java.util.stream.Collectors
|
||||||
|
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class Lama {
|
||||||
|
@Qualifier("chatClient")
|
||||||
|
@Autowired
|
||||||
|
private lateinit var chatClient: OllamaApi
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private lateinit var vectorStore: VectorStore
|
||||||
|
|
||||||
|
fun generateResponse(query: String?): String {
|
||||||
|
println("On generateResponse :: find something")
|
||||||
|
// 1. 유사 문서 검색
|
||||||
|
|
||||||
|
val relevantDocs = vectorStore.similaritySearch(
|
||||||
|
SearchRequest.builder().query(query!!).topK(3).build()
|
||||||
|
)
|
||||||
|
|
||||||
|
// 2. 프롬프트 구성
|
||||||
|
val context = relevantDocs?.map { it.text }?.joinToString(separator = "\n")
|
||||||
|
val prompt = """
|
||||||
|
Context information is below.
|
||||||
|
----
|
||||||
|
$context
|
||||||
|
----
|
||||||
|
Given the context information and not prior knowledge, answer the query: $query
|
||||||
|
\n한국어로 대답해줘
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
|
// 3. Ollama를 사용하여 응답 생성
|
||||||
|
val response: OllamaApi.ChatResponse = chatClient.chat(OllamaApi.ChatRequest.Builder("phi4:14b").stream(false).format("json").messages(
|
||||||
|
listOf(OllamaApi.Message.Builder(OllamaApi.Message.Role.USER).content(prompt).build())
|
||||||
|
).build())
|
||||||
|
println(response.message.content)
|
||||||
|
println("On generateResponse :: END OF Answer")
|
||||||
|
return response.message.content
|
||||||
|
}
|
||||||
|
|
||||||
|
// 문서 추가 메소드
|
||||||
|
fun addDocuments(documents: List<Document?>?) {
|
||||||
|
documents?.let {
|
||||||
|
vectorStore.add(it)
|
||||||
|
}
|
||||||
|
// vectorStore!!.add(documents)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -62,5 +62,14 @@ spring.data.mongodb.option.min-heartbeat-frequency=500
|
|||||||
spring.data.mongodb.option.heartbeat-frequency=10000
|
spring.data.mongodb.option.heartbeat-frequency=10000
|
||||||
spring.data.mongodb.option.local-threshold=15
|
spring.data.mongodb.option.local-threshold=15
|
||||||
|
|
||||||
|
spring.ai.ollama.base-url=https://lama.lunaticbum.kr
|
||||||
|
spring.ai.ollama.chat.options.model=phi4:14b
|
||||||
|
|
||||||
|
spring.data.redis.host=ollama.lunaticbum.kr
|
||||||
|
spring.ai.vectorstore.redis.initialize-schema=true
|
||||||
|
spring.ai.vectorstore.redis.index=spring-ai-redis-index
|
||||||
|
spring.ai.vectorstore.redis.prefix=spring-ai-redis-embedding
|
||||||
|
|
||||||
|
|
||||||
#>>>>>>> ab915d0a416c69708f1df1ad76d7a14c779c1f59
|
#>>>>>>> ab915d0a416c69708f1df1ad76d7a14c779c1f59
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user