package com.zioinfo.mro.rag; import com.zioinfo.mro.common.ApiResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Map; /** * WISE AI — Enterprise AI for Trusted Knowledge (MRO 배선). * *

{@code POST /api/wise/ask {query, retrievalMode?}} → 중앙 guardia-rag {@code /rag/answer} * (solution=mro) 프록시. 근거+인용+환각차단(abstained) 동반. 미가용 시 degraded 안내(스택 미노출). * *

인증: SecurityConfig 의 {@code anyRequest().authenticated()} 로 로그인 사용자만 접근. * 기존 {@code /api/mro/ai/*}(Ollama/Claude 직접) 는 불변 — 본 컨트롤러는 중앙 rag 경유 신규 경로만 추가. */ @Tag(name = "WISE AI (중앙 guardia-rag)", description = "근거·인용 기반 답변 — 온프레미스 전용") @RestController @RequestMapping("/api/wise") @RequiredArgsConstructor public class WiseAskController { private final RagClient ragClient; @Operation(summary = "WISE AI 질의 (/rag/answer 프록시 · 근거+인용+환각차단)") @PostMapping("/ask") public ApiResponse> ask(@RequestBody AskRequest req) { String query = req == null || req.query() == null ? "" : req.query().trim(); if (query.isEmpty()) { return ApiResponse.ok(Map.of( "answer", "질문을 입력해 주세요.", "sources", java.util.List.of(), "grounded", false, "abstained", false, "degraded", true, "degraded_reason", "empty_query")); } return ApiResponse.ok(ragClient.answer(query, req.retrievalMode())); } /** WISE AI 질의 요청 — retrievalMode: vector|hybrid|graph (선택). */ public record AskRequest(String query, String retrievalMode) { } }