Skip to content

Commit

Permalink
Merge pull request #1 from atrifat/add-base64-upload-support
Browse files Browse the repository at this point in the history
Add base64 upload support
  • Loading branch information
atrifat committed Sep 15, 2023
2 parents 1e359b1 + 66da566 commit de6c50e
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 1 deletion.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,23 @@ node src/index.mjs
```

If you want to test the API server, you can use GUI tools like [Postman](https://www.postman.com/) or using curl.

Send request by using image URL:
```
curl --header "Content-Type: application/json" \
--header "Authorization: Bearer myapitokenchangethislater" \
--request POST \
--data '{"url":"https://example.org/image.jpg"}' \
http://localhost:8081/predict
```
or send request by using base64 string of the image:
```
curl --header "Content-Type: application/json" \
--header "Authorization: Bearer myapitokenchangethislater" \
--request POST \
--data '{"data":"base64stringhere"}' \
http://localhost:8081/predict_data
```
The output is JSON which consists of four predicted classes (based on [NsfwSpy.js](https://github.com/NsfwSpy/NsfwSpy.js)) as follows:
```
{
Expand Down
56 changes: 55 additions & 1 deletion src/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const ENABLE_API_TOKEN = process.env.ENABLE_API_TOKEN ? process.env.ENABLE_API_T
const API_TOKEN = process.env.API_TOKEN || "myapitokenchangethislater";

const app = express();
app.use(bodyparser.json())
app.use(bodyparser.json({ limit: '5mb' }));

const reqLogger = function (req, _res, next) {
console.info(`${req.method} request to "${req.url}" by ${req.hostname}`);
Expand Down Expand Up @@ -172,6 +172,60 @@ app.post("/predict", async (req, res) => {
res.status(200).json({ "data": cache });
});

app.post("/predict_data", async (req, res) => {
let err;

const base64_data = (typeof req.body.data !== 'undefined') ? req.body.data : null;

if (base64_data === null) {
err = new Error("Data input is empty, please send base64 string data as input");
err.name = "ValidationError";
return res.status(400).json({ "message": err.message });
}

const buffer = Buffer.from(base64_data, 'base64');

const filename = sha256(base64_data);
let cache = await keyv.get("data" + "-" + filename);
// Return cache result immediately if it is exist
if (cache) {
return res.status(200).json({ "data": cache });
}

// Load metadata for debugging
const img = sharp(buffer);
let metadata;
[err, metadata] = await to.default(img.metadata());

if (err) return res.status(500).json({ "message": err.message });
console.debug(metadata);

console.time("Preprocess");
let outputInfo;
[err, outputInfo] = await to.default(
// Resize to 224 px since it is the input size of model
img.resize(224).jpeg().withMetadata().toFile(IMG_DOWNLOAD_PATH + filename + "_" + "final")
);
if (err) return res.status(500).json({ "message": err.message });
console.timeEnd("Preprocess");

console.time("Classify");
[err, cache] = await to.default(nsfwSpy.classifyImageFile(IMG_DOWNLOAD_PATH + filename + "_" + "final"));
if (err) return res.status(500).json({ "message": err.message });

// Set cache result for 1 day
await keyv.set("data" + "-" + filename, cache, 24 * 60 * 60 * 1000);

console.timeEnd("Classify");
console.debug(cache);

// Cleanup image file
let deleteResult;
[err, deleteResult] = await to.default(deleteFile(IMG_DOWNLOAD_PATH + filename + "_" + "final"));

res.status(200).json({ "data": cache });
});

app.listen(PORT, () => {
console.log(`Listening on ${PORT} ...`);
});

0 comments on commit de6c50e

Please sign in to comment.