ClemSummer commited on
Commit
f66e5e6
Β·
1 Parent(s): b48ecb9

UI Enhancements

Browse files
content_distillery/static/content_distillery.html CHANGED
@@ -49,6 +49,14 @@
49
  πŸ€– Generate Summary
50
  </button>
51
 
 
 
 
 
 
 
 
 
52
  <!-- Output Text -->
53
  <label class="block font-semibold text-gray-700 mt-4">Summary:</label>
54
  <textarea id="outputText" rows="5" class="w-full p-3 border rounded bg-gray-50" readonly placeholder="Summary will appear here..."></textarea>
@@ -62,15 +70,33 @@
62
 
63
  <!-- Help Modal -->
64
  <div id="helpModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden">
65
- <div class="bg-white rounded-lg p-6 max-w-sm w-full shadow-lg text-left">
66
- <h2 class="text-xl font-semibold mb-4">About Content Distillery</h2>
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  <p class="text-gray-700 mb-4">
68
- This tool fetches content from various online sources and distills it into concise summaries using an a PPO model.
69
- Choose a source, optionally edit the text, and press "Generate" to see a summary.
70
- The AI reward and PPO models were from Qwen/Qwen3-0.6B-Base, used openai/summarize_from_feedback dataset and trained according to OpenAI paper "Learning to summarize from human feedback".
 
71
  </p>
 
 
 
 
72
  <button id="closeModal"
73
- class="mt-2 bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700">
74
  Close
75
  </button>
76
  </div>
@@ -101,11 +127,13 @@
101
 
