Skip to content

Instantly share code, notes, and snippets.

@peterhellberg
Last active October 25, 2017 19:32
Show Gist options
  • Save peterhellberg/8d9906e4e2ebc72b5199cb3e9a10aa18 to your computer and use it in GitHub Desktop.
Save peterhellberg/8d9906e4e2ebc72b5199cb3e9a10aa18 to your computer and use it in GitHub Desktop.
Tagbox combined with imagesnap using Go
package main
import (
"bufio"
"bytes"
"context"
"encoding/json"
"flag"
"fmt"
"io"
"log"
"net/http"
"net/url"
"os"
"os/exec"
"time"
"github.com/machinebox/sdk-go/tagbox"
)
var (
images = map[string][]byte{}
imageURL *url.URL
tbox *tagbox.Client
)
func main() {
var ip, port, tb string
flag.StringVar(&ip, "ip", "10.0.0.86", "")
flag.StringVar(&port, "port", "8081", "")
flag.StringVar(&tb, "tb", "http://localhost:8080", "Tagbox URL")
flag.Parse()
imageURL = &url.URL{Scheme: "http", Host: ip + ":" + port, Path: "/image"}
http.HandleFunc("/image", image)
http.HandleFunc("/", index)
tbox = tagbox.New(tb)
fmt.Fprintf(os.Stderr, "Listening on http://0.0.0.0:%s\n", port)
http.ListenAndServe(":"+port, nil)
}
func snap(ctx context.Context, w io.Writer) error {
cmd := exec.CommandContext(ctx, "imagesnap", "-w", "1", "-")
cmd.Stdout = w
return cmd.Run()
}
func image(w http.ResponseWriter, r *http.Request) {
at := requestAt(r, time.Now().UTC())
if b, found := images[at]; found {
w.Write(b)
return
}
var buf bytes.Buffer
bw := bufio.NewWriter(&buf)
if err := snap(r.Context(), bw); err != nil {
log.Println("[ERROR] capturing webcam", err)
return
}
bw.Flush()
b := buf.Bytes()
images[at] = b
w.Write(b)
}
func index(w http.ResponseWriter, r *http.Request) {
timestamp := time.Now().UTC()
meta := Meta{"timestamp": timestamp}
u := imageURL
u.RawQuery = "at=" + requestAt(r, timestamp)
fmt.Fprintf(os.Stderr, "Checking %s\n", u.String())
tags, err := tbox.CheckURL(u)
if err != nil {
log.Println("[ERROR]", err)
writeJSON(w, errorResponse(err, 500, meta), 500)
return
}
resp := Response{
Meta: meta,
Data: Data{
"image": u.String(),
"tags": tags,
},
}
go func() {
for _, tag := range tags {
if tag.Confidence > 0.3 {
exec.Command("say", tag.Tag, "-v", "Samantha", "-r", "160").Run()
break
}
}
}()
json.NewEncoder(os.Stdout).Encode(resp)
writeJSON(w, resp)
}
func requestAt(r *http.Request, t time.Time) string {
if at := r.URL.Query().Get("at"); at != "" {
return at
}
return fmt.Sprintf("%d", t.Nanosecond())
}
func writeJSON(w http.ResponseWriter, v interface{}, statuses ...int) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.Header().Add("Vary", "Accept-Encoding")
if len(statuses) > 0 {
w.WriteHeader(statuses[0])
}
enc := json.NewEncoder(w)
enc.SetIndent("", " ")
enc.Encode(v)
}
type Response struct {
Meta Meta `json:"meta,omitempty"`
Data Data `json:"data,omitempty"`
Errors []Error `json:"errors,omitempty"`
}
func errorResponse(err error, status int, meta Meta) Response {
return Response{
Meta: meta,
Errors: []Error{
{
Status: status,
Title: http.StatusText(status),
Detail: err.Error(),
},
},
}
}
// Meta is a meta object that contains non-standard meta-information.
type Meta map[string]interface{}
// Data is the primary data of the Response
type Data map[string]interface{}
// Error objects provide additional information about problems encountered while performing an operation.
type Error struct {
Status int `json:"status"`
Title string `json:"title"`
Detail string `json:"detail,omitempty"`
}
@peterhellberg
Copy link
Author

