Sahil commited on
Commit
34353f0
Β·
verified Β·
1 Parent(s): 284597a

Upload 4 files

Browse files
Files changed (4) hide show
  1. Dockerfile (1).txt +17 -0
  2. README.md +115 -12
  3. app.py +172 -0
  4. index.html +386 -0
Dockerfile (1).txt ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ FROM python:3.11-slim
3
+
4
+ WORKDIR /app
5
+
6
+ # Install dependencies
7
+ COPY requirements.txt .
8
+ RUN pip install --no-cache-dir -r requirements.txt
9
+
10
+ # Copy application
11
+ COPY . .
12
+
13
+ # Expose port (HuggingFace Spaces uses 7860)
14
+ EXPOSE 7860
15
+
16
+ # Run application
17
+ CMD ["python", "app.py"]
README.md CHANGED
@@ -1,12 +1,115 @@
1
- ---
2
- title: Continuumlearner
3
- emoji: 🌍
4
- colorFrom: blue
5
- colorTo: green
6
- sdk: gradio
7
- sdk_version: 5.49.1
8
- app_file: app.py
9
- pinned: false
10
- ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ # 🧠 ContinuumLearner - Model Copy Training Pipeline
3
+
4
+ ## Overview
5
+ ContinuumLearner trains ContinuumGPT by copying the behavior of top AI models through Puter.js. Instead of storing user conversations, it focuses on **model-to-model learning** - teaching your AI by having it learn from the best responses.
6
+
7
+ ## How It Works
8
+
9
+ 1. **Select a top AI model** (GPT-5, Claude, Gemini, Llama, etc.)
10
+ 2. **Enter a training prompt** (questions, scenarios, topics)
11
+ 3. **AI generates response** using Puter.js (free & unlimited)
12
+ 4. **Response saved as training data** β†’ Stored in `Sahil5112/ContinuumGPT`
13
+ 5. **ContinuumGPT learns** β†’ Reads this dataset to improve responses
14
+
15
+ ## Training Philosophy
16
+
17
+ **Model Copy Learning** - Your AI learns by observing how other AI models respond:
18
+ - βœ… No user data collection
19
+ - βœ… Pure model behavior training
20
+ - βœ… Privacy-focused approach
21
+ - βœ… Continuous improvement
22
+
23
+ ## Features
24
+
25
+ βœ… **8 Top AI Models** - GPT-5, Claude Sonnet 4, Gemini 2.5, Llama 4, DeepSeek, Liquid AI
26
+ βœ… **100% Free** - Powered by Puter.js, no API keys needed
27
+ βœ… **Auto-save Buffer** - Saves 10 examples at a time to HuggingFace
28
+ βœ… **Real-time Stats** - Track dataset growth live
29
+ βœ… **Manual Control** - Flush buffer anytime
30
+ βœ… **No User Data** - Only model responses are saved
31
+
32
+ ## Deployment to HuggingFace Spaces
33
+
34
+ 1. Create a new Space on HuggingFace
35
+ 2. Select "Docker" as SDK
36
+ 3. Upload all files from `continuumlearner/` folder
37
+ 4. Add secret: `HF_TOKEN` (with write access to `Sahil5112/ContinuumGPT`)
38
+ 5. Space will start automatically
39
+
40
+ ## Environment Variables
41
+
42
+ Required:
43
+ - `HF_TOKEN` - Your HuggingFace token (for dataset write access)
44
+
45
+ Optional:
46
+ - `PORT` - Default: 7860
47
+
48
+ ## Training Data Structure
49
+
50
+ Each training example is saved as:
51
+ ```json
52
+ {
53
+ "input": "training prompt",
54
+ "output": "ai model response",
55
+ "model_used": "puter:gpt-5-nano",
56
+ "timestamp": "2025-10-30T12:00:00",
57
+ "training_id": "unique-id",
58
+ "learning_score": 1.0,
59
+ "is_new_learning": true,
60
+ "context": {
61
+ "query_length": 100,
62
+ "response_length": 500,
63
+ "training_mode": "model_copy",
64
+ "source": "puter_ai_models"
65
+ }
66
+ }
67
+ ```
68
+
69
+ ## How ContinuumGPT Uses This
70
+
71
+ Your main ContinuumGPT (in `app.py`) reads from `Sahil5112/ContinuumGPT` to:
72
+ - Learn response patterns from top AI models
73
+ - Improve answer quality over time
74
+ - Build knowledge base from model behaviors
75
+ - No user privacy concerns
76
+
77
+ ## Training Strategy
78
+
79
+ **Recommended Approach:**
80
+ 1. Use diverse prompts (questions, coding, creative writing, analysis)
81
+ 2. Try different models to get varied perspectives
82
+ 3. Train on topics you want ContinuumGPT to excel at
83
+ 4. Regularly flush buffer to update dataset
84
+ 5. Monitor stats to track progress
85
+
86
+ ## Available Models
87
+
88
+ All via Puter.js (no API keys needed):
89
+ - **OpenAI**: GPT-5 Nano
90
+ - **Anthropic**: Claude Sonnet 4
91
+ - **Google**: Gemini 2.5 Flash
92
+ - **Meta**: Llama 4 Scout
93
+ - **DeepSeek**: DeepSeek Chat
94
+ - **Liquid AI**: LFM-7B
95
+
96
+ ## Usage
97
+
98
+ 1. **Select AI model** from the grid
99
+ 2. **Enter training prompt** (what you want ContinuumGPT to learn)
100
+ 3. **Click "Train Model"** - AI generates response
101
+ 4. **Response auto-saves** to buffer
102
+ 5. **Manual flush** or auto-save when buffer full (10 examples)
103
+ 6. **Refresh stats** to see dataset growth
104
+
105
+ ## Privacy & Data
106
+
107
+ - βœ… NO user conversations stored
108
+ - βœ… Only AI model responses saved
109
+ - βœ… All data is training examples
110
+ - βœ… Dataset publicly accessible on HuggingFace
111
+ - βœ… Full transparency
112
+
113
+ ## License
114
+
115
+ MIT License - Free to use and modify
app.py ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import os
3
+ import json
4
+ import time
5
+ from datetime import datetime
6
+ from flask import Flask, request, jsonify, send_from_directory
7
+ from flask_cors import CORS
8
+ from datasets import load_dataset, Dataset
9
+ import requests
10
+
11
+ app = Flask(__name__, static_folder=".", static_url_path="")
12
+ CORS(app, supports_credentials=True)
13
+
14
+ # HuggingFace Configuration
15
+ HF_TOKEN = os.getenv("HF_TOKEN")
16
+ TRAINING_DATASET = "Sahil5112/ContinuumGPT" # Main training dataset for ContinuumGPT
17
+ CONVERSATION_BUFFER = []
18
+ MAX_BUFFER_SIZE = 10 # Save to HF after 10 training examples
19
+
20
+ def load_training_dataset():
21
+ """Load existing training data from HuggingFace"""
22
+ try:
23
+ if HF_TOKEN:
24
+ dataset = load_dataset(TRAINING_DATASET, split="train", token=HF_TOKEN)
25
+ return [dict(row) for row in dataset]
26
+ else:
27
+ print("⚠️ No HF_TOKEN - using local storage only")
28
+ return []
29
+ except Exception as e:
30
+ print(f"Could not load training dataset: {e}")
31
+ return []
32
+
33
+ def save_to_training_dataset(training_examples):
34
+ """Save training examples to HuggingFace dataset"""
35
+ if not HF_TOKEN:
36
+ print("❌ No HF_TOKEN - cannot save to HuggingFace")
37
+ return False
38
+
39
+ try:
40
+ # Load existing data
41
+ existing_data = load_training_dataset()
42
+
43
+ # Add new training examples
44
+ existing_data.extend(training_examples)
45
+
46
+ # Create dataset and push to HF
47
+ dataset = Dataset.from_list(existing_data)
48
+ dataset.push_to_hub(TRAINING_DATASET, token=HF_TOKEN, private=False)
49
+
50
+ print(f"βœ… Saved {len(training_examples)} training examples to {TRAINING_DATASET}")
51
+ print(f"πŸ“Š Total dataset size: {len(existing_data)} examples")
52
+ return True
53
+ except Exception as e:
54
+ print(f"❌ Error saving to dataset: {e}")
55
+ return False
56
+
57
+ @app.route("/")
58
+ def index():
59
+ return send_from_directory(".", "index.html")
60
+
61
+ @app.route("/api/train", methods=["POST"])
62
+ def train_model():
63
+ """Process AI model response and save as training data"""
64
+ global CONVERSATION_BUFFER
65
+
66
+ data = request.get_json()
67
+ user_input = data.get("user_input", "").strip()
68
+ ai_response = data.get("ai_response", "").strip()
69
+ model_used = data.get("model_used", "puter.js")
70
+
71
+ if not user_input or not ai_response:
72
+ return jsonify({"error": "Missing user_input or ai_response"}), 400
73
+
74
+ # Create training entry (model learns from this interaction)
75
+ training_entry = {
76
+ "input": user_input,
77
+ "output": ai_response,
78
+ "model_used": model_used,
79
+ "timestamp": datetime.now().isoformat(),
80
+ "training_id": str(time.time()),
81
+ "learning_score": 1.0,
82
+ "is_new_learning": True,
83
+ "context": {
84
+ "query_length": len(user_input),
85
+ "response_length": len(ai_response),
86
+ "training_mode": "model_copy",
87
+ "source": "puter_ai_models"
88
+ }
89
+ }
90
+
91
+ # Add to buffer
92
+ CONVERSATION_BUFFER.append(training_entry)
93
+
94
+ # Auto-save when buffer is full
95
+ if len(CONVERSATION_BUFFER) >= MAX_BUFFER_SIZE:
96
+ save_to_training_dataset(CONVERSATION_BUFFER.copy())
97
+ CONVERSATION_BUFFER.clear()
98
+
99
+ return jsonify({
100
+ "success": True,
101
+ "buffered": len(CONVERSATION_BUFFER),
102
+ "message": f"Training example buffered ({len(CONVERSATION_BUFFER)}/{MAX_BUFFER_SIZE})"
103
+ })
104
+
105
+ @app.route("/api/dataset-stats", methods=["GET"])
106
+ def dataset_stats():
107
+ """Get statistics about the training dataset"""
108
+ try:
109
+ training_data = load_training_dataset()
110
+
111
+ # Calculate stats
112
+ total_examples = len(training_data)
113
+ total_tokens = sum(len(d.get("input", "")) + len(d.get("output", "")) for d in training_data)
114
+ models_used = {}
115
+
116
+ for example in training_data:
117
+ model = example.get("model_used", "unknown")
118
+ models_used[model] = models_used.get(model, 0) + 1
119
+
120
+ return jsonify({
121
+ "success": True,
122
+ "total_examples": total_examples,
123
+ "total_tokens": total_tokens,
124
+ "models_used": models_used,
125
+ "buffered": len(CONVERSATION_BUFFER),
126
+ "dataset_url": f"https://huggingface.co/datasets/{TRAINING_DATASET}"
127
+ })
128
+ except Exception as e:
129
+ return jsonify({"error": str(e)}), 500
130
+
131
+ @app.route("/api/flush-buffer", methods=["POST"])
132
+ def flush_buffer():
133
+ """Manually flush the training buffer to HuggingFace"""
134
+ global CONVERSATION_BUFFER
135
+
136
+ if not CONVERSATION_BUFFER:
137
+ return jsonify({"message": "Buffer is empty, nothing to flush"})
138
+
139
+ success = save_to_training_dataset(CONVERSATION_BUFFER.copy())
140
+ count = len(CONVERSATION_BUFFER)
141
+ CONVERSATION_BUFFER.clear()
142
+
143
+ if success:
144
+ return jsonify({
145
+ "success": True,
146
+ "message": f"Flushed {count} training examples to HuggingFace"
147
+ })
148
+ else:
149
+ return jsonify({"error": "Failed to flush buffer"}), 500
150
+
151
+ if __name__ == "__main__":
152
+ port = int(os.getenv("PORT", 7860))
153
+
154
+ print("πŸš€ Starting ContinuumLearner Training Server...")
155
+ print(f"πŸ“Š Training Dataset: {TRAINING_DATASET}")
156
+ print(f"πŸŽ“ Dataset URL: https://huggingface.co/datasets/{TRAINING_DATASET}")
157
+ print("")
158
+ print("πŸ€– Training Mode: Model Copy Learning")
159
+ print(" - AI models respond to prompts")
160
+ print(" - Responses are saved as training data")
161
+ print(" - ContinuumGPT learns from these patterns")
162
+ print(" - NO user data is stored")
163
+ print("")
164
+
165
+ if HF_TOKEN:
166
+ print("βœ… HuggingFace Integration Active")
167
+ training_data = load_training_dataset()
168
+ print(f"πŸ“š Current dataset size: {len(training_data)} training examples")
169
+ else:
170
+ print("⚠️ HuggingFace Integration Disabled - Add HF_TOKEN to enable")
171
+
172
+ app.run(host="0.0.0.0", port=port, debug=False, threaded=True)
index.html ADDED
@@ -0,0 +1,386 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <!DOCTYPE html>
3
+ <html lang="en">
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>ContinuumLearner - AI Training Pipeline</title>
8
+ <script src="https://js.puter.com/v2/"></script>
9
+ <style>
10
+ * {
11
+ margin: 0;
12
+ padding: 0;
13
+ box-sizing: border-box;
14
+ }
15
+
16
+ body {
17
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
18
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
19
+ min-height: 100vh;
20
+ padding: 20px;
21
+ }
22
+
23
+ .container {
24
+ max-width: 1200px;
25
+ margin: 0 auto;
26
+ }
27
+
28
+ .header {
29
+ background: white;
30
+ padding: 30px;
31
+ border-radius: 20px;
32
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
33
+ margin-bottom: 30px;
34
+ text-align: center;
35
+ }
36
+
37
+ .header h1 {
38
+ font-size: 36px;
39
+ background: linear-gradient(135deg, #667eea, #764ba2);
40
+ -webkit-background-clip: text;
41
+ -webkit-text-fill-color: transparent;
42
+ margin-bottom: 10px;
43
+ }
44
+
45
+ .stats {
46
+ display: grid;
47
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
48
+ gap: 20px;
49
+ margin-bottom: 30px;
50
+ }
51
+
52
+ .stat-card {
53
+ background: white;
54
+ padding: 20px;
55
+ border-radius: 15px;
56
+ box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1);
57
+ text-align: center;
58
+ }
59
+
60
+ .stat-card h3 {
61
+ color: #667eea;
62
+ font-size: 32px;
63
+ margin-bottom: 5px;
64
+ }
65
+
66
+ .stat-card p {
67
+ color: #666;
68
+ font-size: 14px;
69
+ }
70
+
71
+ .training-area {
72
+ background: white;
73
+ padding: 30px;
74
+ border-radius: 20px;
75
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
76
+ margin-bottom: 30px;
77
+ }
78
+
79
+ .model-selector {
80
+ display: grid;
81
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
82
+ gap: 10px;
83
+ margin-bottom: 20px;
84
+ }
85
+
86
+ .model-btn {
87
+ padding: 15px;
88
+ background: linear-gradient(135deg, #667eea, #764ba2);
89
+ color: white;
90
+ border: none;
91
+ border-radius: 10px;
92
+ cursor: pointer;
93
+ font-size: 14px;
94
+ transition: transform 0.2s;
95
+ }
96
+
97
+ .model-btn:hover {
98
+ transform: translateY(-2px);
99
+ }
100
+
101
+ .model-btn.active {
102
+ background: linear-gradient(135deg, #f093fb, #f5576c);
103
+ }
104
+
105
+ .input-area {
106
+ margin-bottom: 20px;
107
+ }
108
+
109
+ textarea {
110
+ width: 100%;
111
+ padding: 15px;
112
+ border: 2px solid #e0e0e0;
113
+ border-radius: 10px;
114
+ font-size: 16px;
115
+ resize: vertical;
116
+ min-height: 100px;
117
+ }
118
+
119
+ .btn {
120
+ padding: 15px 30px;
121
+ background: linear-gradient(135deg, #667eea, #764ba2);
122
+ color: white;
123
+ border: none;
124
+ border-radius: 10px;
125
+ cursor: pointer;
126
+ font-size: 16px;
127
+ font-weight: bold;
128
+ margin-right: 10px;
129
+ transition: transform 0.2s;
130
+ }
131
+
132
+ .btn:hover {
133
+ transform: translateY(-2px);
134
+ }
135
+
136
+ .btn:disabled {
137
+ opacity: 0.5;
138
+ cursor: not-allowed;
139
+ }
140
+
141
+ .response-area {
142
+ background: #f8f9fa;
143
+ padding: 20px;
144
+ border-radius: 10px;
145
+ margin-top: 20px;
146
+ min-height: 150px;
147
+ }
148
+
149
+ .response-area h3 {
150
+ color: #667eea;
151
+ margin-bottom: 10px;
152
+ }
153
+
154
+ .log {
155
+ background: white;
156
+ padding: 20px;
157
+ border-radius: 15px;
158
+ box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1);
159
+ max-height: 400px;
160
+ overflow-y: auto;
161
+ }
162
+
163
+ .log-entry {
164
+ padding: 10px;
165
+ border-bottom: 1px solid #e0e0e0;
166
+ font-size: 14px;
167
+ }
168
+
169
+ .log-entry:last-child {
170
+ border-bottom: none;
171
+ }
172
+
173
+ .success {
174
+ color: #28a745;
175
+ }
176
+
177
+ .error {
178
+ color: #dc3545;
179
+ }
180
+
181
+ .loading {
182
+ display: inline-block;
183
+ width: 20px;
184
+ height: 20px;
185
+ border: 2px solid rgba(255, 255, 255, 0.3);
186
+ border-radius: 50%;
187
+ border-top-color: white;
188
+ animation: spin 1s linear infinite;
189
+ }
190
+
191
+ @keyframes spin {
192
+ to { transform: rotate(360deg); }
193
+ }
194
+ </style>
195
+ </head>
196
+ <body>
197
+ <div class="container">
198
+ <div class="header">
199
+ <h1>🧠 ContinuumLearner</h1>
200
+ <p>Model Training Pipeline - Copy AI Behavior</p>
201
+ <p style="margin-top: 10px; color: #666;">
202
+ Training dataset: <a href="https://huggingface.co/datasets/Sahil5112/ContinuumGPT" target="_blank" style="color: #667eea;">Sahil5112/ContinuumGPT</a>
203
+ </p>
204
+ <p style="margin-top: 5px; color: #999; font-size: 13px;">
205
+ πŸŽ“ Train ContinuumGPT by copying responses from top AI models
206
+ </p>
207
+ </div>
208
+
209
+ <div class="stats">
210
+ <div class="stat-card">
211
+ <h3 id="totalConversations">0</h3>
212
+ <p>Training Examples</p>
213
+ </div>
214
+ <div class="stat-card">
215
+ <h3 id="totalTokens">0</h3>
216
+ <p>Total Tokens</p>
217
+ </div>
218
+ <div class="stat-card">
219
+ <h3 id="bufferedCount">0</h3>
220
+ <p>Buffered (Unsaved)</p>
221
+ </div>
222
+ <div class="stat-card">
223
+ <h3 id="sessionCount">0</h3>
224
+ <p>This Session</p>
225
+ </div>
226
+ </div>
227
+
228
+ <div class="training-area">
229
+ <h2 style="margin-bottom: 20px; color: #667eea;">Select AI Model</h2>
230
+ <div class="model-selector" id="modelSelector">
231
+ <button class="model-btn active" data-model="puter:gpt-5-nano">GPT-5 Nano</button>
232
+ <button class="model-btn" data-model="puter:claude-sonnet-4">Claude Sonnet 4</button>
233
+ <button class="model-btn" data-model="puter:google/gemini-2.5-flash">Gemini 2.5 Flash</button>
234
+ <button class="model-btn" data-model="puter:meta-llama/llama-4-scout">Llama 4 Scout</button>
235
+ <button class="model-btn" data-model="puter:deepseek-chat">DeepSeek Chat</button>
236
+ <button class="model-btn" data-model="puter:liquid/lfm-7b">Liquid LFM-7B</button>
237
+ </div>
238
+
239
+ <div class="input-area">
240
+ <h3 style="margin-bottom: 10px; color: #667eea;">Training Input</h3>
241
+ <textarea id="userInput" placeholder="Enter a message to train the AI..."></textarea>
242
+ </div>
243
+
244
+ <button class="btn" onclick="trainModel()">πŸš€ Train Model</button>
245
+ <button class="btn" onclick="flushBuffer()">πŸ’Ύ Save to HuggingFace</button>
246
+ <button class="btn" onclick="refreshStats()">πŸ”„ Refresh Stats</button>
247
+
248
+ <div class="response-area">
249
+ <h3>AI Response</h3>
250
+ <div id="responseText" style="white-space: pre-wrap;"></div>
251
+ </div>
252
+ </div>
253
+
254
+ <div class="log">
255
+ <h2 style="margin-bottom: 15px; color: #667eea;">Training Log</h2>
256
+ <div id="trainingLog"></div>
257
+ </div>
258
+ </div>
259
+
260
+ <script>
261
+ let selectedModel = "puter:gpt-5-nano";
262
+ let sessionCount = 0;
263
+
264
+ // Model selector
265
+ document.querySelectorAll('.model-btn').forEach(btn => {
266
+ btn.addEventListener('click', function() {
267
+ document.querySelectorAll('.model-btn').forEach(b => b.classList.remove('active'));
268
+ this.classList.add('active');
269
+ selectedModel = this.dataset.model;
270
+ addLog(`Selected model: ${selectedModel}`, 'success');
271
+ });
272
+ });
273
+
274
+ async function trainModel() {
275
+ const userInput = document.getElementById('userInput').value.trim();
276
+ if (!userInput) {
277
+ alert('Please enter a message');
278
+ return;
279
+ }
280
+
281
+ const responseText = document.getElementById('responseText');
282
+ responseText.innerHTML = '<div class="loading"></div> Generating response...';
283
+
284
+ try {
285
+ // Get AI response using Puter.js
286
+ const response = await puter.ai.chat(userInput, { model: selectedModel });
287
+
288
+ responseText.textContent = response;
289
+ addLog(`βœ… Generated response using ${selectedModel}`, 'success');
290
+
291
+ // Send to backend for training
292
+ const trainResponse = await fetch('/api/train', {
293
+ method: 'POST',
294
+ headers: { 'Content-Type': 'application/json' },
295
+ body: JSON.stringify({
296
+ user_input: userInput,
297
+ ai_response: response,
298
+ model_used: selectedModel
299
+ })
300
+ });
301
+
302
+ const trainData = await trainResponse.json();
303
+
304
+ if (trainData.success) {
305
+ sessionCount++;
306
+ document.getElementById('sessionCount').textContent = sessionCount;
307
+ document.getElementById('bufferedCount').textContent = trainData.buffered;
308
+ addLog(trainData.message, 'success');
309
+
310
+ // Clear input
311
+ document.getElementById('userInput').value = '';
312
+
313
+ // Auto-save when buffer is full
314
+ if (trainData.buffered >= 10) {
315
+ addLog('Buffer full! Auto-saving to HuggingFace...', 'success');
316
+ await flushBuffer();
317
+ }
318
+ } else {
319
+ addLog('❌ Failed to save training data', 'error');
320
+ }
321
+
322
+ } catch (error) {
323
+ responseText.textContent = `Error: ${error.message}`;
324
+ addLog(`❌ Error: ${error.message}`, 'error');
325
+ }
326
+ }
327
+
328
+ async function flushBuffer() {
329
+ try {
330
+ const response = await fetch('/api/flush-buffer', { method: 'POST' });
331
+ const data = await response.json();
332
+
333
+ if (data.success) {
334
+ addLog(`πŸ’Ύ ${data.message}`, 'success');
335
+ await refreshStats();
336
+ } else {
337
+ addLog(data.message || 'Buffer empty', 'success');
338
+ }
339
+ } catch (error) {
340
+ addLog(`❌ Error flushing buffer: ${error.message}`, 'error');
341
+ }
342
+ }
343
+
344
+ async function refreshStats() {
345
+ try {
346
+ const response = await fetch('/api/dataset-stats');
347
+ const data = await response.json();
348
+
349
+ if (data.success) {
350
+ document.getElementById('totalConversations').textContent = data.total_examples;
351
+ document.getElementById('totalTokens').textContent = data.total_tokens.toLocaleString();
352
+ document.getElementById('bufferedCount').textContent = data.buffered;
353
+ addLog('πŸ“Š Stats refreshed', 'success');
354
+ }
355
+ } catch (error) {
356
+ addLog(`❌ Error refreshing stats: ${error.message}`, 'error');
357
+ }
358
+ }
359
+
360
+ function addLog(message, type = '') {
361
+ const log = document.getElementById('trainingLog');
362
+ const entry = document.createElement('div');
363
+ entry.className = `log-entry ${type}`;
364
+ entry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
365
+ log.insertBefore(entry, log.firstChild);
366
+
367
+ // Keep only last 50 entries
368
+ while (log.children.length > 50) {
369
+ log.removeChild(log.lastChild);
370
+ }
371
+ }
372
+
373
+ // Initialize stats on load
374
+ refreshStats();
375
+ addLog('πŸš€ ContinuumLearner initialized', 'success');
376
+ addLog('πŸ’‘ Select a model and start training!', 'success');
377
+
378
+ // Enter key to submit
379
+ document.getElementById('userInput').addEventListener('keydown', function(e) {
380
+ if (e.key === 'Enter' && e.ctrlKey) {
381
+ trainModel();
382
+ }
383
+ });
384
+ </script>
385
+ </body>
386
+ </html>