TiGa-RCE commited on
Commit
8751b29
·
verified ·
1 Parent(s): fce5bcb

Restore private TiGa file workflow with HF wrapper guidance

Browse files
Files changed (6) hide show
  1. README.md +6 -6
  2. RELEASE_MANIFEST.json +4 -5
  3. app.py +101 -56
  4. client.js +7 -3
  5. index.html +1 -1
  6. make_test_inputs.py +0 -27
README.md CHANGED
@@ -6,9 +6,9 @@ python_version: "3.10"
6
  app_file: app.py
7
  ---
8
 
9
- Private standard-Gradio browser baseline, synthetic tests only. No user upload interface.
10
- No custom login, job access keys, or user result store in this diagnostic entrypoint.
11
- Run explicitly through the Hugging Face Space page; GPU uses the visitor allowance.
12
- Simulator by Zorro909: https://github.com/Zorro909/driving_sim_rs
13
- HF implementation and UI by TiGa: https://github.com/seeker-cyber-maker/driving_sim_rs
14
- Not a public release or a full trainer. Earlier custom-interface snapshots are preserved.
 
6
  app_file: app.py
7
  ---
8
 
9
+ Private CPU/ZeroGPU integration candidate. Custom interface with Gradio Server on port 7860.
10
+ Simulator: https://github.com/Zorro909/driving_sim_rs
11
+ Hosting adaptation and UI: TiGa https://github.com/seeker-cyber-maker/driving_sim_rs
12
+ CPU is the default; GPU requests explicitly use ZeroGPU. No automatic fallback. No bundled tracks or networks.
13
+ One server process; no persistent storage. See DATA_POLICY.md for retention limits.
14
+ Not yet verified in the hosted Linux runtime; do not publish as a stable release.
RELEASE_MANIFEST.json CHANGED
@@ -5,18 +5,17 @@
5
  "GODOT_LICENSE": "fb2b3bb82c60f1e76841ba2122eb902f8e39c151476fe21ce10c9a05d1045304",
6
  "IMPORTER_BUILD_RECEIPT.json": "4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d",
7
  "LICENSE": "53d5851b6440feeae36f72a5f57fcab37858c48b7084765ece4b0c54b9a28ed8",
8
- "README.md": "905cadea3a2fe0042254d6b21093c256e3113e9a19592b7abf9a58d873c7c97c",
9
- "app.py": "47605919270f695afd4a5b1ec477ab845014d4b95c57cf22855eba4d34233695",
10
  "app_release.py": "40cef7e65bbcf9798eaa1374a2c7be4bb45a5d4e70e981a1eeb8b0b2f2a00c35",
11
  "assets/formula_template.json": "80f745df82bb7be45af52785fd582460bcddc63c5a4e1d8375d85b3122db4c6b",
12
  "bin/altd-sim": "2f2f2144ae14b0ef599ca8510f95712da00243c6875881491d384b394e7499f7",
13
  "bin/extract_saved_track": "3a7733c45b4301a786fcbfe92660a1c484749272da5f608d62f34878bd4ff31a",
14
  "bin/libaltd_gpu.so": "279d6353b4c691686d6aeeae6abfd4a82b959e9b604f079a6c45f9823b48a87a",
15
- "client.js": "d0a338ff461ef5115019e0362e33a12a15569f135dc4e9573daa74045b31de72",
16
  "delivery.py": "4f5a4e45df92e5cbfdef6eb449ede9ba26217fe24da376fafddae5cbbb73847a",
17
  "gpu_tickets.py": "9e2cf757ddc46ca30b49cd6de07e5d84f328a858240afaad2e72453d24803f5a",
18
- "index.html": "caeafcd208a638cd8c4235ca282b5b6451b81eb0e363fcfbb2ee02ed021a4db0",
19
- "make_test_inputs.py": "3c80813d63787877c071d0ba322dc444fea8a392705867a6965e16a30e104496",
20
  "requirements.txt": "9b532747e51bd052e82090ece860d6dafe027407f4512dc74272c148ea104c22",
