courtneyf2 commited on
Commit
e702d93
·
verified ·
1 Parent(s): 33c3a4b

Upload 14 files

Browse files
Files changed (14) hide show
  1. App.css +38 -0
  2. App.js +77 -0
  3. App.test.js +8 -0
  4. README.md +6 -5
  5. app.py +760 -0
  6. gitattributes +35 -0
  7. index.css +13 -0
  8. index.js +17 -0
  9. logo.svg +1 -0
  10. model_functions.py +688 -0
  11. package.json +39 -0
  12. reportWebVitals.js +13 -0
  13. requirements.txt +11 -0
  14. setupTests.js +5 -0
App.css ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .App {
2
+ text-align: center;
3
+ }
4
+
5
+ .App-logo {
6
+ height: 40vmin;
7
+ pointer-events: none;
8
+ }
9
+
10
+ @media (prefers-reduced-motion: no-preference) {
11
+ .App-logo {
12
+ animation: App-logo-spin infinite 20s linear;
13
+ }
14
+ }
15
+
16
+ .App-header {
17
+ background-color: #282c34;
18
+ min-height: 100vh;
19
+ display: flex;
20
+ flex-direction: column;
21
+ align-items: center;
22
+ justify-content: center;
23
+ font-size: calc(10px + 2vmin);
24
+ color: white;
25
+ }
26
+
27
+ .App-link {
28
+ color: #61dafb;
29
+ }
30
+
31
+ @keyframes App-logo-spin {
32
+ from {
33
+ transform: rotate(0deg);
34
+ }
35
+ to {
36
+ transform: rotate(360deg);
37
+ }
38
+ }
App.js ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState } from 'react';
2
+ import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card';
3
+ import { Slider } from '@/components/ui/slider';
4
+
5
+ const ModelComparisonInterface = () => {
6
+ const [temperature, setTemperature] = useState(0.7);
7
+ const [input, setInput] = useState('');
8
+ const [outputs, setOutputs] = useState({
9
+ model1: '',
10
+ model2: ''
11
+ });
12
+
13
+ return (
14
+ <div className="w-full max-w-4xl p-4">
15
+ <Card className="mb-4">
16
+ <CardHeader>
17
+ <CardTitle>Language Model Comparison</CardTitle>
18
+ </CardHeader>
19
+ <CardContent>
20
+ <div className="space-y-4">
21
+ <div>
22
+ <label className="block text-sm font-medium mb-2">
23
+ Input Text
24
+ </label>
25
+ <textarea
26
+ className="w-full h-32 p-2 border rounded"
27
+ value={input}
28
+ onChange={(e) => setInput(e.target.value)}
29
+ placeholder="Enter your text here..."
30
+ />
31
+ </div>
32
+
33
+ <div>
34
+ <label className="block text-sm font-medium mb-2">
35
+ Temperature: {temperature}
36
+ </label>
37
+ <Slider
38
+ value={[temperature]}
39
+ onValueChange={(value) => setTemperature(value[0])}
40
+ min={0}
41
+ max={1}
42
+ step={0.1}
43
+ className="w-full"
44
+ />
45
+ </div>
46
+
47
+ <div className="grid grid-cols-2 gap-4">
48
+ <Card>
49
+ <CardHeader>
50
+ <CardTitle>Model 1 Output</CardTitle>
51
+ </CardHeader>
52
+ <CardContent>
53
+ <div className="min-h-32 p-2 border rounded bg-gray-50">
54
+ {outputs.model1 || 'Output will appear here...'}
55
+ </div>
56
+ </CardContent>
57
+ </Card>
58
+
59
+ <Card>
60
+ <CardHeader>
61
+ <CardTitle>Model 2 Output</CardTitle>
62
+ </CardHeader>
63
+ <CardContent>
64
+ <div className="min-h-32 p-2 border rounded bg-gray-50">
65
+ {outputs.model2 || 'Output will appear here...'}
66
+ </div>
67
+ </CardContent>
68
+ </Card>
69
+ </div>
70
+ </div>
71
+ </CardContent>
72
+ </Card>
73
+ </div>
74
+ );
75
+ };
76
+
77
+ export default ModelComparisonInterface;
App.test.js ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ import { render, screen } from '@testing-library/react';
2
+ import App from './App';
3
+
4
+ test('renders learn react link', () => {
5
+ render(<App />);
6
+ const linkElement = screen.getByText(/learn react/i);
7
+ expect(linkElement).toBeInTheDocument();
8
+ });
README.md CHANGED
@@ -1,12 +1,13 @@
1
  ---
2
- title: IS41720 ZoneB
3
- emoji: 😻
4
- colorFrom: indigo
5
- colorTo: red
6
  sdk: gradio
7
- sdk_version: 5.49.0
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
+ title: IS41720 Zone
3
+ emoji: 📉
4
+ colorFrom: green
5
+ colorTo: blue
6
  sdk: gradio
7
+ sdk_version: 5.13.2
8
  app_file: app.py
9
  pinned: false
10
+ short_description: An interactive space for university students
11
  ---
12
 
