nruto commited on
Commit
1a47215
·
verified ·
1 Parent(s): 1837321

Upload 5 files

Browse files
Files changed (5) hide show
  1. Index.html +30 -0
  2. Style.css +191 -0
  3. app.py +84 -0
  4. requirements.txt +6 -0
  5. script.js +156 -0
Index.html ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>AI Chatbot</title>
7
+ <link rel="stylesheet" href="style.css">
8
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
9
+ </head>
10
+ <body>
11
+ <div class="container">
12
+ <div class="chat-container">
13
+ <div class="chat-header">
14
+ <h1>AI Assistant</h1>
15
+ </div>
16
+ <div id="connection-status" style="text-align: center; padding: 10px; display: none;">
17
+ <p style="color: red;">⚠️ Not connected to server</p>
18
+ </div>
19
+ <div class="chat-messages" id="chat-messages">
20
+ <!-- Messages will be added here dynamically -->
21
+ </div>
22
+ <div class="chat-input">
23
+ <textarea id="user-input" placeholder="Type your message here..."></textarea>
24
+ <button id="send-button">Send</button>
25
+ </div>
26
+ </div>
27
+ </div>
28
+ <script src="script.js"></script>
29
+ </body>
30
+ </html>
Style.css ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ * {
2
+ margin: 0;
3
+ padding: 0;
4
+ box-sizing: border-box;
5
+ }
6
+
7
+ body {
8
+ font-family: Arial, sans-serif;
9
+ background-color: #f0f2f5;
10
+ }
11
+
12
+ .container {
13
+ max-width: 1200px;
14
+ margin: 0 auto;
15
+ padding: 20px;
16
+ height: 100vh;
17
+ }
18
+
19
+ .chat-container {
20
+ background-color: #343541;
21
+ color: #fff;
22
+ border-radius: 10px;
23
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
24
+ height: 90vh;
25
+ display: flex;
26
+ flex-direction: column;
27
+ }
28
+
29
+ .chat-header {
30
+ padding: 20px;
31
+ border-bottom: 1px solid #e0e0e0;
32
+ background-color: #202123;
33
+ }
34
+
35
+ .chat-header h1 {
36
+ color: #fff;
37
+ font-size: 24px;
38
+ }
39
+
40
+ .chat-messages {
41
+ flex: 1;
42
+ overflow-y: auto;
43
+ padding: 20px;
44
+ }
45
+
46
+ .message {
47
+ margin-bottom: 20px;
48
+ max-width: 70%;
49
+ }
50
+
51
+ .user-message {
52
+ margin-left: auto;
53
+ background-color: #343541;
54
+ color: #fff;
55
+ padding: 10px 15px;
56
+ border-radius: 15px;
57
+ border: 1px solid #565869;
58
+ }
59
+
60
+ .bot-message {
61
+ background-color: #444654;
62
+ color: #fff;
63
+ padding: 10px 15px;
64
+ border-radius: 15px;
65
+ animation: fadeIn 0.3s ease-in;
66
+ }
67
+
68
+ @keyframes fadeIn {
69
+ from {
70
+ opacity: 0;
71
+ transform: translateY(10px);
72
+ }
73
+ to {
74
+ opacity: 1;
75
+ transform: translateY(0);
76
+ }
77
+ }
78
+
79
+ .chat-input {
80
+ padding: 20px;
81
+ border-top: 1px solid #e0e0e0;
82
+ display: flex;
83
+ gap: 10px;
84
+ }
85
+
86
+ #user-input {
87
+ flex: 1;
88
+ padding: 10px;
89
+ border: 1px solid #565869;
90
+ border-radius: 5px;
91
+ resize: none;
92
+ height: 50px;
93
+ background-color: #40414f;
94
+ color: #fff;
95
+ }
96
+
97
+ #user-input::placeholder {
98
+ color: #8e8ea0;
99
+ }
100
+
101
+ #send-button {
102
+ padding: 10px 20px;
103
+ background-color: #19c37d;
104
+ color: white;
105
+ border: none;
106
+ border-radius: 5px;
107
+ cursor: pointer;
108
+ transition: background-color 0.3s;
109
+ }
110
+
111
+ #send-button:hover {
112
+ background-color: #1a8870;
113
+ }
114
+
115
+ .typing-indicator {
116
+ display: flex;
117
+ align-items: center;
118
+ padding: 10px 15px;
119
+ }
120
+
121
+ .typing-indicator span {
122
+ height: 8px;
123
+ width: 8px;
124
+ background: #fff;
125
+ border-radius: 50%;
126
+ margin: 0 2px;
127
+ display: inline-block;
128
+ animation: bounce 1.3s linear infinite;
129
+ }
130
+
131
+ .typing-indicator span:nth-child(2) {
132
+ animation-delay: 0.15s;
133
+ }
134
+
135
+ .typing-indicator span:nth-child(3) {
136
+ animation-delay: 0.3s;
137
+ }
138
+
139
+ @keyframes bounce {
140
+ 0%, 60%, 100% {
141
+ transform: translateY(0);
142
+ }
143
+ 30% {
144
+ transform: translateY(-4px);
145
+ }
146
+ }
147
+
148
+ .code-block-container {
149
+ position: relative;
150
+ background-color: #1e1e1e;
151
+ border-radius: 8px;
152
+ margin: 10px 0;
153
+ padding: 10px;
154
+ }
155
+
156
+ .code-block-container pre {
157
+ margin: 0;
158
+ padding: 10px;
159
+ overflow-x: auto;
160
+ color: #d4d4d4;
161
+ font-family: 'Consolas', 'Monaco', monospace;
162
+ }
163
+
164
+ .code-block-container code {
165
+ display: block;
166
+ white-space: pre-wrap;
167
+ }
168
+
169
+ .copy-btn {
170
+ position: absolute;
171
+ top: 10px;
172
+ right: 10px;
173
+ padding: 5px 10px;
174
+ background-color: #19c37d;
175
+ color: white;
176
+ border: none;
177
+ border-radius: 5px;
178
+ cursor: pointer;
179
+ font-size: 12px;
180
+ transition: background-color 0.3s;
181
+ }
182
+
183
+ .copy-btn:hover {
184
+ background-color: #1a8870;
185
+ }
186
+
187
+ /* Add syntax highlighting colors */
188
+ .code-block-container .keyword { color: #569cd6; }
189
+ .code-block-container .string { color: #ce9178; }
190
+ .code-block-container .comment { color: #6a9955; }
191
+ .code-block-container .function { color: #dcdcaa; }
app.py ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, jsonify, send_from_directory
2
+ from flask_cors import CORS
3
+ from mistralai import Mistral
4
+ import os
5
+
6
+ app = Flask(__name__, static_folder='.')
7
+ CORS(app, resources={
8
+ r"/chat": {
9
+ "origins": ["https://your-netlify-url.netlify.app"],
10
+ "methods": ["POST", "OPTIONS"],
11
+ "allow_headers": ["Content-Type", "Authorization"]
12
+ }
13
+ })
14
+
15
+ # Mistral API configuration
16
+ API_KEY = "SNCMZQyb5CvFLiQdLQAjki4NNrohYClY"
17
+ MODEL = "mistral-large-latest"
18
+ client = Mistral(api_key=API_KEY)
19
+
20
+ @app.route('/')
21
+ def serve_index():
22
+ return send_from_directory('.', 'index.html')
23
+
24
+ @app.route('/<path:path>')
25
+ def serve_static(path):
26
+ return send_from_directory('.', path)
27
+
28
+ @app.route('/chat', methods=['POST'])
29
+ def chat():
30
+ try:
31
+ data = request.json
32
+ if not data:
33
+ return jsonify({"error": "No request data received"}), 400
34
+
35
+ message = data.get('message', '')
36
+ history = data.get('history', [])
37
+
38
+ if not message:
39
+ return jsonify({"error": "No message provided"}), 400
40
+
41
+ # Prepare messages with system prompt
42
+ messages = [{
43
+ "role": "system",
44
+ "content": """You are a professional and friendly conversation partner. Follow these guidelines:
45
+ - Use a warm, professional tone while staying conversational
46
+ - Write naturally as if having a face-to-face conversation
47
+ - Use simple language and avoid technical jargon unless specifically asked
48
+ - Keep responses concise and informative
49
+ - No special formatting, markdown, asterisks, or special characters
50
+ - Use only basic punctuation and natural paragraph breaks
51
+ - Keep responses to 2-3 short paragraphs maximum"""
52
+ }]
53
+
54
+ # Add conversation history and current message
55
+ messages.extend(history)
56
+ messages.append({"role": "user", "content": message})
57
+
58
+ print("Sending request to Mistral API...")
59
+
60
+ try:
61
+ chat_response = client.chat.complete(
62
+ model=MODEL,
63
+ messages=messages
64
+ )
65
+
66
+ bot_response = chat_response.choices[0].message.content
67
+ print(f"Bot response: {bot_response[:50]}...")
68
+
69
+ return jsonify({
70
+ "response": bot_response
71
+ })
72
+
73
+ except Exception as e:
74
+ error_message = f"Mistral API Error: {str(e)}"
75
+ print(error_message)
76
+ return jsonify({"error": error_message}), 500
77
+
78
+ except Exception as e:
79
+ error_message = f"Server error: {str(e)}"
80
+ print(error_message)
81
+ return jsonify({"error": error_message}), 500
82
+
83
+ if __name__ == "__main__":
84
+ app.run(host='0.0.0.0', port=5001, debug=False)
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ Flask==2.0.1
2
+ Flask-CORS==3.0.10
3
+ mistralai==0.0.7
4
+ gunicorn==21.2.0
5
+ requests==2.26.0
6
+ python-dotenv==1.0.0
script.js ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const chatMessages = document.getElementById('chat-messages');
2
+ const userInput = document.getElementById('user-input');
3
+ const sendButton = document.getElementById('send-button');
4
+
5
+ let conversationHistory = [];
6
+ let isProcessing = false;
7
+
8
+ async function checkServerConnection() {
9
+ const statusDiv = document.getElementById('connection-status');
10
+ try {
11
+ const response = await fetch('http://localhost:5001/');
12
+ if (response.ok) {
13
+ statusDiv.style.display = 'none';
14
+ return true;
15
+ }
16
+ } catch (error) {
17
+ console.error('Server connection error:', error);
18
+ statusDiv.style.display = 'block';
19
+ return false;
20
+ }
21
+ }
22
+
23
+ document.addEventListener('DOMContentLoaded', () => {
24
+ checkServerConnection();
25
+ setInterval(checkServerConnection, 5000);
26
+ });
27
+
28
+ function addMessage(content, isUser = false) {
29
+ const messageDiv = document.createElement('div');
30
+ messageDiv.className = `message ${isUser ? 'user-message' : 'bot-message'}`;
31
+
32
+ if (!isUser) {
33
+ const hasCodeBlock = content.includes('```');
34
+ if (hasCodeBlock) {
35
+ const blocks = content.split('```');
36
+ blocks.forEach((block, index) => {
37
+ if (index % 2 === 0) {
38
+ if (block.trim()) {
39
+ const textDiv = document.createElement('p');
40
+ textDiv.textContent = block.trim();
41
+ messageDiv.appendChild(textDiv);
42
+ }
43
+ } else {
44
+ const codeContainer = document.createElement('div');
45
+ codeContainer.className = 'code-block-container';
46
+
47
+ const preBlock = document.createElement('pre');
48
+ const codeBlock = document.createElement('code');
49
+ const codeText = block.trim();
50
+ codeBlock.textContent = codeText;
51
+ preBlock.appendChild(codeBlock);
52
+
53
+ const copyButton = document.createElement('button');
54
+ copyButton.className = 'copy-btn';
55
+ copyButton.textContent = 'Copy';
56
+ copyButton.addEventListener('click', async () => {
57
+ try {
58
+ await navigator.clipboard.writeText(codeText);
59
+ copyButton.textContent = 'Copied!';
60
+ setTimeout(() => {
61
+ copyButton.textContent = 'Copy';
62
+ }, 2000);
63
+ } catch (err) {
64
+ console.error('Failed to copy:', err);
65
+ // Fallback for older browsers
66
+ const textarea = document.createElement('textarea');
67
+ textarea.value = codeText;
68
+ document.body.appendChild(textarea);
69
+ textarea.select();
70
+ document.execCommand('copy');
71
+ document.body.removeChild(textarea);
72
+ copyButton.textContent = 'Copied!';
73
+ setTimeout(() => {
74
+ copyButton.textContent = 'Copy';
75
+ }, 2000);
76
+ }
77
+ });
78
+
79
+ codeContainer.appendChild(preBlock);
80
+ codeContainer.appendChild(copyButton);
81
+ messageDiv.appendChild(codeContainer);
82
+ }
83
+ });
84
+ } else {
85
+ messageDiv.textContent = content;
86
+ }
87
+ } else {
88
+ messageDiv.textContent = content;
89
+ }
90
+
91
+ chatMessages.appendChild(messageDiv);
92
+ chatMessages.scrollTop = chatMessages.scrollHeight;
93
+ }
94
+
95
+ async function sendMessage() {
96
+ if (isProcessing) return;
97
+
98
+ const message = userInput.value.trim();
99
+ if (!message) return;
100
+
101
+ isProcessing = true;
102
+ sendButton.disabled = true;
103
+
104
+ addMessage(message, true);
105
+ userInput.value = '';
106
+
107
+ conversationHistory.push({"role": "user", "content": message});
108
+
109
+ try {
110
+ const response = await fetch('http://your-docker-ip:5001/chat', {
111
+ method: 'POST',
112
+ headers: {
113
+ 'Content-Type': 'application/json',
114
+ },
115
+ body: JSON.stringify({
116
+ message: message,
117
+ history: conversationHistory
118
+ })
119
+ });
120
+
121
+ const data = await response.json();
122
+
123
+ if (data.error) {
124
+ console.error('API Error:', data.error);
125
+ addMessage('Error: ' + data.error);
126
+ return;
127
+ }
128
+
129
+ if (!data.response) {
130
+ throw new Error('No response from API');
131
+ }
132
+
133
+ addMessage(data.response);
134
+ conversationHistory.push({"role": "assistant", "content": data.response});
135
+
136
+ } catch (error) {
137
+ console.error('Error:', error);
138
+ addMessage('Error: ' + error.message);
139
+ } finally {
140
+ isProcessing = false;
141
+ sendButton.disabled = false;
142
+ }
143
+ }
144
+
145
+ // Event listeners
146
+ sendButton.addEventListener('click', sendMessage);
147
+ userInput.addEventListener('keypress', (e) => {
148
+ if (e.key === 'Enter' && !e.shiftKey) {
149
+ e.preventDefault();
150
+ sendMessage();
151
+ }
152
+ });
153
+
154
+ // Focus input on load
155
+ userInput.focus();
156
+