Initial stub for feature flags in settings #284

Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
Michael Mayer 2020-04-12 18:00:31 +02:00
parent 265dafa08e
commit 47814e2fde
16 changed files with 160 additions and 119 deletions

View file

@ -225,7 +225,7 @@
</v-list-tile-content> </v-list-tile-content>
</v-list-tile> </v-list-tile>
<v-list-tile to="/settings" @click="" class="p-navigation-settings"> <v-list-tile to="/settings" @click="" class="p-navigation-settings" v-if="!config.disableSettings">
<v-list-tile-action> <v-list-tile-action>
<v-icon>settings</v-icon> <v-icon>settings</v-icon>
</v-list-tile-action> </v-list-tile-action>

View file

@ -26,7 +26,7 @@ func GetSettings(router *gin.RouterGroup, conf *config.Config) {
// POST /api/v1/settings // POST /api/v1/settings
func SaveSettings(router *gin.RouterGroup, conf *config.Config) { func SaveSettings(router *gin.RouterGroup, conf *config.Config) {
router.POST("/settings", func(c *gin.Context) { router.POST("/settings", func(c *gin.Context) {
if Unauthorized(c, conf) { if conf.DisableSettings() || Unauthorized(c, conf) {
c.AbortWithStatusJSON(http.StatusUnauthorized, ErrUnauthorized) c.AbortWithStatusJSON(http.StatusUnauthorized, ErrUnauthorized)
return return
} }

View file

@ -14,7 +14,7 @@ func TestTensorFlow_LabelsFromFile(t *testing.T) {
t.Run("chameleon_lime.jpg", func(t *testing.T) { t.Run("chameleon_lime.jpg", func(t *testing.T) {
conf := config.TestConfig() conf := config.TestConfig()
tensorFlow := New(conf.ResourcesPath(), conf.TensorFlowDisabled()) tensorFlow := New(conf.ResourcesPath(), conf.DisableTensorFlow())
result, err := tensorFlow.File(conf.ExamplesPath() + "/chameleon_lime.jpg") result, err := tensorFlow.File(conf.ExamplesPath() + "/chameleon_lime.jpg")
@ -38,7 +38,7 @@ func TestTensorFlow_LabelsFromFile(t *testing.T) {
t.Run("not existing file", func(t *testing.T) { t.Run("not existing file", func(t *testing.T) {
conf := config.TestConfig() conf := config.TestConfig()
tensorFlow := New(conf.ResourcesPath(), conf.TensorFlowDisabled()) tensorFlow := New(conf.ResourcesPath(), conf.DisableTensorFlow())
result, err := tensorFlow.File(conf.ExamplesPath() + "/notexisting.jpg") result, err := tensorFlow.File(conf.ExamplesPath() + "/notexisting.jpg")
assert.Contains(t, err.Error(), "no such file or directory") assert.Contains(t, err.Error(), "no such file or directory")
@ -54,7 +54,7 @@ func TestTensorFlow_Labels(t *testing.T) {
t.Run("chameleon_lime.jpg", func(t *testing.T) { t.Run("chameleon_lime.jpg", func(t *testing.T) {
conf := config.TestConfig() conf := config.TestConfig()
tensorFlow := New(conf.ResourcesPath(), conf.TensorFlowDisabled()) tensorFlow := New(conf.ResourcesPath(), conf.DisableTensorFlow())
if imageBuffer, err := ioutil.ReadFile(conf.ExamplesPath() + "/chameleon_lime.jpg"); err != nil { if imageBuffer, err := ioutil.ReadFile(conf.ExamplesPath() + "/chameleon_lime.jpg"); err != nil {
t.Error(err) t.Error(err)
@ -77,7 +77,7 @@ func TestTensorFlow_Labels(t *testing.T) {
t.Run("dog_orange.jpg", func(t *testing.T) { t.Run("dog_orange.jpg", func(t *testing.T) {
conf := config.TestConfig() conf := config.TestConfig()
tensorFlow := New(conf.ResourcesPath(), conf.TensorFlowDisabled()) tensorFlow := New(conf.ResourcesPath(), conf.DisableTensorFlow())
if imageBuffer, err := ioutil.ReadFile(conf.ExamplesPath() + "/dog_orange.jpg"); err != nil { if imageBuffer, err := ioutil.ReadFile(conf.ExamplesPath() + "/dog_orange.jpg"); err != nil {
t.Error(err) t.Error(err)
@ -100,7 +100,7 @@ func TestTensorFlow_Labels(t *testing.T) {
t.Run("Random.docx", func(t *testing.T) { t.Run("Random.docx", func(t *testing.T) {
conf := config.TestConfig() conf := config.TestConfig()
tensorFlow := New(conf.ResourcesPath(), conf.TensorFlowDisabled()) tensorFlow := New(conf.ResourcesPath(), conf.DisableTensorFlow())
if imageBuffer, err := ioutil.ReadFile(conf.ExamplesPath() + "/Random.docx"); err != nil { if imageBuffer, err := ioutil.ReadFile(conf.ExamplesPath() + "/Random.docx"); err != nil {
t.Error(err) t.Error(err)
@ -113,7 +113,7 @@ func TestTensorFlow_Labels(t *testing.T) {
t.Run("6720px_white.jpg", func(t *testing.T) { t.Run("6720px_white.jpg", func(t *testing.T) {
conf := config.TestConfig() conf := config.TestConfig()
tensorFlow := New(conf.ResourcesPath(), conf.TensorFlowDisabled()) tensorFlow := New(conf.ResourcesPath(), conf.DisableTensorFlow())
if imageBuffer, err := ioutil.ReadFile(conf.ExamplesPath() + "/6720px_white.jpg"); err != nil { if imageBuffer, err := ioutil.ReadFile(conf.ExamplesPath() + "/6720px_white.jpg"); err != nil {
t.Error(err) t.Error(err)
@ -129,7 +129,7 @@ func TestTensorFlow_LoadModel(t *testing.T) {
t.Run("model path exists", func(t *testing.T) { t.Run("model path exists", func(t *testing.T) {
conf := config.TestConfig() conf := config.TestConfig()
tensorFlow := New(conf.ResourcesPath(), conf.TensorFlowDisabled()) tensorFlow := New(conf.ResourcesPath(), conf.DisableTensorFlow())
result := tensorFlow.loadModel() result := tensorFlow.loadModel()
assert.Nil(t, result) assert.Nil(t, result)
@ -137,7 +137,7 @@ func TestTensorFlow_LoadModel(t *testing.T) {
t.Run("model path does not exist", func(t *testing.T) { t.Run("model path does not exist", func(t *testing.T) {
conf := config.NewTestErrorConfig() conf := config.NewTestErrorConfig()
tensorFlow := New(conf.ResourcesPath(), conf.TensorFlowDisabled()) tensorFlow := New(conf.ResourcesPath(), conf.DisableTensorFlow())
result := tensorFlow.loadModel() result := tensorFlow.loadModel()
assert.Contains(t, result.Error(), "Could not find SavedModel") assert.Contains(t, result.Error(), "Could not find SavedModel")
@ -148,7 +148,7 @@ func TestTensorFlow_BestLabels(t *testing.T) {
t.Run("labels not loaded", func(t *testing.T) { t.Run("labels not loaded", func(t *testing.T) {
conf := config.TestConfig() conf := config.TestConfig()
tensorFlow := New(conf.ResourcesPath(), conf.TensorFlowDisabled()) tensorFlow := New(conf.ResourcesPath(), conf.DisableTensorFlow())
p := make([]float32, 1000) p := make([]float32, 1000)
@ -160,7 +160,7 @@ func TestTensorFlow_BestLabels(t *testing.T) {
t.Run("labels loaded", func(t *testing.T) { t.Run("labels loaded", func(t *testing.T) {
conf := config.TestConfig() conf := config.TestConfig()
path := conf.TensorFlowModelPath() path := conf.TensorFlowModelPath()
tensorFlow := New(conf.ResourcesPath(), conf.TensorFlowDisabled()) tensorFlow := New(conf.ResourcesPath(), conf.DisableTensorFlow())
tensorFlow.loadLabels(path) tensorFlow.loadLabels(path)
p := make([]float32, 1000) p := make([]float32, 1000)
@ -183,7 +183,7 @@ func TestTensorFlow_MakeTensor(t *testing.T) {
t.Run("cat_brown.jpg", func(t *testing.T) { t.Run("cat_brown.jpg", func(t *testing.T) {
conf := config.TestConfig() conf := config.TestConfig()
tensorFlow := New(conf.ResourcesPath(), conf.TensorFlowDisabled()) tensorFlow := New(conf.ResourcesPath(), conf.DisableTensorFlow())
imageBuffer, err := ioutil.ReadFile(conf.ExamplesPath() + "/cat_brown.jpg") imageBuffer, err := ioutil.ReadFile(conf.ExamplesPath() + "/cat_brown.jpg")
assert.Nil(t, err) assert.Nil(t, err)
@ -195,7 +195,7 @@ func TestTensorFlow_MakeTensor(t *testing.T) {
t.Run("Random.docx", func(t *testing.T) { t.Run("Random.docx", func(t *testing.T) {
conf := config.TestConfig() conf := config.TestConfig()
tensorFlow := New(conf.ResourcesPath(), conf.TensorFlowDisabled()) tensorFlow := New(conf.ResourcesPath(), conf.DisableTensorFlow())
imageBuffer, err := ioutil.ReadFile(conf.ExamplesPath() + "/Random.docx") imageBuffer, err := ioutil.ReadFile(conf.ExamplesPath() + "/Random.docx")
assert.Nil(t, err) assert.Nil(t, err)

View file

@ -52,7 +52,6 @@ func configAction(ctx *cli.Context) error {
fmt.Printf("resources-path %s\n", conf.ResourcesPath()) fmt.Printf("resources-path %s\n", conf.ResourcesPath())
fmt.Printf("tf-version %s\n", conf.TensorFlowVersion()) fmt.Printf("tf-version %s\n", conf.TensorFlowVersion())
fmt.Printf("tf-model-path %s\n", conf.TensorFlowModelPath()) fmt.Printf("tf-model-path %s\n", conf.TensorFlowModelPath())
fmt.Printf("tf-disabled %t\n", conf.TensorFlowDisabled())
fmt.Printf("templates-path %s\n", conf.HttpTemplatesPath()) fmt.Printf("templates-path %s\n", conf.HttpTemplatesPath())
fmt.Printf("favicons-path %s\n", conf.HttpFaviconsPath()) fmt.Printf("favicons-path %s\n", conf.HttpFaviconsPath())
fmt.Printf("static-path %s\n", conf.HttpStaticPath()) fmt.Printf("static-path %s\n", conf.HttpStaticPath())
@ -83,5 +82,8 @@ func configAction(ctx *cli.Context) error {
fmt.Printf("thumb-limit %d\n", conf.ThumbLimit()) fmt.Printf("thumb-limit %d\n", conf.ThumbLimit())
fmt.Printf("thumb-filter %s\n", conf.ThumbFilter()) fmt.Printf("thumb-filter %s\n", conf.ThumbFilter())
fmt.Printf("disable-tf %t\n", conf.DisableTensorFlow())
fmt.Printf("disable-settings %t\n", conf.DisableSettings())
return nil return nil
} }

View file

@ -12,6 +12,31 @@ import (
// ClientConfig contains HTTP client / Web UI config values // ClientConfig contains HTTP client / Web UI config values
type ClientConfig map[string]interface{} type ClientConfig map[string]interface{}
// Flags returns config flags as string slice.
func (c *Config) Flags() (flags []string) {
if c.Public() {
flags = append(flags, "public")
}
if c.Debug() {
flags = append(flags, "debug")
}
if c.Experimental() {
flags = append(flags, "experimental")
}
if c.ReadOnly() {
flags = append(flags, "readonly")
}
if !c.DisableSettings() {
flags = append(flags, "settings")
}
return flags
}
// PublicClientConfig returns reduced config values for non-public sites. // PublicClientConfig returns reduced config values for non-public sites.
func (c *Config) PublicClientConfig() ClientConfig { func (c *Config) PublicClientConfig() ClientConfig {
if c.Public() { if c.Public() {
@ -20,22 +45,7 @@ func (c *Config) PublicClientConfig() ClientConfig {
jsHash := fs.Checksum(c.HttpStaticBuildPath() + "/app.js") jsHash := fs.Checksum(c.HttpStaticBuildPath() + "/app.js")
cssHash := fs.Checksum(c.HttpStaticBuildPath() + "/app.css") cssHash := fs.Checksum(c.HttpStaticBuildPath() + "/app.css")
configFlags := c.Flags()
// Feature Flags
var flags []string
if c.Public() {
flags = append(flags, "public")
}
if c.Debug() {
flags = append(flags, "debug")
}
if c.Experimental() {
flags = append(flags, "experimental")
}
if c.ReadOnly() {
flags = append(flags, "readonly")
}
var noPos = struct { var noPos = struct {
PhotoUUID string `json:"photo"` PhotoUUID string `json:"photo"`
@ -57,34 +67,35 @@ func (c *Config) PublicClientConfig() ClientConfig {
}{} }{}
result := ClientConfig{ result := ClientConfig{
"settings": c.Settings(), "settings": c.Settings(),
"flags": strings.Join(flags, " "), "flags": strings.Join(configFlags, " "),
"name": c.Name(), "name": c.Name(),
"url": c.Url(), "url": c.Url(),
"title": c.Title(), "title": c.Title(),
"subtitle": c.Subtitle(), "subtitle": c.Subtitle(),
"description": c.Description(), "description": c.Description(),
"author": c.Author(), "author": c.Author(),
"twitter": c.Twitter(), "twitter": c.Twitter(),
"version": c.Version(), "version": c.Version(),
"copyright": c.Copyright(), "copyright": c.Copyright(),
"debug": c.Debug(), "debug": c.Debug(),
"readonly": c.ReadOnly(), "readonly": c.ReadOnly(),
"uploadNSFW": c.UploadNSFW(), "uploadNSFW": c.UploadNSFW(),
"public": c.Public(), "public": c.Public(),
"experimental": c.Experimental(), "experimental": c.Experimental(),
"albums": []string{}, "disableSettings": c.DisableSettings(),
"cameras": []string{}, "albums": []string{},
"lenses": []string{}, "cameras": []string{},
"countries": []string{}, "lenses": []string{},
"thumbnails": Thumbnails, "countries": []string{},
"jsHash": jsHash, "thumbnails": Thumbnails,
"cssHash": cssHash, "jsHash": jsHash,
"count": count, "cssHash": cssHash,
"pos": noPos, "count": count,
"years": []int{}, "pos": noPos,
"colors": colors.All.List(), "years": []int{},
"categories": []string{}, "colors": colors.All.List(),
"categories": []string{},
} }
return result return result
@ -198,52 +209,38 @@ func (c *Config) ClientConfig() ClientConfig {
jsHash := fs.Checksum(c.HttpStaticBuildPath() + "/app.js") jsHash := fs.Checksum(c.HttpStaticBuildPath() + "/app.js")
cssHash := fs.Checksum(c.HttpStaticBuildPath() + "/app.css") cssHash := fs.Checksum(c.HttpStaticBuildPath() + "/app.css")
configFlags := c.Flags()
// Feature Flags
var flags []string
if c.Public() {
flags = append(flags, "public")
}
if c.Debug() {
flags = append(flags, "debug")
}
if c.Experimental() {
flags = append(flags, "experimental")
}
if c.ReadOnly() {
flags = append(flags, "readonly")
}
result := ClientConfig{ result := ClientConfig{
"flags": strings.Join(flags, " "), "flags": strings.Join(configFlags, " "),
"name": c.Name(), "name": c.Name(),
"url": c.Url(), "url": c.Url(),
"title": c.Title(), "title": c.Title(),
"subtitle": c.Subtitle(), "subtitle": c.Subtitle(),
"description": c.Description(), "description": c.Description(),
"author": c.Author(), "author": c.Author(),
"twitter": c.Twitter(), "twitter": c.Twitter(),
"version": c.Version(), "version": c.Version(),
"copyright": c.Copyright(), "copyright": c.Copyright(),
"debug": c.Debug(), "debug": c.Debug(),
"readonly": c.ReadOnly(), "readonly": c.ReadOnly(),
"uploadNSFW": c.UploadNSFW(), "uploadNSFW": c.UploadNSFW(),
"public": c.Public(), "public": c.Public(),
"experimental": c.Experimental(), "experimental": c.Experimental(),
"albums": albums, "disableSettings": c.DisableSettings(),
"cameras": cameras, "albums": albums,
"lenses": lenses, "cameras": cameras,
"countries": countries, "lenses": lenses,
"thumbnails": Thumbnails, "countries": countries,
"jsHash": jsHash, "thumbnails": Thumbnails,
"cssHash": cssHash, "jsHash": jsHash,
"settings": c.Settings(), "cssHash": cssHash,
"count": count, "settings": c.Settings(),
"pos": position, "count": count,
"years": years, "pos": position,
"colors": colors.All.List(), "years": years,
"categories": categories, "colors": colors.All.List(),
"categories": categories,
} }
return result return result

View file

@ -51,7 +51,7 @@ func TestConfig_TensorFlowDisabled(t *testing.T) {
ctx := CliTestContext() ctx := CliTestContext()
c := NewConfig(ctx) c := NewConfig(ctx)
version := c.TensorFlowDisabled() version := c.DisableTensorFlow()
assert.Equal(t, false, version) assert.Equal(t, false, version)
} }

View file

@ -230,11 +230,6 @@ var GlobalFlags = []cli.Flag{
Usage: "allow uploads that may contain offensive content", Usage: "allow uploads that may contain offensive content",
EnvVar: "PHOTOPRISM_UPLOAD_NSFW", EnvVar: "PHOTOPRISM_UPLOAD_NSFW",
}, },
cli.BoolFlag{
Name: "tf-disabled, t",
Usage: "don't use TensorFlow for image classification",
EnvVar: "PHOTOPRISM_TF_DISABLED",
},
cli.StringFlag{ cli.StringFlag{
Name: "geocoding-api, g", Name: "geocoding-api, g",
Usage: "geocoding api (none, osm or places)", Usage: "geocoding api (none, osm or places)",
@ -265,4 +260,14 @@ var GlobalFlags = []cli.Flag{
Value: "lanczos", Value: "lanczos",
EnvVar: "PHOTOPRISM_THUMB_FILTER", EnvVar: "PHOTOPRISM_THUMB_FILTER",
}, },
cli.BoolFlag{
Name: "disable-tf",
Usage: "don't use TensorFlow for image classification",
EnvVar: "PHOTOPRISM_DISABLE_TF",
},
cli.BoolFlag{
Name: "disable-settings",
Usage: "user can not change settings",
EnvVar: "PHOTOPRISM_DISABLE_SETTINGS",
},
} }

View file

@ -73,12 +73,13 @@ type Params struct {
DetachServer bool `yaml:"detach-server" flag:"detach-server"` DetachServer bool `yaml:"detach-server" flag:"detach-server"`
DetectNSFW bool `yaml:"detect-nsfw" flag:"detect-nsfw"` DetectNSFW bool `yaml:"detect-nsfw" flag:"detect-nsfw"`
UploadNSFW bool `yaml:"upload-nsfw" flag:"upload-nsfw"` UploadNSFW bool `yaml:"upload-nsfw" flag:"upload-nsfw"`
DisableTensorFlow bool `yaml:"tf-disabled" flag:"tf-disabled"`
GeoCodingApi string `yaml:"geocoding-api" flag:"geocoding-api"` GeoCodingApi string `yaml:"geocoding-api" flag:"geocoding-api"`
ThumbQuality int `yaml:"thumb-quality" flag:"thumb-quality"` ThumbQuality int `yaml:"thumb-quality" flag:"thumb-quality"`
ThumbSize int `yaml:"thumb-size" flag:"thumb-size"` ThumbSize int `yaml:"thumb-size" flag:"thumb-size"`
ThumbLimit int `yaml:"thumb-limit" flag:"thumb-limit"` ThumbLimit int `yaml:"thumb-limit" flag:"thumb-limit"`
ThumbFilter string `yaml:"thumb-filter" flag:"thumb-filter"` ThumbFilter string `yaml:"thumb-filter" flag:"thumb-filter"`
DisableTensorFlow bool `yaml:"disable-tf" flag:"disable-tf"`
DisableSettings bool `yaml:"disable-settings" flag:"disable-settings"`
} }
// NewParams creates a new configuration entity by using two methods: // NewParams creates a new configuration entity by using two methods:

View file

@ -9,16 +9,33 @@ import (
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
) )
// DisableSettings returns true if the user is not allowed to change settings.
func (c *Config) DisableSettings() bool {
return c.config.DisableSettings
}
type MapsSettings struct { type MapsSettings struct {
Animate int `json:"animate" yaml:"animate"` Animate int `json:"animate" yaml:"animate"`
Style string `json:"style" yaml:"style"` Style string `json:"style" yaml:"style"`
} }
type FeatureFlags struct {
Upload bool `json:"upload" yaml:"upload"`
Import bool `json:"import" yaml:"import"`
Labels bool `json:"labels" yaml:"labels"`
Places bool `json:"places" yaml:"places"`
Archive bool `json:"archive" yaml:"archive"`
Download bool `json:"download" yaml:"download"`
Edit bool `json:"edit" yaml:"edit"`
Share bool `json:"share" yaml:"share"`
}
// Settings contains Web UI settings // Settings contains Web UI settings
type Settings struct { type Settings struct {
Theme string `json:"theme" yaml:"theme"` Theme string `json:"theme" yaml:"theme"`
Language string `json:"language" yaml:"language"` Language string `json:"language" yaml:"language"`
Maps MapsSettings `json:"maps" yaml:"maps"` Maps MapsSettings `json:"maps" yaml:"maps"`
Features FeatureFlags `json:"features" yaml:"features"`
} }
// NewSettings returns a empty Settings // NewSettings returns a empty Settings
@ -30,6 +47,16 @@ func NewSettings() *Settings {
Animate: 0, Animate: 0,
Style: "streets", Style: "streets",
}, },
Features: FeatureFlags{
Upload: true,
Import: true,
Labels: true,
Places: true,
Archive: true,
Download: true,
Edit: true,
Share: true,
},
} }
} }

View file

@ -7,7 +7,7 @@ func (c *Config) TensorFlowVersion() string {
return tf.Version() return tf.Version()
} }
// TensorFlowDisabled returns true if the use of TensorFlow is disabled for image classification. // DisableTensorFlow returns true if the use of TensorFlow is disabled for image classification.
func (c *Config) TensorFlowDisabled() bool { func (c *Config) DisableTensorFlow() bool {
return c.config.DisableTensorFlow return c.config.DisableTensorFlow
} }

View file

@ -3,3 +3,12 @@ language: german
maps: maps:
animate: 0 animate: 0
style: streets style: streets
features:
upload: true
import: true
labels: true
places: true
archive: true
download: true
edit: true
share: true

View file

@ -12,7 +12,7 @@ import (
func TestNewImport(t *testing.T) { func TestNewImport(t *testing.T) {
conf := config.TestConfig() conf := config.TestConfig()
tf := classify.New(conf.ResourcesPath(), conf.TensorFlowDisabled()) tf := classify.New(conf.ResourcesPath(), conf.DisableTensorFlow())
nd := nsfw.New(conf.NSFWModelPath()) nd := nsfw.New(conf.NSFWModelPath())
ind := NewIndex(conf, tf, nd) ind := NewIndex(conf, tf, nd)
@ -29,7 +29,7 @@ func TestImport_DestinationFilename(t *testing.T) {
conf.InitializeTestData(t) conf.InitializeTestData(t)
tf := classify.New(conf.ResourcesPath(), conf.TensorFlowDisabled()) tf := classify.New(conf.ResourcesPath(), conf.DisableTensorFlow())
nd := nsfw.New(conf.NSFWModelPath()) nd := nsfw.New(conf.NSFWModelPath())
ind := NewIndex(conf, tf, nd) ind := NewIndex(conf, tf, nd)
@ -58,7 +58,7 @@ func TestImport_Start(t *testing.T) {
conf.InitializeTestData(t) conf.InitializeTestData(t)
tf := classify.New(conf.ResourcesPath(), conf.TensorFlowDisabled()) tf := classify.New(conf.ResourcesPath(), conf.DisableTensorFlow())
nd := nsfw.New(conf.NSFWModelPath()) nd := nsfw.New(conf.NSFWModelPath())
ind := NewIndex(conf, tf, nd) ind := NewIndex(conf, tf, nd)

View file

@ -134,7 +134,7 @@ func (ind *Index) MediaFile(m *MediaFile, o IndexOptions, originalName string) (
if file.FilePrimary { if file.FilePrimary {
primaryFile = file primaryFile = file
if !ind.conf.TensorFlowDisabled() && (fileChanged || o.UpdateKeywords || o.UpdateLabels || o.UpdateTitle) { if !ind.conf.DisableTensorFlow() && (fileChanged || o.UpdateKeywords || o.UpdateLabels || o.UpdateTitle) {
// Image classification via TensorFlow // Image classification via TensorFlow
labels = ind.classifyImage(m) labels = ind.classifyImage(m)
photo.PhotoNSFW = ind.isNSFW(m) photo.PhotoNSFW = ind.isNSFW(m)

View file

@ -17,7 +17,7 @@ func TestIndex_Start(t *testing.T) {
conf.InitializeTestData(t) conf.InitializeTestData(t)
tf := classify.New(conf.ResourcesPath(), conf.TensorFlowDisabled()) tf := classify.New(conf.ResourcesPath(), conf.DisableTensorFlow())
nd := nsfw.New(conf.NSFWModelPath()) nd := nsfw.New(conf.NSFWModelPath())
ind := NewIndex(conf, tf, nd) ind := NewIndex(conf, tf, nd)

View file

@ -27,7 +27,7 @@ func TestResample_Start(t *testing.T) {
conf.InitializeTestData(t) conf.InitializeTestData(t)
tf := classify.New(conf.ResourcesPath(), conf.TensorFlowDisabled()) tf := classify.New(conf.ResourcesPath(), conf.DisableTensorFlow())
nd := nsfw.New(conf.NSFWModelPath()) nd := nsfw.New(conf.NSFWModelPath())
ind := NewIndex(conf, tf, nd) ind := NewIndex(conf, tf, nd)

View file

@ -9,7 +9,7 @@ import (
var onceClassify sync.Once var onceClassify sync.Once
func initClassify() { func initClassify() {
services.Classify = classify.New(Config().ResourcesPath(), Config().TensorFlowDisabled()) services.Classify = classify.New(Config().ResourcesPath(), Config().DisableTensorFlow())
} }
func Classify() *classify.TensorFlow { func Classify() *classify.TensorFlow {