### Setup and Run Flask Backend (Bash)
Source: https://github.com/smauldin100/santiskills/blob/main/README.md
Steps to set up and run the Flask backend application. This includes creating a virtual environment, installing dependencies, setting environment variables, and running the Flask app.
```bash
cd flask_app
python -m venv .venv
. .venv/Scripts/activate # Windows
pip install -r requirements.txt
# Environment (.venv/.env or shell)
export OPENAI_API_KEY=sk-your-secret
export FLASK_SECRET_KEY=super-secret
export CRYPTO_API_KEY=... # optional, CoinGecko demo key also works
export CRYPTO_API_URL=https://api.coingecko.com/api/v3
python app.py # runs on http://127.0.0.1:5003 by default
```
--------------------------------
### Setup and Run Plaid Backend (Bash)
Source: https://github.com/smauldin100/santiskills/blob/main/README.md
Instructions for setting up and running the Plaid backend service, which provides a sandbox link-token endpoint. It involves installing npm dependencies and starting the server.
```bash
cd backend-plaid
npm install
cp .env.example .env # create if needed
# Set PLAID_CLIENT_ID, PLAID_SECRET, PORT=8080 etc.
npm start
```
--------------------------------
### Clone and Install Frontend Dependencies (Bash)
Source: https://github.com/smauldin100/santiskills/blob/main/README.md
This snippet shows the steps to clone the Santiskills repository and install its frontend dependencies using npm. It assumes Node.js and npm are already installed.
```bash
git clone https://github.com/Smauldin100/santiskills.git
cd santiskills
npm install
```
--------------------------------
### Clone and Run AI Dashboard (Bash)
Source: https://github.com/smauldin100/santiskills/blob/main/flask_app/README.md
Steps to clone the AI Dashboard repository, set up a virtual environment, install dependencies, configure environment variables, and run the Flask application.
```bash
git clone https://github.com/Smauldin100/ai-dashboard.git
cd ai-dashboard
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -r requirements.txt
# Create a .env file with FLASK_SECRET_KEY and OPENAI_API_KEY
python app.py
```
--------------------------------
### Run React Development Server (Bash)
Source: https://github.com/smauldin100/santiskills/blob/main/README.md
Command to start the React development server using npm. This command also implicitly covers proxying requests to the Flask backend.
```bash
npm start
```
--------------------------------
### Project Structure Overview (Text)
Source: https://github.com/smauldin100/santiskills/blob/main/flask_app/README.md
Illustrates the directory and file structure of the AI Dashboard project, including the main application file, static assets, and HTML templates.
```text
ai-dashboard/
├── app.py # Main Flask application
├── requirements.txt # Python dependencies
├── static/
│ ├── css/
│ │ └── styles.css # Global styles
│ └── js/
│ └── main.js # Global JavaScript
└── templates/
├── base.html # Base template
├── index.html # Home page
├── chat.html # Chat interface
└── tools.html # AI tools page
```
--------------------------------
### Run Production Build (Bash)
Source: https://github.com/smauldin100/santiskills/blob/main/README.md
Command to create a production-ready build of the React application.
```bash
npm run build
```
--------------------------------
### Configure Environment Variables (dotenv)
Source: https://github.com/smauldin100/santiskills/blob/main/README.md
Illustrates how to set up environment variables required for the application, specifically for API keys. It highlights the difference between keys for the browser and backend.
```dotenv
OPENAI_API_KEY=sk-your-secret
REACT_APP_OPENAI_API_KEY=sk-your-secret # CRA only exposes REACT_APP* vars to the browser
# Optional: point the proxy to a remote Flask instance
# REACT_APP_API_PROXY_TARGET=https://your-backend-host
```
--------------------------------
### Quick Chat UI and Functionality (HTML, CSS, JavaScript)
Source: https://github.com/smauldin100/santiskills/blob/main/flask_app/templates/index.html
This snippet encompasses the HTML structure and CSS styling for the quick chat interface, along with the JavaScript code responsible for handling user input, sending messages to a '/api/chat' endpoint, and displaying AI responses in real-time. It manages message history and scrolling.
```html
```
```css
.grid-container { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: var(--spacing-lg); }
.card { background-color: var(--secondary); border-radius: var(--radius-lg); padding: var(--spacing-lg); }
.card h2 { display: flex; align-items: center; gap: var(--spacing-sm); margin: 0; font-size: 1.25rem; }
.card h2 span.mdi { color: var(--accent); }
.quick-actions { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--spacing-md); margin-top: var(--spacing-md); }
.action-btn { display: flex; flex-direction: column; align-items: center; gap: var(--spacing-sm); padding: var(--spacing-md); background-color: var(--primary); color: var(--text); text-decoration: none; border-radius: var(--radius-md); transition: all var(--transition-speed) var(--transition-ease); }
.action-btn:hover { background-color: var(--accent); transform: translateY(-2px); }
.action-btn span.mdi { font-size: 1.5rem; }
.activity-list { display: flex; flex-direction: column; gap: var(--spacing-md); margin-top: var(--spacing-md); }
.activity-item { display: flex; align-items: center; gap: var(--spacing-md); padding: var(--spacing-sm); border-radius: var(--radius-md); background-color: var(--primary); }
.activity-item span.mdi { font-size: 1.5rem; color: var(--accent); }
.activity-content p { margin: 0; color: var(--text); }
.activity-content small { color: var(--text-muted); }
.tools-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: var(--spacing-md); margin-top: var(--spacing-md); }
.tool-item { display: flex; flex-direction: column; align-items: center; text-align: center; padding: var(--spacing-md); background-color: var(--primary); border-radius: var(--radius-md); transition: transform var(--transition-speed) var(--transition-ease); }
.tool-item:hover { transform: translateY(-4px); }
.tool-item span.mdi { font-size: 2rem; color: var(--accent); margin-bottom: var(--spacing-sm); }
.tool-item h3 { margin: 0; font-size: 1rem; color: var(--text); }
.tool-item p { margin: var(--spacing-xs) 0 0; font-size: 0.875rem; color: var(--text-muted); }
.quick-chat-form { margin-top: var(--spacing-md); }
.input-group { display: flex; gap: var(--spacing-sm); }
.input-group input { flex: 1; padding: var(--spacing-sm) var(--spacing-md); border: none; border-radius: var(--radius-md); background-color: var(--primary); color: var(--text); }
.input-group button { padding: var(--spacing-sm) var(--spacing-md); background-color: var(--accent); color: var(--text); border-radius: var(--radius-md); transition: all var(--transition-speed) var(--transition-ease); }
.input-group button:hover { filter: brightness(1.1); }
.quick-chat-messages { margin-top: var(--spacing-md); max-height: 200px; overflow-y: auto; }
.message { display: flex; align-items: flex-start; gap: var(--spacing-sm); margin-top: var(--spacing-sm); padding: var(--spacing-sm); border-radius: var(--radius-md); background-color: var(--primary); }
.message-user { margin-left: auto; background-color: var(--accent); }
.message-ai { margin-right: auto; }
.message span.mdi { font-size: 1.25rem; }
.message p { margin: 0; font-size: 0.875rem; }
@media (max-width: 768px) {
.grid-container { grid-template-columns: 1fr; }
}
```
```javascript
document.addEventListener('DOMContentLoaded', () => {
const quickChatForm = document.getElementById('quickChatForm');
const quickChatMessages = document.getElementById('quickChatMessages');
quickChatForm.addEventListener('submit', async (e) => {
e.preventDefault();
const input = quickChatForm.querySelector('input');
const message = input.value.trim();
if (message) {
// Add user message
addMessage('user', message);
input.value = '';
try {
const response = await fetch('/api/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ message })
});
if (response.ok) {
const data = await response.json();
addMessage('ai', data.response);
} else {
throw new Error('Failed to get response');
}
} catch (error) {
console.error('Chat error:', error);
addMessage('error', 'Sorry, something went wrong. Please try again.');
}
}
});
function addMessage(type, content) {
const messageDiv = document.createElement('div');
messageDiv.classList.add('message', `message-${type}`);
const icon = document.createElement('span');
icon.classList.add('mdi');
icon.classList.add(type === 'user' ? 'mdi-account' : 'mdi-robot');
const text = document.createElement('p');
text.textContent = content;
messageDiv.appendChild(icon);
messageDiv.appendChild(text);
quickChatMessages.appendChild(messageDiv);
quickChatMessages.scrollTop = quickChatMessages.scrollHeight;
}
});
```
--------------------------------
### Environment Variables Configuration (Environment)
Source: https://github.com/smauldin100/santiskills/blob/main/flask_app/README.md
Specifies the required environment variables for the AI Dashboard application, including the Flask secret key and OpenAI API key.
```env
FLASK_SECRET_KEY=your-secret-key
OPENAI_API_KEY=your-openai-api-key
```
--------------------------------
### Update Git Remotes with PAT (Shell Script)
Source: https://github.com/smauldin100/santiskills/blob/main/README.md
A helper script to update Git remotes using a Personal Access Token (PAT).
```shell
./use-token.sh
```
--------------------------------
### JavaScript for Translation Tool Interaction
Source: https://github.com/smauldin100/santiskills/blob/main/flask_app/templates/tools.html
Handles frontend logic for the translation tools, including enabling analyze buttons upon file selection, managing loading states during API calls, and displaying analysis results or errors. It makes POST requests to the `/api/analyze` endpoint.
```javascript
document.addEventListener('DOMContentLoaded', () => {
// Handle file inputs
const imageInput = document.getElementById('imageInput');
const dataInput = document.getElementById('dataInput');
[imageInput, dataInput].forEach(input => {
if (!input) return;
const button = input.closest('.tool-card').querySelector('.analyze-btn');
input.addEventListener('change', (e) => {
const file = e.target.files[0];
if (file) {
button.disabled = false;
} else {
button.disabled = true;
}
});
});
// Handle analyze buttons
document.querySelectorAll('.analyze-btn').forEach(button => {
button.addEventListener('click', async (e) => {
const card = button.closest('.tool-card');
const content = card.querySelector('.tool-content');
const result = card.querySelector('.tool-result');
const resultContent = result.querySelector('.result-content');
// Show loading state
button.disabled = true;
button.innerHTML = ' Processing...';
try {
// Get tool type and options
const toolType = card.querySelector('select').value;
let data = {};
if (card.querySelector('textarea')) {
data.text = card.querySelector('textarea').value;
}
if (card.querySelector('input[type="file"]')) {
const file = card.querySelector('input[type="file"]').files[0];
if (file) {
data.file = file;
}
}
// Add translation-specific data
if (card.querySelector('.translation-options')) {
data.fromLang = card.querySelector('.from-lang').value;
data.toLang = card.querySelector('.to-lang').value;
}
// Make API call
const response = await fetch('/api/analyze', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
tool: toolType,
...data
})
});
if (response.ok) {
const data = await response.json();
result.classList.remove('hidden');
resultContent.innerHTML = `${JSON.stringify(data.analysis, null, 2)}`;
} else {
throw new Error('Analysis failed');
}
} catch (error) {
console.error('Analysis error:', error);
result.classList.remove('hidden');
resultContent.innerHTML = `Error: ${error.message}
`;
} finally {
// Reset button state
button.disabled = false;
button.innerHTML = 'Analyze'; // Assuming the original text was 'Analyze'
}
});
});
});
```
--------------------------------
### Test OpenAI Credentials (Node.js)
Source: https://github.com/smauldin100/santiskills/blob/main/README.md
A Node.js script used to perform a sanity check on the OpenAI API credentials.
```javascript
node test-openai.mjs
```
--------------------------------
### CSS for Translation Tools UI
Source: https://github.com/smauldin100/santiskills/blob/main/flask_app/templates/tools.html
Provides the CSS rules for styling the translation tool interface. It defines layouts for containers, grids, cards, headers, and options, as well as styling for text areas, upload areas, buttons, and responsiveness.
```css
.tools-container { padding: var(--spacing-lg); }
.tools-grid { display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: var(--spacing-lg);
}
.tool-card { background-color: var(--secondary);
border-radius: var(--radius-lg);
padding: var(--spacing-lg);
display: flex;
flex-direction: column;
gap: var(--spacing-md);
}
.tool-header { display: flex;
align-items: center;
gap: var(--spacing-md);
}
.tool-header span.mdi { font-size: 2rem;
color: var(--accent);
}
.tool-header h3 { margin: 0;
font-size: 1.25rem;
}
.tool-card p { color: var(--text-muted);
margin: 0;
}
.tool-content { display: flex;
flex-direction: column;
gap: var(--spacing-md);
}
.tool-options { display: flex;
gap: var(--spacing-md);
}
.tool-options select, .translation-options select { flex: 1;
padding: var(--spacing-sm) var(--spacing-md);
background-color: var(--primary);
border: none;
border-radius: var(--radius-md);
color: var(--text);
}
textarea { width: 100%;
padding: var(--spacing-md);
background-color: var(--primary);
border: none;
border-radius: var(--radius-md);
color: var(--text);
resize: vertical;
}
.image-upload-area, .data-upload-area { border: 2px dashed var(--accent);
border-radius: var(--radius-md);
padding: var(--spacing-xl);
text-align: center;
cursor: pointer;
transition: all var(--transition-speed) var(--transition-ease);
}
.image-upload-area:hover, .data-upload-area:hover { border-color: var(--text);
background-color: var(--primary);
}
.image-upload-area label, .data-upload-area label { display: flex;
flex-direction: column;
align-items: center;
gap: var(--spacing-sm);
cursor: pointer;
}
.image-upload-area span.mdi, .data-upload-area span.mdi { font-size: 2rem;
color: var(--accent);
}
.analyze-btn { display: flex;
align-items: center;
justify-content: center;
gap: var(--spacing-sm);
padding: var(--spacing-md);
background-color: var(--accent);
color: var(--secondary);
border: none;
border-radius: var(--radius-md);
cursor: pointer;
transition: all var(--transition-speed) var(--transition-ease);
}
.analyze-btn:hover { filter: brightness(1.1);
}
.analyze-btn:disabled { background-color: var(--text-muted);
cursor: not-allowed;
}
.translation-options { display: flex;
align-items: center;
gap: var(--spacing-md);
}
.swap-btn { padding: var(--spacing-sm);
background-color: var(--primary);
border: none;
border-radius: var(--radius-md);
cursor: pointer;
transition: all var(--transition-speed) var(--transition-ease);
}
.swap-btn:hover { background-color: var(--accent);
color: var(--secondary);
}
.tool-result { background-color: var(--primary);
border-radius: var(--radius-md);
padding: var(--spacing-md);
}
.tool-result h4 { margin: 0 0 var(--spacing-sm);
font-size: 1rem;
}
.hidden { display: none; }
@media (max-width: 768px) {
.tools-grid { grid-template-columns: 1fr; }
}
```
--------------------------------
### AI Dashboard Layout and Component Styling
Source: https://github.com/smauldin100/santiskills/blob/main/flask_app/templates/base.html
Styles the main layout container, header, navigation menu, and navigation links. It ensures a responsive grid layout and visually appealing header with navigation.
```css
.app-container {
display: grid;
grid-template-rows: auto 1fr;
min-height: 100vh;
}
.header {
background-color: var(--secondary);
padding: var(--spacing-md) var(--spacing-lg);
display: flex;
align-items: center;
justify-content: space-between;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.header h1 {
font-size: 1.5rem;
font-weight: 600;
}
.nav-menu {
display: flex;
gap: var(--spacing-md);
}
.nav-link {
color: var(--text-muted);
text-decoration: none;
padding: var(--spacing-sm) var(--spacing-md);
border-radius: var(--radius-md);
transition: all var(--transition-speed) var(--transition-ease);
display: flex;
align-items: center;
gap: var(--spacing-sm);
}
.nav-link:hover,
.nav-link.active {
color: var(--text);
background-color: var(--accent);
}
```
--------------------------------
### AI Dashboard Utility and Animation Styles
Source: https://github.com/smauldin100/santiskills/blob/main/flask_app/templates/base.html
Provides styling for navigation links with icons, main content padding, general button resets, error message display, and a fade-in animation for elements.
```css
.nav-link span.mdi {
font-size: 1.25rem;
}
.main-content {
padding: var(--spacing-lg);
}
/* Utility Classes */
.animate-fade-in {
animation: fadeIn 0.3s ease-in-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
button {
background: none;
border: none;
color: inherit;
cursor: pointer;
font: inherit;
}
.error {
color: #ff4444;
padding: var(--spacing-md);
background-color: rgba(255, 68, 68, 0.1);
border-radius: var(--radius-md);
}
```
--------------------------------
### Code Block Styling for AI Dashboard
Source: https://github.com/smauldin100/santiskills/blob/main/flask_app/templates/base.html
Styles `pre` elements to display code snippets with a dark background, padding, rounded corners, and horizontal scrollbars for long lines, ensuring readability.
```css
pre {
background-color: var(--secondary);
padding: var(--spacing-md);
border-radius: var(--radius-md);
overflow-x: auto;
white-space: pre-wrap;
word-wrap: break-word;
}
```
--------------------------------
### Restore Original HTML on Button Click (JavaScript)
Source: https://github.com/smauldin100/santiskills/blob/main/flask_app/templates/tools.html
This snippet captures and restores the original HTML content of a button when it's clicked. It stores the original HTML in a 'data-original-html' attribute. No external dependencies are explicitly mentioned.
```javascript
rHTML = button.dataset.originalHtml || button.innerHTML; } }); });
```
--------------------------------
### Copy and Save Message Functionality (JavaScript)
Source: https://github.com/smauldin100/santiskills/blob/main/flask_app/templates/chat.html
Handles copying message content to the clipboard and toggling a bookmark icon for saving messages. It listens for clicks on specific buttons within a message element and updates the UI accordingly. Requires 'mdi' CSS classes for icons.
```javascript
document.addEventListener('click', (e) => {
const btn = e.target.closest('.action-btn');
if (!btn) return;
const message = btn.closest('.message-content').querySelector('p').textContent;
if (btn.title === 'Copy') {
navigator.clipboard.writeText(message)
.then(() => {
btn.querySelector('span').classList.remove('mdi-content-copy');
btn.querySelector('span').classList.add('mdi-check');
setTimeout(() => {
btn.querySelector('span').classList.remove('mdi-check');
btn.querySelector('span').classList.add('mdi-content-copy');
}, 2000);
})
.catch(console.error);
} else if (btn.title === 'Save') {
btn.querySelector('span').classList.toggle('mdi-bookmark-outline');
btn.querySelector('span').classList.toggle('mdi-bookmark');
}
});
```
--------------------------------
### CSS Variables and Global Styles for AI Dashboard
Source: https://github.com/smauldin100/santiskills/blob/main/flask_app/templates/base.html
Defines CSS custom properties for colors, spacing, borders, and transitions, along with global styles for the body and box-sizing. This serves as the foundational styling for the entire dashboard.
```css
:root {
/* Colors */
--primary: #1a1a1a;
--secondary: #252525;
--accent: #7c4dff;
--text: #ffffff;
--text-muted: #888888;
/* Spacing */
--spacing-xs: 0.25rem;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 1.5rem;
--spacing-xl: 2rem;
/* Border Radius */
--radius-sm: 0.25rem;
--radius-md: 0.5rem;
--radius-lg: 1rem;
/* Transitions */
--transition-speed: 0.2s;
--transition-ease: ease-in-out;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background-color: var(--primary);
color: var(--text);
line-height: 1.6;
}
```
--------------------------------
### Santiskills Chat Interface CSS Styling
Source: https://github.com/smauldin100/santiskills/blob/main/flask_app/templates/chat.html
CSS rules for the Santiskills chat interface, defining grid layout, sidebar styling, message appearance, input fields, and responsive adjustments for different screen sizes. It utilizes CSS variables for theming.
```css
.chat-container { display: grid; grid-template-columns: 300px 1fr; gap: var(--spacing-lg); height: calc(100vh - 140px); padding: var(--spacing-lg); }
.chat-sidebar { background-color: var(--secondary); border-radius: var(--radius-lg); padding: var(--spacing-lg); display: flex; flex-direction: column; gap: var(--spacing-xl); }
.chat-options, .chat-history { display: flex; flex-direction: column; gap: var(--spacing-md); }
.option-group { display: flex; flex-direction: column; gap: var(--spacing-xs); }
.option-group label { font-size: 0.875rem; color: var(--text-muted); }
.option-group select, .option-group input[type="range"] { width: 100%; padding: var(--spacing-sm); background-color: var(--primary); border: none; border-radius: var(--radius-md); color: var(--text); }
.history-list { display: flex; flex-direction: column; gap: var(--spacing-sm); }
.history-item { display: flex; align-items: center; gap: var(--spacing-sm); padding: var(--spacing-sm); border-radius: var(--radius-md); cursor: pointer; transition: background-color var(--transition-speed) var(--transition-ease); }
.history-item:hover, .history-item.active { background-color: var(--primary); }
.history-item span.mdi { font-size: 1.25rem; color: var(--accent); }
.history-content p { margin: 0; font-size: 0.875rem; }
.history-content small { color: var(--text-muted); font-size: 0.75rem; }
.chat-main { display: flex; flex-direction: column; background-color: var(--secondary); border-radius: var(--radius-lg); overflow: hidden; }
.chat-messages { flex: 1; padding: var(--spacing-lg); overflow-y: auto; display: flex; flex-direction: column; gap: var(--spacing-md); }
.message { display: flex; align-items: flex-start; gap: var(--spacing-md); max-width: 80%; }
.message-ai { margin-right: auto; }
.message-user { margin-left: auto; flex-direction: row-reverse; }
.message span.mdi { font-size: 1.5rem; color: var(--accent); }
.message-content { background-color: var(--primary); padding: var(--spacing-md); border-radius: var(--radius-lg); position: relative; }
.message-user .message-content { background-color: var(--accent); color: var(--secondary); }
.message-actions { display: flex; gap: var(--spacing-xs); margin-top: var(--spacing-xs); opacity: 0; transition: opacity var(--transition-speed) var(--transition-ease); }
.message-content:hover .message-actions { opacity: 1; }
.action-btn { padding: var(--spacing-xs); font-size: 0.875rem; }
.chat-input { padding: var(--spacing-lg); background-color: var(--primary); display: flex; flex-direction: column; gap: var(--spacing-md); }
.input-group { display: flex; align-items: flex-end; gap: var(--spacing-sm); }
.input-group textarea { flex: 1; padding: var(--spacing-sm) var(--spacing-md); background-color: var(--secondary); border: none; border-radius: var(--radius-md); color: var(--text); resize: none; min-height: 40px; max-height: 120px; }
.attach-btn, .send-btn { padding: var(--spacing-sm); border-radius: var(--radius-md); background-color: var(--secondary); }
.send-btn { background-color: var(--accent); color: var(--secondary); }
.input-actions { display: flex; gap: var(--spacing-md); }
@media (max-width: 768px) {
.chat-container { grid-template-columns: 1fr; }
.chat-sidebar { display: none; }
}
```
--------------------------------
### Swap Language Selection UI (JavaScript)
Source: https://github.com/smauldin100/santiskills/blob/main/flask_app/templates/tools.html
This JavaScript code handles the functionality of a language swap button. It reads the currently selected 'from' and 'to' languages from dropdowns and swaps their values, unless the 'from' language is set to 'auto'.
```javascript
const swapBtn = document.querySelector('.swap-btn');
if (swapBtn) {
swapBtn.addEventListener('click', () => {
const fromLang = document.querySelector('.from-lang');
const toLang = document.querySelector('.to-lang');
const temp = fromLang.value;
if (temp !== 'auto') {
fromLang.value = toLang.value;
toLang.value = temp;
}
});
}
```
--------------------------------
### Santiskills Chat Interface JavaScript Functionality
Source: https://github.com/smauldin100/santiskills/blob/main/flask_app/templates/chat.html
JavaScript code for enhancing the Santiskills chat interface. It includes event listeners for temperature slider updates, automatic textarea resizing, form submission handling with API calls to '/api/chat', and appending messages to the chat display. It also handles message action button clicks.
```javascript
document.addEventListener('DOMContentLoaded', () => {
const tempRange = document.getElementById('tempRange');
const tempValue = document.getElementById('tempValue');
const chatForm = document.getElementById('chatForm');
const chatMessages = document.getElementById('chatMessages');
const textarea = chatForm.querySelector('textarea');
// Update temperature value display
tempRange.addEventListener('input', (e) => {
tempValue.textContent = e.target.value;
});
// Auto-resize textarea
textarea.addEventListener('input', () => {
textarea.style.height = 'auto';
textarea.style.height = textarea.scrollHeight + 'px';
});
// Handle chat form submission
chatForm.addEventListener('submit', async (e) => {
e.preventDefault();
const message = textarea.value.trim();
if (message) {
// Add user message
appendMessage('user', message);
textarea.value = '';
textarea.style.height = 'auto';
try {
const response = await fetch('/api/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
message,
model: document.getElementById('modelSelect').value,
temperature: parseFloat(tempRange.value),
context: document.getElementById('contextSelect').value
})
});
if (response.ok) {
const data = await response.json();
appendMessage('ai', data.response);
} else {
throw new Error('Failed to get response');
}
} catch (error) {
console.error('Chat error:', error);
appendMessage('error', 'Sorry, something went wrong. Please try again.');
}
}
});
// Handle message actions
chatMessages.addEventListener('click', (e) => {
const btn = e.target.closest('.actio
```
--------------------------------
### Append Message to Chat Interface (JavaScript)
Source: https://github.com/smauldin100/santiskills/blob/main/flask_app/templates/chat.html
Appends a new message to the chat interface. It creates HTML elements for the message, including user/robot icons and action buttons (copy/save) for non-user messages. Ensures the chat scrolls to the latest message. Relies on specific CSS classes like 'message', 'message-user', 'message-robot', 'message-actions', 'action-btn', and 'mdi' icons.
```javascript
function appendMessage(type, content) {
const messageDiv = document.createElement('div');
messageDiv.classList.add('message', `message-${type}`, 'animate-fade-in');
const iconSpan = document.createElement('span');
iconSpan.classList.add('mdi');
iconSpan.classList.add(type === 'user' ? 'mdi-account' : 'mdi-robot');
const contentDiv = document.createElement('div');
contentDiv.classList.add('message-content');
const contentP = document.createElement('p');
contentP.textContent = content;
const actionsDiv = document.createElement('div');
actionsDiv.classList.add('message-actions');
if (type !== 'user') {
const copyBtn = document.createElement('button');
copyBtn.classList.add('action-btn');
copyBtn.title = 'Copy';
copyBtn.innerHTML = '';
const saveBtn = document.createElement('button');
saveBtn.classList.add('action-btn');
saveBtn.title = 'Save';
saveBtn.innerHTML = '';
actionsDiv.appendChild(copyBtn);
actionsDiv.appendChild(saveBtn);
}
contentDiv.appendChild(contentP);
contentDiv.appendChild(actionsDiv);
messageDiv.appendChild(iconSpan);
messageDiv.appendChild(contentDiv);
const chatMessages = document.getElementById('chatMessages');
chatMessages.appendChild(messageDiv);
chatMessages.scrollTop = chatMessages.scrollHeight;
}
```
=== COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.