feat: improved visibility of dataset and improved speed for expand import zip file
This commit is contained in:
parent
00369640a8
commit
143ad3b02b
11
go.mod
11
go.mod
@ -8,15 +8,20 @@ require (
|
|||||||
github.com/galeone/tfgo v0.0.0-20230715013254-16113111dc99
|
github.com/galeone/tfgo v0.0.0-20230715013254-16113111dc99
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/lib/pq v1.10.9
|
github.com/lib/pq v1.10.9
|
||||||
golang.org/x/crypto v0.18.0
|
golang.org/x/crypto v0.19.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/BurntSushi/toml v1.3.2 // indirect
|
github.com/BurntSushi/toml v1.3.2 // indirect
|
||||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||||
github.com/charmbracelet/lipgloss v0.9.1 // indirect
|
github.com/charmbracelet/lipgloss v0.9.1 // indirect
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||||
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
||||||
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
|
github.com/go-playground/validator/v10 v10.19.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.2 // indirect
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||||
@ -24,6 +29,8 @@ require (
|
|||||||
github.com/muesli/termenv v0.15.2 // indirect
|
github.com/muesli/termenv v0.15.2 // indirect
|
||||||
github.com/rivo/uniseg v0.4.6 // indirect
|
github.com/rivo/uniseg v0.4.6 // indirect
|
||||||
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect
|
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect
|
||||||
golang.org/x/sys v0.16.0 // indirect
|
golang.org/x/net v0.21.0 // indirect
|
||||||
|
golang.org/x/sys v0.17.0 // indirect
|
||||||
|
golang.org/x/text v0.14.0 // indirect
|
||||||
google.golang.org/protobuf v1.32.0 // indirect
|
google.golang.org/protobuf v1.32.0 // indirect
|
||||||
)
|
)
|
||||||
|
18
go.sum
18
go.sum
@ -10,6 +10,8 @@ github.com/charmbracelet/log v0.2.5 h1:1yVvyKCKVV639RR4LIq1iy1Cs1AKxuNO+Hx2LJtk7
|
|||||||
github.com/charmbracelet/log v0.2.5/go.mod h1:nQGK8tvc4pS9cvVEH/pWJiZ50eUq1aoXUOjGpXvdD0k=
|
github.com/charmbracelet/log v0.2.5/go.mod h1:nQGK8tvc4pS9cvVEH/pWJiZ50eUq1aoXUOjGpXvdD0k=
|
||||||
github.com/charmbracelet/log v0.3.1 h1:TjuY4OBNbxmHWSwO3tosgqs5I3biyY8sQPny/eCMTYw=
|
github.com/charmbracelet/log v0.3.1 h1:TjuY4OBNbxmHWSwO3tosgqs5I3biyY8sQPny/eCMTYw=
|
||||||
github.com/charmbracelet/log v0.3.1/go.mod h1:OR4E1hutLsax3ZKpXbgUqPtTjQfrh1pG3zwHGWuuq8g=
|
github.com/charmbracelet/log v0.3.1/go.mod h1:OR4E1hutLsax3ZKpXbgUqPtTjQfrh1pG3zwHGWuuq8g=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||||
github.com/galeone/tensorflow/tensorflow/go v0.0.0-20221023090153-6b7fa0680c3e h1:9+2AEFZymTi25FIIcDwuzcOPH04z9+fV6XeLiGORPDI=
|
github.com/galeone/tensorflow/tensorflow/go v0.0.0-20221023090153-6b7fa0680c3e h1:9+2AEFZymTi25FIIcDwuzcOPH04z9+fV6XeLiGORPDI=
|
||||||
github.com/galeone/tensorflow/tensorflow/go v0.0.0-20221023090153-6b7fa0680c3e/go.mod h1:TelZuq26kz2jysARBwOrTv16629hyUsHmIoj54QqyFo=
|
github.com/galeone/tensorflow/tensorflow/go v0.0.0-20221023090153-6b7fa0680c3e/go.mod h1:TelZuq26kz2jysARBwOrTv16629hyUsHmIoj54QqyFo=
|
||||||
github.com/galeone/tensorflow/tensorflow/go v0.0.0-20240119075110-6ad3cf65adfe h1:7yELf1NFEwECpXMGowkoftcInMlVtLTCdwWLmxKgzNM=
|
github.com/galeone/tensorflow/tensorflow/go v0.0.0-20240119075110-6ad3cf65adfe h1:7yELf1NFEwECpXMGowkoftcInMlVtLTCdwWLmxKgzNM=
|
||||||
@ -18,6 +20,12 @@ github.com/galeone/tfgo v0.0.0-20230715013254-16113111dc99 h1:8Bt1P/zy1gb37L4n8C
|
|||||||
github.com/galeone/tfgo v0.0.0-20230715013254-16113111dc99/go.mod h1:3YgYBeIX42t83uP27Bd4bSMxTnQhSbxl0pYSkCDB1tc=
|
github.com/galeone/tfgo v0.0.0-20230715013254-16113111dc99/go.mod h1:3YgYBeIX42t83uP27Bd4bSMxTnQhSbxl0pYSkCDB1tc=
|
||||||
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
|
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
|
||||||
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||||
|
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||||
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
|
github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4=
|
||||||
|
github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
@ -26,6 +34,8 @@ github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
|||||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||||
|
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||||
@ -52,10 +62,14 @@ golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
|
|||||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||||
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||||
|
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
|
||||||
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
|
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
|
||||||
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
|
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
|
||||||
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA=
|
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA=
|
||||||
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
|
golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
|
||||||
|
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
||||||
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
||||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@ -63,6 +77,10 @@ golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
|||||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
|
||||||
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||||
|
@ -309,57 +309,68 @@ func processZipFileExpand(c *Context, model *BaseModel) {
|
|||||||
ids[name] = id
|
ids[name] = id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
back_channel := make(chan int, c.Handle.Config.NumberOfWorkers)
|
||||||
|
|
||||||
|
file_chans := make([]chan *zip.File, c.Handle.Config.NumberOfWorkers)
|
||||||
|
|
||||||
|
for i := 0; i < c.Handle.Config.NumberOfWorkers; i++ {
|
||||||
|
file_chans[i] = make(chan *zip.File, 2)
|
||||||
|
go fileProcessor(c, model, reader, ids, base_path, i, file_chans[i], back_channel)
|
||||||
|
}
|
||||||
|
|
||||||
|
clean_up_channels := func() {
|
||||||
|
for i := 0; i < c.Handle.Config.NumberOfWorkers; i++ {
|
||||||
|
close(file_chans[i])
|
||||||
|
}
|
||||||
|
for i := 0; i < c.Handle.Config.NumberOfWorkers - 1; i++ {
|
||||||
|
_ = <- back_channel
|
||||||
|
}
|
||||||
|
close(back_channel)
|
||||||
|
}
|
||||||
|
|
||||||
|
first_round := true
|
||||||
|
|
||||||
|
channel_to_send := 0
|
||||||
|
|
||||||
|
// Parelalize this
|
||||||
|
|
||||||
for _, file := range reader.Reader.File {
|
for _, file := range reader.Reader.File {
|
||||||
|
// Skip if dir
|
||||||
if file.Name[len(file.Name)-1] == '/' {
|
if file.Name[len(file.Name)-1] == '/' {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := reader.Open(file.Name)
|
file_chans[channel_to_send] <- file
|
||||||
if err != nil {
|
|
||||||
failed(fmt.Sprintf("Could not open file in zip %s\n", file.Name))
|
|
||||||
return
|
if first_round {
|
||||||
|
channel_to_send += 1
|
||||||
|
if c.Handle.Config.NumberOfWorkers == channel_to_send {
|
||||||
|
first_round = false
|
||||||
}
|
}
|
||||||
defer data.Close()
|
}
|
||||||
file_data, err := io.ReadAll(data)
|
|
||||||
if err != nil {
|
// Can not do else if because need to handle the case where the value changes in
|
||||||
failed(fmt.Sprintf("Could not read file file in zip %s\n", file.Name))
|
// previous if
|
||||||
|
if !first_round {
|
||||||
|
new_id, ok := <- back_channel
|
||||||
|
if !ok {
|
||||||
|
c.Logger.Fatal("Something is very wrong please check as this line should be unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
if new_id < 0 {
|
||||||
|
c.Logger.Error("Worker failed", "worker id", -(new_id + 1))
|
||||||
|
clean_up_channels()
|
||||||
|
failed("One of the workers failed due to db error")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO check if the file is a valid photo that matched the defined photo on the database
|
channel_to_send = new_id
|
||||||
|
|
||||||
parts := strings.Split(file.Name, "/")
|
|
||||||
|
|
||||||
mode := model_classes.DATA_POINT_MODE_TRAINING
|
|
||||||
if parts[0] == "testing" {
|
|
||||||
mode = model_classes.DATA_POINT_MODE_TESTING
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data_point_id, err := model_classes.AddDataPoint(c.Db, ids[parts[1]], "id://", mode)
|
|
||||||
if err != nil {
|
|
||||||
failed(fmt.Sprintf("Failed to add data point for %s\n", model.Id))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
file_path := path.Join(base_path, data_point_id+"."+model.Format)
|
clean_up_channels()
|
||||||
f, err := os.Create(file_path)
|
|
||||||
if err != nil {
|
|
||||||
failed(fmt.Sprintf("Could not create file %s\n", file_path))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
f.Write(file_data)
|
|
||||||
|
|
||||||
if !testImgForModel(c, model, file_path) {
|
|
||||||
c.Logger.Errorf("Image did not have valid format for model %s (in zip: %s)!", file_path, file.Name)
|
|
||||||
c.Logger.Warn("Not failling updating data point to status -1")
|
|
||||||
message := "Image did not have valid format for the model"
|
|
||||||
if err = model_classes.UpdateDataPointStatus(c.Db, data_point_id, -1, &message); err != nil {
|
|
||||||
failed(fmt.Sprintf("Failed to update data point status"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Logger.Info("Added data to model", "id", model.Id)
|
c.Logger.Info("Added data to model", "id", model.Id)
|
||||||
ModelUpdateStatus(c, model.Id, READY)
|
ModelUpdateStatus(c, model.Id, READY)
|
||||||
|
@ -5,6 +5,31 @@ import (
|
|||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Auth level set when path is definied as 1
|
||||||
|
func handleStats(c *Context) *Error {
|
||||||
|
var b struct {
|
||||||
|
Id string `json:"id" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if _err := c.ToJSON(&b); _err != nil {
|
||||||
|
return _err;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Row struct {
|
||||||
|
Name string `db:"mc.name" json:"name"`
|
||||||
|
Training string `db:"count(mdp.id) filter (where mdp.model_mode=1)" json:"training"`
|
||||||
|
Testing string `db:"count(mdp.id) filter (where mdp.model_mode=2)" json:"testing"`
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := GetDbMultitple[Row](c, "model_data_point as mdp inner join model_classes as mc on mc.id=mdp.class_id where mc.model_id=$1 group by mc.name order by mc.name asc;", b.Id)
|
||||||
|
if err != nil {
|
||||||
|
return c.Error500(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.ShowMessage = false
|
||||||
|
return c.SendJSON(rows)
|
||||||
|
}
|
||||||
|
|
||||||
func handleList(handle *Handle) {
|
func handleList(handle *Handle) {
|
||||||
handle.Get("/models", func(c *Context) *Error {
|
handle.Get("/models", func(c *Context) *Error {
|
||||||
if !c.CheckAuthLevel(1) {
|
if !c.CheckAuthLevel(1) {
|
||||||
@ -21,6 +46,9 @@ func handleList(handle *Handle) {
|
|||||||
return c.Error500(nil)
|
return c.Error500(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.ShowMessage = true
|
||||||
return c.SendJSON(got)
|
return c.SendJSON(got)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
handle.PostAuth("/models/class/stats", 1, handleStats)
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
dbtypes "git.andr3h3nriqu3s.com/andr3/fyp/logic/db_types"
|
dbtypes "git.andr3h3nriqu3s.com/andr3/fyp/logic/db_types"
|
||||||
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models/utils"
|
. "git.andr3h3nriqu3s.com/andr3/fyp/logic/models/utils"
|
||||||
"github.com/charmbracelet/log"
|
"github.com/charmbracelet/log"
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
"github.com/goccy/go-json"
|
"github.com/goccy/go-json"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -43,6 +44,7 @@ type Handle struct {
|
|||||||
posts []HandleFunc
|
posts []HandleFunc
|
||||||
deletes []HandleFunc
|
deletes []HandleFunc
|
||||||
Config Config
|
Config Config
|
||||||
|
validate *validator.Validate
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodeBody(r *http.Request) (string, *Error) {
|
func decodeBody(r *http.Request) (string, *Error) {
|
||||||
@ -79,6 +81,17 @@ func (x *Handle) Post(path string, fn func(c *Context) *Error) {
|
|||||||
x.posts = append(x.posts, HandleFunc{path, fn})
|
x.posts = append(x.posts, HandleFunc{path, fn})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (x *Handle) PostAuth(path string, authLevel int, fn func(c *Context) *Error) {
|
||||||
|
inner_fn := func(c *Context) *Error {
|
||||||
|
if !c.CheckAuthLevel(authLevel) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fn(c)
|
||||||
|
}
|
||||||
|
x.posts = append(x.posts, HandleFunc{path, inner_fn})
|
||||||
|
}
|
||||||
|
|
||||||
func (x *Handle) Delete(path string, fn func(c *Context) *Error) {
|
func (x *Handle) Delete(path string, fn func(c *Context) *Error) {
|
||||||
x.deletes = append(x.deletes, HandleFunc{path, fn})
|
x.deletes = append(x.deletes, HandleFunc{path, fn})
|
||||||
}
|
}
|
||||||
@ -195,6 +208,12 @@ func (c Context) ToJSON(dat any) *Error {
|
|||||||
return c.Error500(err)
|
return c.Error500(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = c.Handle.validate.Struct(dat)
|
||||||
|
if err != nil {
|
||||||
|
c.Logger.Error("Failed invalid json passed", "dat", dat, "err", err)
|
||||||
|
return c.JsonBadRequest("Bad Request! Invalid body passed!")
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,7 +495,8 @@ func NewHandler(db *sql.DB, config Config) *Handle {
|
|||||||
var gets []HandleFunc
|
var gets []HandleFunc
|
||||||
var posts []HandleFunc
|
var posts []HandleFunc
|
||||||
var deletes []HandleFunc
|
var deletes []HandleFunc
|
||||||
x := &Handle{db, gets, posts, deletes, config}
|
validate := validator.New()
|
||||||
|
x := &Handle{db, gets, posts, deletes, config, validate}
|
||||||
|
|
||||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
Binary file not shown.
@ -3,7 +3,8 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite dev",
|
"dev:raw": "vite dev",
|
||||||
|
"dev": "vite dev --port 5001 --host",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||||
@ -30,5 +31,9 @@
|
|||||||
"typescript": "^5.0.0",
|
"typescript": "^5.0.0",
|
||||||
"vite": "^5.0.3"
|
"vite": "^5.0.3"
|
||||||
},
|
},
|
||||||
"type": "module"
|
"type": "module",
|
||||||
|
"dependencies": {
|
||||||
|
"chart.js": "^4.4.2",
|
||||||
|
"svelte-chartjs": "^3.1.5"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
let {active} = $props<{active?: string}>();
|
let {active, nobox} = $props<{active?: string, nobox?: boolean}>();
|
||||||
|
|
||||||
function setActive(name: string) {
|
function setActive(name: string) {
|
||||||
return () => active = name;
|
return () => active = name;
|
||||||
@ -10,7 +10,7 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="tabs">
|
<div class="tabs" class:nobox>
|
||||||
<div class="tab-buttons">
|
<div class="tab-buttons">
|
||||||
<slot name="buttons" {setActive} {isActive} />
|
<slot name="buttons" {setActive} {isActive} />
|
||||||
</div>
|
</div>
|
||||||
@ -58,5 +58,16 @@
|
|||||||
display: block;
|
display: block;
|
||||||
box-shadow: 0 2px 2px 1px #66666655;
|
box-shadow: 0 2px 2px 1px #66666655;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.nobox {
|
||||||
|
box-shadow: none;
|
||||||
|
overflow: visible;
|
||||||
|
|
||||||
|
|
||||||
|
:global(.content.selected) {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -25,31 +25,33 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from "svelte";
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
import BaseModelInfo from "./BaseModelInfo.svelte";
|
import BaseModelInfo from './BaseModelInfo.svelte';
|
||||||
import DeleteModel from "./DeleteModel.svelte";
|
import DeleteModel from './DeleteModel.svelte';
|
||||||
import { goto } from "$app/navigation";
|
import { goto } from '$app/navigation';
|
||||||
import { get, rdelete } from "src/lib/requests.svelte";
|
import { get, rdelete } from 'src/lib/requests.svelte';
|
||||||
import MessageSimple from "$lib/MessageSimple.svelte"
|
import MessageSimple from '$lib/MessageSimple.svelte';
|
||||||
|
|
||||||
import ModelData from "./ModelData.svelte";
|
import ModelData from './ModelData.svelte';
|
||||||
import DeleteZip from "./DeleteZip.svelte";
|
import DeleteZip from './DeleteZip.svelte';
|
||||||
|
|
||||||
import 'src/styles/forms.css'
|
import ModelDataPage from './ModelDataPage.svelte';
|
||||||
import RunModel from "./RunModel.svelte";
|
|
||||||
|
import 'src/styles/forms.css';
|
||||||
|
import RunModel from './RunModel.svelte';
|
||||||
|
import Tabs from 'src/lib/Tabs.svelte';
|
||||||
let model: Promise<Model> = $state(new Promise(() => {}));
|
let model: Promise<Model> = $state(new Promise(() => {}));
|
||||||
|
let _model: Model | undefined = $state(undefined);
|
||||||
let definitions: Promise<Definitions[]> = $state(new Promise(() => {}));
|
let definitions: Promise<Definitions[]> = $state(new Promise(() => {}));
|
||||||
|
|
||||||
let id: string | undefined = $state()
|
let id: string | undefined = $state();
|
||||||
|
|
||||||
async function getModel() {
|
async function getModel() {
|
||||||
try {
|
try {
|
||||||
let temp_model: Model = await get(`models/edit?id=${id}`);
|
let temp_model: Model = await get(`models/edit?id=${id}`);
|
||||||
|
|
||||||
console.log(temp_model)
|
if ([3, 6].includes(temp_model.status)) {
|
||||||
|
|
||||||
if (temp_model.status == 3) {
|
|
||||||
setTimeout(getModel, 2000);
|
setTimeout(getModel, 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,11 +62,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
model = Promise.resolve(temp_model);
|
model = Promise.resolve(temp_model);
|
||||||
|
_model = temp_model;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof Response) {
|
if (e instanceof Response) {
|
||||||
model = Promise.reject(await e.json())
|
model = Promise.reject(await e.json());
|
||||||
} else {
|
} else {
|
||||||
model = Promise.reject("Could not load model");
|
model = Promise.reject('Could not load model');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,7 +76,7 @@
|
|||||||
let url = new URLSearchParams(window.location.search);
|
let url = new URLSearchParams(window.location.search);
|
||||||
const _id = url.get('id');
|
const _id = url.get('id');
|
||||||
if (!_id) {
|
if (!_id) {
|
||||||
goto('/models')
|
goto('/models');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,21 +87,21 @@
|
|||||||
let resetMessages: MessageSimple;
|
let resetMessages: MessageSimple;
|
||||||
|
|
||||||
async function resetModel() {
|
async function resetModel() {
|
||||||
resetMessages.display("");
|
resetMessages.display('');
|
||||||
|
|
||||||
let _model = await model;
|
let _model = await model;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await rdelete('models/train/reset', {
|
await rdelete('models/train/reset', {
|
||||||
"id": _model.id
|
id: _model.id
|
||||||
});
|
});
|
||||||
|
|
||||||
getModel();
|
getModel();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof Response) {
|
if (e instanceof Response) {
|
||||||
resetMessages.display(await e.json())
|
resetMessages.display(await e.json());
|
||||||
} else {
|
} else {
|
||||||
resetMessages.display("Could not reset model!")
|
resetMessages.display('Could not reset model!');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,6 +130,29 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
|
<Tabs active="model" let:isActive nobox>
|
||||||
|
<div slot="buttons" let:setActive let:isActive>
|
||||||
|
<button
|
||||||
|
class="tab"
|
||||||
|
on:click|preventDefault={setActive('model')}
|
||||||
|
class:selected={isActive('model')}
|
||||||
|
>
|
||||||
|
Model
|
||||||
|
</button>
|
||||||
|
{#if _model && [2, 3, 4, 5, 6, 7].includes(_model.status)}
|
||||||
|
<button
|
||||||
|
class="tab"
|
||||||
|
on:click|preventDefault={setActive('model-data')}
|
||||||
|
class:selected={isActive('model-data')}
|
||||||
|
>
|
||||||
|
Model Data
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{#if _model}
|
||||||
|
<ModelDataPage model={_model} on:reload={getModel} active={isActive('model-data')} />
|
||||||
|
{/if}
|
||||||
|
<div class="content" class:selected={isActive('model')}>
|
||||||
{#await model}
|
{#await model}
|
||||||
Loading
|
Loading
|
||||||
{:then m}
|
{:then m}
|
||||||
@ -285,9 +311,7 @@
|
|||||||
<BaseModelInfo model={m} />
|
<BaseModelInfo model={m} />
|
||||||
<RunModel model={m} />
|
<RunModel model={m} />
|
||||||
{#if m.status == 6}
|
{#if m.status == 6}
|
||||||
<div class="card">
|
<div class="card">Model expading... Processing ZIP file</div>
|
||||||
Model expading... Processing ZIP file
|
|
||||||
</div>
|
|
||||||
{/if}
|
{/if}
|
||||||
{#if m.status == -6}
|
{#if m.status == -6}
|
||||||
<DeleteZip model={m} on:reload={getModel} expand />
|
<DeleteZip model={m} on:reload={getModel} expand />
|
||||||
@ -295,18 +319,19 @@
|
|||||||
{#if m.status == -7}
|
{#if m.status == -7}
|
||||||
<form>
|
<form>
|
||||||
<!-- TODO add more info about the failure -->
|
<!-- TODO add more info about the failure -->
|
||||||
Failed to train the model!
|
Failed to train the model! Try to retrain
|
||||||
Try to retrain
|
|
||||||
</form>
|
</form>
|
||||||
{/if}
|
{/if}
|
||||||
{#if m.model_type == 2}
|
{#if m.model_type == 2}
|
||||||
<ModelData model={m} on:reload={getModel} />
|
<ModelData simple model={m} on:reload={getModel} />
|
||||||
{/if}
|
{/if}
|
||||||
<DeleteModel model={m} />
|
<DeleteModel model={m} />
|
||||||
{:else}
|
{:else}
|
||||||
<h1>Unknown Status of the model.</h1>
|
<h1>Unknown Status of the model.</h1>
|
||||||
{/if}
|
{/if}
|
||||||
{/await}
|
{/await}
|
||||||
|
</div>
|
||||||
|
</Tabs>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@ -3,19 +3,20 @@
|
|||||||
name: string;
|
name: string;
|
||||||
id: string;
|
id: string;
|
||||||
status: number;
|
status: number;
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
<script lang="ts">
|
|
||||||
import FileUpload from "src/lib/FileUpload.svelte";
|
|
||||||
import Tabs from "src/lib/Tabs.svelte";
|
|
||||||
import type { Model } from "./+page.svelte";
|
|
||||||
import { postFormData, get } from "src/lib/requests.svelte";
|
|
||||||
import MessageSimple from "src/lib/MessageSimple.svelte";
|
|
||||||
import { createEventDispatcher } from "svelte";
|
|
||||||
import ModelTable from "./ModelTable.svelte";
|
|
||||||
import TrainModel from "./TrainModel.svelte";
|
|
||||||
|
|
||||||
let { model } = $props<{model: Model}>();
|
<script lang="ts">
|
||||||
|
import FileUpload from 'src/lib/FileUpload.svelte';
|
||||||
|
import Tabs from 'src/lib/Tabs.svelte';
|
||||||
|
import type { Model } from './+page.svelte';
|
||||||
|
import { postFormData, get } from 'src/lib/requests.svelte';
|
||||||
|
import MessageSimple from 'src/lib/MessageSimple.svelte';
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
import ModelTable from './ModelTable.svelte';
|
||||||
|
import TrainModel from './TrainModel.svelte';
|
||||||
|
|
||||||
|
let { model, simple } = $props<{ model: Model; simple?: boolean }>();
|
||||||
|
|
||||||
let classes: Class[] = $state([]);
|
let classes: Class[] = $state([]);
|
||||||
let has_data: boolean = $state(false);
|
let has_data: boolean = $state(false);
|
||||||
@ -23,10 +24,10 @@
|
|||||||
let file: File | undefined = $state();
|
let file: File | undefined = $state();
|
||||||
|
|
||||||
const dispatch = createEventDispatcher<{
|
const dispatch = createEventDispatcher<{
|
||||||
reload: void
|
reload: void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let uploading: Promise<void> = $state(Promise.resolve())
|
let uploading: Promise<void> = $state(Promise.resolve());
|
||||||
let numberOfInvalidImages = $state(0);
|
let numberOfInvalidImages = $state(0);
|
||||||
|
|
||||||
let uploadImage: MessageSimple;
|
let uploadImage: MessageSimple;
|
||||||
@ -62,47 +63,48 @@
|
|||||||
if (!model) return;
|
if (!model) return;
|
||||||
try {
|
try {
|
||||||
let data = await get(`models/edit/classes?id=${model.id}`);
|
let data = await get(`models/edit/classes?id=${model.id}`);
|
||||||
classes = data.classes
|
classes = data.classes;
|
||||||
numberOfInvalidImages = data.number_of_invalid_images;
|
numberOfInvalidImages = data.number_of_invalid_images;
|
||||||
has_data = data.has_data;
|
has_data = data.has_data;
|
||||||
} catch {
|
} catch {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="card">
|
{#if !simple}
|
||||||
<h3>
|
<div class="card">
|
||||||
Training data
|
<h3>Training data</h3>
|
||||||
</h3>
|
|
||||||
{#if classes.length == 0}
|
{#if classes.length == 0}
|
||||||
<p>
|
<p>You need to upload data so the model can train.</p>
|
||||||
You need to upload data so the model can train.
|
|
||||||
</p>
|
|
||||||
<Tabs active="upload" let:isActive>
|
<Tabs active="upload" let:isActive>
|
||||||
<div slot="buttons" let:setActive let:isActive>
|
<div slot="buttons" let:setActive let:isActive>
|
||||||
<button class="tab" class:selected={isActive("upload")} on:click={setActive("upload")}>
|
<button class="tab" class:selected={isActive('upload')} on:click={setActive('upload')}>
|
||||||
Upload
|
Upload
|
||||||
</button>
|
</button>
|
||||||
<button class="tab" class:selected={isActive("create-class")} on:click={setActive("create-class")}>
|
<button
|
||||||
|
class="tab"
|
||||||
|
class:selected={isActive('create-class')}
|
||||||
|
on:click={setActive('create-class')}
|
||||||
|
>
|
||||||
Create Class
|
Create Class
|
||||||
</button>
|
</button>
|
||||||
<button class="tab" class:selected={isActive("api")} on:click={setActive("api")}>
|
<button class="tab" class:selected={isActive('api')} on:click={setActive('api')}>
|
||||||
Api
|
Api
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="content" class:selected={isActive("upload")}>
|
<div class="content" class:selected={isActive('upload')}>
|
||||||
<form on:submit|preventDefault={uploadZip}>
|
<form on:submit|preventDefault={uploadZip}>
|
||||||
<fieldset class="file-upload" >
|
<fieldset class="file-upload">
|
||||||
<label for="file">Data file</label>
|
<label for="file">Data file</label>
|
||||||
<div class="form-msg">
|
<div class="form-msg">
|
||||||
Please provide a file that has the training and testing data<br/>
|
Please provide a file that has the training and testing data<br />
|
||||||
The file must have 2 folders one with testing images and one with training images. <br/>
|
The file must have 2 folders one with testing images and one with training images.
|
||||||
Each of the folders will contain the classes of the model. The folders must be the same in testing and training.
|
<br />
|
||||||
The class folders must have the images for the classes.
|
Each of the folders will contain the classes of the model. The folders must be the same
|
||||||
<pre>
|
in testing and training. The class folders must have the images for the classes.
|
||||||
training\
|
<pre>
|
||||||
|
training\
|
||||||
class1\
|
class1\
|
||||||
img1.png
|
img1.png
|
||||||
img2.png
|
img2.png
|
||||||
@ -114,7 +116,7 @@
|
|||||||
img2.png
|
img2.png
|
||||||
...
|
...
|
||||||
...
|
...
|
||||||
testing\
|
testing\
|
||||||
class1\
|
class1\
|
||||||
img1.png
|
img1.png
|
||||||
img2.png
|
img2.png
|
||||||
@ -128,70 +130,66 @@
|
|||||||
...
|
...
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
<FileUpload replace_slot bind:file={file} accept="application/zip" notExpand >
|
<FileUpload replace_slot bind:file accept="application/zip" notExpand>
|
||||||
<img src="/imgs/upload-icon.png" alt="" />
|
<img src="/imgs/upload-icon.png" alt="" />
|
||||||
<span>
|
<span> Upload Zip File </span>
|
||||||
Upload Zip File
|
|
||||||
</span>
|
|
||||||
<div slot="replaced" style="display: inline;">
|
<div slot="replaced" style="display: inline;">
|
||||||
<img src="/imgs/upload-icon.png" alt="" />
|
<img src="/imgs/upload-icon.png" alt="" />
|
||||||
<span>
|
<span> File selected </span>
|
||||||
File selected
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</FileUpload>
|
</FileUpload>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<MessageSimple bind:this={uploadImage} />
|
<MessageSimple bind:this={uploadImage} />
|
||||||
{#if file}
|
{#if file}
|
||||||
{#await uploading}
|
{#await uploading}
|
||||||
<button disabled>
|
<button disabled> Uploading </button>
|
||||||
Uploading
|
|
||||||
</button>
|
|
||||||
{:then}
|
{:then}
|
||||||
<button>
|
<button> Add </button>
|
||||||
Add
|
|
||||||
</button>
|
|
||||||
{/await}
|
{/await}
|
||||||
{/if}
|
{/if}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="content" class:selected={isActive("create-class")}>
|
<div class="content" class:selected={isActive('create-class')}>
|
||||||
<ModelTable {classes} {model} on:reload={() => dispatch('reload')} />
|
<ModelTable {classes} {model} on:reload={() => dispatch('reload')} />
|
||||||
</div>
|
</div>
|
||||||
<div class="content" class:selected={isActive("api")}>
|
<div class="content" class:selected={isActive('api')}>TODO</div>
|
||||||
TODO
|
|
||||||
</div>
|
|
||||||
</Tabs>
|
</Tabs>
|
||||||
<div class="tabs">
|
<div class="tabs"></div>
|
||||||
</div>
|
|
||||||
{:else}
|
{:else}
|
||||||
<p>
|
<p>You need to upload data so the model can train.</p>
|
||||||
You need to upload data so the model can train.
|
|
||||||
</p>
|
|
||||||
{#if numberOfInvalidImages > 0}
|
{#if numberOfInvalidImages > 0}
|
||||||
<p class="danger">
|
<p class="danger">
|
||||||
There are images {numberOfInvalidImages} that were loaded that do not have the correct format. These images will be delete when the model trains.
|
There are images {numberOfInvalidImages} that were loaded that do not have the correct format.
|
||||||
|
These images will be delete when the model trains.
|
||||||
</p>
|
</p>
|
||||||
{/if}
|
{/if}
|
||||||
<Tabs active="create-class" let:isActive>
|
<Tabs active="create-class" let:isActive>
|
||||||
<div slot="buttons" let:setActive let:isActive>
|
<div slot="buttons" let:setActive let:isActive>
|
||||||
<button class="tab" class:selected={isActive("create-class")} on:click={setActive("create-class")}>
|
<button
|
||||||
|
class="tab"
|
||||||
|
class:selected={isActive('create-class')}
|
||||||
|
on:click={setActive('create-class')}
|
||||||
|
>
|
||||||
Create Class
|
Create Class
|
||||||
</button>
|
</button>
|
||||||
<button class="tab" class:selected={isActive("api")} on:click={setActive("api")}>
|
<button class="tab" class:selected={isActive('api')} on:click={setActive('api')}>
|
||||||
Api
|
Api
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="content" class:selected={isActive("create-class")}>
|
<div class="content" class:selected={isActive('create-class')}>
|
||||||
<ModelTable {classes} {model} on:reload={() => dispatch('reload')} />
|
<ModelTable {classes} {model} on:reload={() => dispatch('reload')} />
|
||||||
</div>
|
</div>
|
||||||
<div class="content" class:selected={isActive("api")}>
|
<div class="content" class:selected={isActive('api')}>TODO</div>
|
||||||
TODO
|
|
||||||
</div>
|
|
||||||
</Tabs>
|
</Tabs>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if classes.some((item) => item.status == 1) && ![-6, 6].includes(model.status)}
|
{#if classes.some((item) => item.status == 1) && ![-6, 6].includes(model.status)}
|
||||||
<TrainModel number_of_invalid_images={numberOfInvalidImages} {model} {has_data} on:reload={() => dispatch('reload')} />
|
<TrainModel
|
||||||
|
number_of_invalid_images={numberOfInvalidImages}
|
||||||
|
{model}
|
||||||
|
{has_data}
|
||||||
|
on:reload={() => dispatch('reload')}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
48
webpage/src/routes/models/edit/ModelDataPage.svelte
Normal file
48
webpage/src/routes/models/edit/ModelDataPage.svelte
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher } from "svelte";
|
||||||
|
import type { Model } from "./+page.svelte";
|
||||||
|
import ModelData from "./ModelData.svelte";
|
||||||
|
import { post } from "src/lib/requests.svelte";
|
||||||
|
import ModelDataPageStatsGraph from "./ModelDataPageStatsGraph.svelte";
|
||||||
|
import type { ModelStats } from "./types";
|
||||||
|
import DeleteZip from "./DeleteZip.svelte";
|
||||||
|
|
||||||
|
let { model, active } = $props<{model: Model, active?: boolean}>()
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher<{ reload: void }>();
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
if (active)
|
||||||
|
getData();
|
||||||
|
});
|
||||||
|
|
||||||
|
let stats: ModelStats | undefined = $state();
|
||||||
|
|
||||||
|
async function getData() {
|
||||||
|
if (!model) return;
|
||||||
|
try {
|
||||||
|
stats = await post(`models/class/stats`, { id: model.id });
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="content" class:selected={active}>
|
||||||
|
|
||||||
|
{#if stats}
|
||||||
|
<ModelDataPageStatsGraph data={stats} />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
|
||||||
|
{#if [-6, -2].includes(model.status)}
|
||||||
|
<DeleteZip model={model} on:reload={() => dispatch('reload')} expand />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<ModelData model={model} on:reload={() => {
|
||||||
|
getData();
|
||||||
|
dispatch('reload');
|
||||||
|
}} />
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,89 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import {
|
||||||
|
Chart,
|
||||||
|
Title,
|
||||||
|
Tooltip,
|
||||||
|
Legend,
|
||||||
|
BarElement,
|
||||||
|
CategoryScale,
|
||||||
|
LinearScale,
|
||||||
|
BarController,
|
||||||
|
Colors
|
||||||
|
} from 'chart.js';
|
||||||
|
import type { ModelStats } from './types';
|
||||||
|
|
||||||
|
Chart.register(
|
||||||
|
Title,
|
||||||
|
Tooltip,
|
||||||
|
Legend,
|
||||||
|
BarElement,
|
||||||
|
CategoryScale,
|
||||||
|
LinearScale,
|
||||||
|
BarController,
|
||||||
|
Colors
|
||||||
|
);
|
||||||
|
|
||||||
|
let { data } = $props<{ data: ModelStats }>();
|
||||||
|
|
||||||
|
let ctx: HTMLCanvasElement;
|
||||||
|
|
||||||
|
let chart: Chart;
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
if (data && ctx) {
|
||||||
|
if (chart) {
|
||||||
|
console.log("update")
|
||||||
|
chart.data = {
|
||||||
|
labels: data.map((a) => a.name),
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: 'Training',
|
||||||
|
data: data.map((a) => a.training)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Testing',
|
||||||
|
data: data.map((a) => a.testing)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
chart.update('resize');
|
||||||
|
} else {
|
||||||
|
console.log("create")
|
||||||
|
chart = new Chart(ctx, {
|
||||||
|
type: 'bar',
|
||||||
|
data: {
|
||||||
|
labels: data.map((a) => a.name),
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: 'Training',
|
||||||
|
data: data.map((a) => a.training)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Testing',
|
||||||
|
data: data.map((a) => a.testing)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
stacked: true
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
stacked: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div><canvas bind:this={ctx} /></div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
canvas {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
@ -44,8 +44,6 @@
|
|||||||
let res = await get('models/data/list?' + url.toString());
|
let res = await get('models/data/list?' + url.toString());
|
||||||
showNext = res.showNext;
|
showNext = res.showNext;
|
||||||
image_list = res.image_list;
|
image_list = res.image_list;
|
||||||
|
|
||||||
console.log(image_list);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('TODO notify user', e);
|
console.error('TODO notify user', e);
|
||||||
}
|
}
|
||||||
|
5
webpage/src/routes/models/edit/types.ts
Normal file
5
webpage/src/routes/models/edit/types.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export type ModelStats = Array<{
|
||||||
|
name: string,
|
||||||
|
training: number,
|
||||||
|
testing: number,
|
||||||
|
}>
|
Loading…
Reference in New Issue
Block a user