Francesco Capuano commited on
Commit
94b3b44
·
1 Parent(s): c69b777

remove: useless

Browse files
Dockerfile DELETED
@@ -1,15 +0,0 @@
1
- FROM python:3.10-slim
2
-
3
- WORKDIR /app
4
-
5
- # Copy the entire project
6
- COPY . .
7
-
8
- # Install dependencies
9
- RUN pip install -r requirements.txt
10
-
11
- # Expose the port that greeter_server listens on
12
- EXPOSE 8080
13
-
14
- # Command to run the server
15
- CMD ["python", "greeter_server.py"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
async_greeter_client.py DELETED
@@ -1,33 +0,0 @@
1
- # Copyright 2020 gRPC authors.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
- """The Python AsyncIO implementation of the GRPC helloworld.Greeter client."""
15
-
16
- import asyncio
17
- import logging
18
-
19
- import grpc
20
- import helloworld_pb2
21
- import helloworld_pb2_grpc
22
-
23
-
24
- async def run() -> None:
25
- async with grpc.aio.insecure_channel("localhost:50051") as channel:
26
- stub = helloworld_pb2_grpc.GreeterStub(channel)
27
- response = await stub.SayHello(helloworld_pb2.HelloRequest(name="you"))
28
- print("Greeter client received: " + response.message)
29
-
30
-
31
- if __name__ == "__main__":
32
- logging.basicConfig()
33
- asyncio.run(run())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
async_greeter_client_with_options.py DELETED
@@ -1,46 +0,0 @@
1
- # Copyright 2020 The gRPC Authors
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
- """gRPC Python AsyncIO helloworld.Greeter client with channel options and timeout parameters."""
15
-
16
- import asyncio
17
- import logging
18
-
19
- import grpc
20
- import helloworld_pb2
21
- import helloworld_pb2_grpc
22
-
23
- # For more channel options, please see https://grpc.io/grpc/core/group__grpc__arg__keys.html
24
- CHANNEL_OPTIONS = [
25
- ("grpc.lb_policy_name", "pick_first"),
26
- ("grpc.enable_retries", 0),
27
- ("grpc.keepalive_timeout_ms", 10000),
28
- ]
29
-
30
-
31
- async def run() -> None:
32
- async with grpc.aio.insecure_channel(
33
- target="localhost:50051", options=CHANNEL_OPTIONS
34
- ) as channel:
35
- stub = helloworld_pb2_grpc.GreeterStub(channel)
36
- # Timeout in seconds.
37
- # Please refer gRPC Python documents for more detail. https://grpc.io/grpc/python/grpc.html
38
- response = await stub.SayHello(
39
- helloworld_pb2.HelloRequest(name="you"), timeout=10
40
- )
41
- print("Greeter client received: " + response.message)
42
-
43
-
44
- if __name__ == "__main__":
45
- logging.basicConfig()
46
- asyncio.run(run())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
async_greeter_server.py DELETED
@@ -1,45 +0,0 @@
1
- # Copyright 2020 gRPC authors.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
- """The Python AsyncIO implementation of the GRPC helloworld.Greeter server."""
15
-
16
- import asyncio
17
- import logging
18
-
19
- import grpc
20
- import helloworld_pb2
21
- import helloworld_pb2_grpc
22
-
23
-
24
- class Greeter(helloworld_pb2_grpc.GreeterServicer):
25
- async def SayHello(
26
- self,
27
- request: helloworld_pb2.HelloRequest,
28
- context: grpc.aio.ServicerContext,
29
- ) -> helloworld_pb2.HelloReply:
30
- return helloworld_pb2.HelloReply(message="Hello, %s!" % request.name)
31
-
32
-
33
- async def serve() -> None:
34
- server = grpc.aio.server()
35
- helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
36
- listen_addr = "[::]:50051"
37
- server.add_insecure_port(listen_addr)
38
- logging.info("Starting server on %s", listen_addr)
39
- await server.start()
40
- await server.wait_for_termination()
41
-
42
-
43
- if __name__ == "__main__":
44
- logging.basicConfig(level=logging.INFO)
45
- asyncio.run(serve())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
async_greeter_server_with_graceful_shutdown.py DELETED
@@ -1,65 +0,0 @@
1
- # Copyright 2021 The gRPC Authors
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
- """The graceful shutdown example for the asyncio Greeter server."""
15
-
16
- import asyncio
17
- import logging
18
-
19
- import grpc
20
- import helloworld_pb2
21
- import helloworld_pb2_grpc
22
-
23
- # Coroutines to be invoked when the event loop is shutting down.
24
- _cleanup_coroutines = []
25
-
26
-
27
- class Greeter(helloworld_pb2_grpc.GreeterServicer):
28
- async def SayHello(
29
- self,
30
- request: helloworld_pb2.HelloRequest,
31
- context: grpc.aio.ServicerContext,
32
- ) -> helloworld_pb2.HelloReply:
33
- logging.info("Received request, sleeping for 4 seconds...")
34
- await asyncio.sleep(4)
35
- logging.info("Sleep completed, responding")
36
- return helloworld_pb2.HelloReply(message="Hello, %s!" % request.name)
37
-
38
-
39
- async def serve() -> None:
40
- server = grpc.aio.server()
41
- helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
42
- listen_addr = "[::]:50051"
43
- server.add_insecure_port(listen_addr)
44
- logging.info("Starting server on %s", listen_addr)
45
- await server.start()
46
-
47
- async def server_graceful_shutdown():
48
- logging.info("Starting graceful shutdown...")
49
- # Shuts down the server with 5 seconds of grace period. During the
50
- # grace period, the server won't accept new connections and allow
51
- # existing RPCs to continue within the grace period.
52
- await server.stop(5)
53
-
54
- _cleanup_coroutines.append(server_graceful_shutdown())
55
- await server.wait_for_termination()
56
-
57
-
58
- if __name__ == "__main__":
59
- logging.basicConfig(level=logging.INFO)
60
- loop = asyncio.get_event_loop()
61
- try:
62
- loop.run_until_complete(serve())
63
- finally:
64
- loop.run_until_complete(*_cleanup_coroutines)
65
- loop.close()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
async_greeter_server_with_reflection.py DELETED
@@ -1,49 +0,0 @@
1
- # Copyright 2020 The gRPC Authors
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
- """The reflection-enabled version of gRPC AsyncIO helloworld.Greeter server."""
15
-
16
- import asyncio
17
- import logging
18
-
19
- import grpc
20
- from grpc_reflection.v1alpha import reflection
21
- import helloworld_pb2
22
- import helloworld_pb2_grpc
23
-
24
-
25
- class Greeter(helloworld_pb2_grpc.GreeterServicer):
26
- async def SayHello(
27
- self,
28
- request: helloworld_pb2.HelloRequest,
29
- context: grpc.aio.ServicerContext,
30
- ) -> helloworld_pb2.HelloReply:
31
- return helloworld_pb2.HelloReply(message="Hello, %s!" % request.name)
32
-
33
-
34
- async def serve() -> None:
35
- server = grpc.aio.server()
36
- helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
37
- SERVICE_NAMES = (
38
- helloworld_pb2.DESCRIPTOR.services_by_name["Greeter"].full_name,
39
- reflection.SERVICE_NAME,
40
- )
41
- reflection.enable_server_reflection(SERVICE_NAMES, server)
42
- server.add_insecure_port("[::]:50051")
43
- await server.start()
44
- await server.wait_for_termination()
45
-
46
-
47
- if __name__ == "__main__":
48
- logging.basicConfig()
49
- asyncio.run(serve())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
greeter_client.py DELETED
@@ -1,38 +0,0 @@
1
- # Copyright 2015 gRPC authors.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
- """The Python implementation of the GRPC helloworld.Greeter client."""
15
-
16
- from __future__ import print_function
17
-
18
- import logging
19
-
20
- import grpc
21
- import helloworld_pb2
22
- import helloworld_pb2_grpc
23
-
24
-
25
- def run():
26
- # NOTE(gRPC Python Team): .close() is possible on a channel and should be
27
- # used in circumstances in which the with statement does not fit the needs
28
- # of the code.
29
- print("Will try to greet world ...")
30
- with grpc.insecure_channel("localhost:50051") as channel:
31
- stub = helloworld_pb2_grpc.GreeterStub(channel)
32
- response = stub.SayHello(helloworld_pb2.HelloRequest(name="you"))
33
- print("Greeter client received: " + response.message)
34
-
35
-
36
- if __name__ == "__main__":
37
- logging.basicConfig()
38
- run()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
greeter_client_reflection.py DELETED
@@ -1,48 +0,0 @@
1
- # Copyright 2023 gRPC authors.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
- """The Python implementation of the GRPC helloworld.Greeter client with reflection."""
15
-
16
- import logging
17
-
18
- from google.protobuf.descriptor_pool import DescriptorPool
19
- import grpc
20
- from grpc_reflection.v1alpha.proto_reflection_descriptor_database import (
21
- ProtoReflectionDescriptorDatabase,
22
- )
23
-
24
-
25
- def run():
26
- print("Will try to greet world ...")
27
- with grpc.insecure_channel("localhost:50051") as channel:
28
- reflection_db = ProtoReflectionDescriptorDatabase(channel)
29
- services = reflection_db.get_services()
30
- print(f"found services: {services}")
31
-
32
- desc_pool = DescriptorPool(reflection_db)
33
- service_desc = desc_pool.FindServiceByName("helloworld.Greeter")
34
- print(f"found Greeter service with name: {service_desc.full_name}")
35
- for methods in service_desc.methods:
36
- print(f"found method name: {methods.full_name}")
37
- input_type = methods.input_type
38
- print(f"input type for this method: {input_type.full_name}")
39
-
40
- request_desc = desc_pool.FindMessageTypeByName(
41
- "helloworld.HelloRequest"
42
- )
43
- print(f"found request name: {request_desc.full_name}")
44
-
45
-
46
- if __name__ == "__main__":
47
- logging.basicConfig()
48
- run()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
greeter_client_with_options.py DELETED
@@ -1,50 +0,0 @@
1
- # Copyright 2018 gRPC authors.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
- """gRPC Python helloworld.Greeter client with channel options and call timeout parameters."""
15
-
16
- from __future__ import print_function
17
-
18
- import logging
19
-
20
- import grpc
21
- import helloworld_pb2
22
- import helloworld_pb2_grpc
23
-
24
-
25
- def run():
26
- # NOTE(gRPC Python Team): .close() is possible on a channel and should be
27
- # used in circumstances in which the with statement does not fit the needs
28
- # of the code.
29
- #
30
- # For more channel options, please see https://grpc.io/grpc/core/group__grpc__arg__keys.html
31
- with grpc.insecure_channel(
32
- target="localhost:50051",
33
- options=[
34
- ("grpc.lb_policy_name", "pick_first"),
35
- ("grpc.enable_retries", 0),
36
- ("grpc.keepalive_timeout_ms", 10000),
37
- ],
38
- ) as channel:
39
- stub = helloworld_pb2_grpc.GreeterStub(channel)
40
- # Timeout in seconds.
41
- # Please refer gRPC Python documents for more detail. https://grpc.io/grpc/python/grpc.html
42
- response = stub.SayHello(
43
- helloworld_pb2.HelloRequest(name="you"), timeout=10
44
- )
45
- print("Greeter client received: " + response.message)
46
-
47
-
48
- if __name__ == "__main__":
49
- logging.basicConfig()
50
- run()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
greeter_server.py DELETED
@@ -1,41 +0,0 @@
1
- # Copyright 2015 gRPC authors.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
- """The Python implementation of the GRPC helloworld.Greeter server."""
15
-
16
- from concurrent import futures
17
- import logging
18
-
19
- import grpc
20
- import helloworld_pb2
21
- import helloworld_pb2_grpc
22
-
23
-
24
- class Greeter(helloworld_pb2_grpc.GreeterServicer):
25
- def SayHello(self, request, context):
26
- return helloworld_pb2.HelloReply(message="Hello, %s!" % request.name)
27
-
28
-
29
- def serve():
30
- port = "50051"
31
- server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
32
- helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
33
- server.add_insecure_port("[::]:" + port)
34
- server.start()
35
- print("Server started, listening on " + port)
36
- server.wait_for_termination()
37
-
38
-
39
- if __name__ == "__main__":
40
- logging.basicConfig()
41
- serve()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
greeter_server_with_reflection.py DELETED
@@ -1,45 +0,0 @@
1
- # Copyright 2018 The gRPC Authors
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
- """The reflection-enabled version of gRPC helloworld.Greeter server."""
15
-
16
- from concurrent import futures
17
- import logging
18
-
19
- import grpc
20
- from grpc_reflection.v1alpha import reflection
21
- import helloworld_pb2
22
- import helloworld_pb2_grpc
23
-
24
-
25
- class Greeter(helloworld_pb2_grpc.GreeterServicer):
26
- def SayHello(self, request, context):
27
- return helloworld_pb2.HelloReply(message="Hello, %s!" % request.name)
28
-
29
-
30
- def serve():
31
- server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
32
- helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
33
- SERVICE_NAMES = (
34
- helloworld_pb2.DESCRIPTOR.services_by_name["Greeter"].full_name,
35
- reflection.SERVICE_NAME,
36
- )
37
- reflection.enable_server_reflection(SERVICE_NAMES, server)
38
- server.add_insecure_port("[::]:50051")
39
- server.start()
40
- server.wait_for_termination()
41
-
42
-
43
- if __name__ == "__main__":
44
- logging.basicConfig()
45
- serve()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
helloworld_pb2.py DELETED
@@ -1,41 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- # Generated by the protocol buffer compiler. DO NOT EDIT!
3
- # NO CHECKED-IN PROTOBUF GENCODE
4
- # source: helloworld.proto
5
- # Protobuf Python Version: 5.27.2
6
- """Generated protocol buffer code."""
7
- from google.protobuf import descriptor as _descriptor
8
- from google.protobuf import descriptor_pool as _descriptor_pool
9
- from google.protobuf import runtime_version as _runtime_version
10
- from google.protobuf import symbol_database as _symbol_database
11
- from google.protobuf.internal import builder as _builder
12
- _runtime_version.ValidateProtobufRuntimeVersion(
13
- _runtime_version.Domain.PUBLIC,
14
- 5,
15
- 27,
16
- 2,
17
- '',
18
- 'helloworld.proto'
19
- )
20
- # @@protoc_insertion_point(imports)
21
-
22
- _sym_db = _symbol_database.Default()
23
-
24
-
25
-
26
-
27
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10helloworld.proto\x12\nhelloworld\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x1d\n\nHelloReply\x12\x0f\n\x07message\x18\x01 \x01(\t2\xe4\x01\n\x07Greeter\x12>\n\x08SayHello\x12\x18.helloworld.HelloRequest\x1a\x16.helloworld.HelloReply\"\x00\x12K\n\x13SayHelloStreamReply\x12\x18.helloworld.HelloRequest\x1a\x16.helloworld.HelloReply\"\x00\x30\x01\x12L\n\x12SayHelloBidiStream\x12\x18.helloworld.HelloRequest\x1a\x16.helloworld.HelloReply\"\x00(\x01\x30\x01\x42\x36\n\x1bio.grpc.examples.helloworldB\x0fHelloWorldProtoP\x01\xa2\x02\x03HLWb\x06proto3')
28
-
29
- _globals = globals()
30
- _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
31
- _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'helloworld_pb2', _globals)
32
- if not _descriptor._USE_C_DESCRIPTORS:
33
- _globals['DESCRIPTOR']._loaded_options = None
34
- _globals['DESCRIPTOR']._serialized_options = b'\n\033io.grpc.examples.helloworldB\017HelloWorldProtoP\001\242\002\003HLW'
35
- _globals['_HELLOREQUEST']._serialized_start=32
36
- _globals['_HELLOREQUEST']._serialized_end=60
37
- _globals['_HELLOREPLY']._serialized_start=62
38
- _globals['_HELLOREPLY']._serialized_end=91
39
- _globals['_GREETER']._serialized_start=94
40
- _globals['_GREETER']._serialized_end=322
41
- # @@protoc_insertion_point(module_scope)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
helloworld_pb2.pyi DELETED
@@ -1,17 +0,0 @@
1
- from google.protobuf import descriptor as _descriptor
2
- from google.protobuf import message as _message
3
- from typing import ClassVar as _ClassVar, Optional as _Optional
4
-
5
- DESCRIPTOR: _descriptor.FileDescriptor
6
-
7
- class HelloRequest(_message.Message):
8
- __slots__ = ("name",)
9
- NAME_FIELD_NUMBER: _ClassVar[int]
10
- name: str
11
- def __init__(self, name: _Optional[str] = ...) -> None: ...
12
-
13
- class HelloReply(_message.Message):
14
- __slots__ = ("message",)
15
- MESSAGE_FIELD_NUMBER: _ClassVar[int]
16
- message: str
17
- def __init__(self, message: _Optional[str] = ...) -> None: ...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
helloworld_pb2_grpc.py DELETED
@@ -1,187 +0,0 @@
1
- # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2
- """Client and server classes corresponding to protobuf-defined services."""
3
- import grpc
4
- import warnings
5
-
6
- import helloworld_pb2 as helloworld__pb2
7
-
8
- GRPC_GENERATED_VERSION = '1.66.0'
9
- GRPC_VERSION = grpc.__version__
10
- _version_not_supported = False
11
-
12
- try:
13
- from grpc._utilities import first_version_is_lower
14
- _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION)
15
- except ImportError:
16
- _version_not_supported = True
17
-
18
- if _version_not_supported:
19
- raise RuntimeError(
20
- f'The grpc package installed is at version {GRPC_VERSION},'
21
- + f' but the generated code in helloworld_pb2_grpc.py depends on'
22
- + f' grpcio>={GRPC_GENERATED_VERSION}.'
23
- + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}'
24
- + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.'
25
- )
26
-
27
-
28
- class GreeterStub(object):
29
- """The greeting service definition.
30
- """
31
-
32
- def __init__(self, channel):
33
- """Constructor.
34
-
35
- Args:
36
- channel: A grpc.Channel.
37
- """
38
- self.SayHello = channel.unary_unary(
39
- '/helloworld.Greeter/SayHello',
40
- request_serializer=helloworld__pb2.HelloRequest.SerializeToString,
41
- response_deserializer=helloworld__pb2.HelloReply.FromString,
42
- _registered_method=True)
43
- self.SayHelloStreamReply = channel.unary_stream(
44
- '/helloworld.Greeter/SayHelloStreamReply',
45
- request_serializer=helloworld__pb2.HelloRequest.SerializeToString,
46
- response_deserializer=helloworld__pb2.HelloReply.FromString,
47
- _registered_method=True)
48
- self.SayHelloBidiStream = channel.stream_stream(
49
- '/helloworld.Greeter/SayHelloBidiStream',
50
- request_serializer=helloworld__pb2.HelloRequest.SerializeToString,
51
- response_deserializer=helloworld__pb2.HelloReply.FromString,
52
- _registered_method=True)
53
-
54
-
55
- class GreeterServicer(object):
56
- """The greeting service definition.
57
- """
58
-
59
- def SayHello(self, request, context):
60
- """Sends a greeting
61
- """
62
- context.set_code(grpc.StatusCode.UNIMPLEMENTED)
63
- context.set_details('Method not implemented!')
64
- raise NotImplementedError('Method not implemented!')
65
-
66
- def SayHelloStreamReply(self, request, context):
67
- """Missing associated documentation comment in .proto file."""
68
- context.set_code(grpc.StatusCode.UNIMPLEMENTED)
69
- context.set_details('Method not implemented!')
70
- raise NotImplementedError('Method not implemented!')
71
-
72
- def SayHelloBidiStream(self, request_iterator, context):
73
- """Missing associated documentation comment in .proto file."""
74
- context.set_code(grpc.StatusCode.UNIMPLEMENTED)
75
- context.set_details('Method not implemented!')
76
- raise NotImplementedError('Method not implemented!')
77
-
78
-
79
- def add_GreeterServicer_to_server(servicer, server):
80
- rpc_method_handlers = {
81
- 'SayHello': grpc.unary_unary_rpc_method_handler(
82
- servicer.SayHello,
83
- request_deserializer=helloworld__pb2.HelloRequest.FromString,
84
- response_serializer=helloworld__pb2.HelloReply.SerializeToString,
85
- ),
86
- 'SayHelloStreamReply': grpc.unary_stream_rpc_method_handler(
87
- servicer.SayHelloStreamReply,
88
- request_deserializer=helloworld__pb2.HelloRequest.FromString,
89
- response_serializer=helloworld__pb2.HelloReply.SerializeToString,
90
- ),
91
- 'SayHelloBidiStream': grpc.stream_stream_rpc_method_handler(
92
- servicer.SayHelloBidiStream,
93
- request_deserializer=helloworld__pb2.HelloRequest.FromString,
94
- response_serializer=helloworld__pb2.HelloReply.SerializeToString,
95
- ),
96
- }
97
- generic_handler = grpc.method_handlers_generic_handler(
98
- 'helloworld.Greeter', rpc_method_handlers)
99
- server.add_generic_rpc_handlers((generic_handler,))
100
- server.add_registered_method_handlers('helloworld.Greeter', rpc_method_handlers)
101
-
102
-
103
- # This class is part of an EXPERIMENTAL API.
104
- class Greeter(object):
105
- """The greeting service definition.
106
- """
107
-
108
- @staticmethod
109
- def SayHello(request,
110
- target,
111
- options=(),
112
- channel_credentials=None,
113
- call_credentials=None,
114
- insecure=False,
115
- compression=None,
116
- wait_for_ready=None,
117
- timeout=None,
118
- metadata=None):
119
- return grpc.experimental.unary_unary(
120
- request,
121
- target,
122
- '/helloworld.Greeter/SayHello',
123
- helloworld__pb2.HelloRequest.SerializeToString,
124
- helloworld__pb2.HelloReply.FromString,
125
- options,
126
- channel_credentials,
127
- insecure,
128
- call_credentials,
129
- compression,
130
- wait_for_ready,
131
- timeout,
132
- metadata,
133
- _registered_method=True)
134
-
135
- @staticmethod
136
- def SayHelloStreamReply(request,
137
- target,
138
- options=(),
139
- channel_credentials=None,
140
- call_credentials=None,
141
- insecure=False,
142
- compression=None,
143
- wait_for_ready=None,
144
- timeout=None,
145
- metadata=None):
146
- return grpc.experimental.unary_stream(
147
- request,
148
- target,
149
- '/helloworld.Greeter/SayHelloStreamReply',
150
- helloworld__pb2.HelloRequest.SerializeToString,
151
- helloworld__pb2.HelloReply.FromString,
152
- options,
153
- channel_credentials,
154
- insecure,
155
- call_credentials,
156
- compression,
157
- wait_for_ready,
158
- timeout,
159
- metadata,
160
- _registered_method=True)
161
-
162
- @staticmethod
163
- def SayHelloBidiStream(request_iterator,
164
- target,
165
- options=(),
166
- channel_credentials=None,
167
- call_credentials=None,
168
- insecure=False,
169
- compression=None,
170
- wait_for_ready=None,
171
- timeout=None,
172
- metadata=None):
173
- return grpc.experimental.stream_stream(
174
- request_iterator,
175
- target,
176
- '/helloworld.Greeter/SayHelloBidiStream',
177
- helloworld__pb2.HelloRequest.SerializeToString,
178
- helloworld__pb2.HelloReply.FromString,
179
- options,
180
- channel_credentials,
181
- insecure,
182
- call_credentials,
183
- compression,
184
- wait_for_ready,
185
- timeout,
186
- metadata,
187
- _registered_method=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lerobot/templates/visualize_dataset_homepage.html DELETED
@@ -1,68 +0,0 @@
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>Interactive Video Background Page</title>
7
- <script src="https://cdn.tailwindcss.com"></script>
8
- <script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>
9
- </head>
10
- <body class="h-screen overflow-hidden font-mono text-white" x-data="{
11
- inputValue: '',
12
- navigateToDataset() {
13
- const trimmedValue = this.inputValue.trim();
14
- if (trimmedValue) {
15
- window.location.href = `/${trimmedValue}`;
16
- }
17
- }
18
- }">
19
- <div class="fixed inset-0 w-full h-full overflow-hidden">
20
- <video class="absolute min-w-full min-h-full w-auto h-auto top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2" autoplay muted loop>
21
- <source src="https://huggingface.co/datasets/cadene/koch_bimanual_folding/resolve/v1.6/videos/observation.images.phone_episode_000037.mp4" type="video/mp4">
22
- Your browser does not support HTML5 video.
23
- </video>
24
- </div>
25
- <div class="fixed inset-0 bg-black bg-opacity-80"></div>
26
- <div class="relative z-10 flex flex-col items-center justify-center h-screen">
27
- <div class="text-center mb-8">
28
- <h1 class="text-4xl font-bold mb-4">LeRobot Dataset Visualizer</h1>
29
-
30
- <a href="https://x.com/RemiCadene/status/1825455895561859185" target="_blank" rel="noopener noreferrer" class="underline">create & train your own robots</a>
31
-
32
- <p class="text-xl mb-4"></p>
33
- <div class="text-left inline-block">
34
- <h3 class="font-semibold mb-2 mt-4">Example Datasets:</h3>
35
- <ul class="list-disc list-inside">
36
- {% for dataset in featured_datasets %}
37
- <li><a href="/{{ dataset }}" class="text-blue-300 hover:text-blue-100 hover:underline">{{ dataset }}</a></li>
38
- {% endfor %}
39
- </ul>
40
- </div>
41
- </div>
42
- <div class="flex w-full max-w-lg px-4 mb-4">
43
- <input
44
- type="text"
45
- x-model="inputValue"
46
- @keyup.enter="navigateToDataset"
47
- placeholder="enter dataset id (ex: lerobot/droid_100)"
48
- class="flex-grow px-4 py-2 rounded-l bg-white bg-opacity-20 text-white placeholder-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-300"
49
- >
50
- <button
51
- @click="navigateToDataset"
52
- class="px-4 py-2 bg-blue-500 text-white rounded-r hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-300"
53
- >
54
- Go
55
- </button>
56
- </div>
57
-
58
- <details class="mt-4 max-w-full px-4">
59
- <summary>More example datasets</summary>
60
- <ul class="list-disc list-inside max-h-28 overflow-y-auto break-all">
61
- {% for dataset in lerobot_datasets %}
62
- <li><a href="/{{ dataset }}" class="text-blue-300 hover:text-blue-100 hover:underline">{{ dataset }}</a></li>
63
- {% endfor %}
64
- </ul>
65
- </details>
66
- </div>
67
- </body>
68
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lerobot/templates/visualize_dataset_template.html DELETED
@@ -1,546 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
-
4
- <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <!-- # TODO(rcadene, mishig25): store the js files locally -->
8
- <script src="https://cdnjs.cloudflare.com/ajax/libs/alpinejs/3.13.5/cdn.min.js" defer></script>
9
- <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/dygraph.min.js" type="text/javascript"></script>
10
- <script src="https://cdn.tailwindcss.com"></script>
11
- <title>{{ dataset_info.repo_id }} episode {{ episode_id }}</title>
12
- </head>
13
-
14
- <!-- Use [Alpin.js](https://alpinejs.dev), a lightweight and easy to learn JS framework -->
15
- <!-- Use [tailwindcss](https://tailwindcss.com/), CSS classes for styling html -->
16
- <!-- Use [dygraphs](https://dygraphs.com/), a lightweight JS charting library -->
17
- <body class="flex flex-col md:flex-row h-screen max-h-screen bg-slate-950 text-gray-200" x-data="createAlpineData()">
18
- <!-- Sidebar -->
19
- <div x-ref="sidebar" class="bg-slate-900 p-5 break-words overflow-y-auto shrink-0 md:shrink md:w-60 md:max-h-screen">
20
- <a href="https://github.com/huggingface/lerobot" target="_blank" class="hidden md:block">
21
- <img src="https://github.com/huggingface/lerobot/raw/main/media/lerobot-logo-thumbnail.png">
22
- </a>
23
- <a href="https://huggingface.co/datasets/{{ dataset_info.repo_id }}" target="_blank">
24
- <h1 class="mb-4 text-xl font-semibold">{{ dataset_info.repo_id }}</h1>
25
- </a>
26
-
27
- <ul>
28
- <li>
29
- Number of samples/frames: {{ dataset_info.num_samples }}
30
- </li>
31
- <li>
32
- Number of episodes: {{ dataset_info.num_episodes }}
33
- </li>
34
- <li>
35
- Frames per second: {{ dataset_info.fps }}
36
- </li>
37
- </ul>
38
-
39
- <p>Episodes:</p>
40
- <!-- episodes menu for medium & large screens -->
41
- <div class="ml-2 hidden md:block" x-data="episodePagination">
42
- <ul>
43
- <template x-for="episode in paginatedEpisodes" :key="episode">
44
- <li class="font-mono text-sm mt-0.5">
45
- <a :href="'episode_' + episode"
46
- :class="{'underline': true, 'font-bold -ml-1': episode == {{ episode_id }}}"
47
- x-text="'Episode ' + episode"></a>
48
- </li>
49
- </template>
50
- </ul>
51
-
52
- <div class="flex items-center mt-3 text-xs" x-show="totalPages > 1">
53
- <button @click="prevPage()"
54
- class="px-2 py-1 bg-slate-800 rounded mr-2"
55
- :class="{'opacity-50 cursor-not-allowed': page === 1}"
56
- :disabled="page === 1">
57
- &laquo; Prev
58
- </button>
59
- <span class="font-mono mr-2" x-text="` ${page} / ${totalPages}`"></span>
60
- <button @click="nextPage()"
61
- class="px-2 py-1 bg-slate-800 rounded"
62
- :class="{'opacity-50 cursor-not-allowed': page === totalPages}"
63
- :disabled="page === totalPages">
64
- Next &raquo;
65
- </button>
66
- </div>
67
- </div>
68
-
69
- <!-- episodes menu for small screens -->
70
- <div class="flex overflow-x-auto md:hidden" x-data="episodePagination">
71
- <button @click="prevPage()"
72
- class="px-2 bg-slate-800 rounded mr-2"
73
- :class="{'opacity-50 cursor-not-allowed': page === 1}"
74
- :disabled="page === 1">&laquo;</button>
75
- <div class="flex">
76
- <template x-for="(episode, index) in paginatedEpisodes" :key="episode">
77
- <p class="font-mono text-sm mt-0.5 px-2"
78
- :class="{
79
- 'font-bold': episode == {{ episode_id }},
80
- 'border-r': index !== paginatedEpisodes.length - 1
81
- }">
82
- <a :href="'episode_' + episode" x-text="episode"></a>
83
- </p>
84
- </template>
85
- </div>
86
- <button @click="nextPage()"
87
- class="px-2 bg-slate-800 rounded ml-2"
88
- :class="{'opacity-50 cursor-not-allowed': page === totalPages}"
89
- :disabled="page === totalPages">&raquo; </button>
90
- </div>
91
-
92
- </div>
93
-
94
- <!-- Toggle sidebar button -->
95
- <button class="flex items-center opacity-50 hover:opacity-100 mx-1 hidden md:block"
96
- @click="() => ($refs.sidebar.classList.toggle('hidden'))" title="Toggle sidebar">
97
- <div class="bg-slate-500 w-2 h-10 rounded-full"></div>
98
- </button>
99
-
100
- <!-- Content -->
101
- <div class="max-h-screen flex flex-col gap-4 overflow-y-auto md:flex-1">
102
- <h1 class="text-xl font-bold mt-4 font-mono">
103
- Episode {{ episode_id }}
104
- </h1>
105
-
106
- <!-- Error message -->
107
- <div class="font-medium text-orange-700 hidden" :class="{ 'hidden': !videoCodecError }">
108
- <p>Videos could NOT play because <a href="https://en.wikipedia.org/wiki/AV1" target="_blank" class="underline">AV1</a> decoding is not available on your browser.</p>
109
- <ul class="list-decimal list-inside">
110
- <li>If iPhone: <span class="italic">It is supported with A17 chip or higher.</span></li>
111
- <li>If Mac with Safari: <span class="italic">It is supported on most browsers except Safari with M1 chip or higher and on Safari with M3 chip or higher.</span></li>
112
- <li>Other: <span class="italic">Contact the maintainers on LeRobot discord channel:</span> <a href="https://discord.com/invite/s3KuuzsPFb" target="_blank" class="underline">https://discord.com/invite/s3KuuzsPFb</a></li>
113
- </ul>
114
- </div>
115
-
116
- <!-- Videos -->
117
- <div class="max-w-32 relative text-sm mb-4 select-none"
118
- @click.outside="isVideosDropdownOpen = false">
119
- <div
120
- @click="isVideosDropdownOpen = !isVideosDropdownOpen"
121
- class="p-2 border border-slate-500 rounded flex justify-between items-center cursor-pointer"
122
- >
123
- <span class="truncate">filter videos</span>
124
- <div class="transition-transform" :class="{ 'rotate-180': isVideosDropdownOpen }">🔽</div>
125
- </div>
126
-
127
- <div x-show="isVideosDropdownOpen"
128
- class="absolute mt-1 border border-slate-500 rounded shadow-lg z-10">
129
- <div>
130
- <template x-for="option in videosKeys" :key="option">
131
- <div
132
- @click="videosKeysSelected = videosKeysSelected.includes(option) ? videosKeysSelected.filter(v => v !== option) : [...videosKeysSelected, option]"
133
- class="p-2 cursor-pointer bg-slate-900"
134
- :class="{ 'bg-slate-700': videosKeysSelected.includes(option) }"
135
- x-text="option"
136
- ></div>
137
- </template>
138
- </div>
139
- </div>
140
- </div>
141
-
142
- <div class="flex flex-wrap gap-x-2 gap-y-6">
143
- {% for video_info in videos_info %}
144
- <div x-show="!videoCodecError && videosKeysSelected.includes('{{ video_info.filename }}')" class="max-w-96 relative">
145
- <p class="absolute inset-x-0 -top-4 text-sm text-gray-300 bg-gray-800 px-2 rounded-t-xl truncate">{{ video_info.filename }}</p>
146
- <video muted loop type="video/mp4" class="object-contain w-full h-full" @canplaythrough="videoCanPlay" @timeupdate="() => {
147
- if (video.duration) {
148
- const time = video.currentTime;
149
- const pc = (100 / video.duration) * time;
150
- $refs.slider.value = pc;
151
- dygraphTime = time;
152
- dygraphIndex = Math.floor(pc * dygraph.numRows() / 100);
153
- dygraph.setSelection(dygraphIndex, undefined, true, true);
154
-
155
- $refs.timer.textContent = formatTime(time) + ' / ' + formatTime(video.duration);
156
-
157
- updateTimeQuery(time.toFixed(2));
158
- }
159
- }" @ended="() => {
160
- $refs.btnPlay.classList.remove('hidden');
161
- $refs.btnPause.classList.add('hidden');
162
- }"
163
- @loadedmetadata="() => ($refs.timer.textContent = formatTime(0) + ' / ' + formatTime(video.duration))">
164
- <source src="{{ video_info.url }}">
165
- Your browser does not support the video tag.
166
- </video>
167
- </div>
168
- {% endfor %}
169
- </div>
170
-
171
- <!-- Language instruction -->
172
- {% if videos_info[0].language_instruction %}
173
- <p class="font-medium mt-2">
174
- Language Instruction: <span class="italic">{{ videos_info[0].language_instruction }}</span>
175
- </p>
176
- {% endif %}
177
-
178
- <!-- Shortcuts info -->
179
- <div class="text-sm hidden md:block">
180
- Hotkeys: <span class="font-mono">Space</span> to pause/unpause, <span class="font-mono">Arrow Down</span> to go to next episode, <span class="font-mono">Arrow Up</span> to go to previous episode.
181
- </div>
182
-
183
- <!-- Controllers -->
184
- <div class="flex gap-1 text-3xl items-center">
185
- <button x-ref="btnPlay" class="-rotate-90" class="-rotate-90" title="Play. Toggle with Space" @click="() => {
186
- videos.forEach(video => video.play());
187
- $refs.btnPlay.classList.toggle('hidden');
188
- $refs.btnPause.classList.toggle('hidden');
189
- }">🔽</button>
190
- <button x-ref="btnPause" class="hidden" title="Pause. Toggle with Space" @click="() => {
191
- videos.forEach(video => video.pause());
192
- $refs.btnPlay.classList.toggle('hidden');
193
- $refs.btnPause.classList.toggle('hidden');
194
- }">⏸️</button>
195
- <button title="Jump backward 5 seconds"
196
- @click="() => (videos.forEach(video => (video.currentTime -= 5)))">⏪</button>
197
- <button title="Jump forward 5 seconds"
198
- @click="() => (videos.forEach(video => (video.currentTime += 5)))">⏩</button>
199
- <button title="Rewind from start"
200
- @click="() => (videos.forEach(video => (video.currentTime = 0.0)))">↩️</button>
201
- <input x-ref="slider" max="100" min="0" step="1" type="range" value="0" class="w-80 mx-2" @input="() => {
202
- const sliderValue = $refs.slider.value;
203
- videos.forEach(video => {
204
- const time = (video.duration * sliderValue) / 100;
205
- video.currentTime = time;
206
- });
207
- }" />
208
- <div x-ref="timer" class="font-mono text-sm border border-slate-500 rounded-lg px-1 py-0.5 shrink-0">0:00 /
209
- 0:00
210
- </div>
211
- </div>
212
-
213
- <!-- Graph -->
214
- <div class="flex gap-2 mb-4 flex-wrap">
215
- <div>
216
- <div id="graph" @mouseleave="() => {
217
- dygraph.setSelection(dygraphIndex, undefined, true, true);
218
- dygraphTime = video.currentTime;
219
- }">
220
- </div>
221
- <p x-ref="graphTimer" class="font-mono ml-14 mt-4"
222
- x-init="$watch('dygraphTime', value => ($refs.graphTimer.innerText = `Time: ${dygraphTime.toFixed(2)}s`))">
223
- Time: 0.00s
224
- </p>
225
- </div>
226
-
227
- <div>
228
- <table class="text-sm border-collapse border border-slate-700" x-show="currentFrameData">
229
- <thead>
230
- <tr>
231
- <th></th>
232
- <template x-for="(_, colIndex) in Array.from({length: columns.length}, (_, index) => index)">
233
- <th class="border border-slate-700">
234
- <div class="flex gap-x-2 justify-between px-2">
235
- <input type="checkbox" :checked="isColumnChecked(colIndex)"
236
- @change="toggleColumn(colIndex)">
237
- <p x-text="`${columns[colIndex].key}`"></p>
238
- </div>
239
- </th>
240
- </template>
241
- </tr>
242
- </thead>
243
- <tbody>
244
- <template x-for="(row, rowIndex) in rows">
245
- <tr class="odd:bg-gray-800 even:bg-gray-900">
246
- <td class="border border-slate-700">
247
- <div class="flex gap-x-2 max-w-64 font-semibold px-1 break-all">
248
- <input type="checkbox" :checked="isRowChecked(rowIndex)"
249
- @change="toggleRow(rowIndex)">
250
- </div>
251
- </td>
252
- <template x-for="(cell, colIndex) in row">
253
- <td x-show="cell" class="border border-slate-700">
254
- <div class="flex gap-x-2 justify-between px-2" :class="{ 'hidden': cell.isNull }">
255
- <div class="flex gap-x-2">
256
- <input type="checkbox" x-model="cell.checked" @change="updateTableValues()">
257
- <span x-text="`${!cell.isNull ? cell.label : null}`"></span>
258
- </div>
259
- <span class="w-14 text-right" x-text="`${!cell.isNull ? (typeof cell.value === 'number' ? cell.value.toFixed(2) : cell.value) : null}`"
260
- :style="`color: ${cell.color}`"></span>
261
- </div>
262
- </td>
263
- </template>
264
- </tr>
265
- </template>
266
- </tbody>
267
- </table>
268
-
269
- <div id="labels" class="hidden">
270
- </div>
271
-
272
- {% if ignored_columns|length > 0 %}
273
- <div class="m-2 text-orange-700 max-w-96">
274
- Columns {{ ignored_columns }} are NOT shown since the visualizer currently does not support 2D or 3D data.
275
- </div>
276
- {% endif %}
277
- </div>
278
-
279
- </div>
280
- </div>
281
-
282
- <script>
283
- const parentOrigin = "https://huggingface.co";
284
- const searchParams = new URLSearchParams();
285
- searchParams.set("dataset", "{{ dataset_info.repo_id }}");
286
- searchParams.set("episode", "{{ episode_id }}");
287
- window.parent.postMessage({ queryString: searchParams.toString() }, parentOrigin);
288
- </script>
289
-
290
- <script>
291
- function createAlpineData() {
292
- return {
293
- // state
294
- dygraph: null,
295
- currentFrameData: null,
296
- checked: [],
297
- dygraphTime: 0.0,
298
- dygraphIndex: 0,
299
- videos: null,
300
- video: null,
301
- colors: null,
302
- nVideos: {{ videos_info | length }},
303
- nVideoReadyToPlay: 0,
304
- videoCodecError: false,
305
- isVideosDropdownOpen: false,
306
- videosKeys: {{ videos_info | map(attribute='filename') | list | tojson }},
307
- videosKeysSelected: [],
308
- columns: {{ columns | tojson }},
309
-
310
- // alpine initialization
311
- init() {
312
- // check if videos can play
313
- const dummyVideo = document.createElement('video');
314
- const canPlayVideos = dummyVideo.canPlayType('video/mp4; codecs="av01.0.05M.08"'); // codec source: https://huggingface.co/blog/video-encoding#results
315
- if(!canPlayVideos){
316
- this.videoCodecError = true;
317
- }
318
- this.videosKeysSelected = this.videosKeys.map(opt => opt)
319
-
320
- // process CSV data
321
- const csvDataStr = {{ episode_data_csv_str|tojson|safe }};
322
- // Create a Blob with the CSV data
323
- const blob = new Blob([csvDataStr], { type: 'text/csv;charset=utf-8;' });
324
- // Create a URL for the Blob
325
- const csvUrl = URL.createObjectURL(blob);
326
-
327
- // process CSV data
328
- this.videos = document.querySelectorAll('video');
329
- this.video = this.videos[0];
330
- this.dygraph = new Dygraph(document.getElementById("graph"), csvUrl, {
331
- pixelsPerPoint: 0.01,
332
- legend: 'always',
333
- labelsDiv: document.getElementById('labels'),
334
- labelsKMB: true,
335
- strokeWidth: 1.5,
336
- pointClickCallback: (event, point) => {
337
- this.dygraphTime = point.xval;
338
- this.updateTableValues(this.dygraphTime);
339
- },
340
- highlightCallback: (event, x, points, row, seriesName) => {
341
- this.dygraphTime = x;
342
- this.updateTableValues(this.dygraphTime);
343
- },
344
- drawCallback: (dygraph, is_initial) => {
345
- if (is_initial) {
346
- // dygraph initialization
347
- this.dygraph.setSelection(this.dygraphIndex, undefined, true, true);
348
- this.colors = this.dygraph.getColors();
349
- this.checked = Array(this.colors.length).fill(true);
350
-
351
- const colors = [];
352
- let lightness = 30; // const LIGHTNESS = [30, 65, 85]; // state_lightness, action_lightness, pred_action_lightness
353
- for(const column of this.columns){
354
- const nValues = column.value.length;
355
- for (let hue = 0; hue < 360; hue += parseInt(360/nValues)) {
356
- const color = `hsl(${hue}, 100%, ${lightness}%)`;
357
- colors.push(color);
358
- }
359
- lightness += 35;
360
- }
361
-
362
- this.dygraph.updateOptions({ colors });
363
- this.colors = colors;
364
-
365
- this.updateTableValues();
366
-
367
- let url = new URL(window.location.href);
368
- let params = new URLSearchParams(url.search);
369
- let time = params.get("t");
370
- if(time){
371
- time = parseFloat(time);
372
- this.videos.forEach(video => (video.currentTime = time));
373
- }
374
- }
375
- },
376
- });
377
- },
378
-
379
- //#region Table Data
380
-
381
- // turn dygraph's 1D data (at a given time t) to 2D data that whose columns names are defined in this.columnNames.
382
- // 2d data view is used to create html table element.
383
- get rows() {
384
- if (!this.currentFrameData) {
385
- return [];
386
- }
387
- const rows = [];
388
- const nRows = Math.max(...this.columns.map(column => column.value.length));
389
- let rowIndex = 0;
390
- while(rowIndex < nRows){
391
- const row = [];
392
- // number of states may NOT match number of actions. In this case, we null-pad the 2D array to make a fully rectangular 2d array
393
- const nullCell = { isNull: true };
394
- // row consists of [state value, action value]
395
- let idx = rowIndex;
396
- for(const column of this.columns){
397
- const nColumn = column.value.length;
398
- row.push(rowIndex < nColumn ? this.currentFrameData[idx] : nullCell);
399
- idx += nColumn; // because this.currentFrameData = [state0, state1, ..., stateN, action0, action1, ..., actionN]
400
- }
401
- rowIndex += 1;
402
- rows.push(row);
403
- }
404
- return rows;
405
- },
406
- isRowChecked(rowIndex) {
407
- return this.rows[rowIndex].every(cell => cell && (cell.isNull || cell.checked));
408
- },
409
- isColumnChecked(colIndex) {
410
- return this.rows.every(row => row[colIndex] && (row[colIndex].isNull || row[colIndex].checked));
411
- },
412
- toggleRow(rowIndex) {
413
- const newState = !this.isRowChecked(rowIndex);
414
- this.rows[rowIndex].forEach(cell => {
415
- if (cell && !cell.isNull) cell.checked = newState;
416
- });
417
- this.updateTableValues();
418
- },
419
- toggleColumn(colIndex) {
420
- const newState = !this.isColumnChecked(colIndex);
421
- this.rows.forEach(row => {
422
- if (row[colIndex] && !row[colIndex].isNull) row[colIndex].checked = newState;
423
- });
424
- this.updateTableValues();
425
- },
426
-
427
- // given time t, update the values in the html table with "data[t]"
428
- updateTableValues(time) {
429
- if (!this.colors) {
430
- return;
431
- }
432
- let pc = (100 / this.video.duration) * (time === undefined ? this.video.currentTime : time);
433
- if (isNaN(pc)) pc = 0;
434
- const index = Math.floor(pc * this.dygraph.numRows() / 100);
435
- // slice(1) to remove the timestamp point that we do not need
436
- const labels = this.dygraph.getLabels().slice(1);
437
- const values = this.dygraph.rawData_[index].slice(1);
438
- const checkedNew = this.currentFrameData ? this.currentFrameData.map(cell => cell.checked) : Array(
439
- this.colors.length).fill(true);
440
- this.currentFrameData = labels.map((label, idx) => ({
441
- label,
442
- value: values[idx],
443
- color: this.colors[idx],
444
- checked: checkedNew[idx],
445
- }));
446
- const shouldUpdateVisibility = !this.checked.every((value, index) => value === checkedNew[index]);
447
- if (shouldUpdateVisibility) {
448
- this.checked = checkedNew;
449
- this.dygraph.setVisibility(this.checked);
450
- }
451
- },
452
-
453
- //#endregion
454
-
455
- updateTimeQuery(time) {
456
- let url = new URL(window.location.href);
457
- let params = new URLSearchParams(url.search);
458
- params.set("t", time);
459
- url.search = params.toString();
460
- window.history.replaceState({}, '', url.toString());
461
- },
462
-
463
- formatTime(time) {
464
- var hours = Math.floor(time / 3600);
465
- var minutes = Math.floor((time % 3600) / 60);
466
- var seconds = Math.floor(time % 60);
467
- return (hours > 0 ? hours + ':' : '') + (minutes < 10 ? '0' + minutes : minutes) + ':' + (seconds <
468
- 10 ?
469
- '0' + seconds : seconds);
470
- },
471
-
472
- videoCanPlay() {
473
- this.nVideoReadyToPlay += 1;
474
- if(this.nVideoReadyToPlay == this.nVideos) {
475
- // start autoplay all videos in sync
476
- this.$refs.btnPlay.click();
477
- }
478
- }
479
- };
480
- }
481
-
482
- document.addEventListener('alpine:init', () => {
483
- // Episode pagination component
484
- Alpine.data('episodePagination', () => ({
485
- episodes: {{ episodes }},
486
- pageSize: 100,
487
- page: 1,
488
-
489
- init() {
490
- // Find which page contains the current episode_id
491
- const currentEpisodeId = {{ episode_id }};
492
- const episodeIndex = this.episodes.indexOf(currentEpisodeId);
493
- if (episodeIndex !== -1) {
494
- this.page = Math.floor(episodeIndex / this.pageSize) + 1;
495
- }
496
- },
497
-
498
- get totalPages() {
499
- return Math.ceil(this.episodes.length / this.pageSize);
500
- },
501
-
502
- get paginatedEpisodes() {
503
- const start = (this.page - 1) * this.pageSize;
504
- const end = start + this.pageSize;
505
- return this.episodes.slice(start, end);
506
- },
507
-
508
- nextPage() {
509
- if (this.page < this.totalPages) {
510
- this.page++;
511
- }
512
- },
513
-
514
- prevPage() {
515
- if (this.page > 1) {
516
- this.page--;
517
- }
518
- }
519
- }));
520
- });
521
- </script>
522
-
523
- <script>
524
- window.addEventListener('keydown', (e) => {
525
- // Use the space bar to play and pause, instead of default action (e.g. scrolling)
526
- const { keyCode, key } = e;
527
-
528
- if (keyCode === 32 || key === ' ') {
529
- e.preventDefault();
530
- const btnPause = document.querySelector('[x-ref="btnPause"]');
531
- const btnPlay = document.querySelector('[x-ref="btnPlay"]');
532
- btnPause.classList.contains('hidden') ? btnPlay.click() : btnPause.click();
533
- } else if (key === 'ArrowDown' || key === 'ArrowUp') {
534
- const episodes = {{ episodes }}; // Access episodes directly from the Jinja template
535
- const nextEpisodeId = key === 'ArrowDown' ? {{ episode_id }} + 1 : {{ episode_id }} - 1;
536
- const lowestEpisodeId = episodes.at(0);
537
- const highestEpisodeId = episodes.at(-1);
538
- if (nextEpisodeId >= lowestEpisodeId && nextEpisodeId <= highestEpisodeId) {
539
- window.location.href = `./episode_${nextEpisodeId}`;
540
- }
541
- }
542
- });
543
- </script>
544
- </body>
545
-
546
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
requirements.txt DELETED
@@ -1,5 +0,0 @@
1
- coverage>=4.0
2
- cython>=3.0.0
3
- protobuf>=6.30.0,<7.0.0
4
- wheel>=0.29
5
- grpcio