21
  "server.py": "6375fb9f0a6ed39be0d7ce3cbe5c4c820e412e91417f424ad10a1b5f6f94062f",
22
  "vendor/gradio-client/LICENSE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
 
5
  "GODOT_LICENSE": "fb2b3bb82c60f1e76841ba2122eb902f8e39c151476fe21ce10c9a05d1045304",
6
  "IMPORTER_BUILD_RECEIPT.json": "4ba5c533cc617105478e4d85c83f456a7dfa68b1388049624619871ba9e42e9d",
7
  "LICENSE": "53d5851b6440feeae36f72a5f57fcab37858c48b7084765ece4b0c54b9a28ed8",
8
+ "README.md": "48b536eb04507f65e4ea4101e30d34368f26719f75a2a294b75523f7c0225c37",
9
+ "app.py": "f45a2e3b11f906650696c0173c96305ae4c9e08f656a6223c7296eb43d98f970",
10
  "app_release.py": "40cef7e65bbcf9798eaa1374a2c7be4bb45a5d4e70e981a1eeb8b0b2f2a00c35",
11
  "assets/formula_template.json": "80f745df82bb7be45af52785fd582460bcddc63c5a4e1d8375d85b3122db4c6b",
12
  "bin/altd-sim": "2f2f2144ae14b0ef599ca8510f95712da00243c6875881491d384b394e7499f7",
13
  "bin/extract_saved_track": "3a7733c45b4301a786fcbfe92660a1c484749272da5f608d62f34878bd4ff31a",
14
  "bin/libaltd_gpu.so": "279d6353b4c691686d6aeeae6abfd4a82b959e9b604f079a6c45f9823b48a87a",
15
+ "client.js": "6862b79a6a97639372a4946456cf8f24e37f38bfc12e1eb48a08cf6ba8f3e26b",
16
  "delivery.py": "4f5a4e45df92e5cbfdef6eb449ede9ba26217fe24da376fafddae5cbbb73847a",
17
  "gpu_tickets.py": "9e2cf757ddc46ca30b49cd6de07e5d84f328a858240afaad2e72453d24803f5a",
18
+ "index.html": "91977f278a2568b5d2b217f9d8108f209568cd4491c8ee629f66d7c86efcd7fd",
 
19
  "requirements.txt": "9b532747e51bd052e82090ece860d6dafe027407f4512dc74272c148ea104c22",
20
  "server.py": "6375fb9f0a6ed39be0d7ce3cbe5c4c820e412e91417f424ad10a1b5f6f94062f",
21
  "vendor/gradio-client/LICENSE": "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
app.py CHANGED
@@ -1,62 +1,107 @@
1
- """Standard Gradio browser baseline: synthetic inputs only, no custom sessions."""
 
 
 
 
 
 
 
 
 
2
  import os
3
  os.environ['GRADIO_ANALYTICS_ENABLED']='False'
4
- import hashlib
5
- import tempfile
6
  import gradio as gr
7
  import spaces