peterhellberg commented Sep 1, 2017

phone

{
    "meta": {
        "timestamp": "2017-09-01T17:19:35.557356552Z"
    },
    "data": {
        "image": "http://10.0.0.86:8081/image?at=557356552",
        "tags": [
            {
                "Tag": "cellular_telephone",
                "Confidence": 0.533503532409668
            },
            {
                "Tag": "iPod",
                "Confidence": 0.22914648056030273
            },
            {
                "Tag": "microphone",
                "Confidence": 0.014935246668756008
            },
            {
                "Tag": "hand_blower",
                "Confidence": 0.013065827079117298
            },
            {
                "Tag": "banjo",
                "Confidence": 0.008280351758003235
            }
        ]
    }
}

@peterhellberg
Copy link
Author

peterhellberg commented Sep 1, 2017

orange

{
    "meta": {
        "timestamp": "2017-09-01T17:29:52.302810177Z"
    },
    "data": {
        "image": "http://10.0.0.86:8081/image?at=302810177",
        "tags": [
            {
                "Tag": "orange",
                "Confidence": 0.9756798148155212
            },
            {
                "Tag": "ping-pong_ball",
                "Confidence": 0.009037220850586891
            },
            {
                "Tag": "lemon",
                "Confidence": 0.0031082637142390013
            },
            {
                "Tag": "pomegranate",
                "Confidence": 0.002462725155055523
            },
            {
                "Tag": "banana",
                "Confidence": 0.001104470225982368
            }
        ]
    }
}

@peterhellberg
Copy link
Author

rubber-eraser

{
    "meta": {
        "timestamp": "2017-09-01T17:37:40.171699873Z"
    },
    "data": {
        "image": "http://10.0.0.86:8081/image?at=171699873",
        "tags": [
            {
                "Tag": "rubber_eraser",
                "Confidence": 0.36174893379211426
            },
            {
                "Tag": "paintbrush",
                "Confidence": 0.17667531967163086
            },
            {
                "Tag": "screwdriver",
                "Confidence": 0.13990812003612518
            },
            {
                "Tag": "syringe",
                "Confidence": 0.12272959202528
            },
            {
                "Tag": "pencil_sharpener",
                "Confidence": 0.049953900277614594
            }
        ]
    }
}

Not totally sure how it “figured” out that the pen has a rubber eraser tip… even with such a low confidence value.

@peterhellberg
Copy link
Author

penguin

{
    "meta": {
        "timestamp": "2017-09-01T17:45:47.514745238Z"
    },
    "data": {
        "image": "http://10.0.0.86:8081/image?at=514745238",
        "tags": [
            {
                "Tag": "king_penguin",
                "Confidence": 0.9592017531394958
            },
            {
                "Tag": "killer_whale",
                "Confidence": 0.020975982770323753
            },
            {
                "Tag": "toucan",
                "Confidence": 0.005348627455532551
            },
            {
                "Tag": "sombrero",
                "Confidence": 0.0010137950303032994
            },
            {
                "Tag": "goose",
                "Confidence": 0.0009246725821867585
            }
        ]
    }
}

@peterhellberg
Copy link
Author

coffee-mug

{
    "meta": {
        "timestamp": "2017-09-01T18:06:32.109913137Z"
    },
    "data": {
        "image": "http://10.0.0.86:8081/image?at=109913137",
        "tags": [
            {
                "Tag": "coffee_mug",
                "Confidence": 0.7345199584960938
            },
            {
                "Tag": "cup",
                "Confidence": 0.1498795747756958
            },
            {
                "Tag": "toilet_tissue",
                "Confidence": 0.027606995776295662
            },
            {
                "Tag": "cowboy_hat",
                "Confidence": 0.023174552246928215
            },
            {
                "Tag": "sombrero",
                "Confidence": 0.018557647243142128
            }
        ]
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment