[Developer] #424 add MCP routing chatbot demo
This commit is contained in:
@@ -503,6 +503,85 @@ body {
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.chat-shell {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.chat-thread {
|
||||
display: grid;
|
||||
gap: .75rem;
|
||||
}
|
||||
|
||||
.chat-message {
|
||||
border: 1px solid var(--rw-border);
|
||||
border-radius: 8px;
|
||||
max-width: 100%;
|
||||
padding: .85rem;
|
||||
}
|
||||
|
||||
.chat-message strong {
|
||||
display: block;
|
||||
font-size: .82rem;
|
||||
margin-bottom: .45rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.chat-message p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.user-message {
|
||||
background: #edf2f7;
|
||||
margin-left: auto;
|
||||
width: min(760px, 92%);
|
||||
}
|
||||
|
||||
.assistant-message {
|
||||
background: var(--rw-surface-muted);
|
||||
width: min(920px, 100%);
|
||||
}
|
||||
|
||||
.chat-form {
|
||||
border-top: 1px solid var(--rw-border);
|
||||
display: grid;
|
||||
gap: .75rem;
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.chat-form-row {
|
||||
display: grid;
|
||||
gap: .75rem;
|
||||
grid-template-columns: minmax(180px, 1fr) minmax(120px, 180px);
|
||||
}
|
||||
|
||||
.chat-form label {
|
||||
color: var(--rw-muted);
|
||||
font-size: .875rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.chat-debug {
|
||||
margin-top: .75rem;
|
||||
}
|
||||
|
||||
.chat-debug summary {
|
||||
color: var(--rw-primary);
|
||||
cursor: pointer;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.chat-form-row {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.user-message,
|
||||
.assistant-message {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.probe-exchange {
|
||||
border: 1px solid var(--rw-border);
|
||||
border-radius: 8px;
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
<div class="rw-menu-group">
|
||||
<button class="rw-menu-trigger" type="button">MCP</button>
|
||||
<div class="rw-menu-panel">
|
||||
<a class="nav-link" href="/mcp-chatbot">Chatbot</a>
|
||||
<a class="nav-link" href="/mcp-reasoning">Reasoning</a>
|
||||
<a class="nav-link" href="/mcp-sse">SSE 서비스</a>
|
||||
<a class="nav-link" href="/mcp-client-demo">Client Demo</a>
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
<!doctype html>
|
||||
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
|
||||
<body>
|
||||
<div th:fragment="result">
|
||||
<div class="chat-message user-message" th:if="${result}">
|
||||
<strong>질문</strong>
|
||||
<p th:text="${result.question()}">question</p>
|
||||
</div>
|
||||
|
||||
<div class="chat-message assistant-message" th:if="${errorMessage}">
|
||||
<strong>Router</strong>
|
||||
<p th:text="${errorMessage}">error</p>
|
||||
</div>
|
||||
|
||||
<div class="chat-message assistant-message" th:if="${result}">
|
||||
<div class="section-heading">
|
||||
<strong>Router</strong>
|
||||
<span class="badge"
|
||||
th:classappend="${result.status() == 'SUCCESS'} ? ' text-bg-success' : ' text-bg-secondary'"
|
||||
th:text="${result.status()}">SUCCESS</span>
|
||||
</div>
|
||||
<div class="meta-row">
|
||||
<span>Context: <code th:text="${result.contextPath()}">vpd-live</code></span>
|
||||
<span>Tool: <code th:text="${result.selectedTool()}">tool</code></span>
|
||||
</div>
|
||||
<div class="markdown-view" th:text="${result.answer()}">answer</div>
|
||||
<details class="chat-debug">
|
||||
<summary>라우팅/도구 응답 보기</summary>
|
||||
<div class="probe-exchange-grid">
|
||||
<section class="probe-exchange">
|
||||
<h3>Routing Reason</h3>
|
||||
<pre th:text="${result.routingReason()}">reason</pre>
|
||||
</section>
|
||||
<section class="probe-exchange">
|
||||
<h3>tools/list</h3>
|
||||
<pre th:text="${result.toolsListJson()}">{}</pre>
|
||||
</section>
|
||||
<section class="probe-exchange">
|
||||
<h3>tools/call</h3>
|
||||
<pre th:text="${result.toolResultJson()}">{}</pre>
|
||||
</section>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
49
src/main/resources/templates/mcp-chatbot.html
Normal file
49
src/main/resources/templates/mcp-chatbot.html
Normal file
@@ -0,0 +1,49 @@
|
||||
<!doctype html>
|
||||
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
|
||||
<head th:replace="~{fragments/layout :: head('MCP Chatbot')}"></head>
|
||||
<body>
|
||||
<nav th:replace="~{fragments/layout :: nav}"></nav>
|
||||
<main class="container page-shell">
|
||||
<section class="page-heading">
|
||||
<h1>MCP Chatbot</h1>
|
||||
<p>질문을 MCP tool로 라우팅하고 ORDS/VPD 조회 결과를 답변으로 정리합니다.</p>
|
||||
</section>
|
||||
|
||||
<section class="content-band chat-shell">
|
||||
<div class="chat-message assistant-message">
|
||||
<strong>Router</strong>
|
||||
<p>보호 객체명이나 업무명을 질문에 넣으면 가장 가까운 MCP tool을 선택합니다. Bearer Token을 입력하면 실제 ORDS 호출까지 실행합니다.</p>
|
||||
</div>
|
||||
|
||||
<div id="mcp-chatbot-result" class="chat-thread">
|
||||
<div class="text-muted">대화 결과가 여기에 표시됩니다.</div>
|
||||
</div>
|
||||
|
||||
<form hx-post="/mcp-chatbot" hx-target="#mcp-chatbot-result" hx-swap="beforeend" class="chat-form">
|
||||
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
|
||||
<div class="chat-form-row">
|
||||
<label>
|
||||
Context
|
||||
<input class="form-control" name="contextPath" value="vpd-live" pattern="[A-Za-z0-9][A-Za-z0-9_-]{0,63}" required>
|
||||
</label>
|
||||
<label>
|
||||
Limit
|
||||
<input class="form-control" name="limit" type="number" min="1" max="500" value="50">
|
||||
</label>
|
||||
</div>
|
||||
<label>
|
||||
Bearer Token 원문
|
||||
<input class="form-control" name="bearerToken" type="password" autocomplete="off"
|
||||
placeholder="비우면 라우팅만 확인합니다.">
|
||||
</label>
|
||||
<label>
|
||||
질문
|
||||
<textarea class="form-control" name="question" rows="3"
|
||||
placeholder="예: BOARD_POSTS에서 이 토큰으로 보이는 행과 NULL 처리 컬럼을 요약해줘." required></textarea>
|
||||
</label>
|
||||
<button class="btn rw-btn-primary" type="submit">질문 보내기</button>
|
||||
</form>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user