8
- from app_release import ROOT,verify_package
9
- from make_test_inputs import make
10
- from worker import run_native
11
-
12
- @spaces.GPU(duration=30)
13
- def gpu_calculation():
14
- import torch
15
- value=torch.arange(16,device='cuda',dtype=torch.float32).sum().item()
16
- if value!=120:raise RuntimeError('Unexpected GPU result')
17
- return {'status':'PASS','test':'GPU arithmetic','sum':value,
18
- 'device':torch.cuda.get_device_name(0),'custom_sessions':False}
19
-
20
- def simulator(gpu=False):
21
- with tempfile.TemporaryDirectory(prefix='tiga-synthetic-') as directory:
22
- p=make(directory)
23
- payload,report=run_native((p/'synthetic.track').read_bytes(),
24
- (p/'synthetic.evolution').read_bytes(),binary=ROOT/'bin/altd-sim',
25
- importer=ROOT/'bin/extract_saved_track',scene_template=ROOT/'assets/formula_template.json',
26
- gpu_library=ROOT/'bin/libaltd_gpu.so' if gpu else None,with_report=True)
27
- receipt={'status':'PASS','test':'synthetic simulator','report':report,
28
- 'candidate_sha256':hashlib.sha256(payload).hexdigest(),'candidate_bytes':len(payload),
29
- 'custom_sessions':False,'user_uploads':False}
30
- return receipt
31
-
32
- @spaces.GPU(duration=90)
33
- def gpu_simulator():
34
- return simulator(True)
35
-
36
- def cpu_simulator():
37
- return simulator(False)
38
-
39
- def build_demo():
40
- with gr.Blocks(analytics_enabled=False) as demo:
41
- gr.Markdown('''# AI Learns To Drive — browser baseline
42
- Simulator by [Zorro909](https://github.com/Zorro909/driving_sim_rs).
43
- HF implementation and UI by TiGa (seeker-cyber-maker).
44
-
45
- Private diagnostic stage: standard Gradio interface, no custom login or job sessions.
46
- Use this page inside Hugging Face while signed in. No personal token is requested.
47
- No user uploads: the simulator generates disposable synthetic inputs and returns only a receipt.
48
- GPU tests use your HF allowance. Nothing runs automatically. This is not the full trainer.
49
- ''')
50
- result=gr.JSON(label='Test receipt')
51
- for label,fn,name in [('1. Test GPU connection',gpu_calculation,'gpu_calculation'),
52
- ('2. Test CPU simulator',cpu_simulator,'cpu_simulator'),
53
- ('3. Test GPU simulator',gpu_simulator,'gpu_simulator')]:
54
- gr.Button(label).click(fn,outputs=result,api_name=name,
55
- concurrency_limit=1,concurrency_id='baseline')
56
- return demo
57
-
58
- if __name__=='__main__':
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  verify_package()
60
  for name in ('altd-sim','extract_saved_track'):(ROOT/'bin'/name).chmod(0o755)
61
- build_demo().queue(max_size=1).launch(server_name='0.0.0.0',server_port=7860,
62
- run_history=False,enable_monitoring=False,show_error=False)
 
 
 
 
 
 
 
 
 
 
1
+ """Private ZeroGPU integration candidate. Never enable on CPU-only hosting.
2
+
3
+ Browser must invoke /gpu_train with @gradio/client for caller quota propagation.
4
+ The queue carries only an opaque ticket; result bytes stay in the existing store.
5
+ """
6
+ import asyncio
7
+ import base64
8
+ from contextlib import asynccontextmanager
9
+ import json
10
+ import threading
11
  import os
12
  os.environ['GRADIO_ANALYTICS_ENABLED']='False'
 
 
13
  import gradio as gr
14
  import spaces
