У меня есть следующий скетч ESP32CAM, который нужно сфотографировать и опубликовать в Clarify:
#include "Arduino.h"
#include "esp_camera.h"
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <base64.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
// Select camera model
//#define CAMERA_MODEL_WROVER_KIT // Has PSRAM
//#define CAMERA_MODEL_ESP_EYE // Has PSRAM
//#define CAMERA_MODEL_M5STACK_PSRAM // Has PSRAM
//#define CAMERA_MODEL_M5STACK_WIDE // Has PSRAM
#define CAMERA_MODEL_AI_THINKER // Has PSRAM
//#define CAMERA_MODEL_TTGO_T_JOURNAL // No PSRAM
//CAMERA_MODEL_AI_THINKER
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
const char* ssid = "mySSID";
const char* password = "myPass";
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true);
Serial.println();
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
// if PSRAM IC present, init with UXGA resolution and higher JPEG quality
// for larger pre-allocated frame buffer.
if (psramFound()){
config.frame_size = FRAMESIZE_QVGA;
config.jpeg_quality = 10;
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_QVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
#if defined(CAMERA_MODEL_ESP_EYE)
pinMode(13, INPUT_PULLUP);
pinMode(14, INPUT_PULLUP);
#endif
// camera init
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
#if defined(CAMERA_MODEL_M5STACK_WIDE)
s->set_vflip(s, 1);
s->set_hmirror(s, 1);
#endif
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
classifyImage();
Serial.println("\nSleep....");
esp_deep_sleep_start();
}
void loop(){
}
void classifyImage() {
String response;
// Capture picture
camera_fb_t * fb = NULL;
fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Camera capture failed");
return;
} else {
Serial.println("Camera capture OK");
}
size_t size = fb->len;
String buffer = base64::encode((uint8_t *) fb->buf, fb->len);
String imgPayload = "{\"inputs\": [{ \"data\": {\"image\": {\"base64\": \"" + buffer + "\"}}}]}";
buffer = "";
// Uncomment this if you want to show the payload
Serial.println(imgPayload);
esp_camera_fb_return(fb);
// Generic model
String model_id = "General";
HTTPClient http;
http.begin("https://api.clarifai.com/v2/models/" + model_id + "/outputs");
http.addHeader("Content-Type", "application/json");
http.addHeader("Authorization", "c7f894790533332388e23d4d21278321");
int httpResponseCode = http.POST(imgPayload);
if (httpResponseCode>0){
Serial.print(httpResponseCode);
Serial.print(" Returned String: ");
Serial.println(http.getString());
} else {
Serial.print("POST Error: ");
Serial.print(httpResponseCode);
}
// Parse the json response: Arduino assistant
const int jsonSize = JSON_ARRAY_SIZE(1) + JSON_ARRAY_SIZE(20) + 3*JSON_OBJECT_SIZE(1) + 6*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) + 20*JSON_OBJECT_SIZE(4) + 2*JSON_OBJECT_SIZE(6);
StaticJsonDocument<jsonSize> doc;
// Deserialize the JSON document
DeserializationError error = deserializeJson(doc, response);
// Test if parsing succeeds.
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
Serial.println(jsonSize);
Serial.println(response);
for (int i=0; i < 10; i++) {
// const name = doc["outputs"][0]["data"]["concepts"][i]["name"];
// const float p = doc["outputs"][0]["data"]["concepts"][i]["value"];
const char* name = doc["outputs"][0]["data"]["concepts"][i]["name"];
const char* p = doc["outputs"][0]["data"]["concepts"][i]["value"];
Serial.println("==================== = ");
Serial.print("Name:");
Serial.println(name[i]);
Serial.print("Prob:");
Serial.println(p);
Serial.println();
}
}
Он отправляет изображение в Clarifai, что я получаю в ответ:
-400 Возвращаемая строка: {"status":{"code":11102,"description":"Неверный запрос","details":"Пустой или неверный заголовок авторизации. Укажите ключ API или токен сеанса.","req_id ":"39d7b4f1b7ad489fb3a9a878000f6e88"},"выводит":[]} -deserializeJson() не удалось: EmptyInput
Мне нужно подтвердить, правильно ли отформатирован запрос HTTP POST.
API не тот, который я печатаю, спасибо... curl: ~$ ls /home/pcborges/car.jpg /home/pcborges/car.jpg Предупреждение: поле ввода неправильно отформатировано! curl: option -F: здесь плохо используется curl -X POST /home/pcborges/car.jpg -H 'Авторизация: ключ c7f894790537423388e23d4d5c078321' -H 'Content-type: application/json' api.clarifai.com/v2 /models/aaa03c23b3724a16a56b629203edc62c/… curl: (3) URL-адрес в неправильном/недопустимом формате или отсутствующий URL-адрес {"status":{"code":11102,"description":"Неверный запрос","details":"Неверный формат или неверный запрос"}}
http.addHeader("Тип контента", "приложение/json"); --------- http.addHeader("Авторизация", "Ключ c7f894790533332388e23d4d21278321"); ------- Решил проблему. Спасибо
Эта проблема заключается не в форматировании вашего POST-запроса, а в том, что ваш заголовок авторизации неверен (как указывает ошибка «Пустой или неправильно сформированный заголовок авторизации»).
Как указано в документации Clarafai, заголовок авторизации должен быть:
Authorization: Key YOUR_API_KEY
ваш код отправляется
Authorization: YOUR_API_KEY
измените строку, которая устанавливает заголовок авторизации, чтобы иметь «Ключ» перед ключом API.
Учитывая, что ESP32 — это суетливая среда, где многое может пойти не так с HTTP-запросом, хороший способ отладки этих проблем — использовать утилиту curl
, чтобы попытаться выполнить ту же операцию в более полнофункциональной среде. В этом случае на компьютере Mac или Linux вы можете запустить
curl -X POST -F filename -H 'Authorization: YOUR_API_KEY' -H 'Content-type: application/json' https://api.clarifai.com/v2/models/MODEL_ID/outputs
где фотография, которую вы тестируете, хранится в filename
. Вы можете быть уверены, что запрос POST верен, и выяснить, что еще может быть не так.
Также кажется, что вы могли разместить свой ключ API в Интернете. Если это так, я бы рекомендовал аннулировать код в опубликованном вами коде и создать новый.
Вы только что опубликовали свой ключ API публично в Интернете?