This commit is contained in:
lunaticbum 2025-03-05 18:08:59 +09:00
parent 15b2c63e95
commit c85996e453
6 changed files with 189 additions and 21 deletions

View File

@ -27,6 +27,9 @@ configurations {
repositories {
mavenCentral()
maven { url = uri("https://repo.spring.io/milestone") }
}
dependencies {
@ -56,6 +59,13 @@ dependencies {
// implementation(platform("com.google.cloud:libraries-bom: 26.55.0"))
// implementation("com.google.cloud:google-cloud-apikeys")
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("io.jsonwebtoken:jjwt-api:0.11.5")

View File

@ -1,5 +1,7 @@
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.context.annotation.Bean
import org.springframework.context.annotation.Configuration
@ -27,6 +29,17 @@ class AppConfig : WebMvcConfigurer {
registry.addInterceptor(authInterceptor())
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
// fun getProperty() : Map<String,String>{
// println("telegramBotKey >>>> $telegramBotKey")

View File

@ -15,9 +15,14 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kr.lunaticbum.back.lun.configs.GlobalEnvironment
import kr.lunaticbum.back.lun.model.*
import kr.lunaticbum.back.lun.service.Lama
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.Qualifier
import org.springframework.context.annotation.Bean
import org.springframework.http.MediaType
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.reactive.function.BodyInserters
import org.springframework.web.reactive.function.client.WebClient
import reactor.core.publisher.Mono
import java.math.BigDecimal
import java.math.RoundingMode
import java.text.SimpleDateFormat
@ -37,6 +43,7 @@ import java.util.prefs.Preferences
@RequestMapping("/tlg")
class Telegram {
@Autowired
lateinit var globalEvv : GlobalEnvironment
@ -89,6 +96,7 @@ class Telegram {
comp = (word).plus(comp)
return comp
}
fun trimWithDecompString(comp : String) : String {
var doubleIpmt = false
var compressed : String? = comp
@ -322,32 +330,32 @@ class Telegram {
} else if (req.reqMsg?.contains("검색") == true) {
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}")
WebClient.create().get()
.uri(gSearch)
.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)}")
var additionalInfo = StringBuffer()
gsResult.items?.forEach {
additionalInfo.append("- 정보 출처 :").append(it.link).append("\n")
try {
Jsoup.connect(it.link).get().body().text().let {
if (it.length > 1000) {
additionalInfo.append("- 정보 내용 :").append(it.chunked(500).first()).append("\n")
} else {
additionalInfo.append("- 정보 내용 :").append(it).append("\n")
}
}
} catch (e : Exception) {
additionalInfo.append("- 정보 타이틀 : ").append(it.title).append("\n")
additionalInfo.append("- 정보 요약 :").append(it.snippet).append("\n")
println(it.link)
e.printStackTrace()
}
additionalInfo.append("\n")
}
// gsResult.items?.forEach {
// additionalInfo.append("- 정보 출처 :").append(it.link).append("\n")
// try {
// Jsoup.connect(it.link).get().body().text().let {
// if (it.length > 1000) {
// additionalInfo.append("- 정보 내용 :").append(it.chunked(500).first()).append("\n")
// } else {
// additionalInfo.append("- 정보 내용 :").append(it).append("\n")
// }
// }
// } catch (e : Exception) {
// additionalInfo.append("- 정보 타이틀 : ").append(it.title).append("\n")
// additionalInfo.append("- 정보 요약 :").append(it.snippet).append("\n")
// println(it.link)
// e.printStackTrace()
// }
// additionalInfo.append("\n")
// }
println("additionalInfo >>> ${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>) {
None(arrayListOf()),
Search(arrayListOf("검색")),

View 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
}

View 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)
}
}

View File

@ -62,5 +62,14 @@ spring.data.mongodb.option.min-heartbeat-frequency=500
spring.data.mongodb.option.heartbeat-frequency=10000
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