From 381469aff826bc615511daa00b6231df6ab59431 Mon Sep 17 00:00:00 2001 From: BBIT-Kai <2911862937@qq.com> Date: Fri, 26 Sep 2025 16:18:48 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4ktor=E5=90=8E=E7=AB=AF?= =?UTF-8?q?=EF=BC=9A=E5=8F=96=E6=B6=88api=E5=89=8D=E7=BC=80=EF=BC=9B?= =?UTF-8?q?=E5=8E=BB=E9=99=A4=E6=97=A0=E7=94=A8=E4=BB=A3=E7=A0=81=EF=BC=9B?= =?UTF-8?q?oss=E5=AF=B9=E8=B1=A1=E4=BD=BF=E7=94=A8=E4=B8=B4=E6=97=B6?= =?UTF-8?q?=E5=9C=B0=E5=9D=80=E8=BF=94=E5=9B=9E=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ktor/build.gradle.kts | 3 +- .../ink/snowflake/server/Application.kt | 9 ---- .../server/controller/ImageAnalytics.kt | 2 +- .../ink/snowflake/server/controller/LLM.kt | 45 ---------------- .../server/controller/RemoteDebug.kt | 3 -- .../ink/snowflake/server/controller/User.kt | 4 +- .../server/controller/VideoAnalytics.kt | 7 +-- .../server/controller/VideoAnalyticsJetson.kt | 2 - .../ink/snowflake/server/utils/OSSUtils.kt | 51 +++++++++++++++++++ .../snowflake/server/utils/dao/ImageDao.kt | 6 +-- 10 files changed, 63 insertions(+), 69 deletions(-) delete mode 100644 ktor/src/main/kotlin/ink/snowflake/server/controller/LLM.kt create mode 100644 ktor/src/main/kotlin/ink/snowflake/server/utils/OSSUtils.kt diff --git a/ktor/build.gradle.kts b/ktor/build.gradle.kts index acb0efb..7da7107 100644 --- a/ktor/build.gradle.kts +++ b/ktor/build.gradle.kts @@ -101,5 +101,6 @@ dependencies { // 数据库迁移 // implementation("org.flywaydb:flyway-core:10.13.0") - implementation("ai.koog:koog-agents:0.3.0") +// implementation("ai.koog:koog-agents:0.3.0") + implementation("io.minio:minio:8.5.17") } diff --git a/ktor/src/main/kotlin/ink/snowflake/server/Application.kt b/ktor/src/main/kotlin/ink/snowflake/server/Application.kt index abe6d36..c31a0d2 100644 --- a/ktor/src/main/kotlin/ink/snowflake/server/Application.kt +++ b/ktor/src/main/kotlin/ink/snowflake/server/Application.kt @@ -4,7 +4,6 @@ import com.google.gson.Gson import ink.snowflake.server.controller.User import ink.snowflake.server.controller.chat import ink.snowflake.server.utils.plugins.configureSockets -import ink.snowflake.server.controller.LLM import ink.snowflake.server.controller.ImageAnalytics import ink.snowflake.server.controller.RemoteDebug import ink.snowflake.server.controller.VideoAnalytics @@ -29,12 +28,6 @@ const val VIDEO_INPUT_PATH = "C:/tmp/" * ADB 秦朗FRP地址 */ const val SERVER_PATH_FRP = "s3.ronsunny.cn" // 171.212.101.201 -/** - * 服务器地址 - * OSS 对象存储服务器地址 - */ -const val SERVER_PATH_OSS = "s1.ronsunny.cn" // 171.212.101.199 - val gson = Gson() fun main(args: Array): Unit = EngineMain.main(args) @@ -72,6 +65,4 @@ fun Application.module() { VideoAnalyticsJetson() // 业务-图片分析 ImageAnalytics() - // 业务-AI - LLM() } diff --git a/ktor/src/main/kotlin/ink/snowflake/server/controller/ImageAnalytics.kt b/ktor/src/main/kotlin/ink/snowflake/server/controller/ImageAnalytics.kt index f52198a..cdfca8b 100644 --- a/ktor/src/main/kotlin/ink/snowflake/server/controller/ImageAnalytics.kt +++ b/ktor/src/main/kotlin/ink/snowflake/server/controller/ImageAnalytics.kt @@ -11,7 +11,7 @@ import io.ktor.server.response.* fun Application.ImageAnalytics() { routing { - route("/api/sca") { + route("/sca") { // 上传分析结果 post("/saveImageAnalyticsData") { val request = call.receive() diff --git a/ktor/src/main/kotlin/ink/snowflake/server/controller/LLM.kt b/ktor/src/main/kotlin/ink/snowflake/server/controller/LLM.kt deleted file mode 100644 index 09f5bfc..0000000 --- a/ktor/src/main/kotlin/ink/snowflake/server/controller/LLM.kt +++ /dev/null @@ -1,45 +0,0 @@ -package ink.snowflake.server.controller - -import ai.koog.agents.core.agent.AIAgent -import ai.koog.prompt.executor.llms.all.simpleOllamaAIExecutor -import ai.koog.prompt.llm.LLMCapability -import ai.koog.prompt.llm.LLMProvider -import ai.koog.prompt.llm.LLModel -import ink.snowflake.server.SERVER_PATH_OSS -import ink.snowflake.server.model.response.AiListForUserResponse -import ink.snowflake.server.model.response.BaseResponse -import ink.snowflake.server.model.response.SessionListResponse -import ink.snowflake.server.utils.TokenUtils.getUserIdByToken -import ink.snowflake.server.utils.dao.AIDao -import io.ktor.server.application.Application -import io.ktor.server.auth.authenticate -import io.ktor.server.response.respond -import io.ktor.server.routing.get -import io.ktor.server.routing.route -import io.ktor.server.routing.routing -import kotlinx.html.Entities - -fun Application.LLM() { - - routing { - route("/api/llm") { -// authenticate { -// get("/getAiList") { -// val allAIProfile = AIDao.getAllAIProfiles().map { -// AiListForUserResponse( -// id = it.id, -// name = it.name ?: "", -// welcomeWords = it.welcome_words ?: "" -// ) -// } -// call.respond(BaseResponse(data = allAIProfile)) -// } -// get("/getSessions") { -// val userId = getUserIdByToken(call) -// val sessionList = AIDao.getSessionList(userId) -// call.respond(BaseResponse(data = sessionList)) -// } -// } - } - } -} \ No newline at end of file diff --git a/ktor/src/main/kotlin/ink/snowflake/server/controller/RemoteDebug.kt b/ktor/src/main/kotlin/ink/snowflake/server/controller/RemoteDebug.kt index e8bd241..b78420b 100644 --- a/ktor/src/main/kotlin/ink/snowflake/server/controller/RemoteDebug.kt +++ b/ktor/src/main/kotlin/ink/snowflake/server/controller/RemoteDebug.kt @@ -40,7 +40,6 @@ fun Application.RemoteDebug() { } } routing { - route("/api") { authenticate { route("/remote") { get("/connect") { @@ -100,7 +99,6 @@ fun Application.RemoteDebug() { } } } - } } webSocket("/logStream") { send("日志系统连接成功") @@ -155,7 +153,6 @@ fun Application.RemoteDebug() { clients.remove(this) } } - } } diff --git a/ktor/src/main/kotlin/ink/snowflake/server/controller/User.kt b/ktor/src/main/kotlin/ink/snowflake/server/controller/User.kt index 6a75926..bd04d85 100644 --- a/ktor/src/main/kotlin/ink/snowflake/server/controller/User.kt +++ b/ktor/src/main/kotlin/ink/snowflake/server/controller/User.kt @@ -38,7 +38,7 @@ import kotlin.text.Charsets.UTF_8 // 配置和初始化 Redis 客户端 fun setupRedis(): RedissonClient { val config = Config() - config.useSingleServer().setAddress("redis://localhost:6379") + config.useSingleServer().setAddress("redis://10.10.10.9:6379") return Redisson.create(config) } @@ -46,7 +46,7 @@ fun Application.User(config: AppConfig) { // 初始化 Redis 连接 val redisClient: RedissonClient = setupRedis() routing { - route("/api/user") { + route("/user") { post("/login") { val loginRequest = call.receive() val email = loginRequest.account diff --git a/ktor/src/main/kotlin/ink/snowflake/server/controller/VideoAnalytics.kt b/ktor/src/main/kotlin/ink/snowflake/server/controller/VideoAnalytics.kt index ff217aa..5b79a65 100644 --- a/ktor/src/main/kotlin/ink/snowflake/server/controller/VideoAnalytics.kt +++ b/ktor/src/main/kotlin/ink/snowflake/server/controller/VideoAnalytics.kt @@ -1,7 +1,7 @@ package ink.snowflake.server.controller -import ink.snowflake.server.SERVER_PATH_OSS import ink.snowflake.server.VIDEO_INPUT_PATH +import ink.snowflake.server.model.database.ScaImagesTable import ink.snowflake.server.utils.dao.VideoDao import ink.snowflake.server.model.database.VideosTable import ink.snowflake.server.model.database.VideosTable.vAAverageMaskedRatio @@ -15,6 +15,7 @@ import ink.snowflake.server.model.response.* import ink.snowflake.server.utils.CommandUtils.runCommand import ink.snowflake.server.utils.MyUtils import ink.snowflake.server.utils.MyUtils.getFriendlyActionName +import ink.snowflake.server.utils.OSSUtils import ink.snowflake.server.utils.WebSocketManager.broadcastMessage import io.ktor.http.content.* import io.ktor.server.application.* @@ -38,7 +39,7 @@ val clients = Collections.synchronizedList(ArrayList()) fun Application.VideoAnalytics() { routing { - route("/api/iva") { + route("/iva") { // 上传分析结果 post("/saveVideoAnalyticsData") { val request = call.receive() @@ -218,7 +219,7 @@ fun Application.VideoAnalytics() { data = VideoAnalyticsDetail( v_id = vId, v_name = video[VideosTable.vName], - v_video_play_path = "http://${SERVER_PATH_OSS}:9000/video/" + video[VideosTable.vObjectName], + v_video_play_path = OSSUtils.getPresignedUrl("video",video[VideosTable.vObjectName]), v_file_name = video[VideosTable.vFileName], v_duration = video[VideosTable.vDuration], v_size = video[VideosTable.vSize], diff --git a/ktor/src/main/kotlin/ink/snowflake/server/controller/VideoAnalyticsJetson.kt b/ktor/src/main/kotlin/ink/snowflake/server/controller/VideoAnalyticsJetson.kt index df87cc9..07572a0 100644 --- a/ktor/src/main/kotlin/ink/snowflake/server/controller/VideoAnalyticsJetson.kt +++ b/ktor/src/main/kotlin/ink/snowflake/server/controller/VideoAnalyticsJetson.kt @@ -26,7 +26,6 @@ fun Application.VideoAnalyticsJetson() { webSocket("/handleState1") { } - route("/api") { static("/camera/stream") { // files("camera/stream") // 确保 FFmpeg 输出的 HLS 片段和 m3u8 文件存放在这里 files(File(streamFile)) @@ -65,7 +64,6 @@ fun Application.VideoAnalyticsJetson() { call.respond(BaseResponse(message = "摄像头流已停止", data = null)) } } - } } // 确保应用退出时清理所有 FFmpeg 进程 diff --git a/ktor/src/main/kotlin/ink/snowflake/server/utils/OSSUtils.kt b/ktor/src/main/kotlin/ink/snowflake/server/utils/OSSUtils.kt new file mode 100644 index 0000000..2f016f4 --- /dev/null +++ b/ktor/src/main/kotlin/ink/snowflake/server/utils/OSSUtils.kt @@ -0,0 +1,51 @@ +package ink.snowflake.server.utils +import io.minio.MinioClient +import io.minio.PutObjectArgs +import io.minio.GetPresignedObjectUrlArgs +import io.minio.http.Method +import java.io.InputStream +import java.util.concurrent.TimeUnit + +object OSSUtils { + + private val client: MinioClient = MinioClient.builder() + .endpoint("http://10.10.10.9:9000") // 你的MinIO地址 + .credentials("minioadmin", "minioadmin") // 账号密码 + .build() + + /** + * 上传文件 + * @param bucket 桶名 + * @param objName 对象名(路径也放这里,例如 "images/test.png") + * @param input 输入流 + * @param size 文件大小(字节) + * @param contentType 文件MIME类型,比如 "image/png" + */ + fun uploadFile(bucket: String, objName: String, input: InputStream, size: Long, contentType: String) { + client.putObject( + PutObjectArgs.builder() + .bucket(bucket) + .`object`(objName) + .stream(input, size, -1) // -1 表示不限制分片大小,MinIO自己切 + .contentType(contentType) + .build() + ) + } + + /** + * 获取临时访问地址 + * @param bucket 桶名 + * @param objName 对象名 + * @param expiryMinutes 过期时间,分钟 + */ + fun getPresignedUrl(bucket: String, objName: String, expiryMinutes: Int = 15): String { + return client.getPresignedObjectUrl( + GetPresignedObjectUrlArgs.builder() + .method(Method.GET) + .bucket(bucket) + .`object`(objName) + .expiry(expiryMinutes, TimeUnit.MINUTES) + .build() + ) + } +} diff --git a/ktor/src/main/kotlin/ink/snowflake/server/utils/dao/ImageDao.kt b/ktor/src/main/kotlin/ink/snowflake/server/utils/dao/ImageDao.kt index 544eadd..7a1b12f 100644 --- a/ktor/src/main/kotlin/ink/snowflake/server/utils/dao/ImageDao.kt +++ b/ktor/src/main/kotlin/ink/snowflake/server/utils/dao/ImageDao.kt @@ -1,9 +1,9 @@ package ink.snowflake.server.utils.dao -import ink.snowflake.server.SERVER_PATH_OSS import ink.snowflake.server.model.request.ImageAnalyticsRequest import ink.snowflake.server.model.database.ScaImagesTable import ink.snowflake.server.utils.MyUtils.formatLocalDateTimeToString +import ink.snowflake.server.utils.OSSUtils import kotlinx.datetime.toKotlinLocalDateTime import org.jetbrains.exposed.v1.core.SortOrder import org.jetbrains.exposed.v1.jdbc.insert @@ -43,8 +43,8 @@ object ImageDao { name = it[ScaImagesTable.name], upload_datetime = formatLocalDateTimeToString(it[ScaImagesTable.upload_datetime]), file_name = it[ScaImagesTable.file_name], - image_pre = "http://${SERVER_PATH_OSS}:9000/image-sca/raw/" + it[ScaImagesTable.image_pre], - image_after = "http://${SERVER_PATH_OSS}:9000/image-sca/ai/" + it[ScaImagesTable.image_after], + image_pre = OSSUtils.getPresignedUrl("image-sca","raw/" + it[ScaImagesTable.image_pre]), + image_after = OSSUtils.getPresignedUrl("image-sca","ai/" + it[ScaImagesTable.image_after]), resolution = it[ScaImagesTable.resolution], size = it[ScaImagesTable.size], cocoon_count = it[ScaImagesTable.cocoon_count],