...
This commit is contained in:
parent
931ec332d7
commit
2e3667d0a1
@ -55,6 +55,7 @@ dependencies {
|
||||
|
||||
implementation ("org.seleniumhq.selenium:selenium-java:4.10.0")
|
||||
|
||||
implementation ("org.commonmark:commonmark:0.18.0")
|
||||
|
||||
implementation ("com.drewnoakes:metadata-extractor:2.19.0")
|
||||
implementation("org.springframework.boot:spring-boot-starter-security")
|
||||
|
||||
@ -87,8 +87,8 @@ class BumsInterceptor : HandlerInterceptor {
|
||||
|
||||
request.cookies?.forEach {
|
||||
if (it.name.equals("CLEAR", true)) {
|
||||
request.getSession(true)?.let { session ->
|
||||
session.invalidate()
|
||||
request.getSession(false)?.let { session ->
|
||||
// session.invalidate()
|
||||
session.setAttribute(WRITE_PERMISSION_KEY, false)
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,13 +46,16 @@ class SecurityConfig {
|
||||
logService.log(it.toString())
|
||||
it.requestMatchers(HttpMethod.POST,"/user/**").permitAll()
|
||||
// it.requestMatchers(HttpMethod.POST,"/user/**").permitAll()
|
||||
// it.requestMatchers(HttpMethod.POST,"/user/**").permitAll()
|
||||
// it.requestMatchers("/", "/user/**").permitAll()
|
||||
// .requestMatchers(".ajax").permitAll()
|
||||
// it.requestMatchers("/", "/user/joinUser.api").permitAll()
|
||||
// it.requestMatchers("user/joinUser.api").permitAll()
|
||||
it.requestMatchers("/blog/viewer/**").permitAll()
|
||||
it.anyRequest().permitAll()
|
||||
|
||||
// .requestMatchers("/", "/login/**").permitAll()
|
||||
// .requestMatchers("/posts/**", "/api/v1/posts/**").hasRole(Role.USER.name)
|
||||
|
||||
// .requestMatchers("/admins/**", "/api/v1/admins/**").hasRole(Role.ADMIN.name)
|
||||
// .anyRequest().authenticated()
|
||||
}
|
||||
|
||||
@ -5,6 +5,11 @@ import jakarta.servlet.http.HttpServletResponse
|
||||
import kr.lunaticbum.back.lun.model.PostManageg
|
||||
import kr.lunaticbum.back.lun.model.ResultMV
|
||||
import kr.lunaticbum.back.lun.utils.LogService
|
||||
import org.commonmark.node.Node
|
||||
import org.commonmark.parser.Parser
|
||||
import org.commonmark.renderer.html.HtmlRenderer
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Element
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.data.domain.Pageable
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
@ -25,13 +30,24 @@ class Home {
|
||||
@GetMapping("/","/home")
|
||||
fun home() : ResultMV {
|
||||
val vm = ResultMV("content/home")
|
||||
vm.modelMap.put("Posts", postManageg.find20(Pageable.ofSize(20)).apply {
|
||||
this.forEach {
|
||||
it.title = URLDecoder.decode(it.title)
|
||||
it.content = URLDecoder.decode(it.content)
|
||||
logService.log(Gson().toJson(it))
|
||||
}
|
||||
})
|
||||
try {
|
||||
vm.modelMap.put("Posts", postManageg.find4().apply {
|
||||
this.forEach {
|
||||
it.title = URLDecoder.decode(it.title)
|
||||
it.content = URLDecoder.decode(it.content)
|
||||
val parser: Parser = Parser.builder().build()
|
||||
val document: Node = parser.parse(it.content)
|
||||
val renderer = HtmlRenderer.builder().build()
|
||||
Jsoup.parse(renderer.render(document))?.let { doc ->
|
||||
val firstImg: Element? = doc.select("img")?.first()
|
||||
val imgSrc: String = firstImg?.attr("src") ?: ""
|
||||
it.image = imgSrc
|
||||
it.html = doc.text()
|
||||
}
|
||||
it.title = if ((it.title?.length ?: 0) >= 1) it.title else ""
|
||||
}
|
||||
}.chunked(2))
|
||||
}catch (ex: Exception){ex.printStackTrace()}
|
||||
vm.modelMap.put("path","/blog/viewer/")
|
||||
return vm
|
||||
}
|
||||
|
||||
@ -312,8 +312,8 @@ class Telegram {
|
||||
.bodyToMono(String::class.java).block()
|
||||
}
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
var originalQuery = msg.text
|
||||
lama.generateResponse(originalQuery?.replace("오늘","오늘(${SimpleDateFormat("yyyy-MM-dd").format(Date())})"),msg.from?.id.toString())
|
||||
var originalQuery = msg.text ?: ""
|
||||
lama.generateResponse(originalQuery.replace("오늘","오늘(${SimpleDateFormat("yyyy-MM-dd").format(Date())})"),msg.from?.id.toString())
|
||||
}
|
||||
}
|
||||
|
||||
@ -371,7 +371,7 @@ class Telegram {
|
||||
// }
|
||||
// }
|
||||
CoroutineScope(Dispatchers.IO).async {
|
||||
lama.generateResponse(originalQuery?.replace("오늘","오늘(${SimpleDateFormat("yyyy-MM-dd").format(Date())})"))
|
||||
lama.generateResponse(originalQuery.replace("오늘","오늘(${SimpleDateFormat("yyyy-MM-dd").format(Date())})"))
|
||||
}
|
||||
return "TEST"
|
||||
}
|
||||
|
||||
@ -34,6 +34,9 @@ class Post {
|
||||
var category : String? = null
|
||||
var tags : String? = null
|
||||
|
||||
var html : String? = null
|
||||
var image : String? = null
|
||||
|
||||
var writer : String? = null
|
||||
var writeTime : Long = 0
|
||||
var posting : Boolean = false
|
||||
@ -69,6 +72,19 @@ class PostManageg {
|
||||
return postRepository.findAllByPostingTrue(pageable).takeLast(20).buffer(20).blockLast(Duration.ofSeconds(30)) ?: listOf()
|
||||
}
|
||||
|
||||
|
||||
fun find4() : List<Post> {
|
||||
val originalList = postRepository.findAllByModifyTime(0)
|
||||
.takeLast(4)
|
||||
.buffer(4)
|
||||
.blockLast(Duration.ofSeconds(30)) ?: listOf()
|
||||
|
||||
return originalList + List((4 - originalList.size).coerceAtLeast(0)) {
|
||||
Post() // 기본값 생성 (필드 초기화 필요)
|
||||
}
|
||||
// return postRepository.findAllByModifyTime(0).takeLast(4).buffer(4).blockLast(Duration.ofSeconds(30)) ?: listOf()
|
||||
}
|
||||
|
||||
fun find20() : List<Post> {
|
||||
return postRepository.findAllByModifyTime(0).takeLast(20).buffer(20).blockLast(Duration.ofSeconds(30)) ?: listOf()
|
||||
}
|
||||
|
||||
@ -2,22 +2,21 @@ package kr.lunaticbum.back.lun.service
|
||||
|
||||
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParser
|
||||
import io.micrometer.observation.ObservationRegistry
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.reactive.awaitSingle
|
||||
import kr.lunaticbum.back.lun.configs.GlobalEnvironment
|
||||
import kr.lunaticbum.back.lun.controllers.TelegramSendMsg
|
||||
import kr.lunaticbum.back.lun.model.*
|
||||
import kr.lunaticbum.back.lun.utils.RssFeedsParser
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.select.Elements
|
||||
import org.openqa.selenium.By
|
||||
import org.openqa.selenium.WebDriver
|
||||
import org.openqa.selenium.chrome.ChromeOptions
|
||||
import org.openqa.selenium.remote.RemoteWebDriver
|
||||
import org.springframework.ai.embedding.EmbeddingRequest
|
||||
@ -37,6 +36,8 @@ import java.net.URLEncoder
|
||||
import java.text.SimpleDateFormat
|
||||
import java.time.Duration
|
||||
import java.util.*
|
||||
import java.util.regex.Matcher
|
||||
import java.util.regex.Pattern
|
||||
|
||||
|
||||
@Service
|
||||
@ -84,54 +85,108 @@ class Lama {
|
||||
val joinString = "\n#"
|
||||
var lastElements : Elements = Elements()
|
||||
var body = Jsoup.connect(url).timeout(30000).get().body()
|
||||
// var elements : Elements? = null
|
||||
// if (url.contains("nate.com", true)) {
|
||||
// if (url.contains("view", true)) {
|
||||
// elements = body.select("[class*=articleView]")
|
||||
// }else {
|
||||
// elements = body.select("[class*=postRankSubjectList]")
|
||||
// }
|
||||
// } else if (url.contains("newsis.com/view", true)) {
|
||||
// elements = body.select("[class*=articleView]")
|
||||
// } else if (url.contains("blog.naver.com", true)) {
|
||||
// elements = body.select("[class*=se-viewer]")
|
||||
// } else if (url.contains("bbc.com/korean/articles", true)) {
|
||||
// elements = body.select("main[role$=main]")
|
||||
// } else if (url.contains("chosun.com/client", true)) {
|
||||
// elements = body.select("[class*=articleBody]")
|
||||
// } else if (url.contains("nocutnews.co.kr/news", true)) {
|
||||
// elements = body.select("[class*=container]")
|
||||
// } else if (url.contains("hani.co.kr/arti/", true)) {
|
||||
// elements = body.select("[class*=ArticleDetail]")
|
||||
// } else if (url.contains("yna.co.kr/view", true)) {
|
||||
// elements = body.select("[class*=container]")
|
||||
// } else if (url.contains("newspim.com/news", true)) {
|
||||
// elements = body.select("[class*=container]")
|
||||
// } else {
|
||||
//
|
||||
// }
|
||||
// if (elements?.size ?: 0 > 0) {
|
||||
// elements?.forEach {
|
||||
// lastElements.add(it)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (lastElements.size < 1) {
|
||||
// arrayOf("container","article","main","viewer","content").forEach {
|
||||
// var result = Elements()
|
||||
// result.addAll(body.select("[class*=$it]"))
|
||||
// result.addAll(body.select("[id*=$it]"))
|
||||
// result.addAll(body.select(it))
|
||||
// result.forEach { if (it.text().length > 100 && it.children().size < 5) { lastElements.add(it) } }
|
||||
// }
|
||||
// }
|
||||
return if (lastElements.size > 0) {
|
||||
lastElements.eachText().joinToString(joinString)
|
||||
var elements : Elements? = null
|
||||
if (url.contains("nate.com", true)) {
|
||||
if (url.contains("view", true)) {
|
||||
elements = body.select("[class*=articleView]")
|
||||
}else {
|
||||
elements = body.select("[class*=postRankSubjectList]")
|
||||
}
|
||||
} else if (url.contains("newsis.com/view", true)) {
|
||||
elements = body.select("[class*=articleView]")
|
||||
} else if (url.contains("blog.naver.com", true)) {
|
||||
elements = body.select("[class*=se-viewer]")
|
||||
} else if (url.contains("bbc.com/korean/articles", true)) {
|
||||
elements = body.select("main[role$=main]")
|
||||
} else if (url.contains("chosun.com/client", true)) {
|
||||
elements = body.select("[class*=articleBody]")
|
||||
} else if (url.contains("nocutnews.co.kr/news", true)) {
|
||||
elements = body.select("[class*=container]")
|
||||
} else if (url.contains("hani.co.kr/arti/", true)) {
|
||||
elements = body.select("[class*=ArticleDetail]")
|
||||
} else if (url.contains("yna.co.kr/view", true)) {
|
||||
elements = body.select("[class*=container]")
|
||||
} else if (url.contains("newspim.com/news", true)) {
|
||||
elements = body.select("[class*=container]")
|
||||
} else {
|
||||
body.children().eachText().joinToString(joinString)
|
||||
|
||||
}
|
||||
if (elements?.size ?: 0 > 0) {
|
||||
elements?.forEach {
|
||||
lastElements.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
if (lastElements.size < 1) {
|
||||
arrayOf("container","article","main","viewer","content").forEach {
|
||||
var result = Elements()
|
||||
result.addAll(body.select("[class*=$it]"))
|
||||
result.addAll(body.select("[id*=$it]"))
|
||||
result.addAll(body.select(it))
|
||||
result.forEach { if (it.text().length > 100 && it.children().size < 5) { lastElements.add(it) } }
|
||||
}
|
||||
}
|
||||
return if (lastElements.size > 0) {
|
||||
lastElements.text()
|
||||
} else {
|
||||
body.text()
|
||||
}
|
||||
}
|
||||
|
||||
fun jsopFilter(doc : Document) : String {
|
||||
var url = doc.baseUri()
|
||||
val joinString = "\n#"
|
||||
var lastElements : Elements = Elements()
|
||||
var body = doc
|
||||
var elements : Elements? = null
|
||||
if (url.contains("nate.com", true)) {
|
||||
if (url.contains("view", true)) {
|
||||
elements = body.select("[class*=articleView]")
|
||||
}else {
|
||||
elements = body.select("[class*=postRankSubjectList]")
|
||||
}
|
||||
} else if (url.contains("newsis.com/view", true)) {
|
||||
elements = body.select("[class*=articleView]")
|
||||
} else if (url.contains("blog.naver.com", true)) {
|
||||
elements = body.select("[class*=se-viewer]")
|
||||
} else if (url.contains("bbc.com/korean/articles", true)) {
|
||||
elements = body.select("main[role$=main]")
|
||||
} else if (url.contains("chosun.com/client", true)) {
|
||||
elements = body.select("[class*=articleBody]")
|
||||
} else if (url.contains("nocutnews.co.kr/news", true)) {
|
||||
elements = body.select("[class*=container]")
|
||||
} else if (url.contains("hani.co.kr/arti/", true)) {
|
||||
elements = body.select("[class*=ArticleDetail]")
|
||||
} else if (url.contains("yna.co.kr/view", true)) {
|
||||
elements = body.select("[class*=container]")
|
||||
} else if (url.contains("newspim.com/news", true)) {
|
||||
elements = body.select("[class*=container]")
|
||||
} else {
|
||||
|
||||
}
|
||||
if (elements?.size ?: 0 > 0) {
|
||||
elements?.forEach {
|
||||
lastElements.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
if (lastElements.size < 1) {
|
||||
arrayOf("container","article","main","viewer","content").forEach {
|
||||
var result = Elements()
|
||||
result.addAll(body.select("[class*=$it]"))
|
||||
result.addAll(body.select("[id*=$it]"))
|
||||
result.addAll(body.select(it))
|
||||
result.forEach { if (it.text().length > 100 && it.children().size < 5) { lastElements.add(it) } }
|
||||
}
|
||||
}
|
||||
return if (lastElements.size > 0) {
|
||||
lastElements.text()
|
||||
} else {
|
||||
body.text()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// class WebScrap {
|
||||
// @SerializedName("query", alternate = ["question"])
|
||||
// var query: String? = null
|
||||
@ -153,17 +208,65 @@ class Lama {
|
||||
val llmPhi4Mini = "phi4-mini"
|
||||
val llmDolphin3 = "dolphin3"
|
||||
|
||||
var llm_gemma3_4b = "gemma3:4b"
|
||||
var llm_phi4_mini = "phi4-mini:latest"
|
||||
var llm_dolphin3 = "dolphin3:latest"
|
||||
var llm_gemma3_12b = "gemma3:12b"
|
||||
var llm_phi4_14b = "phi4:14b"
|
||||
var llm_mistral_7b = "mistral:7b"
|
||||
|
||||
|
||||
|
||||
val currentLLM = llmDolphin3
|
||||
|
||||
val currentLLM = llm_dolphin3
|
||||
fun getGoogleSearch(query:String){
|
||||
Jsoup.connect("https://www.google.com/search?q=".plus(query)).timeout(30000).get().select("a[href]").forEach { }
|
||||
}
|
||||
|
||||
val waitTime = 1000L
|
||||
val waitTime = 1500L
|
||||
val topCount = 2
|
||||
|
||||
fun webDriver() : RemoteWebDriver {
|
||||
val options : ChromeOptions = ChromeOptions();
|
||||
options.addArguments("--headless");
|
||||
options.addArguments("--disable-popup-blocking");
|
||||
options.addArguments("--disable-default-apps");
|
||||
options.addArguments("--disable-notifications");
|
||||
options.addArguments("--disable-blink-features=AutomationControlled")
|
||||
return RemoteWebDriver(URL("https://video.lunaticbum.kr"), options)
|
||||
}
|
||||
|
||||
fun isValidUrl(url: String): Boolean {
|
||||
val urlRegex = "^(https?|ftp)://[-a-zA-Z0-9@:%._+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_+.~#?&/=]*)$".toRegex()
|
||||
return url.matches(urlRegex)
|
||||
}
|
||||
|
||||
@Async
|
||||
suspend fun getterUrl(urlString: String) {
|
||||
try {
|
||||
webDriver()?.let { driver ->
|
||||
var findCount = 0
|
||||
try {
|
||||
driver.get("urlString");
|
||||
Thread.sleep(waitTime)
|
||||
println(driver.currentUrl)
|
||||
driver.findElement(By.ByTagName("Body"))?.let { webElement ->
|
||||
Jsoup.parse(driver.pageSource).select("[href*=https]").forEach {
|
||||
var href = it.attr("href")
|
||||
println(href)
|
||||
}
|
||||
}
|
||||
|
||||
}catch (e:Exception){
|
||||
e.printStackTrace()
|
||||
}
|
||||
driver.close()
|
||||
driver.quit()
|
||||
}
|
||||
}catch (e:Exception){}
|
||||
}
|
||||
|
||||
|
||||
@Async
|
||||
suspend fun addDocuments(query : String , refinedQuery: RefinedQuery?) {
|
||||
var querys : ArrayList<String> = ArrayList()
|
||||
@ -171,48 +274,65 @@ class Lama {
|
||||
|
||||
refinedQuery?.ko_query?.let { querys.add(it) }
|
||||
refinedQuery?.en_query?.let { querys.add(it) }
|
||||
refinedQuery?.keywords?.let { querys.add(it.joinToString { " " })}
|
||||
refinedQuery?.ko_keywords?.let { querys.add(it.joinToString( " "))}
|
||||
refinedQuery?.en_keywords?.let { querys.add(it.joinToString( " "))}
|
||||
val readedUrls = ArrayList<String>()
|
||||
|
||||
try {
|
||||
var options : ChromeOptions = ChromeOptions();
|
||||
options.addArguments("--disable-popup-blocking");
|
||||
options.addArguments("--disable-default-apps");
|
||||
options.addArguments("--disable-notifications");
|
||||
options.addArguments("--disable-blink-features=AutomationControlled");
|
||||
|
||||
val targetUrls = hashSetOf<String>()
|
||||
RemoteWebDriver(URL("https://video.lunaticbum.kr"), options).let { driver ->
|
||||
querys.forEach { refinedQuery->
|
||||
var findCount = 0
|
||||
try {
|
||||
driver.get("https://www.google.com/search?q=$refinedQuery");
|
||||
Thread.sleep(waitTime)
|
||||
println(driver.currentUrl)
|
||||
driver.findElement(By.ByTagName("Body"))?.let { webElement ->
|
||||
Jsoup.parse(driver.pageSource).select("[href*=https]").forEach {
|
||||
var href = it.attr("href")
|
||||
if (href?.length ?: 0 > 5 && href.startsWith("https://") && findCount < topCount && href.contains("google") == false && href.contains("youtube") == false) {
|
||||
targetUrls.add(href)
|
||||
println("add targetUrls $href")
|
||||
findCount += 1
|
||||
|
||||
querys.forEach { refinedQuery->
|
||||
try {
|
||||
webDriver()?.let { driver ->
|
||||
var findCount = 0
|
||||
try {
|
||||
driver.get("https://www.google.com/search?q=$refinedQuery");
|
||||
Thread.sleep(waitTime)
|
||||
println(driver.currentUrl)
|
||||
driver.findElement(By.ByTagName("Body"))?.let { webElement ->
|
||||
Jsoup.parse(driver.pageSource).select("[href*=https]").forEach {
|
||||
var href = it.attr("href")
|
||||
if (href?.length ?: 0 > 5 && href.startsWith("https://") && findCount < topCount && href.contains("google") == false && href.contains("youtube") == false) {
|
||||
targetUrls.add(href)
|
||||
println("add targetUrls $href")
|
||||
findCount += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}catch (e:Exception){
|
||||
e.printStackTrace()
|
||||
}catch (e:Exception){
|
||||
e.printStackTrace()
|
||||
}
|
||||
driver.close()
|
||||
driver.quit()
|
||||
}
|
||||
}
|
||||
driver.close()
|
||||
driver.quit()
|
||||
}catch (e:Exception){}
|
||||
}
|
||||
options = ChromeOptions();
|
||||
options.addArguments("--disable-popup-blocking");
|
||||
options.addArguments("--disable-default-apps");
|
||||
options.addArguments("--disable-notifications");
|
||||
options.addArguments("--disable-blink-features=AutomationControlled");
|
||||
RemoteWebDriver(URL("https://video.lunaticbum.kr"), options).let { driver ->
|
||||
targetUrls.forEach { url ->
|
||||
|
||||
querys.forEach { refinedQuery ->
|
||||
try {
|
||||
webDriver()?.let { driver ->
|
||||
var findCount = 0
|
||||
RssFeedsParser().readFeed("https://news.google.com/rss/search?q=${URLEncoder.encode(refinedQuery)}=ko&gl=KR&ceid=KR%3Ako/")?.messages?.forEach {
|
||||
var url: String? = it.link
|
||||
if (url?.length ?: 0 > 5 && url?.startsWith("https://") == true && readedUrls.contains(url) == false && findCount < topCount) {
|
||||
println("url >>>> $url")
|
||||
targetUrls.add(url!!)
|
||||
findCount += 1
|
||||
}
|
||||
}
|
||||
driver.close()
|
||||
driver.quit()
|
||||
}
|
||||
}catch (e:Exception){
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
targetUrls.forEach { url ->
|
||||
webDriver()?.let { driver ->
|
||||
var result = SearXngResult()
|
||||
if (url?.length ?: 0 > 5 && url?.startsWith("https://") == true && readedUrls.contains(url) == false) {
|
||||
readedUrls.add(url!!)
|
||||
@ -222,85 +342,47 @@ class Lama {
|
||||
driver.get(url);
|
||||
Thread.sleep(waitTime)
|
||||
driver.findElement(By.ByTagName("Body"))?.let { webElement ->
|
||||
if(webElement.text.length > 120) {
|
||||
println(driver.currentUrl)
|
||||
println(webElement.text)
|
||||
result.title = driver.title
|
||||
result.originHtml = webElement.text
|
||||
webPageSummarize(result, webElement.text)
|
||||
jsopFilter(Jsoup.parse(driver.pageSource)).let { text ->
|
||||
result.originHtml = text
|
||||
webPageSummarize(result)
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
// e.printStackTrace()
|
||||
}
|
||||
}
|
||||
driver.close();
|
||||
driver.quit()
|
||||
}
|
||||
driver.close();
|
||||
driver.quit()
|
||||
}
|
||||
options = ChromeOptions();
|
||||
options.addArguments("--disable-popup-blocking");
|
||||
options.addArguments("--disable-default-apps");
|
||||
options.addArguments("--disable-notifications");
|
||||
options.addArguments("--disable-blink-features=AutomationControlled");
|
||||
RemoteWebDriver(URL("https://video.lunaticbum.kr"), options).let { driver ->
|
||||
querys.forEach { refinedQuery ->
|
||||
var googleSCount = 0
|
||||
RssFeedsParser().readFeed("https://news.google.com/rss/search?q=${URLEncoder.encode(query)}=ko&gl=KR&ceid=KR%3Ako/")?.messages?.forEach {
|
||||
var url: String? = it.link
|
||||
var result = SearXngResult()
|
||||
println("url >>>> $url")
|
||||
if (url?.length ?: 0 > 5 && url?.startsWith("https://") == true && readedUrls.contains(url) == false && googleSCount < topCount) {
|
||||
readedUrls.add(url!!)
|
||||
result.url = url!!
|
||||
result.originQuery = query
|
||||
result.refinedQuery = refinedQuery
|
||||
result.title = it.title
|
||||
println(result.title)
|
||||
try {
|
||||
driver.get(url);
|
||||
Thread.sleep(waitTime)
|
||||
println(driver.currentUrl)
|
||||
driver.findElement(By.ByTagName("Body"))?.let { webElement ->
|
||||
println(driver.currentUrl)
|
||||
println(webElement.text)
|
||||
result.title = driver.title
|
||||
result.originHtml = webElement.text
|
||||
webPageSummarize(result, webElement.text)
|
||||
googleSCount += 1
|
||||
}
|
||||
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
driver.close()
|
||||
driver.quit()
|
||||
}
|
||||
|
||||
} catch (e:Exception){e.printStackTrace()}
|
||||
|
||||
querys.forEach { refinedQuery ->
|
||||
val gSearch = "https://psn.lunaticbum.kr/search?q=${refinedQuery?.replace("오늘", SimpleDateFormat("yyyMMdd").format(Date()))}&language=ko&time_range=month&safesearch=0&categories=general&format=json"
|
||||
println("gSearch >>> ${gSearch}")
|
||||
// println("gSearch >>> ${gSearch}")
|
||||
WebClient.create().get()
|
||||
.uri(gSearch)
|
||||
.retrieve()
|
||||
.bodyToMono(SearXng::class.java).timeout(Duration.ofMinutes(20L)).block()?.let { gsResult ->
|
||||
gsResult.results?.filter { it.url?.startsWith("https://") == true && it.score > 0.4 }?.forEach {
|
||||
println("in filter ${it.url}")
|
||||
gsResult.results?.filter { it.url?.startsWith("https://") == true && it.score > 5.0 }?.forEach {
|
||||
if (readedUrls.contains(it.url) == false) {
|
||||
readedUrls.add(it.url!!)
|
||||
it.originQuery = query
|
||||
it.refinedQuery = refinedQuery
|
||||
println(it.title)
|
||||
try {
|
||||
jsopFilter(it.url!!).let { text ->
|
||||
it.originHtml = text
|
||||
webPageSummarize(it, text)
|
||||
webDriver()?.let { driver ->
|
||||
driver.get(it.url!!)
|
||||
Thread.sleep(waitTime)
|
||||
driver.findElement(By.ByTagName("Body"))?.let { webElement ->
|
||||
jsopFilter(it.url!!).let { text ->
|
||||
it.originHtml = text
|
||||
webPageSummarize(it)
|
||||
}
|
||||
}
|
||||
driver.close()
|
||||
driver.quit()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
@ -308,37 +390,107 @@ class Lama {
|
||||
}
|
||||
}
|
||||
}
|
||||
println("end of search")
|
||||
// println("end of search")
|
||||
}
|
||||
}
|
||||
|
||||
var format = "context:'%s'\ncontext는 웹 페이지 문자를 가져온 것 '%s'이 질문에 대해 연관 결과로 받은 내용임. 해당 context 정리 해서 본문 내용을 최대한 자세히 알려줘\n'{query:질문 내용, contents_ko:자세한 내용 한국어 , summary_ko:요약된 내용 한국어, keywords:[키워드], related_links:[{link,description}}], relatedness_score:0.0~10.0}'\n이 형식의 결과로 만들어 줘"
|
||||
var format = "\"context:'%s'\n" +
|
||||
"The context is extracted text from a web page. '%s' is the content received as a relevant result for this question. Please analyze and summarize the given context in detail, and provide the following information in JSON format.\n" +
|
||||
"\n" +
|
||||
"Please provide the result in this format, ensuring that all information is in Korean language."
|
||||
|
||||
|
||||
var webSummaryResultFormat : String = """{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"query": {
|
||||
"type": "string",
|
||||
"description": "Original question"
|
||||
},
|
||||
"contents_ko": {
|
||||
"type": "string",
|
||||
"description": "Detailed content in Korean"
|
||||
},
|
||||
"summary_ko": {
|
||||
"type": "string",
|
||||
"description": "Concise summary in Korean"
|
||||
},
|
||||
"keywords": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"minItems": 1
|
||||
},
|
||||
"related_links": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"link": { "type": "string" },
|
||||
"description": { "type": "string" }
|
||||
},
|
||||
"required": ["link", "description"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"relatedness_score": {
|
||||
"type": "number",
|
||||
"minimum": 0.0,
|
||||
"maximum": 10.0
|
||||
}
|
||||
},
|
||||
"required": ["query", "contents_ko", "summary_ko", "keywords", "related_links", "relatedness_score"],
|
||||
"additionalProperties": false
|
||||
}""";
|
||||
|
||||
|
||||
internal fun makeSummarizeRequestMsg(it : SearXngResult) : String= format.format(it.originHtml,it.originQuery)
|
||||
|
||||
internal fun makeCahtReq(reqMsg:String) = OllamaApi.ChatRequest.Builder(currentLLM).stream(false).format("json").messages(reqMsg.chunked(100).map { println(it); OllamaApi.Message.Builder(OllamaApi.Message.Role.USER).content(it).build()}.toList()).build()
|
||||
internal fun makeCahtReq(reqMsg:String, ollamaOptions: OllamaOptions?, format: Any) = OllamaApi.ChatRequest.Builder(currentLLM).options(ollamaOptions).stream(false).format(format).messages(reqMsg.chunked(100).map { OllamaApi.Message.Builder(OllamaApi.Message.Role.USER).content(it).build()}.toList()).build()
|
||||
var options = OllamaOptions.builder().build()//.temperature(0.8).topK(3).seed(30)
|
||||
|
||||
@Async
|
||||
fun webPageSummarize(it : SearXngResult , text : String) {
|
||||
fun webPageSummarize(it : SearXngResult) {
|
||||
try {
|
||||
infomationDic.get(it.originQuery)!!.put(it.url!!, text)
|
||||
val chatClient = OllamaApi("https://lama.lunaticbum.kr")
|
||||
val embeddingModel = OllamaEmbeddingModel(chatClient, OllamaOptions.builder().build(), ObservationRegistry.create(), ModelManagementOptions.defaults())
|
||||
val embeddingResponse = embeddingModel.call(EmbeddingRequest(text.chunked(400).toList(), OllamaOptions.builder().model(currentEmbedimg).truncate(false).build()))
|
||||
it.originHtml = text
|
||||
val sdss = QPut(arrayListOf())
|
||||
sdss.points.add(QData(id = System.currentTimeMillis(), embeddingResponse.result.output, it))
|
||||
if (sdss.points.size > 0) {
|
||||
val qUrl = "https://ollama.lunaticbum.kr/collections/blama_vectors".plus("/points")
|
||||
val client = WebClient.create()
|
||||
client.put()
|
||||
.uri(qUrl)
|
||||
.header("api-key", "blama-admin-key-gb")
|
||||
.body(BodyInserters.fromValue(Gson().toJson(sdss)))
|
||||
.retrieve()
|
||||
.bodyToMono(String::class.java).timeout(Duration.ofMinutes(20L)).subscribe(
|
||||
{ resultString -> }, { error -> error.printStackTrace() }
|
||||
)
|
||||
// println("send to blama >> ${it.url}")
|
||||
infomationDic.get(it.originQuery)?.put(it.url!!,Gson().toJson(it))
|
||||
try {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val chatClient = OllamaApi("https://lama.lunaticbum.kr")
|
||||
chatClient.chat(makeCahtReq(makeSummarizeRequestMsg(it), options, ObjectMapper().readValue(webSummaryResultFormat,Map::class.java))).toMono().subscribe({aiResponce ->
|
||||
it.pageData = aiResponce.message.content
|
||||
var needSave = true
|
||||
try {
|
||||
var jsonObj = JsonParser.parseString(aiResponce.message.content)
|
||||
needSave = jsonObj.isJsonObject && (jsonObj as JsonObject)?.get("relatedness_score")?.asDouble ?: 0.0 > 0.5 } catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
if (needSave) {
|
||||
sendTlg("유효한 정보가 수집됨.".plus(aiResponce.message.content))
|
||||
val embeddingModel = OllamaEmbeddingModel(chatClient, OllamaOptions.builder().build(), ObservationRegistry.create(), ModelManagementOptions.defaults())
|
||||
val embeddingResponse = embeddingModel.call(EmbeddingRequest(Gson().toJson(it).chunked(400).toList(), OllamaOptions.builder().model(currentEmbedimg).truncate(false).build()))
|
||||
|
||||
val sdss = QPut(arrayListOf())
|
||||
sdss.points.add(QData(id = System.currentTimeMillis(), embeddingResponse.result.output, it))
|
||||
if (sdss.points.size > 0) {
|
||||
val qUrl = "https://ollama.lunaticbum.kr/collections/blama_vectors".plus("/points")
|
||||
val client = WebClient.create()
|
||||
client.put()
|
||||
.uri(qUrl)
|
||||
.header("api-key", "blama-admin-key-gb")
|
||||
.body(BodyInserters.fromValue(Gson().toJson(sdss)))
|
||||
.retrieve()
|
||||
.bodyToMono(String::class.java).timeout(Duration.ofMinutes(20L)).subscribe(
|
||||
{ resultString -> }, { error -> error.printStackTrace() }
|
||||
)
|
||||
}}
|
||||
},{err->
|
||||
err.printStackTrace()
|
||||
})
|
||||
}
|
||||
}
|
||||
catch (e:Exception){e.printStackTrace()}
|
||||
}catch (e : Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
@ -347,16 +499,46 @@ class Lama {
|
||||
class RefinedQuery {
|
||||
var ko_query : String? = null
|
||||
var en_query : String? = null
|
||||
var keywords : Array<String>? = null
|
||||
var ko_keywords : Array<String>? = null
|
||||
var en_keywords : Array<String>? = null
|
||||
}
|
||||
|
||||
var queryFormat = "질문:\n'%s'\n앞은 질문의 내용을 정리해서 '{ko_query:한국어 질문,en_query:영어 번역된 질문,ko_keywords:[한국어 키워드],en_keyword:[영문키워드]}'이 형식의 결과를 부탁할께"
|
||||
|
||||
var jsonSchema: String = """{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ko_query": {
|
||||
"type": "string",
|
||||
"description": "korean query"
|
||||
},
|
||||
"en_query": {
|
||||
"type": "string",
|
||||
"description": "english query"
|
||||
},
|
||||
"ko_keywords": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"minItems": 1,
|
||||
"description": "korean keywords"
|
||||
},
|
||||
"en_keywords": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"minItems": 1,
|
||||
"description": "query keyword"
|
||||
}
|
||||
},
|
||||
"required": ["ko_query", "en_query", "ko_keywords", "en_keywords"],
|
||||
"additionalProperties": false
|
||||
}""".trimIndent()
|
||||
var queryFormat = "Question:\n'%s'\nBased on the above question, please provide a JSON result formatted\nPlease ensure:\n1. Faithful translation maintaining original intent\n2. Keyword extraction focusing on core concepts\n3. Bilingual keyword matching\n4. Proper JSON formatting"
|
||||
|
||||
internal fun makeQuerySummarizeRequestMsg(query : String) : String= queryFormat.format(query)
|
||||
fun querySummarize(query: String) : RefinedQuery? {
|
||||
var refinedQuery : RefinedQuery? = null
|
||||
try {
|
||||
val chatClient = OllamaApi("https://lama.lunaticbum.kr")
|
||||
var dispoable = chatClient.chat(makeCahtReq(makeQuerySummarizeRequestMsg(query))).toMono().subscribe({aiResponce ->
|
||||
var dispoable = chatClient.chat(makeCahtReq(makeQuerySummarizeRequestMsg(query),options, ObjectMapper().readValue(jsonSchema,Map::class.java))).toMono().subscribe({aiResponce ->
|
||||
println("summary result >>>>> ${aiResponce.message.content}")
|
||||
refinedQuery = Gson().fromJson(aiResponce.message.content, RefinedQuery::class.java)
|
||||
},{err->
|
||||
@ -380,7 +562,7 @@ class Lama {
|
||||
.body(BodyInserters.fromValue(Gson().toJson(QSearchData(embedFlots,3))))
|
||||
.retrieve()
|
||||
.bodyToMono(QSearch::class.java).timeout(Duration.ofMinutes(20L)).block()
|
||||
println(Gson().toJson(lists))
|
||||
|
||||
return if (lists?.result?.size ?: 0 > 0) {
|
||||
val qContents = QContentsList()
|
||||
lists?.result?.filter { it.score > 8.0 }?.forEach { qContents.ids.add(it.id) }
|
||||
@ -400,64 +582,195 @@ class Lama {
|
||||
@Autowired
|
||||
lateinit var globalEvv : GlobalEnvironment
|
||||
|
||||
|
||||
val resultJsonScheme = """{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"querys": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "사용자의 질문 목록"
|
||||
},
|
||||
"answers": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "질문에 대한 상세한 답변 목록"
|
||||
},
|
||||
"keywords": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "답변과 관련된 주요 키워드 목록"
|
||||
},
|
||||
"links": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "참고할 만한 관련 링크 목록"
|
||||
}
|
||||
},
|
||||
"required": ["querys", "answers", "keywords", "links"],
|
||||
"additionalProperties": false
|
||||
}""".trimIndent()
|
||||
|
||||
var infomationDic = hashMapOf<String,HashMap<String,String>>()
|
||||
suspend fun generateResponse(query: String?, targetId: String? = globalEvv.telegramMyId) {
|
||||
suspend fun generateResponse(query: String, targetId: String? = globalEvv.telegramMyId) {
|
||||
|
||||
val chatClient = OllamaApi("https://lama.lunaticbum.kr")
|
||||
val embeddingModel = OllamaEmbeddingModel(
|
||||
chatClient, OllamaOptions.builder().build(), ObservationRegistry.create(), ModelManagementOptions.defaults())
|
||||
println("On generateResponse :: find something ${query}")
|
||||
if (isValidUrl(query)) {
|
||||
getterUrl(query)
|
||||
}else {
|
||||
|
||||
query?.let { originalQuery ->
|
||||
infomationDic.put(query!!, hashMapOf())
|
||||
var embeddingResponse = embeddingModel.call(EmbeddingRequest(listOf(originalQuery), OllamaOptions.builder().model(currentEmbedimg).truncate(false).build()))
|
||||
addDocuments(originalQuery, querySummarize(originalQuery))
|
||||
println("points size ${embeddingResponse.result.output.size}")
|
||||
var context : StringBuffer = StringBuffer()
|
||||
try {
|
||||
embedQuery(embeddingResponse.result.output)?.result?.forEach { result ->
|
||||
if (infomationDic.get(query!!)!!.contains(result.payload?.url ?: "NONE") == false) {
|
||||
context.append("\n# :".plus(if (result.payload?.pageData?.length ?: 0 > 10) {
|
||||
result.payload?.pageData
|
||||
} else {
|
||||
result.payload?.content
|
||||
}))
|
||||
}
|
||||
}
|
||||
}catch (e:Exception){
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
infomationDic.get(query!!)!!.iterator().forEach { context.append("\n#${it.key}:${it.value}") }
|
||||
|
||||
val prompt : StringBuffer = StringBuffer().append("참조:\n").append(context).append("\n참조 내용을 고려 해서\n'$query'").append(query).append("\n에 {querys:[],answers:[],keywords:[],links:[]}형식으로 최대한 자세히 대답 해줘 모든 내용은 한국어로 해줘")
|
||||
val fullUrl = "https://api.telegram.org/${globalEvv.telegramBotKey}/sendMessage"
|
||||
val chatClient = OllamaApi("https://lama.lunaticbum.kr")
|
||||
val embeddingModel = OllamaEmbeddingModel(
|
||||
chatClient,
|
||||
OllamaOptions.builder().build(),
|
||||
ObservationRegistry.create(),
|
||||
ModelManagementOptions.defaults()
|
||||
)
|
||||
println("On generateResponse :: find something ${query}")
|
||||
|
||||
val response: OllamaApi.ChatResponse = chatClient.chat(OllamaApi.ChatRequest.Builder(currentLLM).stream(false).format("json").messages(
|
||||
prompt.chunked(300).map { println(it); OllamaApi.Message.Builder(OllamaApi.Message.Role.USER).content(it).build()}.toList()).build())
|
||||
// println(response.message.content)
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
var toalmsg = "${query}의 대답이 도착했어요.\n${response.message.content}"
|
||||
toalmsg.chunked(512).forEach { chunkedMsg ->
|
||||
println("chunkedMsg >>> ${chunkedMsg}")
|
||||
(targetId ?: globalEvv.telegramMyId)?.let {
|
||||
var tlgSend = TelegramSendMsg(it, chunkedMsg)
|
||||
WebClient
|
||||
.create(fullUrl)
|
||||
.post()
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.body(BodyInserters.fromValue(Gson().toJson(tlgSend)))
|
||||
.retrieve().bodyToMono(String::class.java).timeout(Duration.ofMinutes(20L))
|
||||
.block()?.let { result ->
|
||||
println("result >>> ${result}")
|
||||
}
|
||||
query.let { originalQuery ->
|
||||
infomationDic.put(query!!, hashMapOf())
|
||||
|
||||
try {
|
||||
var embeddingResponse = embeddingModel.call(
|
||||
EmbeddingRequest(
|
||||
listOf(originalQuery),
|
||||
OllamaOptions.builder().model(currentEmbedimg).truncate(false).build()
|
||||
)
|
||||
)
|
||||
addDocuments(originalQuery, querySummarize(originalQuery))
|
||||
println("points size ${embeddingResponse.result.output.size}")
|
||||
var context: StringBuffer = StringBuffer()
|
||||
embedQuery(embeddingResponse.result.output)?.result?.forEach { result ->
|
||||
if (infomationDic.get(query!!)!!.contains(result.payload?.url ?: "NONE") == false) {
|
||||
context.append(
|
||||
"\nReference:#".plus(
|
||||
if (result.payload?.pageData?.length ?: 0 > 10) {
|
||||
result.payload?.pageData
|
||||
} else {
|
||||
result.payload?.content
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
infomationDic.get(query!!)!!.iterator()
|
||||
.forEach { context.append("\nReference:#${it.key}:${it.value}") }
|
||||
|
||||
|
||||
val prompt: StringBuffer = StringBuffer()
|
||||
prompt.append(context)
|
||||
prompt.append("\nConsidering the above reference, please answer the following question:\n'$query'\n\nProvide a detailed response in the following JSON format\nPlease ensure all content is in Korean language and as detailed as possible.")
|
||||
|
||||
|
||||
val answers = StringBuffer()
|
||||
chatClient.streamingChat(OllamaApi.ChatRequest.Builder(currentLLM).stream(true)
|
||||
.format(ObjectMapper().readValue(resultJsonScheme, Map::class.java)).messages(
|
||||
prompt.chunked(1024)
|
||||
.map { OllamaApi.Message.Builder(OllamaApi.Message.Role.USER).content(it).build() }.toList()
|
||||
).build()
|
||||
).timeout(Duration.ofMinutes(20)).subscribe({ responce ->
|
||||
answers.append(responce.message.content)
|
||||
println("responce.message.content >>> ${answers.length}")
|
||||
try {
|
||||
if (answers.length % 100 == 0) {
|
||||
var tlgSend = TelegramSendMsg(
|
||||
targetId ?: globalEvv.telegramMyId!!,
|
||||
"결과를 수집 중 ${responce.message.content.length}의 문자열이 추가됨. 수집된 통 데이터는 ${answers.length}"
|
||||
)
|
||||
WebClient
|
||||
.create(fullUrl)
|
||||
.post()
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.body(BodyInserters.fromValue(Gson().toJson(tlgSend)))
|
||||
.retrieve().bodyToMono(String::class.java).timeout(Duration.ofMinutes(20L))
|
||||
.block()?.let { result ->
|
||||
println("result >>> ${result}")
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
}, { error ->
|
||||
|
||||
}, {
|
||||
var toalmsg: StringBuffer = StringBuffer("${query}의 대답이 도착했어요.\n").append(answers.toString())
|
||||
sendTlg(toalmsg.toString())
|
||||
infomationDic.remove(query)
|
||||
println("On generateResponse :: END OF Answer")
|
||||
})
|
||||
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
infomationDic.remove(query!!)
|
||||
|
||||
}
|
||||
println("On generateResponse :: END OF Answer")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun sendTlg(toalmsg : String) {
|
||||
telegramScope.launch {
|
||||
val fullUrl = "https://api.telegram.org/${globalEvv.telegramBotKey}/sendMessage"
|
||||
toalmsg.chunked(512).forEach { chunkedMsg ->
|
||||
launch {
|
||||
println("chunkedMsg >>> ${chunkedMsg}")
|
||||
globalEvv.telegramMyId?.let {
|
||||
try {
|
||||
var tlgSend = TelegramSendMsg(it, chunkedMsg)
|
||||
WebClient
|
||||
.create(fullUrl)
|
||||
.post()
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.body(BodyInserters.fromValue(Gson().toJson(tlgSend)))
|
||||
.retrieve().bodyToMono(String::class.java).timeout(Duration.ofMinutes(20L))
|
||||
.awaitSingle()?.let { result ->
|
||||
println("result >>> ${result}")
|
||||
}
|
||||
}catch (e:Exception){
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private val telegramScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||
|
||||
// fun sendTlg2(toalmsg: String) {
|
||||
// telegramScope.launch {
|
||||
// val fullUrl = "https://api.telegram.org/${globalEvv.telegramBotKey}/sendMessage"
|
||||
// val chunkedMessages = toalmsg.chunked(512)
|
||||
// chunkedMessages.forEach { chunkedMsg ->
|
||||
// launch {
|
||||
// try {
|
||||
// globalEvv.telegramMyId?.let { chatId ->
|
||||
// val tlgSend = TelegramSendMsg(chatId, chunkedMsg)
|
||||
// val result = WebClient.create(fullUrl)
|
||||
// .post()
|
||||
// .contentType(MediaType.APPLICATION_JSON)
|
||||
// .bodyValue(Gson().toJson(tlgSend))
|
||||
// .retrieve()
|
||||
// .awaitBody<String>()
|
||||
//
|
||||
// println("Telegram send success: $result")
|
||||
// }
|
||||
// } catch (e: Exception) {
|
||||
// println("Telegram send failed: ${e.localizedMessage}")
|
||||
// // 추가 에러 처리 로직
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 3.1 KiB |
File diff suppressed because it is too large
Load Diff
@ -20,6 +20,8 @@ function goToEditor(path,id,sk) {
|
||||
location.href = path + id+"?token="+sk;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function onclickWrite(type, keyword, html) {
|
||||
let title_field = document.getElementById('title_field')
|
||||
var hasValues = true
|
||||
|
||||
@ -34,16 +34,25 @@
|
||||
</script>
|
||||
</th:block>
|
||||
<th:block layout:fragment="content" id="content">
|
||||
<div id="main_layer">
|
||||
<label id="title_layer" class="write_option" ></label>
|
||||
<div id="editor" ></div>
|
||||
<div class="write_controllbox">
|
||||
<div class="write_option btn-example" to="#popLayer1" onclick="openPopup(this)" ></div>
|
||||
<div style="width: 15px" ></div>
|
||||
<div class="write_option btn-example" to="#popLayer2" onclick="openPopup(this)" id="hashtag_field"></div>
|
||||
<div style="width: 15px" ></div>
|
||||
<label class="write_option" readonly id="location_field"></label>
|
||||
<section class="wrapper style1">
|
||||
<div class="container">
|
||||
<div id="content">
|
||||
|
||||
<!-- Content -->
|
||||
|
||||
<article>
|
||||
<label id="title_layer" class="write_option" ></label>
|
||||
<div id="editor" ></div>
|
||||
<div class="write_controllbox">
|
||||
<div class="write_option btn-example" to="#popLayer1" onclick="openPopup(this)" ></div>
|
||||
<div style="width: 15px" ></div>
|
||||
<div class="write_option btn-example" to="#popLayer2" onclick="openPopup(this)" id="hashtag_field"></div>
|
||||
<div style="width: 15px" ></div>
|
||||
<label class="write_option" readonly id="location_field"></label>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</th:block>
|
||||
</html>
|
||||
|
||||
@ -10,25 +10,10 @@
|
||||
<script type="text/javascript" th:src="@{/js/test.js}"></script>
|
||||
<link th:href="@{/css/toast-ui-dark.css}" rel="stylesheet" />
|
||||
<script th:inline="javascript">
|
||||
let editor
|
||||
document.addEventListener("DOMContentLoaded", onLoaded);
|
||||
function onLoaded() {
|
||||
var els = document.getElementsByClassName('content')
|
||||
for (i=0;i<els.length;i++) {
|
||||
var item = $(els[i])
|
||||
console.log(item[0])
|
||||
|
||||
console.log(item.attr("data"))
|
||||
new toastui.Editor({
|
||||
el: item[0],
|
||||
width : (item[0].getBoundingClientRect().width * 0.8) + 'px',
|
||||
height : (item[0].getBoundingClientRect().width * 0.8) + 'px',
|
||||
viewer: true,
|
||||
usageStatistics : false,
|
||||
initialValue: item.attr("data"),
|
||||
theme:"dark",
|
||||
});
|
||||
}
|
||||
function goToViewer(item) {
|
||||
let uploadUrl = getMainPath() + "/blog/viewer/"+item.attributes['data'].value;
|
||||
location.href = uploadUrl
|
||||
}
|
||||
</script>
|
||||
</th:block>
|
||||
@ -36,7 +21,7 @@
|
||||
<section id="banner">
|
||||
<header>
|
||||
<h2>Bum's: <em>짧은 헛소리 혹은 기사?! 링크 있으면 링크까지</a></em></h2>
|
||||
<a href="#" class="button">더 읽으쉴?!<br>[Read More Gibberish]</a>
|
||||
<a href="#" class="button">더 읽으쉴?!<br>[Read More Gibberish]</a>
|
||||
</header>
|
||||
</section>
|
||||
|
||||
@ -52,7 +37,7 @@
|
||||
</header>
|
||||
</div>
|
||||
</section>
|
||||
<section id="cta__3" class="wrapper style3">
|
||||
<section id="cta2" class="wrapper style3">
|
||||
<div class="container">
|
||||
<header>
|
||||
<h2>Are you ready to continue your quest?</h2>
|
||||
@ -62,42 +47,14 @@
|
||||
<!-- Posts -->
|
||||
<section class="wrapper style2">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<section class="col-6 col-12-narrower">
|
||||
<div class="box post">
|
||||
<a href="#" class="image left"><img src="images/pic01.jpg" alt="" /></a>
|
||||
<div class="row" th:each="row : ${Posts}">
|
||||
<section class="col-6 col-12-narrower" th:each="post : ${row}">
|
||||
<!-- <span th:text="${cell}"></span>-->
|
||||
<div class="box post" onclick="goToViewer(this)" th:data="${post.id}">
|
||||
<a href="#" class="image left"><img th:src="${#strings.length(post.image) > 0} ? ${post.image} : 'images/pic01.jpg'" alt="" /></a>
|
||||
<div class="inner">
|
||||
<h3>The First Thing</h3>
|
||||
<p>Duis neque nisi, dapibus sed mattis et quis, nibh. Sed et dapibus nisl amet mattis, sed a rutrum accumsan sed. Suspendisse eu.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="col-6 col-12-narrower">
|
||||
<div class="box post">
|
||||
<a href="#" class="image left"><img src="images/pic02.jpg" alt="" /></a>
|
||||
<div class="inner">
|
||||
<h3>The Second Thing</h3>
|
||||
<p>Duis neque nisi, dapibus sed mattis et quis, nibh. Sed et dapibus nisl amet mattis, sed a rutrum accumsan sed. Suspendisse eu.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="row">
|
||||
<section class="col-6 col-12-narrower">
|
||||
<div class="box post">
|
||||
<a href="#" class="image left"><img src="images/pic03.jpg" alt="" /></a>
|
||||
<div class="inner">
|
||||
<h3>The Third Thing</h3>
|
||||
<p>Duis neque nisi, dapibus sed mattis et quis, nibh. Sed et dapibus nisl amet mattis, sed a rutrum accumsan sed. Suspendisse eu.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="col-6 col-12-narrower">
|
||||
<div class="box post">
|
||||
<a href="#" class="image left"><img src="images/pic04.jpg" alt="" /></a>
|
||||
<div class="inner">
|
||||
<h3>The Fourth Thing</h3>
|
||||
<p>Duis neque nisi, dapibus sed mattis et quis, nibh. Sed et dapibus nisl amet mattis, sed a rutrum accumsan sed. Suspendisse eu.</p>
|
||||
<h3 th:text="${#strings.length(post.title) > 0} ? ${post.title} : ('untitled[' + ${#temporals.format(T(java.time.Instant).ofEpochMilli(post.writeTime).atZone(T(java.time.ZoneId).systemDefault()).toLocalDateTime(), 'yyyy-MM-dd HH:mm:ss')} + ']')"></h3>
|
||||
<p th:text="${#strings.abbreviate(post.html, 80)}" class="ellipsis"></p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -133,11 +90,10 @@
|
||||
</div>
|
||||
</section>
|
||||
<!-- CTA -->
|
||||
<section id="cta" class="wrapper style3">
|
||||
<section id="cta2" class="wrapper style3">
|
||||
<div class="container">
|
||||
<header>
|
||||
<h2>Are you ready to continue your quest?</h2>
|
||||
<a href="#" class="button">Insert Coin</a>
|
||||
</header>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@ -64,7 +64,7 @@
|
||||
<!-- Copyright -->
|
||||
<div class="copyright">
|
||||
<ul class="menu">
|
||||
<li>© Untitled. All rights reserved</li><li>Design: <a href="http://html5up.net">HTML5 UP</a></li>
|
||||
<li>©lunaticbum. All rights reserved</li><li>Design: <a href="http://html5up.net">HTML5 UP</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user