-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.js
More file actions
176 lines (148 loc) · 7.21 KB
/
Copy pathscript.js
File metadata and controls
176 lines (148 loc) · 7.21 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
document.addEventListener('DOMContentLoaded', function() {
// DOM Elements
const chatMessages = document.getElementById('chat-messages');
const userInput = document.getElementById('user-input');
const sendButton = document.getElementById('send-button');
// API Configuration
const OPENROUTER_API_KEY = 'Your API Key';
const OPENROUTER_API_URL = 'API URL';
const MODEL = "anthropic/claude-3-haiku";
// Travel Concierge Configuration
const CONCIERGE_NAME = "SAMR";
const CONCIERGE_GREETING = {
role: "assistant",
content: `Hello! I'm ${CONCIERGE_NAME}, your personal travel and culture assistant. 🌍✈️\n\nI can help you with:\n• Cultural etiquette do's and don'ts\n• Must-try local foods\n• Travel planning tips\n• Dress code advice\n\nWhere shall we explore today?`
};
// Conversation History
let conversationHistory = [
{
role: "system",
content: `You are ${CONCIERGE_NAME}, a friendly but professional travel concierge. Follow these rules:
1. SPECIALIZE in travel destinations, cultural norms, dining etiquette, and trip planning
2. RESPOND in warm, helpful tone with bullet points/headings
3. USE relevant emojis (🌍🍜👔)
4. For off-topic requests, respond:
"${CONCIERGE_NAME} here! ✨ I specialize in travel and cultural advice. Try asking:
• 'What should I pack for Bali in December?'
• 'How to greet someone in Japan?'
• 'Best food markets in Bangkok?'"
5. NEVER answer non-travel questions, even if pressed`
},
CONCIERGE_GREETING
];
// Enhanced Topic Validation
function isTravelRelated(prompt) {
const lowerPrompt = prompt.toLowerCase();
// Match any country/region/city name
const locationMatch = /\b(india|japan|thailand|france|italy|spain|usa|u\.?s\.?|uk|china|dubai|bali|vietnam|korea|brazil|mexico|canada|australia)\b/i.test(lowerPrompt);
// Match travel/etiquette keywords
const keywordMatch = [
// Travel terms
'travel', 'trip', 'visit', 'destination', 'vacation', 'itinerary',
'sightseeing', 'tour', 'holiday', 'backpack', 'suitcase', 'pack',
// Food terms
'food', 'cuisine', 'dish', 'eat', 'dining', 'restaurant', 'meal',
'breakfast', 'lunch', 'dinner', 'snack', 'street food', 'market',
// Culture terms
'etiquette', 'custom', 'culture', 'manner', 'norm', 'tradition',
'polite', 'rude', 'behavior', 'greet', 'handshake', 'bow',
// Practical terms
'weather', 'season', 'month', 'wear', 'dress', 'attire', 'clothes',
'hotel', 'hostel', 'flight', 'airport', 'train', 'bus', 'transport',
// Recommendation terms
'best', 'top', 'famous', 'popular', 'must', 'should', 'recommend',
'advice', 'tip', 'suggestion'
].some(keyword => lowerPrompt.includes(keyword));
return locationMatch || keywordMatch;
}
// Send Message Function
async function sendMessage() {
const query = userInput.value.trim();
if (!query) return;
// Add user message to UI immediately
addMessage(query, 'user');
userInput.value = '';
// Show typing indicator
const loadingId = showLoading();
try {
// Add to conversation history
conversationHistory.push({ role: "user", content: query });
// Get AI response
const response = await fetch(OPENROUTER_API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${OPENROUTER_API_KEY}`,
'HTTP-Referer': window.location.href,
'X-Title': 'AI Cultural Guide'
},
body: JSON.stringify({
model: MODEL,
messages: conversationHistory,
temperature: 0.7,
max_tokens: 1000
})
});
if (!response.ok) throw new Error(`API error: ${response.status}`);
const data = await response.json();
// Process response
if (data.choices?.[0]?.message) {
const aiResponse = data.choices[0].message.content;
// Add to conversation history
conversationHistory.push({ role: "assistant", content: aiResponse });
// Display response
removeLoading(loadingId);
addMessage(aiResponse, 'bot');
} else {
throw new Error("Unexpected API response format");
}
} catch (error) {
console.error('Error:', error);
removeLoading(loadingId);
addMessage(`${CONCIERGE_NAME} is having connection issues 🛠️. Please try again shortly!`, 'bot');
}
}
// Helper Functions
function addMessage(text, sender) {
const messageDiv = document.createElement('div');
messageDiv.classList.add('message', `${sender}-message`);
const contentDiv = document.createElement('div');
contentDiv.classList.add('message-content');
contentDiv.innerHTML = formatResponseText(text);
messageDiv.appendChild(contentDiv);
chatMessages.appendChild(messageDiv);
chatMessages.scrollTop = chatMessages.scrollHeight;
}
function formatResponseText(text) {
// Convert markdown-like formatting to HTML
return text
.replace(/^#\s+(.+)$/gm, '<h3>$1</h3>') // Headings
.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>') // Bold
.replace(/\*(.*?)\*/g, '<em>$1</em>') // Italics
.replace(/^\s*-\s*(.*)$/gm, '<li>$1</li>') // List items
.replace(/\n/g, '<br>') // Line breaks
.replace(/<li>.*?<\/li>/g, match => `<ul>${match}</ul>`); // Wrap lists
}
function showLoading() {
const loadingId = 'loading-' + Date.now();
const loadingDiv = document.createElement('div');
loadingDiv.classList.add('message', 'bot-message');
loadingDiv.id = loadingId;
const contentDiv = document.createElement('div');
contentDiv.classList.add('message-content', 'loading-message');
contentDiv.innerHTML = '<div class="typing-indicator"><span></span><span></span><span></span></div>';
loadingDiv.appendChild(contentDiv);
chatMessages.appendChild(loadingDiv);
chatMessages.scrollTop = chatMessages.scrollHeight;
return loadingId;
}
function removeLoading(id) {
const loadingElement = document.getElementById(id);
if (loadingElement) loadingElement.remove();
}
// Event Listeners
sendButton.addEventListener('click', sendMessage);
userInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') sendMessage();
});
});