Публикация изображения, сделанного ESP32 CAM, в Clarifai не работает

У меня есть следующий скетч 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 публично в Интернете?

romkey 14.12.2020 02:56

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":"Неверный формат или неверный запрос"}}

Paulo Borges 14.12.2020 17:25

http.addHeader("Тип контента", "приложение/json"); --------- http.addHeader("Авторизация", "Ключ c7f894790533332388e23d4d21278321"); ------- Решил проблему. Спасибо

Paulo Borges 14.12.2020 20:46
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
1 281
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Эта проблема заключается не в форматировании вашего 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 в Интернете. Если это так, я бы рекомендовал аннулировать код в опубликованном вами коде и создать новый.

Другие вопросы по теме