102
  document.getElementById('generateBtn').addEventListener('click', async function () {
103
  const btn = document.getElementById('generateBtn');
 
104
  const post = document.getElementById('inputText').value;
105
 
106
  btn.disabled = true;
107
  btn.textContent = "πŸ€– Generating...";
108
  btn.classList.add("opacity-50");
 
109
 
110
  try {
111
  const res = await fetch('/contentdistillery', {
@@ -116,9 +144,10 @@
116
  const summary = await res.text();
117
  document.getElementById('outputText').value = summary;
118
  } catch (e) {
119
- document.getElementById('outputText').value = "Error generating summary.";
120
  }
121
 
 
122
  btn.disabled = false;
123
  btn.textContent = "πŸ€– Generate Summary";
124
  btn.classList.remove("opacity-50");
 
49
  πŸ€– Generate Summary
50
  </button>
51
 
52
+ <div id="spinner" class="flex items-center justify-center mt-2 hidden">
53
+ <svg class="animate-spin h-6 w-6 text-blue-600" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
54
+ <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
55
+ <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v8z"></path>
56
+ </svg>
57
+ <span class="ml-2 text-blue-600 font-medium">Generating summary...</span>
58
+ </div>
59
+
60
  <!-- Output Text -->
61
  <label class="block font-semibold text-gray-700 mt-4">Summary:</label>
62
  <textarea id="outputText" rows="5" class="w-full p-3 border rounded bg-gray-50" readonly placeholder="Summary will appear here..."></textarea>
 
70
 
71
  <!-- Help Modal -->
72
  <div id="helpModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden">
73
+ <div class="bg-white rounded-lg p-6 max-w-2xl w-full shadow-lg text-left overflow-y-auto max-h-[80vh]">
74
+ <h2 class="text-2xl font-bold mb-4 text-gray-900">Discussion Content Summarizer</h2>
75
+ <p class="text-gray-700 mb-6">
76
+ This tool automatically extracts content from online discussion platforms and generates concise,
77
+ high-quality summaries using advanced AI techniques.
78
+ </p>
79
+
80
+ <h3 class="text-xl font-semibold mb-3 text-gray-800">How it works</h3>
81
+ <ol class="list-decimal list-inside text-gray-700 mb-6 space-y-2">
82
+ <li><span class="font-semibold">Select a source</span> β€” Choose from supported discussion websites</li>
83
+ <li><span class="font-semibold">Review and edit</span> β€” Optionally modify the extracted text before processing</li>
84
+ <li><span class="font-semibold">Generate summary</span> β€” Click "Generate" to create an AI‑powered summary</li>
85
+ </ol>
86
+
87
+ <h3 class="text-xl font-semibold mb-3 text-gray-800">Technical foundation</h3>
88
  <p class="text-gray-700 mb-4">
89
+ The summarization is powered by a <span class="font-semibold">Proximal Policy Optimization (PPO)</span> model built on
90
+ the <span class="font-semibold">Qwen3‑0.6B‑Base</span> architecture. The system incorporates both reward modeling and policy optimization,
91
+ trained using the <code class="bg-gray-100 px-1 py-0.5 rounded">openai/summarize_from_feedback</code> dataset following methodologies
92
+ outlined in OpenAI’s <em>"Learning to summarize from human feedback"</em> research paper.
93
  </p>
94
+ <p class="text-gray-700 mb-6">
95
+ This approach ensures summaries that align with human preferences for clarity, accuracy, and relevance.
96
+ </p>
97
+
98
  <button id="closeModal"
99
+ class="mt-4 bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700">
100
  Close
101
  </button>
102
  </div>
 
127
 
128
  document.getElementById('generateBtn').addEventListener('click', async function () {
129
  const btn = document.getElementById('generateBtn');
130
+ const spinner = document.getElementById('spinner');
131
  const post = document.getElementById('inputText').value;
132
 
133
  btn.disabled = true;
134
  btn.textContent = "πŸ€– Generating...";
135
  btn.classList.add("opacity-50");
136
+ spinner.classList.remove('hidden'); // show spinner
137
 
138
  try {
139
  const res = await fetch('/contentdistillery', {
 
144
  const summary = await res.text();
145
  document.getElementById('outputText').value = summary;
146
  } catch (e) {
147
+ document.getElementById('outputText').value = "⚠️ Error generating summary.";
148
  }
149
 
150
+ spinner.classList.add('hidden'); // hide spinner
151
  btn.disabled = false;
152
  btn.textContent = "πŸ€– Generate Summary";
153
  btn.classList.remove("opacity-50");
prep/hf_save_cbow.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from huggingface_hub import upload_file
2
+
3
+ # Upload cbow_model.kv
4
+ upload_file(
5
+ path_or_fileobj="./models/cbow_model.kv",
6
+ path_in_repo="cbow_model.kv",
7
+ repo_id="ClemSummer/cbow-model-cache",
8
+ repo_type="dataset"
9
+ )
10
+
11
+ # Upload cbow_model.kv.vectors.npy
12
+ upload_file(
13
+ path_or_fileobj="./models/cbow_model.kv.vectors.npy",
14
+ path_in_repo="cbow_model.kv.vectors.npy",
15
+ repo_id="ClemSummer/cbow-model-cache",
16
+ repo_type="dataset"
17
+ )
prep/hf_save_qwen.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ from transformers import AutoTokenizer, AutoModelForCausalLM
2
+
3
+ MODEL_NAME = "Qwen/Qwen3-0.6B-Base"
4
+ tok = AutoTokenizer.from_pretrained(MODEL_NAME)
5
+ tok.save_pretrained("./qwen_model")
6
+
7
+ model = AutoModelForCausalLM.from_pretrained(MODEL_NAME)
8
+ model.save_pretrained("./qwen_model")
prep/hf_save_qwen_hf_api.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ from huggingface_hub import upload_folder
2
+
3
+ upload_folder(
4
+ repo_id="ClemSummer/qwen-model-cache",
5
+ repo_type="dataset",
6
+ folder_path="./qwen_model"
7
+ )
save_cbow_model.py β†’ prep/save_cbow_model.py RENAMED
File without changes
templates/cbow.html CHANGED
@@ -3,6 +3,7 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
 
6
  <title>CBOW Vector Calculator</title>
7
  <style>
8
  body {
@@ -97,6 +98,20 @@
97
  background-color: rgba(0,0,0,0.4);
98
  }
99
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  .modal-content {
101
  background-color: #fff;
102
  margin: 10% auto;
@@ -175,18 +190,7 @@
175
  <span class="close" onclick="closeModal('suggestionsModal')">&times;</span>
176
  <h3>Suggestions</h3>
177
  <p>What's your guess, before calculating it?</p>
178
- <ul>
179
- <li><code>mother - woman + man</code></li>
180
- <li><code>iphone - phone + tablet</code></li>
181
- <li><code>hotdog - sausage + beef</code></li>
182
- <li><code>brisbane - city + capital</code></li>
183
- <li><code>uk - monarchy</code></li>
184
- <li><code>kfc - chicken + pork</code></li>
185
- <li><code>skoda - czech + germany</code></li>
186
- <li><code>starwars - darthvader + sauron</code></li>
187
- <li><code>callofduty - gun + knife</code></li>
188
- </ul>
189
-
190
  <p><strong>Tips:</strong></p>
191
  <ul>
192
  <li>Use <code>-</code> and <code>+</code> operators, with a space before and after each operator.</li>
@@ -266,6 +270,37 @@
266
  }
267
  });
268
  </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
269
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
270
  </body>
271
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <script src="https://cdn.tailwindcss.com"></script>
7
  <title>CBOW Vector Calculator</title>
8
  <style>
9
  body {
 
98
  background-color: rgba(0,0,0,0.4);
99
  }
100
 
101
+ .use-suggestion {
102
+ margin-left: 8px;
103
+ padding: 2px 6px;
104
+ font-size: 0.8rem;
105
+ background-color: #007bff;
106
+ color: white;
107
+ border: none;
108
+ border-radius: 4px;
109
+ cursor: pointer;
110
+ }
111
+ .use-suggestion:hover {
112
+ background-color: #0056b3;
113
+ }
114
+
115
  .modal-content {
116
  background-color: #fff;
117
  margin: 10% auto;
 
190
  <span class="close" onclick="closeModal('suggestionsModal')">&times;</span>
191
  <h3>Suggestions</h3>
192
  <p>What's your guess, before calculating it?</p>
193
+ <ul id="suggestions-list"></ul>
 
 
 
 
 
 
 
 
 
 
 
194
  <p><strong>Tips:</strong></p>
195
  <ul>
196
  <li>Use <code>-</code> and <code>+</code> operators, with a space before and after each operator.</li>
 
270
  }
271
  });
272
  </script>
273
+ <script>
274
+ document.addEventListener("DOMContentLoaded", function () {
275
+ const textarea = document.querySelector("textarea[name='expression']");
276
+ const modal = document.getElementById("suggestionsModal");
277
+ const suggestions = [
278
+ "mother - woman + man",
279
+ "iphone - phone + tablet",
280
+ "hotdog - sausage + beef",
281
+ "brisbane - city + capital",
282
+ "uk - monarchy",
283
+ "kfc - chicken + pork",
284
+ "skoda - czech + germany",
285
+ "starwars - darthvader + sauron",
286
+ "callofduty - gun + knife"
287
+ ];
288
 
289
+ const list = document.getElementById("suggestions-list");
290
+
291
+ // Build the list dynamically
292
+ suggestions.forEach(suggestion => {
293
+ const li = document.createElement("li");
294
+ li.innerHTML = `<code>${suggestion}</code>
295
+ <button type="button" class="use-suggestion">Use</button>`;
296
+ li.querySelector("button").addEventListener("click", function () {
297
+ textarea.value = suggestion; // fill textarea
298
+ textarea.focus(); // optional
299
+ modal.style.display = "none"; // auto close modal
300
+ });
301
+ list.appendChild(li);
302
+ });
303
+ });
304
+ </script>
305
  </body>
306
  </html>
vit_captioning/static/captioning/index.html CHANGED
@@ -38,10 +38,11 @@
38
  </div>
39
 
40
  <button
 
41
  type="submit"
42
  class="w-full bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-4 rounded-lg transition"
43
  >
44
- Generate Captions (can repeat)
45
  </button>
46
  </form>
47
 
@@ -55,41 +56,47 @@
55
  </div>
56
 
57
  <script>
58
- const fileInput = document.getElementById('fileInput');
59
- const previewContainer = document.getElementById('previewContainer');
60
- const previewImage = document.getElementById('previewImage');
61
- const form = document.getElementById('uploadForm');
62
- const result = document.getElementById('result');
63
-
64
- // βœ… Live preview + clear old captions
65
- fileInput.addEventListener('change', () => {
66
- const file = fileInput.files[0];
67
- if (file) {
68
- const reader = new FileReader();
69
- reader.onload = e => {
70
- previewImage.src = e.target.result;
71
- previewContainer.classList.remove('hidden');
72
- };
73
- reader.readAsDataURL(file);
74
-
75
- // Clear old captions
76
- document.getElementById('greedy').innerText = "";
77
- document.getElementById('topk').innerText = "";
78
- document.getElementById('topp').innerText = "";
79
- result.classList.add('hidden');
80
-
81
- } else {
82
- previewContainer.classList.add('hidden');
83
- }
84
- });
85
-
86
- // βœ… Submit form
87
- form.addEventListener('submit', async e => {
88
- e.preventDefault();
89
- const file = fileInput.files[0];
90
- const formData = new FormData();
91
- formData.append('file', file);
 
92
 
 
 
 
 
 
93
  const res = await fetch('/generate', {
94
  method: 'POST',
95
  body: formData
@@ -100,8 +107,15 @@
100
  document.getElementById('topk').innerText = data.topk || "N/A";
101
  document.getElementById('topp').innerText = data.topp || "N/A";
102
  result.classList.remove('hidden');
103
- });
104
- </script>
 
 
 
 
 
 
 
105
 
106
  <!-- Floating Help Button -->
107
  <button id="helpButton"
 
38
  </div>
39
 
40
  <button
41
+ id="generateButton"
42
  type="submit"
43
  class="w-full bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-4 rounded-lg transition"
44
  >
45
+ Generate Captions
46
  </button>
47
  </form>
48
 
 
56
  </div>
57
 
58
  <script>
59
+ const fileInput = document.getElementById('fileInput');
60
+ const previewContainer = document.getElementById('previewContainer');
61
+ const previewImage = document.getElementById('previewImage');
62
+ const form = document.getElementById('uploadForm');
63
+ const result = document.getElementById('result');
64
+ const generateButton = document.getElementById('generateButton');
65
+
66
+ // βœ… Live preview + clear old captions
67
+ fileInput.addEventListener('change', () => {
68
+ const file = fileInput.files[0];
69
+ if (file) {
70
+ const reader = new FileReader();
71
+ reader.onload = e => {
72
+ previewImage.src = e.target.result;
73
+ previewContainer.classList.remove('hidden');
74
+ };
75
+ reader.readAsDataURL(file);
76
+
77
+ // Clear old captions
78
+ document.getElementById('greedy').innerText = "";
79
+ document.getElementById('topk').innerText = "";
80
+ document.getElementById('topp').innerText = "";
81
+ result.classList.add('hidden');
82
+ } else {
83
+ previewContainer.classList.add('hidden');
84
+ }
85
+ });
86
+
87
+ // βœ… Submit form
88
+ form.addEventListener('submit', async e => {
89
+ e.preventDefault();
90
+
91
+ // Disable button while generating
92
+ generateButton.disabled = true;
93
+ generateButton.innerText = "Generating...";
94
 
95
+ const file = fileInput.files[0];
96
+ const formData = new FormData();
97
+ formData.append('file', file);
98
+
99
+ try {
100
  const res = await fetch('/generate', {
101
  method: 'POST',
102
  body: formData
 
107
  document.getElementById('topk').innerText = data.topk || "N/A";
108
  document.getElementById('topp').innerText = data.topp || "N/A";
109
  result.classList.remove('hidden');
110
+ } catch (error) {
111
+ alert("⚠️ Error generating captions. Please try again.");
112
+ } finally {
113
+ // Re-enable button with new text
114
+ generateButton.disabled = false;
115
+ generateButton.innerText = "Generate Captions (can repeat)";
116
+ }
117
+ });
118
+ </script>
119
 
120
  <!-- Floating Help Button -->
121
  <button id="helpButton"