rasa2 commited on
Commit
59bdabf
·
1 Parent(s): a0cc9e0

Add model, GPU and prompt options

Browse files
Files changed (1) hide show
  1. app.py +40 -64
app.py CHANGED
@@ -30,7 +30,7 @@ if not UI_TOKEN:
30
 
31
 
32
  # =============================================================================
33
- # Safe, predefined options exposed in the UI
34
  # =============================================================================
35
 
36
  MODEL_OPTIONS = {
@@ -40,16 +40,6 @@ MODEL_OPTIONS = {
40
  "qwen2.5-coder-32b": "Qwen/Qwen2.5-Coder-32B-Instruct",
41
  }
42
 
43
- # Replace these with your real second-parameter options.
44
- # This is intentionally a fixed allowlist.
45
- RUN_MODE_OPTIONS = {
46
- "scan": "scan",
47
- "summarize": "summarize",
48
- "full": "full",
49
- }
50
-
51
- # Simple predefined operational commands.
52
- # These do not accept user free text.
53
  BASIC_COMMANDS = {
54
  "hostname": "Run hostname",
55
  "whoami": "Run whoami",
@@ -59,6 +49,10 @@ BASIC_COMMANDS = {
59
  "list_home": "List home directory",
60
  }
61
 
 
 
 
 
62
 
63
  # =============================================================================
64
  # Data model
@@ -79,7 +73,6 @@ class Job(BaseModel):
79
 
80
  # Parameters for run_paper_reader
81
  model: Optional[str] = None
82
- run_mode: Optional[str] = None
83
  gpus: Optional[int] = None
84
  user_text: Optional[str] = None
85
 
@@ -96,9 +89,9 @@ jobs: dict[str, Job] = {}
96
 
97
  def verify_broker_token(x_broker_token: Optional[str]) -> None:
98
  """
99
- Used by the Fury worker.
100
 
101
- The worker sends:
102
  X-Broker-Token: BROKER_TOKEN
103
  """
104
  if x_broker_token != BROKER_TOKEN:
@@ -107,9 +100,10 @@ def verify_broker_token(x_broker_token: Optional[str]) -> None:
107
 
108
  def verify_ui_token(ui_token: Optional[str]) -> None:
109
  """
110
- Used by the browser UI.
111
 
112
- The browser form sends the UI token as a form field.
 
113
  """
114
  if ui_token != UI_TOKEN:
115
  raise HTTPException(status_code=401, detail="Invalid UI token")
@@ -122,31 +116,30 @@ def validate_basic_command(command: str) -> None:
122
 
123
  def validate_paper_reader_args(
124
  model: str,
125
- run_mode: str,
126
  gpus: int,
127
  user_text: str,
128
  ) -> None:
129
  if model not in MODEL_OPTIONS:
130
  raise HTTPException(status_code=400, detail=f"Model is not allowed: {model}")
131
 
132
- if run_mode not in RUN_MODE_OPTIONS:
133
- raise HTTPException(status_code=400, detail=f"Run mode is not allowed: {run_mode}")
134
-
135
  if gpus < 1 or gpus > 16:
136
  raise HTTPException(status_code=400, detail="GPUs must be between 1 and 16")
137
 
138
  if user_text is None:
139
- raise HTTPException(status_code=400, detail="User text is required")
140
 
141
  if len(user_text.strip()) == 0:
142
- raise HTTPException(status_code=400, detail="User text cannot be empty")
143
 
144
  if len(user_text) > 10_000:
145
- raise HTTPException(status_code=400, detail="User text is too long; max 10,000 characters")
 
 
 
146
 
147
 
148
  # =============================================================================
149
- # Health and API inspection
150
  # =============================================================================
151
 
152
  @app.get("/health")
@@ -164,9 +157,14 @@ def list_commands(x_broker_token: Optional[str] = Header(default=None)):
164
 
165
  return {
166
  "basic_commands": BASIC_COMMANDS,
167
- "model_options": MODEL_OPTIONS,
168
- "run_mode_options": RUN_MODE_OPTIONS,
169
- "gpu_range": [1, 16],
 
 
 
 
 
170
  }
171
 
172
 
@@ -186,13 +184,8 @@ def home():
186
  for key, value in MODEL_OPTIONS.items()
187
  )
188
 
189
- run_mode_options_html = "\n".join(
190
- f'<option value="{escape(key)}">{escape(value)}</option>'
191
- for key, value in RUN_MODE_OPTIONS.items()
192
- )
193
-
194
  gpu_options_html = "\n".join(
195
- f'<option value="{i}">{i}</option>'
196
  for i in range(1, 17)
197
  )
198
 
@@ -204,9 +197,6 @@ def home():
204
  if job.model:
205
  details.append(f"model={job.model}")
206
 
207
- if job.run_mode:
208
- details.append(f"run_mode={job.run_mode}")
209
-
210
  if job.gpus:
211
  details.append(f"gpus={job.gpus}")
212
 
@@ -214,7 +204,7 @@ def home():
214
  preview = job.user_text[:500]
215
  if len(job.user_text) > 500:
216
  preview += "..."
217
- details.append(f"user_text={preview}")
218
 
219
  safe_details = escape("\n".join(details))
220
  safe_result = escape(job.result or "")
@@ -300,8 +290,9 @@ def home():
300
  </div>
301
 
302
  <div class="warning">
303
- This UI does not allow arbitrary shell commands. It only submits predefined
304
- command names and validated parameters. The Fury worker validates again locally.
 
305
  </div>
306
 
307
  <form method="post" action="/submit-basic">
@@ -323,7 +314,7 @@ def home():
323
  </form>
324
 
325
  <form method="post" action="/submit-paper-reader">
326
- <h2>Run Paper Reader on Fury</h2>
327
 
328
  <div>
329
  <label><strong>UI token:</strong></label>
@@ -337,13 +328,6 @@ def home():
337
  </select>
338
  </div>
339
 
340
- <div>
341
- <label><strong>Run mode:</strong></label>
342
- <select name="run_mode">
343
- {run_mode_options_html}
344
- </select>
345
- </div>
346
-
347
  <div>
348
  <label><strong>Number of GPUs:</strong></label>
349
  <select name="gpus">
@@ -352,16 +336,15 @@ def home():
352
  </div>
353
 
354
  <div>
355
- <label><strong>Free text to send to the LLM:</strong></label><br>
356
  <textarea
357
  name="user_text"
358
- rows="10"
359
- placeholder="Enter the text/question/instructions to send to the model..."
360
  required
361
- ></textarea>
362
  </div>
363
 
364
- <button type="submit">Submit paper reader job</button>
365
  </form>
366
 
367
  <p>
@@ -411,16 +394,14 @@ def submit_basic_from_ui(
411
  @app.post("/submit-paper-reader")
412
  def submit_paper_reader_from_ui(
413
  model: str = Form(...),
414
- run_mode: str = Form(...),
415
- gpus: int = Form(...),
416
- user_text: str = Form(...),
417
  ui_token: str = Form(...),
418
  ):
419
  verify_ui_token(ui_token)
420
 
421
  validate_paper_reader_args(
422
  model=model,
423
- run_mode=run_mode,
424
  gpus=gpus,
425
  user_text=user_text,
426
  )
@@ -431,7 +412,6 @@ def submit_paper_reader_from_ui(
431
  id=job_id,
432
  command="run_paper_reader",
433
  model=model,
434
- run_mode=run_mode,
435
  gpus=gpus,
436
  user_text=user_text,
437
  status=JobStatus.queued,
@@ -467,16 +447,14 @@ def submit_basic_job_api(
467
  @app.post("/api/jobs/paper-reader")
468
  def submit_paper_reader_job_api(
469
  model: str = Form(...),
470
- run_mode: str = Form(...),
471
- gpus: int = Form(...),
472
- user_text: str = Form(...),
473
  x_broker_token: Optional[str] = Header(default=None),
474
  ):
475
  verify_broker_token(x_broker_token)
476
 
477
  validate_paper_reader_args(
478
  model=model,
479
- run_mode=run_mode,
480
  gpus=gpus,
481
  user_text=user_text,
482
  )
@@ -487,7 +465,6 @@ def submit_paper_reader_job_api(
487
  id=job_id,
488
  command="run_paper_reader",
489
  model=model,
490
- run_mode=run_mode,
491
  gpus=gpus,
492
  user_text=user_text,
493
  status=JobStatus.queued,
@@ -497,7 +474,7 @@ def submit_paper_reader_job_api(
497
  return job
498
 
499
 
500
- # Backward-compatible endpoint for your previous add_job.sh.
501
  @app.post("/api/jobs")
502
  def submit_job_legacy_api(
503
  command: str = Form(...),
@@ -534,7 +511,6 @@ def get_next_job(x_broker_token: Optional[str] = Header(default=None)):
534
  "id": job.id,
535
  "command": job.command,
536
  "model": job.model,
537
- "run_mode": job.run_mode,
538
  "gpus": job.gpus,
539
  "user_text": job.user_text,
540
  }
 
30
 
31
 
32
  # =============================================================================
33
+ # Safe predefined options
34
  # =============================================================================
35
 
36
  MODEL_OPTIONS = {
 
40
  "qwen2.5-coder-32b": "Qwen/Qwen2.5-Coder-32B-Instruct",
41
  }
42
 
 
 
 
 
 
 
 
 
 
 
43
  BASIC_COMMANDS = {
44
  "hostname": "Run hostname",
45
  "whoami": "Run whoami",
 
49
  "list_home": "List home directory",
50
  }
51
 
52
+ PARAMETERIZED_COMMANDS = {
53
+ "run_paper_reader": "Run paper_reader with model, GPU count, and prompt",
54
+ }
55
+
56
 
57
  # =============================================================================
58
  # Data model
 
73
 
74
  # Parameters for run_paper_reader
75
  model: Optional[str] = None
 
76
  gpus: Optional[int] = None
77
  user_text: Optional[str] = None
78
 
 
89
 
90
  def verify_broker_token(x_broker_token: Optional[str]) -> None:
91
  """
92
+ Used by the Fury worker and command-line API calls.
93
 
94
+ Header:
95
  X-Broker-Token: BROKER_TOKEN
96
  """
97
  if x_broker_token != BROKER_TOKEN:
 
100
 
101
  def verify_ui_token(ui_token: Optional[str]) -> None:
102
  """
103
+ Used by browser form submissions.
104
 
105
+ Form field:
106
+ ui_token
107
  """
108
  if ui_token != UI_TOKEN:
109
  raise HTTPException(status_code=401, detail="Invalid UI token")
 
116
 
117
  def validate_paper_reader_args(
118
  model: str,
 
119
  gpus: int,
120
  user_text: str,
121
  ) -> None:
122
  if model not in MODEL_OPTIONS:
123
  raise HTTPException(status_code=400, detail=f"Model is not allowed: {model}")
124
 
 
 
 
125
  if gpus < 1 or gpus > 16:
126
  raise HTTPException(status_code=400, detail="GPUs must be between 1 and 16")
127
 
128
  if user_text is None:
129
+ raise HTTPException(status_code=400, detail="Prompt is required")
130
 
131
  if len(user_text.strip()) == 0:
132
+ raise HTTPException(status_code=400, detail="Prompt cannot be empty")
133
 
134
  if len(user_text) > 10_000:
135
+ raise HTTPException(
136
+ status_code=400,
137
+ detail="Prompt is too long; max 10,000 characters",
138
+ )
139
 
140
 
141
  # =============================================================================
142
+ # Health and inspection APIs
143
  # =============================================================================
144
 
145
  @app.get("/health")
 
157
 
158
  return {
159
  "basic_commands": BASIC_COMMANDS,
160
+ "parameterized_commands": PARAMETERIZED_COMMANDS,
161
+ "paper_reader": {
162
+ "command": "run_paper_reader",
163
+ "model_options": MODEL_OPTIONS,
164
+ "gpu_range": [1, 16],
165
+ "default_gpus": 1,
166
+ "default_prompt": "hello",
167
+ },
168
  }
169
 
170
 
 
184
  for key, value in MODEL_OPTIONS.items()
185
  )
186
 
 
 
 
 
 
187
  gpu_options_html = "\n".join(
188
+ f'<option value="{i}" {"selected" if i == 1 else ""}>{i}</option>'
189
  for i in range(1, 17)
190
  )
191
 
 
197
  if job.model:
198
  details.append(f"model={job.model}")
199
 
 
 
 
200
  if job.gpus:
201
  details.append(f"gpus={job.gpus}")
202
 
 
204
  preview = job.user_text[:500]
205
  if len(job.user_text) > 500:
206
  preview += "..."
207
+ details.append(f"prompt={preview}")
208
 
209
  safe_details = escape("\n".join(details))
210
  safe_result = escape(job.result or "")
 
290
  </div>
291
 
292
  <div class="warning">
293
+ This UI does not allow arbitrary shell commands.
294
+ It submits only predefined command names and validated parameters.
295
+ Fury validates the job again locally before execution.
296
  </div>
297
 
298
  <form method="post" action="/submit-basic">
 
314
  </form>
315
 
316
  <form method="post" action="/submit-paper-reader">
317
+ <h2>run_paper_reader</h2>
318
 
319
  <div>
320
  <label><strong>UI token:</strong></label>
 
328
  </select>
329
  </div>
330
 
 
 
 
 
 
 
 
331
  <div>
332
  <label><strong>Number of GPUs:</strong></label>
333
  <select name="gpus">
 
336
  </div>
337
 
338
  <div>
339
+ <label><strong>Prompt to send to the LLM:</strong></label><br>
340
  <textarea
341
  name="user_text"
342
+ rows="8"
 
343
  required
344
+ >hello</textarea>
345
  </div>
346
 
347
+ <button type="submit">Submit run_paper_reader job</button>
348
  </form>
349
 
350
  <p>
 
394
  @app.post("/submit-paper-reader")
395
  def submit_paper_reader_from_ui(
396
  model: str = Form(...),
397
+ gpus: int = Form(1),
398
+ user_text: str = Form("hello"),
 
399
  ui_token: str = Form(...),
400
  ):
401
  verify_ui_token(ui_token)
402
 
403
  validate_paper_reader_args(
404
  model=model,
 
405
  gpus=gpus,
406
  user_text=user_text,
407
  )
 
412
  id=job_id,
413
  command="run_paper_reader",
414
  model=model,
 
415
  gpus=gpus,
416
  user_text=user_text,
417
  status=JobStatus.queued,
 
447
  @app.post("/api/jobs/paper-reader")
448
  def submit_paper_reader_job_api(
449
  model: str = Form(...),
450
+ gpus: int = Form(1),
451
+ user_text: str = Form("hello"),
 
452
  x_broker_token: Optional[str] = Header(default=None),
453
  ):
454
  verify_broker_token(x_broker_token)
455
 
456
  validate_paper_reader_args(
457
  model=model,
 
458
  gpus=gpus,
459
  user_text=user_text,
460
  )
 
465
  id=job_id,
466
  command="run_paper_reader",
467
  model=model,
 
468
  gpus=gpus,
469
  user_text=user_text,
470
  status=JobStatus.queued,
 
474
  return job
475
 
476
 
477
+ # Backward-compatible endpoint for simple jobs.
478
  @app.post("/api/jobs")
479
  def submit_job_legacy_api(
480
  command: str = Form(...),
 
511
  "id": job.id,
512
  "command": job.command,
513
  "model": job.model,
 
514
  "gpus": job.gpus,
515
  "user_text": job.user_text,
516
  }