15
+ from fastapi import HTTPException,Request
16
+ from fastapi.responses import FileResponse,JSONResponse
17
+ from app_release import ROOT,cpu_worker,verify_package
18
+ from gpu_tickets import InputTickets
19
+ from server import create_app
20
+ from worker import run_native,track_input,network_input
21
+
22
+ def build_app(cuda_call):
23
+ base=create_app(worker=cpu_worker)
24
+ tickets=InputTickets()
25
+ admission=threading.BoundedSemaphore(1)
26
+
27
+ @asynccontextmanager
28
+ async def lifespan(app):
29
+ async def expire():
30
+ while True:
31
+ await asyncio.sleep(1)
32
+ tickets.expire()
33
+ async with base.router.lifespan_context(base):
34
+ task=asyncio.create_task(expire())
35
+ try:yield
36
+ finally:
37
+ task.cancel()
38
+ try:await task
39
+ except asyncio.CancelledError:pass
40
+ tickets.clear()
41
+
42
+ app=gr.Server(lifespan=lifespan,docs_url=None,redoc_url=None,openapi_url=None)
43
+
44
+ @app.middleware('http')
45
+ async def no_framework_file_storage(request,call_next):
46
+ # This UI sends bounded bytes through prepare, never Gradio file uploads.
47
+ path=request.url.path
48
+ if path.startswith(('/gradio_api/upload','/gradio_api/file=',
49
+ '/gradio_api/stream/','/gradio_api/run/','/gradio_api/runs')):
50
+ return JSONResponse({'detail':'File storage and run history are disabled'},status_code=404)
51
+ return await call_next(request)
52
+
53
+ @app.get('/api/capabilities')
54
+ def capabilities():
55
+ return {'cpu':True,'gpu':True,'default':'cpu','gpu_transport':'gradio-ticket'}
56
+
57
+ @app.get('/gradio-client.js')
58
+ def javascript_client():
59
+ return FileResponse(ROOT/'vendor/gradio-client/dist/index.min.js',media_type='text/javascript')
60
+
61
+ @app.post('/api/gpu/prepare')
62
+ async def prepare(request:Request):
63
+ data=bytearray()
64
+ async for chunk in request.stream():
65
+ if len(data)+len(chunk)>3*1024*1024:raise HTTPException(413,'Request too large')
66
+ data.extend(chunk)
67
+ try:
68
+ body=json.loads(data)
69
+ track=base64.b64decode(body['track'],validate=True)
70
+ network=base64.b64decode(body['network'],validate=True)
71
+ track_input(track);network_input(network)
72
+ ticket=tickets.put(track,network,body.get('automatic',True))
73
+ return {'ticket':ticket,'expires_in_seconds':120}
74
+ except RuntimeError:raise HTTPException(429,'GPU input capacity reached') from None
75
+ except Exception:raise HTTPException(400,'Invalid GPU input') from None
76
+ finally:data.clear()
77
+
78
+ @app.api(name='gpu_train',concurrency_limit=1,concurrency_id='gpu',api_visibility='undocumented')
79
+ def gpu_train(ticket:str)->dict:
80
+ if not admission.acquire(blocking=False):raise ValueError('GPU worker busy')
81
+ try:
82
+ track,network,automatic=tickets.take(ticket)
83
+ payload,report=cuda_call(track,network)
84
+ return {**base.state.results.publish(payload,automatic),'backend':'gpu','report':report}
85
+ finally:admission.release()
86
+
87
+ # Existing download/status/ACK/delete and CPU routes use the same result store.
88
+ for route in base.router.routes:
89
+ if getattr(route,'path',None)!='/api/capabilities':app.router.routes.append(route)
90
+ for middleware in base.user_middleware:
91
+ app.add_middleware(middleware.cls,*middleware.args,**middleware.kwargs)
92
+ return app
93
+
94
+ def main():
95
  verify_package()
96
  for name in ('altd-sim','extract_saved_track'):(ROOT/'bin'/name).chmod(0o755)
97
+
98
+ @spaces.GPU(duration=90)
99
+ def cuda(track,network):
100
+ return run_native(track,network,binary=ROOT/'bin/altd-sim',
101
+ importer=ROOT/'bin/extract_saved_track',scene_template=ROOT/'assets/formula_template.json',
102
+ gpu_library=ROOT/'bin/libaltd_gpu.so',with_report=True)
103
+
104
+ build_app(cuda).launch(server_name='0.0.0.0',server_port=7860,run_history=False,
105
+ enable_monitoring=False,show_error=False)
106
+
107
+ if __name__=='__main__':main()
client.js CHANGED
@@ -6,6 +6,8 @@ let localResult = null;
6
  let capabilitiesReady = false;
7
  let gpuTransport = null;
8
  let gradioClient = null;
 
 
9
  const say = text => { $('status').textContent = text; };
