Polarium commited on
Commit
70ca8e2
·
1 Parent(s): b09fd17

Application pushed to huggingface

Browse files
Files changed (8) hide show
  1. .gitignore +1 -0
  2. Dockerfile +18 -0
  3. README.md +76 -6
  4. app.py +80 -0
  5. requirements.txt +9 -0
  6. static/css/style.css +296 -0
  7. static/js/app.js +125 -0
  8. templates/index.html +62 -0
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ venv
Dockerfile ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10-slim
2
+
3
+ RUN useradd -m -u 1000 user
4
+ USER user
5
+ ENV PATH="/home/user/.local/bin:$PATH"
6
+
7
+ WORKDIR /app
8
+
9
+ # Copy requirements and install Python dependencies
10
+ COPY --chown=user ./requirements.txt requirements.txt .
11
+ RUN pip install --no-cache-dir -r requirements.txt
12
+
13
+ # Copy application files
14
+ COPY . .
15
+
16
+ # Run the application
17
+ COPY --chown=user . /app
18
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
README.md CHANGED
@@ -1,10 +1,80 @@
1
  ---
2
- title: Text Analyzer Llm
3
- emoji: 📊
4
- colorFrom: green
5
- colorTo: yellow
6
- sdk: docker
 
 
7
  pinned: false
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: AI Text Assistant
3
+ emoji: 🤖
4
+ colorFrom: purple
5
+ colorTo: blue
6
+ sdk: gradio
7
+ sdk_version: 4.0.0
8
+ app_file: app.py
9
  pinned: false
10
+ license: mit
11
  ---
12
 
