-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsimple.html
More file actions
209 lines (181 loc) · 8.97 KB
/
Copy pathsimple.html
File metadata and controls
209 lines (181 loc) · 8.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>생활 계획 AI</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif; background: #f5f5f5; }
.container { max-width: 900px; margin: 0 auto; padding: 20px; }
.header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px; border-radius: 12px; margin-bottom: 20px; }
.header h1 { font-size: 28px; margin-bottom: 8px; }
.header p { opacity: 0.9; }
.chat-box { background: white; border-radius: 12px; padding: 20px; margin-bottom: 20px; height: 500px; overflow-y: auto; box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
.message { margin: 12px 0; padding: 12px 16px; border-radius: 8px; max-width: 80%; word-break: break-word; }
.message.user { background: #e3f2fd; margin-left: auto; text-align: right; }
.message.assistant { background: #f3e5f5; margin-right: auto; }
.message .role { font-weight: bold; font-size: 12px; opacity: 0.6; margin-bottom: 4px; }
.input-box { display: flex; gap: 8px; margin-bottom: 20px; }
.input-box input { flex: 1; padding: 12px 16px; border: 1px solid #ddd; border-radius: 8px; font-size: 14px; }
.input-box button { padding: 12px 24px; background: #667eea; color: white; border: none; border-radius: 8px; cursor: pointer; font-weight: bold; }
.input-box button:hover { background: #764ba2; }
.quick-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 20px; }
.quick-btn { padding: 8px 16px; background: #f0f0f0; border: 1px solid #ddd; border-radius: 6px; cursor: pointer; font-size: 13px; }
.quick-btn:hover { background: #e0e0e0; }
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin-top: 20px; }
.stat { background: white; padding: 16px; border-radius: 8px; text-align: center; box-shadow: 0 2px 4px rgba(0,0,0,0.05); }
.stat-value { font-size: 24px; font-weight: bold; color: #667eea; }
.stat-label { font-size: 12px; color: #999; margin-top: 4px; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🎯 생활 계획 AI</h1>
<p>일정, 메모, 우선순위를 말해주면 AI가 정리해줍니다</p>
</div>
<div class="quick-actions" id="quick-actions">
<button class="quick-btn" onclick="quickMessage('내일 3시 회의 있어')">내일 3시 회의</button>
<button class="quick-btn" onclick="quickMessage('지금부터 1시간 공부하고 싶어')">1시간 공부</button>
<button class="quick-btn" onclick="quickMessage('저녁 약 먹는 거 잊지 말기')">저녁 약 복용</button>
<button class="quick-btn" onclick="quickMessage('아침운동 25분했어')">아침운동 완료</button>
</div>
<div class="chat-box" id="chat-box"></div>
<div class="input-box">
<input type="text" id="message-input" placeholder="일정, 메모, 생각을 말해보세요..." onkeypress="handleKeyPress(event)">
<button onclick="sendMessage()">전송</button>
</div>
<div class="stats">
<div class="stat">
<div class="stat-value" id="msg-count">0</div>
<div class="stat-label">대화 수</div>
</div>
<div class="stat">
<div class="stat-value" id="saved-items">0</div>
<div class="stat-label">저장된 항목</div>
</div>
<div class="stat">
<div class="stat-value" id="ai-mode">켜짐</div>
<div class="stat-label">AI 상태</div>
</div>
</div>
</div>
<script>
const chatBox = document.getElementById('chat-box');
const messageInput = document.getElementById('message-input');
let messageCount = 0;
let savedItems = 0;
let azureReady = false;
const LLM_ENDPOINT = 'http://localhost:8787/api/llm/chat';
const AZURE_MODEL = 'gpt-4o-mini';
// Azure OpenAI 연결 확인
checkAzure();
async function checkAzure() {
try {
const response = await fetch('http://localhost:8787/health');
if (response.ok) {
const data = await response.json();
azureReady = Boolean(data?.providers?.azure?.configured);
if (azureReady) {
document.getElementById('ai-mode').textContent = '✓ Azure AI';
document.getElementById('ai-mode').style.color = '#4caf50';
} else {
document.getElementById('ai-mode').textContent = '⚠ Azure 설정 필요';
document.getElementById('ai-mode').style.color = '#ff9800';
}
}
} catch (e) {
azureReady = false;
document.getElementById('ai-mode').textContent = '⚠ 프록시 연결 실패';
document.getElementById('ai-mode').style.color = '#ff9800';
}
}
// 초기 인사말
addMessage('assistant', '안녕하세요! 🎯\n\n일정, 메모, 건강 정보를 자유롭게 말씀해주세요.\n예: "내일 3시 회의", "30분 운동했어", "알약 4개 준비해야 함" 등');
function addMessage(role, text) {
const div = document.createElement('div');
div.className = `message ${role}`;
div.innerHTML = `<div class="role">${role === 'assistant' ? 'AI 어시스턴트' : '당신'}</div><div>${text}</div>`;
chatBox.appendChild(div);
chatBox.scrollTop = chatBox.scrollHeight;
messageCount++;
document.getElementById('msg-count').textContent = messageCount;
}
function generateResponse(text) {
const lower = text.toLowerCase();
// 일정 감지
if (lower.includes('시') || lower.includes('회의') || lower.includes('약속')) {
savedItems++;
document.getElementById('saved-items').textContent = savedItems;
return `📅 "일정 추가됨"\n\n${text} 를 캘린더에 추가했습니다.\n관련 준비 시간을 함께 블록할까요?`;
}
// 운동 감지
if (lower.includes('운동') || lower.includes('걷') || lower.includes('뛰') || lower.includes('했어')) {
return `💪 좋은 활동이네요!\n\n해주신 내용을 기록했습니다. 계속해서 건강한 습관을 유지하세요!`;
}
// 약/의료 감지
if (lower.includes('약') || lower.includes('복용') || lower.includes('먹')) {
return `💊 의료 정보 기록됨\n\n약 복용 일정을 추적했습니다. 매일 정해진 시간에 챙기세요!`;
}
// 메모 감지
if (lower.includes('메모') || lower.includes('기억') || lower.includes('잊지')) {
savedItems++;
document.getElementById('saved-items').textContent = savedItems;
return `📝 메모 저장됨\n\n"${text}"\n\n나중에 빠르게 찾을 수 있도록 저장했습니다.`;
}
// 기본 응답
return `✅ 알겠습니다!\n\n"${text}"\n\n이 내용을 기록했습니다. 다른 정보가 있으신가요?`;
}
function sendMessage() {
const text = messageInput.value.trim();
if (!text) return;
addMessage('user', text);
messageInput.value = '';
// 로딩 표시
const loadingDiv = document.createElement('div');
loadingDiv.className = 'message assistant';
loadingDiv.innerHTML = `<div class="role">AI 어시스턴트</div><div>⏳ 생각 중...</div>`;
chatBox.appendChild(loadingDiv);
chatBox.scrollTop = chatBox.scrollHeight;
callAzure(text, loadingDiv);
}
async function callAzure(text, loadingDiv) {
try {
const response = await fetch(LLM_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
provider: 'azure',
model: AZURE_MODEL,
messages: [
{
role: 'system',
content: '당신은 일정/메모를 도와주는 한국어 생활 비서입니다. 간결하고 실용적으로 답변하세요.'
},
{ role: 'user', content: text }
],
temperature: 0.3,
max_tokens: 600
})
});
if (!response.ok) throw new Error('Azure 요청 실패');
const data = await response.json();
loadingDiv.remove();
addMessage('assistant', data.content || '응답 생성 중...');
} catch (e) {
loadingDiv.remove();
const fallbackResponse = generateResponse(text);
addMessage('assistant', fallbackResponse);
}
}
function quickMessage(text) {
messageInput.value = text;
sendMessage();
}
function handleKeyPress(e) {
if (e.key === 'Enter') sendMessage();
}
</script>
</body>
</html>