From 8a829842dd1598ad21bae3ebde6535946b4d9e47 Mon Sep 17 00:00:00 2001 From: Xu Han Date: Wed, 4 Oct 2023 15:37:04 +0800 Subject: [PATCH 1/4] enable use local files --- app/action/option.go | 1 + app/action/start.go | 6 ++++++ app/frontend/src/state/image/store.ts | 9 ++++++++- main.go | 6 ++++++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/app/action/option.go b/app/action/option.go index 651e1f6..69ee319 100644 --- a/app/action/option.go +++ b/app/action/option.go @@ -13,6 +13,7 @@ var StartOption struct { Port int Readonly bool OnlineSegmentation string + DataDir string } var ImportOption struct { diff --git a/app/action/start.go b/app/action/start.go index ac44b87..95a28e5 100644 --- a/app/action/start.go +++ b/app/action/start.go @@ -66,6 +66,12 @@ func Start(ctx context.Context) error { } e.Use(middlewares...) + // local data + if StartOption.DataDir != "" { + zap.L().Info("serving local data", zap.String("dir", StartOption.DataDir)) + e.Static("/local", StartOption.DataDir) + } + // backend s, teardown, err := createServer() if err != nil { diff --git a/app/frontend/src/state/image/store.ts b/app/frontend/src/state/image/store.ts index 404ebeb..686f1be 100644 --- a/app/frontend/src/state/image/store.ts +++ b/app/frontend/src/state/image/store.ts @@ -4,7 +4,14 @@ import {useQuery, QueryClient} from '@tanstack/react-query'; const client = new QueryClient(); const context = createContext(client); -const query = (url: string) => { +const query = (u: string) => { + let url = u; + + const localPrefix = 'file://'; + if (u.startsWith(localPrefix)) { + url = `/local/${u.substring(localPrefix.length)}`; + } + return { queryKey: ['downloadImage', url], queryFn: async () => await (await fetch(url)).blob(), diff --git a/main.go b/main.go index 62ab428..05795e0 100644 --- a/main.go +++ b/main.go @@ -62,6 +62,12 @@ func main() { EnvVars: []string{"NUTSH_ONLINE_SEGMENTATION"}, Destination: &action.StartOption.OnlineSegmentation, }, + &cli.StringFlag{ + Name: "data-dir", + Usage: "data directory to serve to the frontend", + EnvVars: []string{"NUTSH_DATA_DIR"}, + Destination: &action.StartOption.DataDir, + }, }, Commands: []*cli.Command{ { From 7f783597b44e209bf1a7fb5c41ef808152cf2358 Mon Sep 17 00:00:00 2001 From: Xu Han Date: Wed, 4 Oct 2023 15:45:10 +0800 Subject: [PATCH 2/4] fix sam for local images --- app/action/start.go | 1 + app/backend/option.go | 7 +++++++ app/backend/segmentation.go | 24 +++++++++++++++++++++++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/app/action/start.go b/app/action/start.go index 95a28e5..4aba6ca 100644 --- a/app/action/start.go +++ b/app/action/start.go @@ -111,6 +111,7 @@ func createServer() (nutshapi.ServerInterface, func(), error) { backend.WithPublicStorage(localfs.NewPublic(publicDir(), publicUrlPrefix)), backend.WithSampleStorage(localfs.NewSample(sampleDir())), backend.WithOnlineSegmentationServerAddr(StartOption.OnlineSegmentation), + backend.WithDataDir(StartOption.DataDir), backend.WithConfig(&nutshapi.Config{ Readonly: StartOption.Readonly, OnlineSegmentationEnabled: StartOption.OnlineSegmentation != "", diff --git a/app/backend/option.go b/app/backend/option.go index 09686af..f504584 100644 --- a/app/backend/option.go +++ b/app/backend/option.go @@ -16,6 +16,7 @@ type Options struct { config *nutshapi.Config onlineSegmentationServerAddr string + dataDir string } func (o *Options) Validate() error { @@ -73,3 +74,9 @@ func WithOnlineSegmentationServerAddr(addr string) Option { o.onlineSegmentationServerAddr = addr } } + +func WithDataDir(dir string) Option { + return func(o *Options) { + o.dataDir = dir + } +} diff --git a/app/backend/segmentation.go b/app/backend/segmentation.go index b3e9dd8..bfc7628 100644 --- a/app/backend/segmentation.go +++ b/app/backend/segmentation.go @@ -10,7 +10,10 @@ import ( "nutsh/openapi/gen/nutshapi" schemav1 "nutsh/proto/gen/schema/v1" servicev1 "nutsh/proto/gen/service/v1" + "os" "path" + "path/filepath" + "strings" "github.com/labstack/echo/v4" "github.com/pkg/errors" @@ -136,7 +139,7 @@ func (s *mServer) onlineSegmentationEmbed(ctx context.Context, request nutshapi. hasCrop := (w > 0 && h > 0) imUrl := request.Params.ImageUrl - im, err := downloadImage(ctx, imUrl) + im, err := s.loadImage(ctx, imUrl) if err != nil { return nil, err } @@ -202,6 +205,25 @@ func (s *mServer) onlineSegmentationEmbed(ctx context.Context, request nutshapi. }, nil } +func (s *mServer) loadImage(ctx context.Context, url string) ([]byte, error) { + localPrefix := "file://" + if strings.HasPrefix(url, localPrefix) { + // the image should be loaded from data dir + relPath := strings.TrimPrefix(url, localPrefix) + dir := s.options.dataDir + if dir == "" { + return nil, errors.Errorf("missing data dir to load local image [%s]", relPath) + } + fpath := filepath.Join(dir, relPath) + data, err := os.ReadFile(fpath) + if err != nil { + return nil, errors.WithStack(err) + } + return data, nil + } + return downloadImage(ctx, url) +} + func downloadImage(ctx context.Context, url string) ([]byte, error) { zap.L().Info("downloading image", zap.String("url", url)) From 2a931d972af11a1766a30569cfc9b6cc21e786ff Mon Sep 17 00:00:00 2001 From: Xu Han Date: Wed, 4 Oct 2023 16:12:03 +0800 Subject: [PATCH 3/4] add doc for loading local files --- docs/docs/03-Usage/02-Resource.mdx | 38 ++++++++++++++++++++++++++++++ main.go | 2 +- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/docs/docs/03-Usage/02-Resource.mdx b/docs/docs/03-Usage/02-Resource.mdx index 1912b55..f1a60fb 100644 --- a/docs/docs/03-Usage/02-Resource.mdx +++ b/docs/docs/03-Usage/02-Resource.mdx @@ -7,3 +7,41 @@ Resources refer to objects that are to be annotated, such as images, videos, poi Through the user interface, you can effortlessly create, search for, update, and delete videos. + +## Loading Local Files + +Resource assets are specified by their URLs, e.g. a video is represented by a list of urls of its frames. +By default, the URL should use the HTTP protocol, which isn't convenient for directly loading local files. +You can take the following steps to work with local files. + +1. Start nutsh with an additional flag `--data-dir [data_dir]` pointing to some directory where your data is located. +2. Use `file://[rel_path]` as the URL for your resources, which will point to the file at `[data_dir]/[rel_path]` on your local machine. + +For instance, if you're working with videos stored in + +``` +/var/data/abc + - video0001 + - frame0001.jpg + - frame0002.jpg + - ... + - video0002 + - frame0001.jpg + - frame0002.jpg + - ... + - ... +``` + +Start nutsh with the flag `--data-dir /var/data/abc`, and create your videos with urls like + +``` +file://video0001/frame0001.jpg +file://video0001/frame0002.jpg +... +``` + +:::danger + +You may use `--data-dir /` to serve files with absolute paths, like `file:///var/data/abc/video0001/frame0001.jpg`, but do note that it exposes security risks for your host machine. + +::: diff --git a/main.go b/main.go index 05795e0..5961d11 100644 --- a/main.go +++ b/main.go @@ -64,7 +64,7 @@ func main() { }, &cli.StringFlag{ Name: "data-dir", - Usage: "data directory to serve to the frontend", + Usage: "data directory to serve local files under `file://`", EnvVars: []string{"NUTSH_DATA_DIR"}, Destination: &action.StartOption.DataDir, }, From 7c339298e2b7d8406a2e436237049dabeca769d3 Mon Sep 17 00:00:00 2001 From: Xu Han Date: Wed, 4 Oct 2023 16:26:08 +0800 Subject: [PATCH 4/4] updated doc to emphasis using relative path --- docs/docs/03-Usage/02-Resource.mdx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/docs/03-Usage/02-Resource.mdx b/docs/docs/03-Usage/02-Resource.mdx index f1a60fb..77ec8f5 100644 --- a/docs/docs/03-Usage/02-Resource.mdx +++ b/docs/docs/03-Usage/02-Resource.mdx @@ -40,8 +40,14 @@ file://video0001/frame0002.jpg ... ``` +:::caution + +Always use relative paths. Namely, a local url should never start with `file:///` but only two slashes `file://`. + +::: + :::danger -You may use `--data-dir /` to serve files with absolute paths, like `file:///var/data/abc/video0001/frame0001.jpg`, but do note that it exposes security risks for your host machine. +You may use `--data-dir /` to serve files with absolute paths, like `file://var/data/abc/video0001/frame0001.jpg`, but do note that it exposes security risks for your host machine. :::