13
+ # AI Text Assistant
14
+
15
+ An interactive web application for text generation, summarization, and next-word prediction using transformer models.
16
+
17
+ ## Features
18
+
19
+ - **Text Generation**: Generate creative text continuations using Qwen2.5-0.5B-Instruct model
20
+ - **Text Summarization**: Summarize long texts using BART-large-CNN model
21
+ - **Next Word Prediction**: Get top 10 predictions for the next word with probability scores
22
+
23
+ ## Models Used
24
+
25
+ - **Text Generation**: [Qwen/Qwen2.5-0.5B-Instruct](https://huggingface.co/Qwen/Qwen2.5-0.5B-Instruct)
26
+ - **Summarization**: [facebook/bart-large-cnn](https://huggingface.co/facebook/bart-large-cnn)
27
+
28
+ ## Project Structure
29
+
30
+ ```
31
+ LocalInference/
32
+ ├── app.py # Main FastAPI application
33
+ ├── requirements.txt # Python dependencies
34
+ ├── static/
35
+ │ ├── css/
36
+ │ │ └── style.css # UI styles
37
+ │ └── js/
38
+ │ └── app.js # Client-side JavaScript
39
+ └── templates/
40
+ └── index.html # Main HTML interface
41
+ ```
42
+
43
+ ## Local Setup
44
+
45
+ 1. **Clone the repository:**
46
+ ```bash
47
+ git clone <repository-url>
48
+ cd LocalInference
49
+ ```
50
+
51
+ 2. **Install dependencies:**
52
+ ```bash
53
+ pip install -r requirements.txt
54
+ ```
55
+
56
+ 3. **Run the application:**
57
+ ```bash
58
+ python app.py
59
+ ```
60
+
61
+ The application will be accessible at `http://localhost:7860`
62
+
63
+ ## Usage
64
+
65
+ 1. Open the application in your web browser
66
+ 2. Choose between "Text Generation" or "Text Summarization" mode
67
+ 3. Enter your text in the input field
68
+ 4. Adjust max tokens and sampling options as needed
69
+ 5. Click "Process" to generate results
70
+ 6. Use "Get Next Word Predictions" to see likely next words
71
+
72
+ ## API Endpoints
73
+
74
+ - `GET /` - Web interface
75
+ - `POST /generate` - Generate or summarize text
76
+ - `POST /predict_next` - Get next word predictions
77
+
78
+ ## License
79
+
80
+ This project is licensed under the MIT License.
app.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from fastapi.responses import HTMLResponse
3
+ from fastapi.staticfiles import StaticFiles
4
+ from pydantic import BaseModel
5
+ from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
6
+ import torch
7
+ import uvicorn
8
+ import os
9
+
10
+ app = FastAPI()
11
+
12
+ # Load models and tokenizer
13
+ model_name = "Qwen/Qwen2.5-0.5B-Instruct"
14
+ tokenizer = AutoTokenizer.from_pretrained(model_name)
15
+ model = AutoModelForCausalLM.from_pretrained(model_name)
16
+ generator_pipe = pipeline("text-generation", model=model_name, tokenizer=tokenizer)
17
+ summarizer_pipe = pipeline("summarization", model="facebook/bart-large-cnn")
18
+
19
+ app.mount("/static", StaticFiles(directory="static"), name="static")
20
+
21
+ class GenRequest(BaseModel):
22
+ text: str
23
+ max_new_tokens: int = 150
24
+ do_sample: bool = False
25
+ mode: str = "generate" # "generate" or "summarize"
26
+
27
+ @app.get("/", response_class=HTMLResponse)
28
+ async def read_root():
29
+ with open("templates/index.html", "r") as f:
30
+ return f.read()
31
+
32
+ @app.post("/generate")
33
+ def generate(req: GenRequest):
34
+ if req.mode == "summarize":
35
+ # Use summarization pipeline
36
+ out = summarizer_pipe(
37
+ req.text,
38
+ max_length=req.max_new_tokens,
39
+ min_length=30,
40
+ do_sample=req.do_sample,
41
+ )
42
+ return {"generated_text": out[0]["summary_text"]}
43
+ else:
44
+ # Use text generation pipeline
45
+ out = generator_pipe(
46
+ req.text,
47
+ max_new_tokens=req.max_new_tokens,
48
+ do_sample=req.do_sample,
49
+ truncation=True,
50
+ return_full_text=False,
51
+ )
52
+ return {"generated_text": out[0]["generated_text"]}
53
+
54
+ @app.post("/predict_next")
55
+ def predict_next(req: GenRequest):
56
+ """Get top predictions for next word/token"""
57
+ inputs = tokenizer(req.text, return_tensors="pt")
58
+
59
+ with torch.no_grad():
60
+ outputs = model(**inputs)
61
+ next_token_logits = outputs.logits[0, -1, :]
62
+
63
+ # Get top 10 predictions
64
+ top_k = 10
65
+ probs = torch.softmax(next_token_logits, dim=-1)
66
+ top_probs, top_indices = torch.topk(probs, top_k)
67
+
68
+ predictions = []
69
+ for prob, idx in zip(top_probs.tolist(), top_indices.tolist()):
70
+ token = tokenizer.decode([idx])
71
+ predictions.append({
72
+ "token": token,
73
+ "probability": round(prob * 100, 2)
74
+ })
75
+
76
+ return {"predictions": predictions}
77
+
78
+ if __name__ == "__main__":
79
+ port = int(os.environ.get("PORT", 7860))
80
+ uvicorn.run(app, host="0.0.0.0", port=port)
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ fastapi==0.104.1
2
+ uvicorn[standard]==0.24.0
3
+ pydantic==2.4.2
4
+ transformers==4.45.0
5
+ torch==2.2.0
6
+ numpy<2.0.0
7
+ accelerate==0.24.1
8
+ sentencepiece==0.1.99
9
+ protobuf==4.25.0
static/css/style.css ADDED
@@ -0,0 +1,296 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ * {
2
+ margin: 0;
3
+ padding: 0;
4
+ box-sizing: border-box;
5
+ }
6
+
7
+ body {
8
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
9
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
10
+ min-height: 100vh;
11
+ padding: 20px;
12
+ }
13
+
14
+ .container {
15
+ max-width: 800px;
16
+ margin: 0 auto;
17
+ background: white;
18
+ border-radius: 16px;
19
+ padding: 40px;
20
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
21
+ }
22
+
23
+ h1 {
24
+ color: #333;
25
+ margin-bottom: 30px;
26
+ text-align: center;
27
+ font-size: 2.5em;
28
+ }
29
+
30
+ h2 {
31
+ color: #555;
32
+ margin-bottom: 15px;
33
+ font-size: 1.3em;
34
+ }
35
+
36
+ /* Mode Toggle Styles */
37
+ .mode-toggle {
38
+ display: flex;
39
+ gap: 10px;
40
+ margin-bottom: 30px;
41
+ padding: 5px;
42
+ background: #f0f0f0;
43
+ border-radius: 12px;
44
+ }
45
+
46
+ .toggle-option {
47
+ flex: 1;
48
+ text-align: center;
49
+ cursor: pointer;
50
+ transition: all 0.3s ease;
51
+ }
52
+
53
+ .toggle-option input[type="radio"] {
54
+ display: none;
55
+ }
56
+
57
+ .toggle-label {
58
+ display: block;
59
+ padding: 12px 20px;
60
+ border-radius: 8px;
61
+ font-weight: 600;
62
+ color: #666;
63
+ transition: all 0.3s ease;
64
+ }
65
+
66
+ .toggle-option input[type="radio"]:checked + .toggle-label {
67
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
68
+ color: white;
69
+ box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
70
+ }
71
+
72
+ .toggle-option:hover .toggle-label {
73
+ background: #e0e0e0;
74
+ }
75
+
76
+ .toggle-option input[type="radio"]:checked + .toggle-label:hover {
77
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
78
+ }
79
+
80
+ /* Input Section */
81
+ .input-section {
82
+ margin-bottom: 30px;
83
+ }
84
+
85
+ label {
86
+ display: block;
87
+ margin-bottom: 8px;
88
+ color: #555;
89
+ font-weight: 600;
90
+ }
91
+
92
+ textarea {
93
+ width: 100%;
94
+ padding: 15px;
95
+ border: 2px solid #ddd;
96
+ border-radius: 8px;
97
+ font-size: 16px;
98
+ font-family: inherit;
99
+ resize: vertical;
100
+ transition: border-color 0.3s ease;
101
+ }
102
+
103
+ textarea:focus {
104
+ outline: none;
105
+ border-color: #667eea;
106
+ }
107
+
108
+ .controls {
109
+ display: flex;
110
+ gap: 20px;
111
+ margin: 20px 0;
112
+ flex-wrap: wrap;
113
+ }
114
+
115
+ .control-group {
116
+ flex: 1;
117
+ min-width: 200px;
118
+ }
119
+
120
+ .control-group input[type="number"] {
121
+ width: 100%;
122
+ padding: 10px;
123
+ border: 2px solid #ddd;
124
+ border-radius: 8px;
125
+ font-size: 16px;
126
+ transition: border-color 0.3s ease;
127
+ }
128
+
129
+ .control-group input[type="number"]:focus {
130
+ outline: none;
131
+ border-color: #667eea;
132
+ }
133
+
134
+ .control-group input[type="checkbox"] {
135
+ margin-right: 8px;
136
+ width: 18px;
137
+ height: 18px;
138
+ cursor: pointer;
139
+ }
140
+
141
+ button {
142
+ width: 100%;
143
+ padding: 15px;
144
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
145
+ color: white;
146
+ border: none;
147
+ border-radius: 8px;
148
+ font-size: 18px;
149
+ font-weight: 600;
150
+ cursor: pointer;
151
+ transition: transform 0.2s ease, box-shadow 0.3s ease;
152
+ }
153
+
154
+ button:hover {
155
+ transform: translateY(-2px);
156
+ box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
157
+ }
158
+
159
+ button:active {
160
+ transform: translateY(0);
161
+ }
162
+
163
+ /* Output Section */
164
+ .output-section {
165
+ margin-top: 30px;
166
+ }
167
+
168
+ .output-box {
169
+ background: #f8f9fa;
170
+ border: 2px solid #ddd;
171
+ border-radius: 8px;
172
+ padding: 20px;
173
+ min-height: 150px;
174
+ color: #333;
175
+ line-height: 1.6;
176
+ white-space: pre-wrap;
177
+ word-wrap: break-word;
178
+ }
179
+
180
+ .output-box.loading {
181
+ color: #999;
182
+ font-style: italic;
183
+ }
184
+
185
+ /* Predictions Section */
186
+ .predictions-section {
187
+ margin-top: 30px;
188
+ padding-top: 30px;
189
+ border-top: 2px solid #eee;
190
+ }
191
+
192
+ .predictions-section button {
193
+ margin-bottom: 20px;
194
+ }
195
+
196
+ .predictions-box {
197
+ background: #f8f9fa;
198
+ border: 2px solid #ddd;
199
+ border-radius: 8px;
200
+ padding: 20px;
201
+ min-height: 100px;
202
+ color: #555;
203
+ }
204
+
205
+ .predictions-list {
206
+ display: flex;
207
+ flex-direction: column;
208
+ gap: 12px;
209
+ }
210
+
211
+ .prediction-item {
212
+ background: white;
213
+ border-radius: 8px;
214
+ padding: 12px;
215
+ border: 1px solid #e0e0e0;
216
+ transition: all 0.2s ease;
217
+ }
218
+
219
+ .prediction-item:hover {
220
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
221
+ transform: translateX(4px);
222
+ }
223
+
224
+ .prediction-header {
225
+ display: flex;
226
+ justify-content: space-between;
227
+ align-items: center;
228
+ margin-bottom: 8px;
229
+ gap: 10px;
230
+ }
231
+
232
+ .prediction-rank {
233
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
234
+ color: white;
235
+ padding: 4px 10px;
236
+ border-radius: 12px;
237
+ font-size: 0.85em;
238
+ font-weight: 600;
239
+ min-width: 35px;
240
+ text-align: center;
241
+ }
242
+
243
+ .prediction-token {
244
+ flex: 1;
245
+ font-family: 'Courier New', monospace;
246
+ font-weight: 600;
247
+ color: #333;
248
+ font-size: 1.1em;
249
+ }
250
+
251
+ .prediction-probability {
252
+ color: #667eea;
253
+ font-weight: 700;
254
+ font-size: 1em;
255
+ }
256
+
257
+ .prediction-bar-container {
258
+ width: 100%;
259
+ height: 6px;
260
+ background: #e0e0e0;
261
+ border-radius: 3px;
262
+ overflow: hidden;
263
+ }
264
+
265
+ .prediction-bar {
266
+ height: 100%;
267
+ background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
268
+ border-radius: 3px;
269
+ transition: width 0.5s ease;
270
+ }
271
+
272
+ @media (max-width: 600px) {
273
+ .container {
274
+ padding: 20px;
275
+ }
276
+
277
+ h1 {
278
+ font-size: 1.8em;
279
+ }
280
+
281
+ .controls {
282
+ flex-direction: column;
283
+ }
284
+
285
+ .mode-toggle {
286
+ flex-direction: column;
287
+ }
288
+
289
+ .prediction-header {
290
+ flex-wrap: wrap;
291
+ }
292
+
293
+ .prediction-token {
294
+ font-size: 0.95em;
295
+ }
296
+ }
static/js/app.js ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const generateText = async () => {
2
+ const textInput = document.getElementById("textInput").value;
3
+ const maxTokens = document.getElementById("maxTokens").value;
4
+ const doSample = document.getElementById("doSample").checked;
5
+ const mode = document.querySelector('input[name="mode"]:checked').value;
6
+
7
+ // Show loading state
8
+ const outputElement = document.getElementById("output");
9
+ outputElement.innerText = "Processing...";
10
+ outputElement.classList.add("loading");
11
+
12
+ try {
13
+ const response = await fetch("/generate", {
14
+ method: "POST",
15
+ headers: {
16
+ "Content-Type": "application/json",
17
+ },
18
+ body: JSON.stringify({
19
+ text: textInput,
20
+ max_new_tokens: parseInt(maxTokens),
21
+ do_sample: doSample,
22
+ mode: mode,
23
+ }),
24
+ });
25
+
26
+ if (response.ok) {
27
+ const data = await response.json();
28
+ outputElement.innerText = data.generated_text;
29
+ outputElement.classList.remove("loading");
30
+ } else {
31
+ outputElement.innerText = "Error: Unable to process request.";
32
+ outputElement.classList.remove("loading");
33
+ }
34
+ } catch (error) {
35
+ outputElement.innerText = "Error: " + error.message;
36
+ outputElement.classList.remove("loading");
37
+ }
38
+ };
39
+
40
+ const predictNext = async () => {
41
+ const textInput = document.getElementById("textInput").value;
42
+
43
+ if (!textInput.trim()) {
44
+ alert("Please enter some text first!");
45
+ return;
46
+ }
47
+
48
+ // Show loading state
49
+ const predictionsElement = document.getElementById("predictions");
50
+ predictionsElement.innerHTML = "Loading predictions...";
51
+
52
+ try {
53
+ const response = await fetch("/predict_next", {
54
+ method: "POST",
55
+ headers: {
56
+ "Content-Type": "application/json",
57
+ },
58
+ body: JSON.stringify({
59
+ text: textInput,
60
+ }),
61
+ });
62
+
63
+ if (response.ok) {
64
+ const data = await response.json();
65
+ displayPredictions(data.predictions);
66
+ } else {
67
+ predictionsElement.innerHTML = "Error: Unable to get predictions.";
68
+ }
69
+ } catch (error) {
70
+ predictionsElement.innerHTML = "Error: " + error.message;
71
+ }
72
+ };
73
+
74
+ const displayPredictions = (predictions) => {
75
+ const predictionsElement = document.getElementById("predictions");
76
+
77
+ if (predictions.length === 0) {
78
+ predictionsElement.innerHTML = "No predictions available.";
79
+ return;
80
+ }
81
+
82
+ let html = '<div class="predictions-list">';
83
+ predictions.forEach((pred, index) => {
84
+ const barWidth = pred.probability;
85
+ html += `
86
+ <div class="prediction-item">
87
+ <div class="prediction-header">
88
+ <span class="prediction-rank">#${index + 1}</span>
89
+ <span class="prediction-token">"${pred.token}"</span>
90
+ <span class="prediction-probability">${pred.probability}%</span>
91
+ </div>
92
+ <div class="prediction-bar-container">
93
+ <div class="prediction-bar" style="width: ${barWidth}%"></div>
94
+ </div>
95
+ </div>
96
+ `;
97
+ });
98
+ html += '</div>';
99
+
100
+ predictionsElement.innerHTML = html;
101
+ };
102
+
103
+ // Update UI based on selected mode
104
+ const updateModeUI = () => {
105
+ const mode = document.querySelector('input[name="mode"]:checked').value;
106
+ const placeholder = document.getElementById("textInput");
107
+ const label = document.querySelector('label[for="textInput"]');
108
+
109
+ if (mode === "summarize") {
110
+ placeholder.placeholder = "Enter text to summarize...";
111
+ label.innerText = "Text to Summarize:";
112
+ } else {
113
+ placeholder.placeholder = "Enter your prompt...";
114
+ label.innerText = "Your Prompt:";
115
+ }
116
+ };
117
+
118
+ document.getElementById("generateButton").addEventListener("click", generateText);
119
+ document.getElementById("predictButton").addEventListener("click", predictNext);
120
+ document.querySelectorAll('input[name="mode"]').forEach(radio => {
121
+ radio.addEventListener("change", updateModeUI);
122
+ });
123
+
124
+ // Initialize UI
125
+ updateModeUI();
templates/index.html ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>AI Text Tool</title>
7
+ <link rel="stylesheet" href="/static/css/style.css">
8
+ </head>
9
+ <body>
10
+ <div class="container">
11
+ <h1>AI Text Assistant</h1>
12
+
13
+ <!-- Mode Toggle -->
14
+ <div class="mode-toggle">
15
+ <label class="toggle-option">
16
+ <input type="radio" name="mode" value="generate" checked>
17
+ <span class="toggle-label">Text Generation</span>
18
+ </label>
19
+ <label class="toggle-option">
20
+ <input type="radio" name="mode" value="summarize">
21
+ <span class="toggle-label">Text Summarization</span>
22
+ </label>
23
+ </div>
24
+
25
+ <div class="input-section">
26
+ <label for="textInput">Your Prompt:</label>
27
+ <textarea id="textInput" rows="6" placeholder="Enter your prompt..."></textarea>
28
+
29
+ <div class="controls">
30
+ <div class="control-group">
31
+ <label for="maxTokens">Max Tokens:</label>
32
+ <input type="number" id="maxTokens" value="150" min="10" max="500">
33
+ </div>
34
+
35
+ <div class="control-group">
36
+ <label for="doSample">
37
+ <input type="checkbox" id="doSample">
38
+ Enable Sampling
39
+ </label>
40
+ </div>
41
+ </div>
42
+
43
+ <button id="generateButton">Process</button>
44
+ </div>
45
+
46
+ <div class="output-section">
47
+ <h2>Output:</h2>
48
+ <div id="output" class="output-box">Your result will appear here...</div>
49
+ </div>
50
+
51
+ <div class="predictions-section">
52
+ <h2>Next Word Predictions:</h2>
53
+ <button id="predictButton">Get Next Word Predictions</button>
54
+ <div id="predictions" class="predictions-box">
55
+ Click the button above to see possible next words...
56
+ </div>
57
+ </div>
58
+ </div>
59
+
60
+ <script src="/static/js/app.js"></script>
61
+ </body>
62
+ </html>