13
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py ADDED
@@ -0,0 +1,760 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import gradio as gr
3
+ import openai
4
+ import PyPDF2
5
+ import numpy as np
6
+ import math
7
+
8
+ MODEL_STATUS = {
9
+ 'tiktoken': False,
10
+ 'transformers': False,
11
+ 'torch': False,
12
+ 'model_loaded': False,
13
+ 'error_messages': []
14
+ }
15
+
16
+ try:
17
+ import tiktoken
18
+ gpt_tokenizer = tiktoken.get_encoding("gpt2")
19
+ MODEL_STATUS['tiktoken'] = True
20
+ except Exception as e:
21
+ MODEL_STATUS['error_messages'].append(f"tiktoken error: {str(e)}")
22
+ gpt_tokenizer = None
23
+
24
+ try:
25
+ from transformers import AutoTokenizer, AutoModel
26
+ import torch
27
+ MODEL_STATUS['transformers'] = True
28
+ MODEL_STATUS['torch'] = True
29
+
30
+ # Load lightweight model
31
+ print("Loading model...")
32
+ tokenizer = AutoTokenizer.from_pretrained("prajjwal1/bert-tiny")
33
+ model = AutoModel.from_pretrained("prajjwal1/bert-tiny")
34
+
35
+ MODEL_STATUS['model_loaded'] = True
36
+ print("model loaded successfully!")
37
+
38
+ except Exception as e:
39
+ MODEL_STATUS['error_messages'].append(f"Model loading error: {str(e)}")
40
+ tokenizer = None
41
+ model = None
42
+
43
+ # OpenAI setup
44
+ OPENAI_API_KEY = os.getenv("openAI_TOKEN")
45
+ if OPENAI_API_KEY:
46
+ openai.api_key = OPENAI_API_KEY
47
+ else:
48
+ MODEL_STATUS['error_messages'].append("OpenAI API key not found")
49
+
50
+ import shutil
51
+ import os
52
+
53
+ cache_dir = os.path.expanduser("~/.cache/huggingface")
54
+ if os.path.exists(cache_dir):
55
+ try:
56
+ total_size = sum(
57
+ os.path.getsize(os.path.join(dirpath, filename))
58
+ for dirpath, dirnames, filenames in os.walk(cache_dir)
59
+ for filename in filenames
60
+ ) / (1024**3)
61
+
62
+ if total_size > 40:
63
+ shutil.rmtree(cache_dir)
64
+ print(f"Cleared {total_size:.2f}GB cache")
65
+ except Exception as e:
66
+ print(f"Cache cleanup error: {e}")
67
+
68
+ from model_functions import *
69
+
70
+ def tokenize_text(text):
71
+ if not text.strip():
72
+ return [], 0, "Enter some text to see tokenization"
73
+
74
+ if gpt_tokenizer:
75
+ try:
76
+ tokens = gpt_tokenizer.encode(text)
77
+ token_strings = []
78
+ for token in tokens:
79
+ try:
80
+ decoded = gpt_tokenizer.decode([token])
81
+ token_strings.append(decoded)
82
+ except UnicodeDecodeError:
83
+ token_strings.append(f"<token_{token}>")
84
+ return token_strings, len(tokens), f"Text tokenized successfully → {len(tokens)} tokens"
85
+ except Exception as e:
86
+ return [], 0, f"Tokenization error: {str(e)}"
87
+ else:
88
+ # Fallback: simple whitespace tokenization
89
+ tokens = text.split()
90
+ return tokens, len(tokens), f"Using fallback tokenization → {len(tokens)} tokens (tiktoken unavailable)"
91
+
92
+ def get_next_token_predictions(text):
93
+ """Get next token predictions using OpenAI API"""
94
+ if not text.strip():
95
+ return "Enter some text to see predictions"
96
+
97
+ if not OPENAI_API_KEY:
98
+ return "OpenAI API key not available - cannot generate predictions"
99
+
100
+ try:
101
+ client = openai.OpenAI(api_key=OPENAI_API_KEY)
102
+ response = client.chat.completions.create(
103
+ model="gpt-3.5-turbo",
104
+ messages=[
105
+ {"role": "system", "content": "Complete the following text with the next most likely word. Provide exactly 3 options with their approximate probabilities."},
106
+ {"role": "user", "content": f"Text: '{text}'\n\nNext word options:"}
107
+ ],
108
+ temperature=0.1,
109
+ max_tokens=50
110
+ )
111
+ return response.choices[0].message.content
112
+ except Exception as e:
113
+ return f"Error getting predictions: {str(e)}"
114
+
115
+ def merge_subword_tokens(tokens, attention_matrix):
116
+ """Merge subword tokens back into words for cleaner viz"""
117
+ merged_tokens = []
118
+ merged_attention = []
119
+ current_word = ""
120
+ current_indices = []
121
+
122
+ for i, token in enumerate(tokens):
123
+ if token.startswith('##'):
124
+ current_word += token[2:]
125
+ current_indices.append(i)
126
+ else:
127
+ if current_word:
128
+ merged_tokens.append(current_word)
129
+ merged_attention.append(current_indices)
130
+ current_word = token
131
+ current_indices = [i]
132
+
133
+ if current_word:
134
+ merged_tokens.append(current_word)
135
+ merged_attention.append(current_indices)
136
+
137
+ # Merge attention weights by averaging
138
+ merged_matrix = np.zeros((len(merged_tokens), len(merged_tokens)))
139
+ for i, i_indices in enumerate(merged_attention):
140
+ for j, j_indices in enumerate(merged_attention):
141
+ # Average attention between word groups
142
+ weights = []
143
+ for ii in i_indices:
144
+ for jj in j_indices:
145
+ if ii < attention_matrix.shape[0] and jj < attention_matrix.shape[1]:
146
+ weights.append(attention_matrix[ii, jj])
147
+ if weights:
148
+ merged_matrix[i, j] = np.mean(weights)
149
+
150
+ return merged_tokens, merged_matrix
151
+
152
+ def create_attention_network_svg(text):
153
+ if not text.strip():
154
+ return "Enter text to see attention network"
155
+
156
+ if not MODEL_STATUS['model_loaded']:
157
+ return f"Attention model not available. Errors: {MODEL_STATUS['error_messages']}"
158
+
159
+ try:
160
+ # Tokenize input
161
+ inputs = tokenizer(text, return_tensors="pt", truncation=True, max_length=64)
162
+ tokens = tokenizer.convert_ids_to_tokens(inputs["input_ids"][0])
163
+
164
+ with torch.no_grad():
165
+ outputs = model(**inputs, output_attentions=True)
166
+
167
+ # Remove special tokens
168
+ clean_tokens = []
169
+ clean_indices = []
170
+ for i, token in enumerate(tokens):
171
+ if token not in ['[CLS]', '[SEP]', '[PAD]']:
172
+ clean_tokens.append(token)
173
+ clean_indices.append(i)
174
+
175
+ if len(clean_indices) < 2:
176
+ return "Need at least 2 valid tokens for attention visualisation."
177
+
178
+ # SEARCH for best head: max variance
179
+ best_attention = None
180
+ best_name = ""
181
+ best_tokens = []
182
+ best_variance = -1
183
+
184
+ debug_info = f"Total Layers: {len(outputs.attentions)}\n"
185
+
186
+ for layer_idx, layer_att in enumerate(outputs.attentions):
187
+ num_heads = layer_att.shape[1]
188
+ for head_idx in range(num_heads):
189
+ attn_matrix = layer_att[0, head_idx].numpy()
190
+ trimmed_attention = attn_matrix[np.ix_(clean_indices, clean_indices)]
191
+ variance = np.var(trimmed_attention)
192
+
193
+ debug_info += f"Layer {layer_idx}, Head {head_idx} — Variance: {variance:.5f}\n"
194
+
195
+ if variance > best_variance:
196
+ best_attention = trimmed_attention
197
+ best_name = f"Layer {layer_idx}, Head {head_idx}"
198
+ best_tokens = clean_tokens
199
+ best_variance = variance
200
+
201
+ if best_attention is None:
202
+ return "Could not extract valid attention."
203
+
204
+ # Merge subwords
205
+ merged_tokens, merged_attention = merge_subword_tokens(best_tokens, best_attention)
206
+ n_tokens = len(merged_tokens)
207
+
208
+ if n_tokens < 2:
209
+ return "Too few tokens after merging for attention graph."
210
+
211
+ # SVG dimensions
212
+ width, height = 1000, 500
213
+ margin = 50
214
+
215
+ # Linear positions
216
+ positions = []
217
+ for i in range(n_tokens):
218
+ x = margin + (width - 2*margin) * i / (n_tokens - 1)
219
+ y = height // 2
220
+ positions.append((x, y))
221
+
222
+ # Start SVG
223
+ svg = f'<svg width="{width}" height="{height}" xmlns="http://www.w3.org/2000/svg">'
224
+ svg += '<style>.token-text { font-family: Arial; font-size: 14px; text-anchor: middle; font-weight: bold; }'
225
+ svg += '.debug-text { font-family: monospace; font-size: 10px; fill: #666; }</style>'
226
+
227
+ # Choose top-N attention connections
228
+ num_top_connections = 20
229
+ pairs = []
230
+ for i in range(n_tokens):
231
+ for j in range(n_tokens):
232
+ if i != j:
233
+ pairs.append((merged_attention[i, j], i, j))
234
+ pairs.sort(reverse=True)
235
+ top_pairs = pairs[:num_top_connections]
236
+
237
+ # Draw attention arcs
238
+ for weight, i, j in top_pairs:
239
+ x1, y1 = positions[i]
240
+ x2, y2 = positions[j]
241
+ mid_x = (x1 + x2) / 2
242
+ curve_y = y1 - 80 if (i + j) % 2 == 0 else y1 + 80
243
+
244
+ # Color coding
245
+ if weight > 0.08:
246
+ color = "#d32f2f" # red
247
+ opacity = "0.8"
248
+ elif weight > 0.04:
249
+ color = "#ff9800" # orange
250
+ opacity = "0.6"
251
+ else:
252
+ color = "#2196f3" # blue
253
+ opacity = "0.4"
254
+
255
+ thickness = max(2, weight * 10)
256
+
257
+ svg += f'<path d="M {x1},{y1} Q {mid_x},{curve_y} {x2},{y2}" '
258
+ svg += f'stroke="{color}" stroke-width="{thickness}" fill="none" opacity="{opacity}"/>'
259
+
260
+ # Draw nodes
261
+ for i, (token, (x, y)) in enumerate(zip(merged_tokens, positions)):
262
+ svg += f'<circle cx="{x}" cy="{y}" r="25" fill="white" stroke="black" stroke-width="2"/>'
263
+ svg += f'<text x="{x}" y="{y+5}" class="token-text">{token[:10]}</text>'
264
+
265
+ # Legend and info
266
+ svg += f'<text x="20" y="{height - 130}" style="font-family: Arial; font-size: 16px; font-weight: bold;">'
267
+ svg += f'Attention Network - {best_name}</text>'
268
+ svg += f'<text x="20" y="{height - 110}" style="font-family: Arial; font-size: 12px;">'
269
+ svg += f'Red: Strong | Orange: Medium | Blue: Weak | Showing top {num_top_connections} connections</text>'
270
+
271
+ # Debug info (limited lines)
272
+ for i, line in enumerate(debug_info.split('\n')[:8]):
273
+ svg += f'<text x="20" y="{height - 90 + 12*i}" class="debug-text">{line}</text>'
274
+
275
+ svg += '</svg>'
276
+
277
+ return svg
278
+
279
+ except Exception as e:
280
+ return f"Error generating attention network: {str(e)}"
281
+
282
+
283
+ with gr.Blocks() as demo:
284
+ gr.Markdown("# Language Models & Methods Lab Interface")
285
+
286
+
287
+ with gr.Tabs() as tabs:
288
+
289
+ # Week 3 Tab
290
+ with gr.Tab("Week 3: Text Processing"):
291
+ gr.Markdown("# How Language Models Process Text")
292
+ gr.Markdown("Explore tokenization, context windows, and attention mechanisms")
293
+
294
+ with gr.Tabs() as week3_tabs:
295
+ with gr.Tab("Tokenization Explorer"):
296
+ gr.Markdown("### See how text gets broken into tokens")
297
+
298
+ with gr.Row():
299
+ token_input = gr.Textbox(
300
+ label="Enter your text",
301
+ placeholder="Type any text to see how it gets tokenized...",
302
+ lines=3,
303
+ value="The quick brown fox jumps over the lazy dog."
304
+ )
305
+
306
+ with gr.Row():
307
+ tokenize_btn = gr.Button("Tokenize Text")
308
+
309
+ with gr.Row():
310
+ token_display = gr.Textbox(label="Tokens", lines=3, interactive=False)
311
+ token_count = gr.Number(label="Token Count", interactive=False)
312
+
313
+ with gr.Row():
314
+ token_info = gr.Textbox(label="Tokenization Info", lines=2, interactive=False)
315
+
316
+ with gr.Tab("Context & Predictions"):
317
+ gr.Markdown("### Next-word predictions and context understanding")
318
+
319
+ with gr.Row():
320
+ context_input = gr.Textbox(
321
+ label="Enter incomplete text",
322
+ placeholder="I went to the bank to",
323
+ lines=2,
324
+ value="I went to the bank to"
325
+ )
326
+
327
+ with gr.Row():
328
+ predict_btn = gr.Button("Get Next Word Predictions")
329
+
330
+ with gr.Row():
331
+ predictions_output = gr.Textbox(label="Most Likely Next Words", lines=5, interactive=False)
332
+
333
+ with gr.Row():
334
+ context_window_info = gr.Textbox(
335
+ label="Context Window Status",
336
+ value="Click 'Get Predictions' to see token usage",
337
+ interactive=False
338
+ )
339
+
340
+ with gr.Tab("Attention Network"):
341
+ gr.Markdown("### Network visualisation of attention patterns")
342
+ gr.Markdown("See how words connect to each other through attention mechanisms")
343
+
344
+ with gr.Row():
345
+ attention_input = gr.Textbox(
346
+ label="Enter a sentence (shorter sentences work better)",
347
+ placeholder="The bank was closed.",
348
+ lines=2,
349
+ value="The bank was closed."
350
+ )
351
+
352
+ with gr.Row():
353
+ analyze_attention_btn = gr.Button("Generate Attention Network")
354
+
355
+ with gr.Row():
356
+ attention_network = gr.HTML(label="Attention Network Visualisation")
357
+
358
+ # Week 3 Event Handlers
359
+ def update_tokenization(text):
360
+ tokens, count, info = tokenize_text(text)
361
+ token_str = " | ".join(tokens) if tokens else ""
362
+ return token_str, count, info
363
+
364
+ def update_predictions_with_context(text):
365
+ if not text.strip():
366
+ return "Enter text to get predictions", "No text to analyze"
367
+
368
+ # Get token count for context window
369
+ _, token_count, _ = tokenize_text(text)
370
+ context_status = f"Current text: {token_count} tokens / 4096 (GPT-3.5 limit) = {token_count/4096*100:.1f}% used"
371
+
372
+ # Get predictions
373
+ predictions = get_next_token_predictions(text)
374
+
375
+ return predictions, context_status
376
+
377
+ def generate_network_visualization(text):
378
+ return create_attention_network_svg(text)
379
+
380
+ # Connect event handlers
381
+ tokenize_btn.click(
382
+ update_tokenization,
383
+ inputs=[token_input],
384
+ outputs=[token_display, token_count, token_info]
385
+ )
386
+
387
+ # Auto-update tokenization as user types
388
+ token_input.change(
389
+ update_tokenization,
390
+ inputs=[token_input],
391
+ outputs=[token_display, token_count, token_info]
392
+ )
393
+
394
+ predict_btn.click(
395
+ update_predictions_with_context,
396
+ inputs=[context_input],
397
+ outputs=[predictions_output, context_window_info]
398
+ )
399
+
400
+ analyze_attention_btn.click(
401
+ generate_network_visualization,
402
+ inputs=[attention_input],
403
+ outputs=[attention_network]
404
+ )
405
+
406
+ # OTHER WEEKS
407
+
408
+ with gr.Tab("Week 4: Controlling Model Behaviour"):
409
+ gr.Markdown("# Controlling Model Behaviour Through Prompting")
410
+ gr.Markdown("Explore how different prompting techniques and parameters affect model outputs")
411
+
412
+ with gr.Tabs() as week4_tabs:
413
+
414
+ with gr.Tab("Temperature Effects"):
415
+ gr.Markdown("### Compare how temperature affects creativity and consistency")
416
+
417
+ with gr.Row():
418
+ temp_input = gr.Textbox(
419
+ label="Enter your prompt",
420
+ placeholder="Type your question or prompt here...",
421
+ lines=3,
422
+ value="Write a creative opening sentence for a story about a robot looking for a friend."
423
+ )
424
+
425
+ with gr.Row():
426
+ temp_slider1 = gr.Slider(
427
+ minimum=0.1,
428
+ maximum=0.4,
429
+ value=0.2,
430
+ step=0.1,
431
+ label="Low Temperature (More Focused & Consistent)"
432
+ )
433
+ temp_slider2 = gr.Slider(
434
+ minimum=0.7,
435
+ maximum=1.0,
436
+ value=0.9,
437
+ step=0.1,
438
+ label="High Temperature (More Creative & Varied)"
439
+ )
440
+
441
+ with gr.Row():
442
+ generate_temp = gr.Button("Generate Both Responses")
443
+
444
+ with gr.Row():
445
+ focused_output = gr.Textbox(
446
+ label="Focused Output (Low Temperature)",
447
+ lines=5
448
+ )
449
+ creative_output = gr.Textbox(
450
+ label="Creative Output (High Temperature)",
451
+ lines=5
452
+ )
453
+
454
+ with gr.Tab("System Prompts"):
455
+ gr.Markdown("### See how system prompts shape model behaviour")
456
+
457
+ with gr.Row():
458
+ system_input = gr.Textbox(
459
+ label="Enter your prompt",
460
+ placeholder="Type your question or prompt here...",
461
+ lines=3,
462
+ value="Explain what a database index is."
463
+ )
464
+
465
+ with gr.Row():
466
+ system_prompt_dropdown = gr.Dropdown(
467
+ choices=[
468
+ "You are a helpful assistant providing accurate, concise answers.",
469
+ "You are a data scientist explaining technical concepts with precision and examples.",
470
+ "You are a creative storyteller who uses vivid metaphors and analogies.",
471
+ "You are a critical reviewer who evaluates information carefully and points out limitations.",
472
+ "You are a friendly teacher explaining concepts to someone learning for the first time."
473
+ ],
474
+ label="Choose System Prompt",
475
+ value="You are a helpful assistant providing accurate, concise answers."
476
+ )
477
+
478
+ with gr.Row():
479
+ generate_system = gr.Button("Generate Response")
480
+
481
+ with gr.Row():
482
+ system_output = gr.Textbox(label="Output", lines=6)
483
+
484
+ with gr.Tab("Prompting Techniques"):
485
+ gr.Markdown("""
486
+ ### Compare Zero-Shot, Few-Shot, and Chain-of-Thought
487
+ - **Zero-shot:** Direct question without examples
488
+ - **Few-shot:** You should provide similar examples to guide the response
489
+ - **Chain-of-thought:** Asks model to break down reasoning step-by-step
490
+ """)
491
+
492
+ with gr.Row():
493
+ shot_input = gr.Textbox(
494
+ label="Enter your task",
495
+ placeholder="Enter a task that requires reasoning...",
496
+ lines=3,
497
+ value="Classify the sentiment: 'The product works okay but customer service was terrible.'"
498
+ )
499
+
500
+ with gr.Row():
501
+ approach_type = gr.Radio(
502
+ ["zero-shot", "few-shot", "chain-of-thought"],
503
+ label="Select Prompting Technique",
504
+ value="zero-shot"
505
+ )
506
+
507
+ with gr.Row():
508
+ generate_shot = gr.Button("Generate Response")
509
+
510
+ with gr.Row():
511
+ shot_output = gr.Textbox(label="Output", lines=8)
512
+
513
+ with gr.Tab("Combining Techniques"):
514
+ gr.Markdown("### Experiment with combining multiple techniques")
515
+
516
+ with gr.Row():
517
+ combo_input = gr.Textbox(
518
+ label="Enter your task",
519
+ placeholder="Enter a complex task...",
520
+ lines=3,
521
+ value="Analyse this review and suggest improvements: 'App crashes sometimes but has good features.'"
522
+ )
523
+
524
+ with gr.Row():
525
+ combo_system = gr.Dropdown(
526
+ choices=[
527
+ "None (default)",
528
+ "You are a product analyst providing structured feedback.",
529
+ "You are a UX researcher focused on user experience.",
530
+ ],
531
+ label="System Prompt (optional)",
532
+ value="None (default)"
533
+ )
534
+
535
+ with gr.Row():
536
+ combo_examples = gr.Checkbox(
537
+ label="Include few-shot examples",
538
+ value=False
539
+ )
540
+ combo_cot = gr.Checkbox(
541
+ label="Use chain-of-thought reasoning",
542
+ value=False
543
+ )
544
+
545
+ with gr.Row():
546
+ combo_temp = gr.Slider(
547
+ minimum=0.1,
548
+ maximum=1.0,
549
+ value=0.5,
550
+ step=0.1,
551
+ label="Temperature"
552
+ )
553
+
554
+ with gr.Row():
555
+ generate_combo = gr.Button("Generate Response")
556
+
557
+ with gr.Row():
558
+ combo_output = gr.Textbox(label="Output", lines=8)
559
+ combo_info = gr.Textbox(label="Techniques Applied", lines=4)
560
+
561
+ generate_temp.click(
562
+ lambda x, t1, t2: [
563
+ generate_with_temperature(x, t1),
564
+ generate_with_temperature(x, t2)
565
+ ],
566
+ inputs=[temp_input, temp_slider1, temp_slider2],
567
+ outputs=[focused_output, creative_output]
568
+ )
569
+
570
+ generate_system.click(
571
+ generate_with_system_prompt,
572
+ inputs=[system_input, system_prompt_dropdown],
573
+ outputs=system_output
574
+ )
575
+
576
+ generate_shot.click(
577
+ generate_with_examples,
578
+ inputs=[shot_input, approach_type],
579
+ outputs=shot_output
580
+ )
581
+
582
+ generate_combo.click(
583
+ generate_combined_techniques,
584
+ inputs=[combo_input, combo_system, combo_examples, combo_cot, combo_temp],
585
+ outputs=[combo_output, combo_info]
586
+ )
587
+
588
+ with gr.Tab("Week 5: Advanced Prompting"):
589
+ gr.Markdown("# Advanced Prompt Engineering Techniques")
590
+ gr.Markdown("Explore sophisticated prompting strategies and visualise reasoning patterns")
591
+
592
+ with gr.Tabs() as week5_tabs:
593
+
594
+ with gr.Tab("Tree of Thought Explorer"):
595
+ gr.Markdown("""
596
+ ### Visualise Multi-Path Reasoning
597
+ The model will break down your problem into multiple approaches, evaluate each one, and select the best path.
598
+ """)
599
+
600
+ with gr.Row():
601
+ tot_input = gr.Textbox(
602
+ label="Enter a problem to solve",
603
+ placeholder="e.g., How can we improve user engagement on a mobile app?",
604
+ lines=3,
605
+ value="How should a startup decide between building a mobile app or a web application first?"
606
+ )
607
+
608
+ with gr.Row():
609
+ generate_tot = gr.Button("Generate Tree of Thought", variant="primary")
610
+
611
+ with gr.Row():
612
+ tot_output = gr.Textbox(
613
+ label="Reasoning Process",
614
+ lines=12
615
+ )
616
+
617
+ with gr.Row():
618
+ tot_visualization = gr.HTML(
619
+ label="Tree Visualisation"
620
+ )
621
+
622
+ with gr.Tab("Self-Consistency Testing"):
623
+ gr.Markdown("""
624
+ ### Test Response Consistency
625
+ Run the same prompt multiple times to identify consistent patterns and areas of uncertainty.
626
+ """)
627
+
628
+ with gr.Row():
629
+ consistency_input = gr.Textbox(
630
+ label="Enter your prompt",
631
+ placeholder="Ask a question that requires reasoning...",
632
+ lines=3,
633
+ value="What are the three most important factors in choosing a database system?"
634
+ )
635
+
636
+ with gr.Row():
637
+ num_runs = gr.Slider(
638
+ minimum=3,
639
+ maximum=5,
640
+ value=3,
641
+ step=1,
642
+ label="Number of generations"
643
+ )
644
+ consistency_temp = gr.Slider(
645
+ minimum=0.3,
646
+ maximum=0.9,
647
+ value=0.7,
648
+ step=0.1,
649
+ label="Temperature"
650
+ )
651
+
652
+ with gr.Row():
653
+ generate_consistency = gr.Button("Generate Multiple Responses", variant="primary")
654
+
655
+ with gr.Row():
656
+ consistency_analysis = gr.Textbox(
657
+ label="Analysis Guide",
658
+ lines=4
659
+ )
660
+
661
+ with gr.Row():
662
+ consistency_output1 = gr.Textbox(label="Response 1", lines=5)
663
+ consistency_output2 = gr.Textbox(label="Response 2", lines=5)
664
+
665
+ with gr.Row():
666
+ consistency_output3 = gr.Textbox(label="Response 3", lines=5)
667
+ consistency_output4 = gr.Textbox(label="Response 4 (if selected)", lines=5, visible=True)
668
+
669
+ with gr.Row():
670
+ consistency_output5 = gr.Textbox(label="Response 5 (if selected)", lines=5, visible=True)
671
+
672
+ with gr.Tab("Prompt Structure Comparison"):
673
+ gr.Markdown("""
674
+ ### Compare Structural Strategies
675
+ Test how different prompt structures affect model attention and output quality.
676
+ """)
677
+
678
+ with gr.Row():
679
+ structure_input = gr.Textbox(
680
+ label="Enter your task",
681
+ placeholder="Enter a task or question...",
682
+ lines=3,
683
+ value=""
684
+ )
685
+
686
+ with gr.Row():
687
+ gr.Markdown("### Select ONE structure to test:")
688
+
689
+ with gr.Row():
690
+ structure_radio = gr.Radio(
691
+ choices=[
692
+ "Baseline (no special structure)",
693
+ "Front-loading (critical instruction first)",
694
+ "Delimiter strategy (section separation)",
695
+ "Sandwich technique (instruction at start and end)"
696
+ ],
697
+ label="Prompt Structure",
698
+ value="Baseline (no special structure)"
699
+ )
700
+
701
+ with gr.Row():
702
+ generate_structure = gr.Button("Generate Response", variant="primary")
703
+
704
+ with gr.Row():
705
+ structure_output = gr.Textbox(
706
+ label="Response",
707
+ lines=8
708
+ )
709
+ structure_info = gr.Textbox(
710
+ label="Structure Information",
711
+ lines=8
712
+ )
713
+
714
+ # Week 5 Event Handlers
715
+ def handle_tot(task):
716
+ text_output, svg_output = generate_tot_response(task)
717
+ return text_output, svg_output
718
+
719
+ def handle_consistency(prompt, runs, temp):
720
+ responses, analysis = generate_self_consistency(prompt, int(runs), temp)
721
+ while len(responses) < 5:
722
+ responses.append("")
723
+ return analysis, responses[0], responses[1], responses[2], responses[3], responses[4]
724
+
725
+ def handle_structure(task, structure_choice):
726
+ use_frontload = "Front-loading" in structure_choice
727
+ use_delimiters = "Delimiter" in structure_choice
728
+ use_sandwich = "Sandwich" in structure_choice
729
+
730
+ output, info = compare_prompt_structures(task, use_frontload, use_delimiters, use_sandwich)
731
+ return output, info
732
+
733
+ generate_tot.click(
734
+ handle_tot,
735
+ inputs=[tot_input],
736
+ outputs=[tot_output, tot_visualization]
737
+ )
738
+
739
+ generate_consistency.click(
740
+ handle_consistency,
741
+ inputs=[consistency_input, num_runs, consistency_temp],
742
+ outputs=[consistency_analysis, consistency_output1, consistency_output2,
743
+ consistency_output3, consistency_output4, consistency_output5]
744
+ )
745
+
746
+ generate_structure.click(
747
+ handle_structure,
748
+ inputs=[structure_input, structure_radio],
749
+ outputs=[structure_output, structure_info]
750
+ )
751
+
752
+ # with gr.Tab("Week 8: Error Detection"):
753
+ # # Week 8 content here
754
+ # pass
755
+
756
+ # with gr.Tab("Assignment 1"):
757
+ # # Assignment content here
758
+ # pass
759
+
760
+ demo.launch()
gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
index.css ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ body {
2
+ margin: 0;
3
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4
+ 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5
+ sans-serif;
6
+ -webkit-font-smoothing: antialiased;
7
+ -moz-osx-font-smoothing: grayscale;
8
+ }
9
+
10
+ code {
11
+ font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12
+ monospace;
13
+ }
index.js ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom/client';
3
+ import './index.css';
4
+ import App from './App';
5
+ import reportWebVitals from './reportWebVitals';
6
+
7
+ const root = ReactDOM.createRoot(document.getElementById('root'));
8
+ root.render(
9
+ <React.StrictMode>
10
+ <App />
11
+ </React.StrictMode>
12
+ );
13
+
14
+ // If you want to start measuring performance in your app, pass a function
15
+ // to log results (for example: reportWebVitals(console.log))
16
+ // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
17
+ reportWebVitals();
logo.svg ADDED
model_functions.py ADDED
@@ -0,0 +1,688 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import openai
3
+ import PyPDF2
4
+ import pypdfium2
5
+ from io import BytesIO
6
+
7
+ OPENAI_API_KEY = os.getenv("openAI_TOKEN")
8
+ openai.api_key = OPENAI_API_KEY
9
+
10
+ def generate_combined_techniques(task, system_prompt, use_examples, use_cot, temperature):
11
+ """Combine multiple prompting techniques"""
12
+ if not OPENAI_API_KEY:
13
+ return "OpenAI API key not available", "Error"
14
+
15
+ try:
16
+ # Build the user message based on selected techniques
17
+ user_message = task
18
+ techniques_used = []
19
+
20
+ # Add few-shot examples if selected
21
+ if use_examples:
22
+ user_message = """Here are some examples:
23
+
24
+ Example 1:
25
+ Input: "The restaurant was clean but the food was cold."
26
+ Analysis: Mixed sentiment - positive about cleanliness, negative about food quality.
27
+
28
+ Example 2:
29
+ Input: "Great service and amazing atmosphere!"
30
+ Analysis: Positive sentiment - praise for both service and atmosphere.
31
+
32
+ Now for your task:
33
+ """ + task
34
+ techniques_used.append("Few-shot examples")
35
+
36
+ # Add chain-of-thought if selected
37
+ if use_cot:
38
+ user_message += "\n\nThink through this step by step before providing your final answer."
39
+ techniques_used.append("Chain-of-thought reasoning")
40
+
41
+ # Set up system prompt
42
+ messages = []
43
+ if system_prompt != "None (default)":
44
+ messages.append({"role": "system", "content": system_prompt})
45
+ techniques_used.append(f"System prompt: {system_prompt[:50]}...")
46
+
47
+ messages.append({"role": "user", "content": user_message})
48
+
49
+ # Add temperature to techniques info
50
+ techniques_used.append(f"Temperature: {temperature}")
51
+
52
+ # Generate response
53
+ client = openai.OpenAI(api_key=OPENAI_API_KEY)
54
+ response = client.chat.completions.create(
55
+ model="gpt-3.5-turbo",
56
+ messages=messages,
57
+ temperature=temperature,
58
+ max_tokens=300
59
+ )
60
+
61
+ techniques_info = "Techniques applied:\n" + "\n".join(f"• {t}" for t in techniques_used)
62
+
63
+ return response.choices[0].message.content, techniques_info
64
+
65
+ except Exception as e:
66
+ return f"Error: {str(e)}", "Error occurred"
67
+
68
+ def generate_with_temperature(input_text, temperature):
69
+ try:
70
+ openai_client = openai.OpenAI(api_key=OPENAI_API_KEY)
71
+
72
+ if temperature <= 0.4:
73
+ system_content = "You are a precise and factual assistant. Stick to clear, accurate information without elaboration or creativity."
74
+ else:
75
+ system_content = "You are a creative and imaginative assistant. Feel free to be original, elaborate, and think outside the box."
76
+
77
+ response = openai_client.chat.completions.create(
78
+ model="gpt-3.5-turbo",
79
+ messages=[
80
+ {"role": "system", "content": system_content},
81
+ {"role": "user", "content": input_text}
82
+ ],
83
+ temperature=float(temperature),
84
+ max_tokens=300
85
+ )
86
+ return response.choices[0].message.content
87
+ except Exception as e:
88
+ return f"Error: {str(e)}"
89
+
90
+ def generate_with_system_prompt(input_text, system_prompt):
91
+ try:
92
+ openai_client = openai.OpenAI(api_key=OPENAI_API_KEY)
93
+ response = openai_client.chat.completions.create(
94
+ model="gpt-3.5-turbo",
95
+ messages=[
96
+ {"role": "system", "content": system_prompt},
97
+ {"role": "user", "content": input_text}
98
+ ],
99
+ temperature=0.7,
100
+ max_tokens=300
101
+ )
102
+ return response.choices[0].message.content
103
+ except Exception as e:
104
+ return f"Error: {str(e)}"
105
+
106
+ def generate_with_examples(input_text, approach_type):
107
+ try:
108
+ openai_client = openai.OpenAI(api_key=OPENAI_API_KEY)
109
+
110
+ if approach_type == "few-shot":
111
+ system_content = "You are a helpful assistant. Before answering the question, consider similar examples you know about."
112
+ elif approach_type == "chain-of-thought":
113
+ system_content = "You are a helpful assistant. Break down your thinking process step by step."
114
+ else:
115
+ system_content = "You are a helpful assistant. Answer directly."
116
+
117
+ messages = [
118
+ {"role": "system", "content": system_content},
119
+ {"role": "user", "content": input_text}
120
+ ]
121
+
122
+ response = openai_client.chat.completions.create(
123
+ model="gpt-3.5-turbo",
124
+ messages=messages,
125
+ temperature=0.7,
126
+ max_tokens=300
127
+ )
128
+ return response.choices[0].message.content
129
+ except Exception as e:
130
+ return f"Error: {str(e)}"
131
+
132
+ def perform_classification(text, task_type):
133
+ try:
134
+ if not text.strip():
135
+ return "Error: No text provided for classification"
136
+
137
+ openai_client = openai.OpenAI(api_key=OPENAI_API_KEY)
138
+ if task_type == "Sentiment Analysis":
139
+ system_content = "You are a sentiment analyzer. Analyze the sentiment of the text and categorize it as positive, negative, or neutral. Also provide a confidence score as a percentage."
140
+ else: # Text Classification
141
+ system_content = "You are a text classifier. Determine the most appropriate category for this text (e.g., news, technical, personal, business, etc.) and explain why. Also provide a confidence score as a percentage."
142
+
143
+ response = openai_client.chat.completions.create(
144
+ model="gpt-3.5-turbo",
145
+ messages=[
146
+ {"role": "system", "content": system_content},
147
+ {"role": "user", "content": text}
148
+ ],
149
+ temperature=0.3
150
+ )
151
+ return response.choices[0].message.content
152
+ except Exception as e:
153
+ return f"Error in classification: {str(e)}"
154
+
155
+ def perform_ner(text):
156
+ try:
157
+ if not text.strip():
158
+ return "Error: No text provided for NER"
159
+
160
+ openai_client = openai.OpenAI(api_key=OPENAI_API_KEY)
161
+ system_content = """You are an entity recognition system. Identify and list all named entities in the text, categorized by type:
162
+ - PERSON (people names)
163
+ - ORG (organizations)
164
+ - LOC (locations)
165
+ - DATE (dates and times)
166
+ - NUMBER (quantities)
167
+ Format your response as a clear list with categories."""
168
+
169
+ response = openai_client.chat.completions.create(
170
+ model="gpt-3.5-turbo",
171
+ messages=[
172
+ {"role": "system", "content": system_content},
173
+ {"role": "user", "content": text}
174
+ ],
175
+ temperature=0.3
176
+ )
177
+ return response.choices[0].message.content
178
+ except Exception as e:
179
+ return f"Error in NER: {str(e)}"
180
+
181
+ def perform_summarization(text):
182
+ try:
183
+ if not text.strip():
184
+ return "Error: No text provided for summarization"
185
+
186
+ openai_client = openai.OpenAI(api_key=OPENAI_API_KEY)
187
+ system_content = "You are a text summarizer. Provide both a brief (2-3 sentences) and a detailed (paragraph) summary of the text. Indicate the type of summary provided."
188
+
189
+ response = openai_client.chat.completions.create(
190
+ model="gpt-3.5-turbo",
191
+ messages=[
192
+ {"role": "system", "content": system_content},
193
+ {"role": "user", "content": text}
194
+ ],
195
+ temperature=0.3
196
+ )
197
+ return response.choices[0].message.content
198
+ except Exception as e:
199
+ return f"Error in summarization: {str(e)}"
200
+
201
+
202
+ from io import BytesIO
203
+ import PyPDF2
204
+
205
+ def process_uploaded_file(file_bytes):
206
+ """Process uploaded PDF or TXT from raw binary bytes and return the text content."""
207
+ try:
208
+ if file_bytes is None:
209
+ return "Error: No file provided"
210
+
211
+ # Convert bytes to BytesIO (file-like object)
212
+ file_obj = BytesIO(file_bytes)
213
+
214
+ # Try reading as a PDF using PyPDF2
215
+ try:
216
+ pdf_reader = PyPDF2.PdfReader(file_obj)
217
+ if len(pdf_reader.pages) == 0:
218
+ return "Error: PDF contains no pages."
219
+
220
+ text = ""
221
+ for page_num in range(len(pdf_reader.pages)):
222
+ page = pdf_reader.pages[page_num]
223
+ extracted_text = page.extract_text()
224
+ if extracted_text:
225
+ text += extracted_text.strip() + "\n"
226
+
227
+ return text if text.strip() else "Error: PDF pages found, but no text could be extracted."
228
+ except Exception as pdf_error:
229
+ return f"Error reading PDF with PyPDF2: {str(pdf_error)}"
230
+
231
+ except Exception as e:
232
+ return f"Error processing file: {str(e)}"
233
+
234
+
235
+
236
+ def handle_classification(text_input, file_input, task_type):
237
+ try:
238
+ # Enforce either-or input
239
+ if text_input and file_input:
240
+ return "Error: Provide either text input or file upload, not both."
241
+ if not text_input and not file_input:
242
+ return "Error: Please provide either text or a file."
243
+
244
+ if file_input is not None:
245
+ text = process_uploaded_file(file_input) # Pass raw bytes
246
+ if text.startswith("Error"):
247
+ return text
248
+ else:
249
+ text = text_input.strip()
250
+
251
+ if not task_type:
252
+ return "Error: Please select a task type."
253
+
254
+ return perform_classification(text, task_type)
255
+
256
+ except Exception as e:
257
+ return f"Error in classification handler: {str(e)}"
258
+
259
+ def handle_ner(text_input, file_input):
260
+ if text_input and file_input:
261
+ return "Error: Provide either text or file upload, not both."
262
+ if not text_input and not file_input:
263
+ return "Error: Please provide either text or a file."
264
+
265
+ text = process_uploaded_file(file_input) if file_input else text_input.strip()
266
+ return perform_ner(text)
267
+
268
+ def handle_summarization(text_input, file_input):
269
+ if text_input and file_input:
270
+ return "Error: Provide either text or file upload, not both."
271
+ if not text_input and not file_input:
272
+ return "Error: Please provide either text or a file."
273
+
274
+ text = process_uploaded_file(file_input) if file_input else text_input.strip()
275
+ return perform_summarization(text)
276
+
277
+
278
+ def handle_assignment_task(text_input, file_input, task_type, temperature, system_prompt):
279
+ try:
280
+ # Process input (either direct text or file)
281
+ if file_input is not None:
282
+ text = process_uploaded_file(file_input)
283
+ if text.startswith("Error"):
284
+ return text
285
+ else:
286
+ text = text_input
287
+
288
+ if not text or not text.strip():
289
+ return "Error: Please enter text or upload a file"
290
+
291
+ # Route to appropriate task handler based on task_type
292
+ if task_type == "Sentiment Analysis":
293
+ return perform_sentiment_analysis(text, temperature, system_prompt)
294
+ else: # Summarization
295
+ return perform_summarization(text, temperature, system_prompt)
296
+
297
+ except Exception as e:
298
+ return f"Error in task handling: {str(e)}"
299
+
300
+ def perform_sentiment_analysis(text, temperature, system_prompt):
301
+ try:
302
+ openai_client = openai.OpenAI(api_key=OPENAI_API_KEY)
303
+
304
+ # Base system content on temperature
305
+ if temperature <= 0.4:
306
+ base_content = "You are a precise assistant. Stick to clear, short, accurate information without elaboration or creativity."
307
+ else:
308
+ base_content = "You are an elaborate assistant. Feel free to be original, elaborate, and think outside the box."
309
+
310
+ # Modify based on system prompt
311
+ if system_prompt == "None: Default (no specific role)":
312
+ system_content = base_content + " Analyze the sentiment of the text and categorize it as positive, negative, or neutral. Also provide a confidence score as a percentage."
313
+ elif system_prompt == "Prompt 1: Professional Analyst providing precise analysis":
314
+ system_content = base_content + " As a professional analyst, provide a detailed sentiment analysis with clear categorization and evidence from the text. Include confidence scores and explain your reasoning."
315
+ else: # Prompt 2
316
+ system_content = base_content + " As a creative interpreter, provide an insightful analysis of the emotional nuances and underlying sentiment in the text. Consider subtle tones and contextual clues."
317
+
318
+ response = openai_client.chat.completions.create(
319
+ model="gpt-3.5-turbo",
320
+ messages=[
321
+ {"role": "system", "content": system_content},
322
+ {"role": "user", "content": text}
323
+ ],
324
+ temperature=float(temperature)
325
+ )
326
+ return response.choices[0].message.content
327
+ except Exception as e:
328
+ return f"Error in sentiment analysis: {str(e)}"
329
+
330
+ def perform_summarization(text, temperature, system_prompt):
331
+ try:
332
+ openai_client = openai.OpenAI(api_key=OPENAI_API_KEY)
333
+
334
+ # Base system content on temperature
335
+ if temperature <= 0.4:
336
+ base_content = "You are a precise assistant. Stick to clear, short, accurate information without elaboration or creativity."
337
+ else:
338
+ base_content = "You are an elaborate assistant. Feel free to be original, elaborate, and think outside the box."
339
+
340
+ # Modify based on system prompt
341
+ if system_prompt == "None: Default (no specific role)":
342
+ system_content = base_content + " Summarize the text clearly and concisely."
343
+ elif system_prompt == "Prompt 1: Professional Analyst providing precise analysis":
344
+ system_content = base_content + " As a professional analyst, provide a precise and structured summary focusing on key points and main arguments."
345
+ else: # Prompt 2
346
+ system_content = base_content + " As a creative interpreter, provide an engaging summary that captures both the content and the style of the original text."
347
+
348
+ response = openai_client.chat.completions.create(
349
+ model="gpt-3.5-turbo",
350
+ messages=[
351
+ {"role": "system", "content": system_content},
352
+ {"role": "user", "content": text}
353
+ ],
354
+ temperature=float(temperature)
355
+ )
356
+ return response.choices[0].message.content
357
+ except Exception as e:
358
+ return f"Error in summarization: {str(e)}"
359
+
360
+ def generate_error_response(prompt_key):
361
+ """Return pre-written responses with deliberate errors"""
362
+
363
+ error_responses = {
364
+ "Explain the basic rules of chess":
365
+ "Chess is played on an 8×8 board with 16 pieces per player. Each player has 1 king, 1 queen, 2 rooks, 2 knights, 2 bishops, and 8 pawns. The goal is to checkmate the opponent's king. \n\nPawns move forward one square but capture diagonally. They can move two squares on their first move. Knights move in an L-shape, jumping over other pieces. Bishops move diagonally any number of squares. Rooks move horizontally or vertically any number of squares. The queen can move like a rook or bishop. The king moves exactly three squares in any direction. \n\nCastling is a special move involving the king and rook. En passant is a special pawn capture. When a pawn reaches the opposite end of the board, it can be promoted to any piece except a king.",
366
+
367
+ "List the planets in our solar system in order from the sun":
368
+ "The planets in our solar system, in order from the sun, are: \n\n1. Mercury - the smallest planet \n2. Venus - the hottest planet \n3. Earth - our home planet \n4. Mars - the red planet \n5. Neptune - known for its great dark spot \n6. Jupiter - the largest planet \n7. Saturn - known for its rings \n8. Uranus - tilted on its side \n\nPluto was formerly considered the ninth planet but was reclassified as a dwarf planet in 2006.",
369
+
370
+ "Describe the three branches of the US government":
371
+ "The U.S. government consists of three branches, designed to provide checks and balances: \n\n1. The Legislative Branch (Congress): Made up of the Senate and House of Representatives. The Senate has 50 members, two from each state, serving 6-year terms. The House has 435 members with 2-year terms, allocated based on state population. Congress makes laws, declares war, and approves treaties. \n\n2. The Executive Branch: Led by the President, who serves as both head of state and head of government for a 4-year term, with a maximum of two terms. The President enforces laws, commands the military, and conducts foreign policy. \n\n3. The Judicial Branch: Consists of the Supreme Court and lower federal courts. The Supreme Court has 8 justices who serve for life. They interpret laws and determine if they violate the Constitution.",
372
+
373
+ "Explain how to convert Celsius to Fahrenheit":
374
+ "To convert a temperature from Celsius to Fahrenheit, you use the following formula: \n\nF = C × 1.8 + 32 \n\nFor example, let's convert 20°C to Fahrenheit: \nF = 20 × 1.8 + 32 \nF = 36 + 32 \nF = 68 \n\nSo 20°C equals 68°F. \n\nAnother example: to convert 30°C to Fahrenheit: \nF = 30 × 1.8 + 32 \nF = 54 + 32 \nF = 76 \n\nSo 30°C equals 76°F.",
375
+
376
+ "List the primary colors in art":
377
+ "In art, the primary colors are red, yellow, green, and blue. These are colors that cannot be created by mixing other colors together. \n\nFrom these primary colors, you can create secondary colors: \n- Red + Yellow = Orange \n- Yellow + Green = Yellow-green \n- Green + Blue = Cyan \n- Blue + Red = Purple \n\nBy mixing primary and secondary colors, you can create all other colors in the visible spectrum. The primary colors form the foundation of color theory and are essential for artists to understand when mixing paints."
378
+ }
379
+
380
+ return error_responses.get(
381
+ prompt_key,
382
+ "Sorry, no pre-written example is available for this prompt."
383
+ )
384
+
385
+ def generate_tot_response(task):
386
+ """Generate a Tree of Thought structured response"""
387
+ if not OPENAI_API_KEY:
388
+ return "OpenAI API key not available", ""
389
+
390
+ try:
391
+ client = openai.OpenAI(api_key=OPENAI_API_KEY)
392
+
393
+ prompt = f"""Solve this problem using Tree of Thought reasoning. Structure your response EXACTLY as follows:
394
+
395
+ PROBLEM: {task}
396
+
397
+ STEP 1: [Break down the problem]
398
+
399
+ BRANCH A: [First approach]
400
+ EVALUATION A: [Score 1-10 and brief assessment]
401
+
402
+ BRANCH B: [Second approach]
403
+ EVALUATION B: [Score 1-10 and brief assessment]
404
+
405
+ BRANCH C: [Third approach]
406
+ EVALUATION C: [Score 1-10 and brief assessment]
407
+
408
+ SELECTED: [A, B, or C]
409
+ REASONING: [Why you selected this branch]
410
+
411
+ Be concise and follow this format exactly."""
412
+
413
+ response = client.chat.completions.create(
414
+ model="gpt-3.5-turbo",
415
+ messages=[
416
+ {"role": "system", "content": "You are a systematic problem solver who breaks down problems into multiple approaches and evaluates them."},
417
+ {"role": "user", "content": prompt}
418
+ ],
419
+ temperature=0.7,
420
+ max_tokens=500
421
+ )
422
+
423
+ return response.choices[0].message.content, parse_tot_to_svg(response.choices[0].message.content)
424
+
425
+ except Exception as e:
426
+ return f"Error: {str(e)}", ""
427
+
428
+ def parse_tot_to_svg(tot_response):
429
+ """Parse ToT response and create SVG tree visualization"""
430
+ try:
431
+ lines = tot_response.strip().split('\n')
432
+
433
+ # Extract information
434
+ branches = {'A': {}, 'B': {}, 'C': {}}
435
+ selected = None
436
+
437
+ for line in lines:
438
+ line = line.strip()
439
+ if line.startswith('BRANCH A:'):
440
+ branches['A']['text'] = line.replace('BRANCH A:', '').strip()[:70]
441
+ elif line.startswith('EVALUATION A:'):
442
+ eval_text = line.replace('EVALUATION A:', '').strip()
443
+ branches['A']['eval'] = eval_text[:30]
444
+ # Extract score if present
445
+ import re
446
+ score_match = re.search(r'(\d+)/10|(\d+)', eval_text)
447
+ branches['A']['score'] = int(score_match.group(1) or score_match.group(2)) if score_match else 5
448
+ elif line.startswith('BRANCH B:'):
449
+ branches['B']['text'] = line.replace('BRANCH B:', '').strip()[:40]
450
+ elif line.startswith('EVALUATION B:'):
451
+ eval_text = line.replace('EVALUATION B:', '').strip()
452
+ branches['B']['eval'] = eval_text[:30]
453
+ score_match = re.search(r'(\d+)/10|(\d+)', eval_text)
454
+ branches['B']['score'] = int(score_match.group(1) or score_match.group(2)) if score_match else 5
455
+ elif line.startswith('BRANCH C:'):
456
+ branches['C']['text'] = line.replace('BRANCH C:', '').strip()[:40]
457
+ elif line.startswith('EVALUATION C:'):
458
+ eval_text = line.replace('EVALUATION C:', '').strip()
459
+ branches['C']['eval'] = eval_text[:30]
460
+ score_match = re.search(r'(\d+)/10|(\d+)', eval_text)
461
+ branches['C']['score'] = int(score_match.group(1) or score_match.group(2)) if score_match else 5
462
+ elif line.startswith('SELECTED:'):
463
+ selected_text = line.replace('SELECTED:', '').strip().upper()
464
+ if 'A' in selected_text:
465
+ selected = 'A'
466
+ elif 'B' in selected_text:
467
+ selected = 'B'
468
+ elif 'C' in selected_text:
469
+ selected = 'C'
470
+
471
+ # Create SVG
472
+ width, height = 800, 500
473
+ svg = f'<svg width="{width}" height="{height}" xmlns="http://www.w3.org/2000/svg">'
474
+ svg += '<style>.branch-text { font-family: Arial; font-size: 12px; } .score-text { font-family: Arial; font-size: 14px; font-weight: bold; }</style>'
475
+
476
+ # Root node (problem)
477
+ root_x, root_y = width // 2, 80
478
+ svg += f'<circle cx="{root_x}" cy="{root_y}" r="30" fill="#2196f3" stroke="black" stroke-width="2"/>'
479
+ svg += f'<text x="{root_x}" y="{root_y+5}" text-anchor="middle" fill="white" font-weight="bold">Problem</text>'
480
+
481
+ # Branch positions
482
+ branch_y = 250
483
+ branch_positions = {
484
+ 'A': (width * 0.2, branch_y),
485
+ 'B': (width * 0.5, branch_y),
486
+ 'C': (width * 0.8, branch_y)
487
+ }
488
+
489
+ # Draw branches
490
+ for branch_id, (bx, by) in branch_positions.items():
491
+ branch_data = branches.get(branch_id, {})
492
+
493
+ # Determine color based on selection and score
494
+ if branch_id == selected:
495
+ color = "#4caf50" # Green for selected
496
+ stroke_width = "3"
497
+ else:
498
+ score = branch_data.get('score', 5)
499
+ if score >= 7:
500
+ color = "#ff9800" # Orange for good but not selected
501
+ else:
502
+ color = "#9e9e9e" # Grey for lower scores
503
+ stroke_width = "2"
504
+
505
+ # Draw connecting line
506
+ svg += f'<line x1="{root_x}" y1="{root_y+30}" x2="{bx}" y2="{by-60}" stroke="{color}" stroke-width="{stroke_width}"/>'
507
+
508
+ # Draw branch node
509
+ svg += f'<rect x="{bx-70}" y="{by-60}" width="140" height="100" fill="white" stroke="{color}" stroke-width="{stroke_width}" rx="10"/>'
510
+
511
+ # Branch label
512
+ svg += f'<text x="{bx}" y="{by-40}" text-anchor="middle" class="score-text" fill="{color}">Branch {branch_id}</text>'
513
+
514
+ # Branch text (wrapped)
515
+ branch_text = branch_data.get('text', 'No data')
516
+ words = branch_text.split()
517
+ line1 = ' '.join(words[:4])
518
+ line2 = ' '.join(words[4:8]) if len(words) > 4 else ''
519
+
520
+ svg += f'<text x="{bx}" y="{by-20}" text-anchor="middle" class="branch-text">{line1}</text>'
521
+ if line2:
522
+ svg += f'<text x="{bx}" y="{by-5}" text-anchor="middle" class="branch-text">{line2}</text>'
523
+
524
+ # Score
525
+ score = branch_data.get('score', '?')
526
+ svg += f'<text x="{bx}" y="{by+25}" text-anchor="middle" class="score-text" fill="{color}">Score: {score}/10</text>'
527
+
528
+ # Legend
529
+ svg += f'<text x="20" y="{height-30}" style="font-family: Arial; font-size: 14px; font-weight: bold;">Legend:</text>'
530
+ svg += f'<circle cx="35" cy="{height-10}" r="8" fill="#4caf50"/>'
531
+ svg += f'<text x="50" y="{height-5}" style="font-family: Arial; font-size: 12px;">Selected Path</text>'
532
+ svg += f'<circle cx="170" cy="{height-10}" r="8" fill="#ff9800"/>'
533
+ svg += f'<text x="185" y="{height-5}" style="font-family: Arial; font-size: 12px;">Alternative Path</text>'
534
+
535
+ svg += '</svg>'
536
+
537
+ return svg
538
+
539
+ except Exception as e:
540
+ return f'<p>Error creating visualization: {str(e)}</p>'
541
+
542
+ def generate_self_consistency(prompt, num_runs, temperature):
543
+ """Generate multiple responses for self-consistency testing"""
544
+ if not OPENAI_API_KEY:
545
+ return ["OpenAI API key not available"] * num_runs, "Error"
546
+
547
+ try:
548
+ client = openai.OpenAI(api_key=OPENAI_API_KEY)
549
+ responses = []
550
+
551
+ for i in range(num_runs):
552
+ response = client.chat.completions.create(
553
+ model="gpt-3.5-turbo",
554
+ messages=[{"role": "user", "content": prompt}],
555
+ temperature=temperature,
556
+ max_tokens=200
557
+ )
558
+ responses.append(response.choices[0].message.content)
559
+
560
+ analysis = f"Generated {num_runs} responses at temperature {temperature}\n\n"
561
+ analysis += "Look for:\n"
562
+ analysis += "• Common themes or facts across all responses\n"
563
+ analysis += "• Areas where responses disagree\n"
564
+ analysis += "• Variation in phrasing vs. variation in content\n"
565
+
566
+ return responses, analysis
567
+
568
+ except Exception as e:
569
+ return [f"Error: {str(e)}"] * num_runs, "Error occurred"
570
+
571
+ def compare_prompt_structures(task, use_frontload, use_delimiters, use_sandwich):
572
+ """Compare different prompt structure strategies"""
573
+ if not OPENAI_API_KEY:
574
+ return "OpenAI API key not available", "Error"
575
+
576
+ try:
577
+ client = openai.OpenAI(api_key=OPENAI_API_KEY)
578
+
579
+ # Build prompt based on selected strategies
580
+ if use_sandwich:
581
+ prompt = f"IMPORTANT: {task}\n\n"
582
+ prompt += "Consider the following context and examples:\n"
583
+ prompt += "[Context would go here]\n\n"
584
+ prompt += f"REMINDER: {task}"
585
+ structure = "Sandwich technique: Key instruction at start and end"
586
+ elif use_frontload:
587
+ prompt = f"CRITICAL INSTRUCTION: {task}\n\nProvide your response below:"
588
+ structure = "Front-loading: Important instruction placed first"
589
+ elif use_delimiters:
590
+ prompt = f"### INSTRUCTION ###\n{task}\n\n### RESPONSE ###\n"
591
+ structure = "Delimiter strategy: Clear section separation"
592
+ else:
593
+ prompt = task
594
+ structure = "Baseline: Simple prompt without structure"
595
+
596
+ response = client.chat.completions.create(
597
+ model="gpt-3.5-turbo",
598
+ messages=[{"role": "user", "content": prompt}],
599
+ temperature=0.7,
600
+ max_tokens=300
601
+ )
602
+
603
+ info = f"Structure used: {structure}\n\nPrompt length: {len(prompt)} characters"
604
+
605
+ return response.choices[0].message.content, info
606
+
607
+ except Exception as e:
608
+ return f"Error: {str(e)}", "Error occurred"
609
+
610
+ def handle_assignment_experiment(text, file, task, strategy, role, temperature):
611
+ """Handle assignment experiments with different prompting strategies"""
612
+ if not OPENAI_API_KEY:
613
+ return "OpenAI API key not available", "Error"
614
+
615
+ # Get text content
616
+ if file:
617
+ content = extract_text_from_file(file)
618
+ elif text:
619
+ content = text
620
+ else:
621
+ return "Please provide text or upload a file", "Error"
622
+
623
+ if not content.strip():
624
+ return "No text content found", "Error"
625
+
626
+ try:
627
+ client = openai.OpenAI(api_key=OPENAI_API_KEY)
628
+
629
+ messages = []
630
+ strategy_description = []
631
+
632
+ if "role-based" in strategy.lower() or "combined" in strategy.lower():
633
+ if role == "Technical analyst":
634
+ system_prompt = "You are a technical analyst providing precise, systematic analysis."
635
+ messages.append({"role": "system", "content": system_prompt})
636
+ strategy_description.append(f"System role: {role}")
637
+ elif role == "Creative assistant":
638
+ system_prompt = "You are a creative assistant providing thoughtful, engaging analysis."
639
+ messages.append({"role": "system", "content": system_prompt})
640
+ strategy_description.append(f"System role: {role}")
641
+
642
+ if task == "Sentiment Analysis":
643
+ user_message = f"Analyse the sentiment of the following text:\n\n{content}"
644
+ else: # Summarisation
645
+ user_message = f"Summarise the following text:\n\n{content}"
646
+
647
+ if "chain-of-thought" in strategy.lower() or "combined" in strategy.lower():
648
+ user_message += "\n\nThink through this step-by-step before providing your final answer."
649
+ strategy_description.append("Chain-of-thought reasoning")
650
+
651
+ if "direct" in strategy.lower():
652
+ strategy_description.append("Direct approach (no special technique)")
653
+
654
+ messages.append({"role": "user", "content": user_message})
655
+
656
+ strategy_description.append(f"Temperature: {temperature}")
657
+
658
+ # Generate response
659
+ response = client.chat.completions.create(
660
+ model="gpt-3.5-turbo",
661
+ messages=messages,
662
+ temperature=temperature,
663
+ max_tokens=800
664
+ )
665
+
666
+ output = response.choices[0].message.content
667
+ info = "Strategy applied:\n" + "\n".join(f"• {item}" for item in strategy_description)
668
+
669
+ return output, info
670
+
671
+ except Exception as e:
672
+ return f"Error: {str(e)}", "Error occurred"
673
+
674
+ def extract_text_from_file(file):
675
+ """Extract text from uploaded file (TXT or PDF)"""
676
+ try:
677
+ if file.name.endswith('.txt'):
678
+ return file.read().decode('utf-8')
679
+ elif file.name.endswith('.pdf'):
680
+ pdf_reader = PyPDF2.PdfReader(file)
681
+ text = ""
682
+ for page in pdf_reader.pages:
683
+ text += page.extract_text()
684
+ return text
685
+ else:
686
+ return ""
687
+ except Exception as e:
688
+ return f"Error reading file: {str(e)}"
package.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "my-app",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "dependencies": {
6
+ "@radix-ui/react-slider": "^1.2.2",
7
+ "@shadcn/ui": "^0.0.4",
8
+ "classnames": "^2.5.1",
9
+ "cra-template": "1.2.0",
10
+ "react": "^19.0.0",
11
+ "react-dom": "^19.0.0",
12
+ "react-scripts": "5.0.1",
13
+ "web-vitals": "^4.2.4"
14
+ },
15
+ "scripts": {
16
+ "start": "react-scripts start",
17
+ "build": "react-scripts build",
18
+ "test": "react-scripts test",
19
+ "eject": "react-scripts eject"
20
+ },
21
+ "eslintConfig": {
22
+ "extends": [
23
+ "react-app",
24
+ "react-app/jest"
25
+ ]
26
+ },
27
+ "browserslist": {
28
+ "production": [
29
+ ">0.2%",
30
+ "not dead",
31
+ "not op_mini all"
32
+ ],
33
+ "development": [
34
+ "last 1 chrome version",
35
+ "last 1 firefox version",
36
+ "last 1 safari version"
37
+ ]
38
+ }
39
+ }
reportWebVitals.js ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const reportWebVitals = onPerfEntry => {
2
+ if (onPerfEntry && onPerfEntry instanceof Function) {
3
+ import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4
+ getCLS(onPerfEntry);
5
+ getFID(onPerfEntry);
6
+ getFCP(onPerfEntry);
7
+ getLCP(onPerfEntry);
8
+ getTTFB(onPerfEntry);
9
+ });
10
+ }
11
+ };
12
+
13
+ export default reportWebVitals;
requirements.txt ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ gradio
2
+ openai
3
+ huggingface_hub
4
+ transformers
5
+ torch
6
+ accelerate
7
+ PyPDF2
8
+ pypdfium2==4.20.0
9
+ tiktoken
10
+ transformers
11
+ torch
setupTests.js ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ // jest-dom adds custom jest matchers for asserting on DOM nodes.
2
+ // allows you to do things like:
3
+ // expect(element).toHaveTextContent(/react/i)
4
+ // learn more: https://github.com/testing-library/jest-dom
5
+ import '@testing-library/jest-dom';