10
  function buttons() {
11
  $('run').disabled = busy || !!job || !capabilitiesReady;
@@ -47,6 +49,7 @@ $('run').onclick = async () => {
47
  try {
48
  const body={track:await encoded($('track').files[0]),network:await encoded($('network').files[0]),automatic:$('automatic').checked,backend:$('backend').value};
49
  if(body.backend==='gpu' && gpuTransport==='gradio-ticket'){
 
50
  // Official client preserves the caller's ZeroGPU quota context.
51
  if(!gradioClient){
52
  const {Client}=await import('/gradio-client.js');
@@ -123,14 +126,15 @@ async function connect(){
123
  const capabilities=await (await request('/api/capabilities',{signal:controller.signal})).json();
124
  if(capabilities.cpu!==true)throw new Error('CPU unavailable');
125
  gpuTransport=capabilities.gpu_transport??null;
126
- $('gpuOption').disabled=!capabilities.gpu;
127
- $('backendNote').textContent=capabilities.gpu?'CPU uses no GPU allowance. GPU requires available allowance. No automatic switching.':'CPU available. GPU is not connected on this deployment; no GPU allowance is needed for CPU.';
 
128
  capabilitiesReady=true; buttons();
129
  say('Connected. Choose your track and network, then run the test.');
130
  } catch(error) {
131
  capabilitiesReady=false; buttons();
132
  $('backendNote').textContent='Connection unavailable — training is disabled.';
133
- say('Private HF access may be blocked inside the embedded page. Use “Open app in its own tab” above, or retry. No run was started.');
134
  } finally {clearTimeout(timeout);$('retry').disabled=false;}
135
  }
136
  $('retry').onclick=()=>{if(!busy&&!job)connect();};
 
6
  let capabilitiesReady = false;
7
  let gpuTransport = null;
8
  let gradioClient = null;
9
+ // Navigation guard only, not an authentication or authorization check.
10
+ const hostedStandalone = location.hostname.endsWith('.hf.space') && window.self === window.top;
11
  const say = text => { $('status').textContent = text; };
12
  function buttons() {
13
  $('run').disabled = busy || !!job || !capabilitiesReady;
 
49
  try {
50
  const body={track:await encoded($('track').files[0]),network:await encoded($('network').files[0]),automatic:$('automatic').checked,backend:$('backend').value};
51
  if(body.backend==='gpu' && gpuTransport==='gradio-ticket'){
52
+ if(hostedStandalone)throw new Error('For GPU, open the Hugging Face Space page while signed in. CPU remains available here.');
53
  // Official client preserves the caller's ZeroGPU quota context.
54
  if(!gradioClient){
55
  const {Client}=await import('/gradio-client.js');
 
126
  const capabilities=await (await request('/api/capabilities',{signal:controller.signal})).json();
127
  if(capabilities.cpu!==true)throw new Error('CPU unavailable');
128
  gpuTransport=capabilities.gpu_transport??null;
129
+ $('gpuOption').disabled=!capabilities.gpu || hostedStandalone;
130
+ if(hostedStandalone && $('backend').value==='gpu')$('backend').value='cpu';
131
+ $('backendNote').textContent=capabilities.gpu?(hostedStandalone?'CPU available here. For GPU, open the Hugging Face Space page above to use your signed-in allowance.':'CPU uses no GPU allowance. GPU uses your HF allowance; stay inside the HF Space page. No automatic switching.'):'CPU available. GPU is not connected on this deployment; no GPU allowance is needed for CPU.';
132
  capabilitiesReady=true; buttons();
133
  say('Connected. Choose your track and network, then run the test.');
134
  } catch(error) {
135
  capabilitiesReady=false; buttons();
136
  $('backendNote').textContent='Connection unavailable — training is disabled.';
137
+ say('Could not reach this app. Confirm HF access and retry. Private embedded access can depend on browser cookie settings. No run was started.');
138
  } finally {clearTimeout(timeout);$('retry').disabled=false;}
139
  }
140
  $('retry').onclick=()=>{if(!busy&&!job)connect();};
index.html CHANGED
@@ -7,7 +7,7 @@
7
  <p>Game by ActivationFunction · <a href="https://store.steampowered.com/app/3312030/AI_Learns_To_Drive/">Steam store</a></p>
8
  <p>Simulator by <a href="https://github.com/Zorro909/driving_sim_rs">Zorro909</a> · UI and HF implementation by <a href="https://github.com/seeker-cyber-maker/driving_sim_rs">TiGa (seeker-cyber-maker)</a></p>
9
  <p class="hint">Private release integration · bounded training test. No app account needed; private hosting may require access.</p>
10
- <p><a id="standalone" href="" target="_blank" rel="noopener noreferrer">Open app in its own tab — recommended for private HF access</a><br><small>Uses this page’s existing HF access link. No privacy-setting changes needed. Select files again in the new tab; do not share private access links.</small></p>
11
  <div class="grid"><section class="card"><h2>Simulation</h2><p>4 vehicles · 1 generation · 60 requested ticks. Formula networks, steering and acceleration; speed and raycast sensors. This is not yet the full trainer.</p>
12
  <p><label for="backend">Compute</label><select id="backend" disabled><option value="cpu">CPU — no GPU allowance</option><option id="gpuOption" value="gpu" disabled>GPU — uses GPU allowance</option></select></p><p id="backendNote" class="hint">Checking available backends…</p>
13
  <button id="retry" type="button">Retry connection</button>
 
7
  <p>Game by ActivationFunction · <a href="https://store.steampowered.com/app/3312030/AI_Learns_To_Drive/">Steam store</a></p>
8
  <p>Simulator by <a href="https://github.com/Zorro909/driving_sim_rs">Zorro909</a> · UI and HF implementation by <a href="https://github.com/seeker-cyber-maker/driving_sim_rs">TiGa (seeker-cyber-maker)</a></p>
9
  <p class="hint">Private release integration · bounded training test. No app account needed; private hosting may require access.</p>
10
+ <p><a href="https://huggingface.co/spaces/TiGa-RCE/ald-tao-gpu" target="_blank" rel="noopener noreferrer">Open the Hugging Face Space page</a><br><small>For GPU, use the app inside that page while signed in to HF. A standalone app tab may not receive your account allowance. CPU does not use GPU allowance. No personal token or separate app login is requested.</small></p>
11
  <div class="grid"><section class="card"><h2>Simulation</h2><p>4 vehicles · 1 generation · 60 requested ticks. Formula networks, steering and acceleration; speed and raycast sensors. This is not yet the full trainer.</p>
12
  <p><label for="backend">Compute</label><select id="backend" disabled><option value="cpu">CPU — no GPU allowance</option><option id="gpuOption" value="gpu" disabled>GPU — uses GPU allowance</option></select></p><p id="backendNote" class="hint">Checking available backends…</p>
13
  <button id="retry" type="button">Retry connection</button>
make_test_inputs.py DELETED
@@ -1,27 +0,0 @@
1
- """Write disposable synthetic inputs, never copy a campaign track or trained network.
2
-
3
- Track layout matches upstream print_saved_fixture's fixed generator output.
4
- Tile IDs reference upstream resources: their provenance remains a release gate.
5
- """
6
- import gzip
7
- import json
8
- from pathlib import Path
9
- import tempfile
10
-
11
- def make(directory):
12
- directory=Path(directory); directory.mkdir(parents=True,exist_ok=True)
13
- cells=[(0,0,2,3),*( (x,0,5,0) for x in range(1,5)),(5,0,2,2),
14
- (5,1,102,0),*((x,1,105,0) for x in range(4,0,-1)),(0,1,102,1)]
15
- tiles={}
16
- for x,y,atlas,alternative in cells:
17
- coord=f'Vector2i({x}, {y})'
18
- tiles[coord]={'Block':{'TileSetId':{'AtlasId':atlas,'AlternativeId':alternative}},'Coords':coord}
19
- track={'Tiles':tiles,'StartTileCoords':'Vector2i(0, 0)',
20
- 'StartTileConnection':{'Side':3,'Index':1,'Type':0}}
21
- network={'Name':'Synthetic smoke input','Type':0,'Outputs':[0,1],'Sensors':[{'$type':'speed'}],
22
- 'NeuralNetwork':{'Shape':[1,2],'Weights':[[[0.,0.]]],'Biases':[[0.,1.]]}}
23
- for name,obj in [('synthetic.track',track),('synthetic.evolution',network)]:
24
- (directory/name).write_bytes(gzip.compress(json.dumps(obj).encode(),mtime=0))
25
- return directory
26
-
27
- if __name__=='__main__': print(make(tempfile.mkdtemp(prefix='tiga-browser-fixtures-')))