mirror of
https://github.com/m5stack/CoreS3-Box.git
synced 2026-05-20 10:59:43 -07:00
example:ChatGPT_demo using uf2
This commit is contained in:
@@ -8,9 +8,9 @@ In this example, we are utilizing the OpenAI API in conjunction with an ESP-Box
|
||||
git checkout master && git pull && git submodule update --init --recursive
|
||||
|
||||
```
|
||||
* If you encounter any errors during the upgrade process, please make sure to use the ESP-IDF version [master](https://github.com/espressif/esp-idf) at commit ID `df9310ada26123d8d478bcfa203f874d8c21d654`. This specific commit represents a stable state of the ESP-IDF repository and can help ensure a smoother transition or troubleshooting process.
|
||||
* If you encounter any errors during the upgrade process, please make sure to use the ESP-IDF version [master](https://github.com/espressif/esp-idf) at commit ID `d2471b11e78fb0af612dfa045255ac7fe497bea8`. This specific commit represents a stable state of the ESP-IDF repository and can help ensure a smoother transition or troubleshooting process.
|
||||
```
|
||||
git checkout df9310ada26123d8d478bcfa203f874d8c21d654 && git pull && git submodule update --init --recursive
|
||||
git checkout 67552c31dac8cd94fb0d63192a538f4f984c5b6e && git pull && git submodule update --init --recursive
|
||||
|
||||
```
|
||||
|
||||
@@ -18,6 +18,8 @@ git checkout df9310ada26123d8d478bcfa203f874d8c21d654 && git pull && git submodu
|
||||
Due to the lack of native text-to-speech support in the [OpenAI](https://platform.openai.com/docs/api-reference) API, an external API is used to meet this requirement. This example utilizes the text-to-speech functionality offered by [TalkingGenie](https://www.talkinggenie.com/tts). Additional information can be found in this [blog post](https://czyt.tech/post/a-free-tts-api/?from_wecom=1).
|
||||
|
||||
## **Reproducing the demo**
|
||||
There is another project called **factory_nvs** within the **ChatGPT_demo** project. It includes the code to store credentials in the NVS (Non-Volatile Storage) of the ESP-Box. On the other hand, **Chat_GPT Demo**consists of the demo code. Therefore, it is essential to build both projects.
|
||||
|
||||
|
||||
### 1. Clone the Github repository
|
||||
|
||||
@@ -26,26 +28,51 @@ git clone https://github.com/espressif/esp-box
|
||||
|
||||
```
|
||||
|
||||
### 2. Change the working directory to model_deployment
|
||||
### 2. Change the working directory
|
||||
|
||||
```bash
|
||||
cd examples/chatgpt_demo/factory_nvs
|
||||
|
||||
```
|
||||
|
||||
### 3. Build the factory_nvs
|
||||
|
||||
```bash
|
||||
idf.py build
|
||||
|
||||
```
|
||||
|
||||
### 4. Change the working directory
|
||||
|
||||
```bash
|
||||
cd examples/chatgpt_demo/
|
||||
|
||||
```
|
||||
|
||||
### 3. Set up OpenAI Key, WiFi SSID and Password
|
||||
|
||||
```
|
||||
idf.py menuconfig
|
||||
|
||||
```
|
||||
### 4. Build the project
|
||||
### 5. Build the chatgpt_demo
|
||||
|
||||
```bash
|
||||
idf.py build flash monitor
|
||||
idf.py build
|
||||
|
||||
```
|
||||
|
||||
### 6. Flash on ESP-BOX
|
||||
```
|
||||
python -m esptool -p /dev/ttyACM0 --chip esp32s3 -b 460800 --before default_reset --after hard_reset write_flash --flash_mode dio --flash_size 16MB --flash_freq 80m 0x0 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0xd000 build/ota_data_initial.bin 0x10000 build/chatgpt_demo.bin 0x900000 build/storage.bin 0xb00000 build/srmodels/srmodels.bin 0x700000 factory_nvs/build/factory_nvs.bin
|
||||
|
||||
```
|
||||
|
||||
In case found error during the building process [follow the official IDF guide for more details](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html#build-your-first-project).
|
||||
|
||||
> **Note :**
|
||||
> Please note that you require an OpenAI API key to proceed with the demo. To enter the WIFI credentials and OpenAI secret key, access the menuconfig using "idf.py menuconfig"
|
||||
|
||||
## Known compilation errors
|
||||
When encountering compilation errors related to the "espressif__esp-sr" component, a common solution is to remove the ".component_hash" file located at "managed_components/espressif__esp-sr" and proceed with the rebuild. This step helps resolve the issue and allows the compilation process to continue smoothly.
|
||||
|
||||
|
||||
### **Note**:
|
||||
Please note that,
|
||||
1. You require an **OpenAI API** key to proceed with the demo.
|
||||
2. To enter the WIFI credentials and OpenAI secret key.
|
||||
3. The example does not currently support ESP-BOX Lite.
|
||||
4. Additionally, as a result of **OpenAI's restrictions**, this particular example cannot be supported within Mainland China.
|
||||
@@ -1 +0,0 @@
|
||||
6761973f9f117571afcf1f70db4036a226dddee347c39e66518e4fcb3f521c16
|
||||
@@ -234,12 +234,12 @@ static esp_err_t aplay_file(audio_instance_t *i, uint8_t *stream, uint32_t strea
|
||||
memset(&i2s_format, 0, sizeof(i2s_format));
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
audio_player_event_t audio_event = { .type = AUDIO_PLAYER_REQUEST_NONE, .stream = NULL };
|
||||
audio_player_event_t audio_event = { .type = AUDIO_PLAYER_REQUEST_NONE, .stream = NULL, .stream_len = 0 };
|
||||
|
||||
FILE_TYPE file_type = FILE_TYPE_UNKNOWN;
|
||||
uint8_t *p_stream = stream;
|
||||
// LOGI_1("start to decode,%p, %p, stream_len:%d", stream, p_stream, stream_len);
|
||||
LOGI_1("start to decode, %p, %p, stream_len:%"PRIu32, stream, p_stream, stream_len);
|
||||
LOGI_1("start to decode, %p, %p, stream_len:%" PRIu32 , stream, p_stream, stream_len);
|
||||
|
||||
|
||||
#if defined(CONFIG_AUDIO_PLAYER_ENABLE_MP3)
|
||||
@@ -359,7 +359,7 @@ static esp_err_t aplay_file(audio_instance_t *i, uint8_t *stream, uint32_t strea
|
||||
(i2s_format.channels != i->output.fmt.channels) ||
|
||||
(i2s_format.bits_per_sample != i->output.fmt.bits_per_sample)) {
|
||||
i2s_format = i->output.fmt;
|
||||
LOGI_1("format change: sr=%d, bit=%"PRIu32", ch=%"PRIu32,
|
||||
LOGI_1("format change: sr=%d, bit=%" PRIu32 ", ch=%" PRIu32 ,
|
||||
i2s_format.sample_rate,
|
||||
i2s_format.bits_per_sample,
|
||||
i2s_format.channels);
|
||||
@@ -482,21 +482,21 @@ esp_err_t audio_player_play(uint8_t *stream, uint32_t file_len)
|
||||
esp_err_t audio_player_pause(void)
|
||||
{
|
||||
LOGI_1("%s", __FUNCTION__);
|
||||
audio_player_event_t event = { .type = AUDIO_PLAYER_REQUEST_PAUSE, .stream = NULL };
|
||||
audio_player_event_t event = { .type = AUDIO_PLAYER_REQUEST_PAUSE, .stream = NULL, .stream_len = 0};
|
||||
return audio_send_event(&instance, event);
|
||||
}
|
||||
|
||||
esp_err_t audio_player_resume(void)
|
||||
{
|
||||
LOGI_1("%s", __FUNCTION__);
|
||||
audio_player_event_t event = { .type = AUDIO_PLAYER_REQUEST_RESUME, .stream = NULL };
|
||||
audio_player_event_t event = { .type = AUDIO_PLAYER_REQUEST_RESUME, .stream = NULL, .stream_len = 0};
|
||||
return audio_send_event(&instance, event);
|
||||
}
|
||||
|
||||
esp_err_t audio_player_stop(void)
|
||||
{
|
||||
LOGI_1("%s", __FUNCTION__);
|
||||
audio_player_event_t event = { .type = AUDIO_PLAYER_REQUEST_STOP, .stream = NULL };
|
||||
audio_player_event_t event = { .type = AUDIO_PLAYER_REQUEST_STOP, .stream = NULL, .stream_len = 0};
|
||||
return audio_send_event(&instance, event);
|
||||
}
|
||||
|
||||
@@ -507,7 +507,7 @@ esp_err_t audio_player_stop(void)
|
||||
static esp_err_t _internal_audio_player_shutdown_thread(void)
|
||||
{
|
||||
LOGI_1("%s", __FUNCTION__);
|
||||
audio_player_event_t event = { .type = AUDIO_PLAYER_REQUEST_SHUTDOWN_THREAD, .stream = NULL };
|
||||
audio_player_event_t event = { .type = AUDIO_PLAYER_REQUEST_SHUTDOWN_THREAD, .stream = NULL, .stream_len = 0 };
|
||||
return audio_send_event(&instance, event);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# ChangeLog
|
||||
|
||||
## v0.0.1 - 2023-6-15
|
||||
|
||||
### Enhancements:
|
||||
|
||||
* OpenAI ChatGPT and Whisper AI support
|
||||
@@ -1,5 +0,0 @@
|
||||
idf_component_register(
|
||||
SRCS "OpenAI.c"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES tcp_transport esp_http_client
|
||||
)
|
||||
@@ -1,202 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -1,398 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include "OpenAI.h"
|
||||
#include "esp_log.h"
|
||||
#include <json_parser.h>
|
||||
#include "esp_http_client.h"
|
||||
#include "esp_crt_bundle.h"
|
||||
|
||||
static const char *json_fmt = "{\"model\":\"%s\",\"max_tokens\":%d,\"messages\":[{\"role\":\"user\",\"content\":\"%s\"}]}";
|
||||
static const char *TAG = "Open AI";
|
||||
|
||||
char OPENAI_API_KEY[OPENAI_API_KEY_MAX_LEN];
|
||||
char message_content[MESSAGE_CONTENT_SIZE] = {0};
|
||||
char message_content_for_whisper[1024] = {0};
|
||||
char json_payload[512];
|
||||
|
||||
// Forward Declaration will be remove in new version of OpenAI component
|
||||
|
||||
typedef struct {
|
||||
bool need_hint;
|
||||
region_t current_server;
|
||||
char ssid[32];
|
||||
char password[64];
|
||||
uint8_t ssid_len;
|
||||
uint8_t password_len;
|
||||
} sys_param_t;
|
||||
|
||||
// Declaration of the weak function will be remove in new version of OpenAI component
|
||||
|
||||
sys_param_t* __attribute__((weak)) settings_get_parameter(void) {
|
||||
static sys_param_t default_parameters = {
|
||||
.current_server = REGION_Espressif, // Default server
|
||||
};
|
||||
return &default_parameters;
|
||||
}
|
||||
|
||||
// Declaration of the weak function will be remove in new version of OpenAI component
|
||||
|
||||
esp_err_t __attribute__((weak)) settings_write_parameter_to_nvs(void){
|
||||
|
||||
printf("This is the weak function.\n");
|
||||
return NULL; // Or return a default sys_param_t value
|
||||
}
|
||||
|
||||
/* Function to set the OpenAI API key */
|
||||
|
||||
void set_api_key(const char *key)
|
||||
{
|
||||
if (key == NULL) {
|
||||
ESP_LOGE(TAG, "OpenAI API key is NULL");
|
||||
return;
|
||||
}
|
||||
size_t key_length = strlen(key);
|
||||
if (key_length >= OPENAI_API_KEY_MAX_LEN) {
|
||||
ESP_LOGE(TAG, "OpenAI API key is too long: %s", key);
|
||||
return;
|
||||
}
|
||||
strncpy(OPENAI_API_KEY, key, OPENAI_API_KEY_MAX_LEN - 1);
|
||||
OPENAI_API_KEY[OPENAI_API_KEY_MAX_LEN - 1] = '\0';
|
||||
|
||||
ESP_LOGI(TAG, "API Key entered");
|
||||
}
|
||||
|
||||
/* Parsing response coming from server */
|
||||
|
||||
void parse_response (const char *data, int len)
|
||||
{
|
||||
jparse_ctx_t jctx;
|
||||
int ret = json_parse_start(&jctx, data, len);
|
||||
if (ret != OS_SUCCESS) {
|
||||
ESP_LOGE(TAG, "Parser failed");
|
||||
return;
|
||||
}
|
||||
printf("\n");
|
||||
int num_choices;
|
||||
/* Parsing OpenAI & Espressif server Chat GPT response */
|
||||
if (json_obj_get_array(&jctx, "choices", &num_choices) == OS_SUCCESS) {
|
||||
for (int i = 0; i < num_choices; i++) {
|
||||
if (json_arr_get_object(&jctx, i) == OS_SUCCESS && json_obj_get_object(&jctx, "message") == OS_SUCCESS &&
|
||||
json_obj_get_string(&jctx, "content", message_content, sizeof(message_content)) == OS_SUCCESS) {
|
||||
ESP_LOGI(TAG, "ChatGPT message_content: %s\n", message_content);
|
||||
}
|
||||
json_arr_leave_object(&jctx);
|
||||
}
|
||||
json_obj_leave_array(&jctx);
|
||||
}
|
||||
/* Parsing OpenAI server Whisper AI response */
|
||||
else if (json_obj_get_string(&jctx, "text", message_content, sizeof(message_content)) == OS_SUCCESS) {
|
||||
ESP_LOGI(TAG, "Whisper message_content: %s", message_content);
|
||||
} else if (json_obj_get_object(&jctx, "error") == OS_SUCCESS) {
|
||||
if (json_obj_get_string(&jctx, "type", message_content, sizeof(message_content)) == OS_SUCCESS) {
|
||||
ESP_LOGE(TAG, "API returns an error: %s", message_content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Parsing espressif server Whisper AI response */
|
||||
|
||||
void parse_espressif_server_whisper_response(const char *data, int len)
|
||||
{
|
||||
jparse_ctx_t jctx;
|
||||
int ret = json_parse_start(&jctx, data, len);
|
||||
if (ret != OS_SUCCESS) {
|
||||
ESP_LOGE(TAG, "Parser failed");
|
||||
return;
|
||||
}
|
||||
if (json_obj_get_string(&jctx, "whisper", message_content_for_whisper, sizeof(message_content_for_whisper)) == OS_SUCCESS) {
|
||||
ESP_LOGI(TAG, "Whisper message_content: %s", message_content_for_whisper);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Error in parse whisper AI response data");
|
||||
}
|
||||
}
|
||||
|
||||
/* Intermediate function to correctly parse data*/
|
||||
|
||||
void parsing_data(const char *data, int len)
|
||||
{
|
||||
if (data == NULL) {
|
||||
ESP_LOGE(TAG, "Response data is NULL");
|
||||
return;
|
||||
}
|
||||
sys_param_t *sys_set = settings_get_parameter();
|
||||
|
||||
if (sys_set->current_server == REGION_Espressif) {
|
||||
ESP_LOGI(TAG, "parsing Espressif server response");
|
||||
parse_espressif_server_whisper_response(data, len);
|
||||
}
|
||||
parse_response(data, len);
|
||||
}
|
||||
|
||||
/* Response handler for HTTPS request */
|
||||
|
||||
esp_err_t response_handler(esp_http_client_event_t *evt)
|
||||
{
|
||||
static char *data = NULL; // Initialize data to NULL
|
||||
static int data_len = 0; // Initialize data to NULL
|
||||
|
||||
switch (evt->event_id) {
|
||||
case HTTP_EVENT_ERROR:
|
||||
ESP_LOGI(TAG, "HTTP_EVENT_ERROR");
|
||||
break;
|
||||
|
||||
case HTTP_EVENT_ON_CONNECTED:
|
||||
ESP_LOGI(TAG, "HTTP_EVENT_ON_CONNECTED");
|
||||
break;
|
||||
|
||||
case HTTP_EVENT_HEADER_SENT:
|
||||
ESP_LOGI(TAG, "HTTP_EVENT_HEADER_SENT");
|
||||
break;
|
||||
|
||||
case HTTP_EVENT_ON_HEADER:
|
||||
if (evt->data_len) {
|
||||
ESP_LOGI(TAG, "HTTP_EVENT_ON_HEADER");
|
||||
ESP_LOGI(TAG, "%.*s", evt->data_len, (char *)evt->data);
|
||||
}
|
||||
break;
|
||||
|
||||
case HTTP_EVENT_ON_DATA:
|
||||
ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA (%d +)%d", data_len, evt->data_len);
|
||||
ESP_LOGI(TAG, "Raw Response: data length: (%d +)%d: %.*s", data_len, evt->data_len, evt->data_len, (char *)evt->data);
|
||||
data = heap_caps_realloc(data, data_len + evt->data_len + 1, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
if (data == NULL) {
|
||||
ESP_LOGE(TAG, "data realloc failed");
|
||||
free(data);
|
||||
data = NULL;
|
||||
break;
|
||||
}
|
||||
memcpy(data + data_len, (char *)evt->data, evt->data_len);
|
||||
data_len += evt->data_len;
|
||||
data[data_len] = '\0';
|
||||
break;
|
||||
|
||||
case HTTP_EVENT_ON_FINISH:
|
||||
ESP_LOGI(TAG, "HTTP_EVENT_ON_FINISH");
|
||||
if (data != NULL) {
|
||||
parsing_data(data, strlen(data));
|
||||
free(data); // Free memory
|
||||
data = NULL;
|
||||
data_len = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case HTTP_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/* This function creates an HTTP POST request to the OpenAI chatGPT API */
|
||||
|
||||
esp_err_t create_chatgpt_request(const char *content)
|
||||
{
|
||||
char url[128] = "https://api.openai.com/v1/chat/completions";
|
||||
char model[16] = "gpt-3.5-turbo";
|
||||
char headers[512];
|
||||
snprintf(headers, sizeof(headers), "Bearer %s", OPENAI_API_KEY);
|
||||
ESP_LOGI(TAG, "Set Header %s", headers);
|
||||
esp_http_client_config_t config = {
|
||||
.url = url,
|
||||
.method = HTTP_METHOD_POST,
|
||||
.event_handler = response_handler,
|
||||
.buffer_size = MAX_HTTP_RECV_BUFFER,
|
||||
.timeout_ms = 30000,
|
||||
.crt_bundle_attach = esp_crt_bundle_attach,
|
||||
};
|
||||
|
||||
uint32_t starttime = esp_log_timestamp();
|
||||
ESP_LOGE(TAG, "[Start] create_CHATGPT_request, timestamp:%"PRIu32, starttime);
|
||||
|
||||
// Set the headers
|
||||
esp_http_client_handle_t client = esp_http_client_init(&config);
|
||||
esp_http_client_set_header(client, "Content-Type", "application/json");
|
||||
esp_http_client_set_header(client, "Authorization", headers);
|
||||
|
||||
snprintf(json_payload, sizeof(json_payload), json_fmt, model, MAX_RESPONSE_TOKEN, content);
|
||||
ESP_LOGI(TAG, "JSON Payload: %s", json_payload);
|
||||
esp_http_client_set_post_field(client, json_payload, strlen(json_payload));
|
||||
|
||||
// Send the request
|
||||
esp_err_t err = esp_http_client_perform(client);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "HTTP POST request failed: %s\n", esp_err_to_name(err));
|
||||
}
|
||||
ESP_LOGE(TAG, "[End] create_CHATGPT_request, + offset: %" PRIu32, esp_log_timestamp() - starttime);
|
||||
esp_http_client_cleanup(client);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* This function creates an HTTP POST request to the OpenAI whisper API */
|
||||
|
||||
esp_err_t create_whisper_request_from_record(uint8_t *audio, int audio_len)
|
||||
{
|
||||
if (audio == NULL) {
|
||||
// Handle the error condition appropriately
|
||||
ESP_LOGE(TAG, "Audio data is NULL");
|
||||
return ESP_ERR_INVALID_ARG; // Or any other error code indicating the issue
|
||||
}
|
||||
char url[128]; // declare the variable here
|
||||
char headers[512];
|
||||
sys_param_t *sys_set = settings_get_parameter();
|
||||
|
||||
if (sys_set->current_server == REGION_Espressif) {
|
||||
ESP_LOGI(TAG, "Espressif server");
|
||||
snprintf(url, sizeof(url), "https://flask-production-1b02.up.railway.app/audio");
|
||||
} else {
|
||||
snprintf(url, sizeof(url), "https://api.openai.com/v1/audio/transcriptions");
|
||||
}
|
||||
snprintf(headers, sizeof(headers), "Bearer %s", OPENAI_API_KEY);
|
||||
esp_http_client_config_t config = {
|
||||
.url = url,
|
||||
.method = HTTP_METHOD_POST,
|
||||
.event_handler = response_handler,
|
||||
.buffer_size = MAX_HTTP_RECV_BUFFER,
|
||||
.timeout_ms = 60000,
|
||||
.crt_bundle_attach = esp_crt_bundle_attach,
|
||||
};
|
||||
uint32_t starttime = esp_log_timestamp();
|
||||
ESP_LOGE(TAG, "[Start] create_whisper_request, timestamp:%"PRIu32, starttime);
|
||||
|
||||
esp_http_client_handle_t client = esp_http_client_init(&config);
|
||||
|
||||
// Set the headers
|
||||
esp_http_client_set_header(client, "Authorization", headers);
|
||||
|
||||
// Set the content type and the boundary string
|
||||
char boundary[] = "boundary1234567890";
|
||||
char content_type[64];
|
||||
snprintf(content_type, sizeof(content_type), "multipart/form-data; boundary=%s", boundary);
|
||||
esp_http_client_set_header(client, "Content-Type", content_type);
|
||||
|
||||
char *file_data = NULL;
|
||||
size_t file_size;
|
||||
|
||||
file_data = (char *)audio;
|
||||
file_size = audio_len;
|
||||
|
||||
// Build the multipart/form-data request
|
||||
char *form_data = (char *)malloc(MAX_HTTP_RECV_BUFFER);
|
||||
assert(form_data);
|
||||
ESP_LOGI(TAG, "Size of form_data buffer: %zu bytes", sizeof(*form_data) * MAX_HTTP_RECV_BUFFER);
|
||||
int form_data_len = 0;
|
||||
form_data_len += snprintf(form_data + form_data_len, MAX_HTTP_RECV_BUFFER - form_data_len,
|
||||
"--%s\r\n"
|
||||
"Content-Disposition: form-data; name=\"file\"; filename=\"%s\"\r\n"
|
||||
"Content-Type: application/octet-stream\r\n"
|
||||
"\r\n", boundary, get_file_format(file_type));
|
||||
ESP_LOGI(TAG, "form_data_len %d", form_data_len);
|
||||
ESP_LOGI(TAG, "form_data %s\n", form_data);
|
||||
|
||||
// Append the audio file contents
|
||||
memcpy(form_data + form_data_len, file_data, file_size);
|
||||
form_data_len += file_size;
|
||||
ESP_LOGI(TAG, "Size of form_data: %zu", form_data_len);
|
||||
|
||||
// Append the rest of the form-data
|
||||
form_data_len += snprintf(form_data + form_data_len, MAX_HTTP_RECV_BUFFER - form_data_len,
|
||||
"\r\n"
|
||||
"--%s\r\n"
|
||||
"Content-Disposition: form-data; name=\"model\"\r\n"
|
||||
"\r\n"
|
||||
"whisper-1\r\n"
|
||||
"--%s--\r\n", boundary, boundary);
|
||||
|
||||
ESP_LOGI(TAG, "Size of form_data: %zu", form_data_len);
|
||||
// Set the headers and post field
|
||||
esp_http_client_set_post_field(client, form_data, form_data_len);
|
||||
|
||||
// Send the request
|
||||
esp_err_t err = esp_http_client_perform(client);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "HTTP POST request failed: %s\n", esp_err_to_name(err));
|
||||
}
|
||||
ESP_LOGE(TAG, "[End] create_wisper_request, + offset:%"PRIu32, esp_log_timestamp() - starttime);
|
||||
|
||||
esp_http_client_cleanup(client);
|
||||
free(form_data);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* This function set the server based on region */
|
||||
|
||||
void set_server(const region_t server)
|
||||
{
|
||||
sys_param_t *sys_set = settings_get_parameter();
|
||||
|
||||
switch (server) {
|
||||
case REGION_OpenAI:
|
||||
sys_set->current_server = REGION_OpenAI;
|
||||
ESP_LOGI(TAG, "Current server: OpenAI");
|
||||
break;
|
||||
case REGION_Espressif:
|
||||
sys_set->current_server = REGION_Espressif;
|
||||
ESP_LOGI(TAG, "Current server: Espressif");
|
||||
break;
|
||||
default:
|
||||
// Invalid region value
|
||||
ESP_LOGE(TAG, "Error: Invalid region value %d", sys_set->current_server);
|
||||
break;
|
||||
}
|
||||
|
||||
settings_write_parameter_to_nvs();
|
||||
}
|
||||
|
||||
/* Set the audio file format to use */
|
||||
|
||||
void set_audio_type(const format_t type)
|
||||
{
|
||||
file_type = type;
|
||||
ESP_LOGI(TAG, "Audio file format: %s", get_file_format(file_type));
|
||||
}
|
||||
|
||||
/* Get the message content for the last response from ChatGPT */
|
||||
|
||||
char *get_message_content_for_chatgpt(void)
|
||||
{
|
||||
return message_content;
|
||||
}
|
||||
|
||||
/* Get the message content for the last response from Whisper AI */
|
||||
|
||||
char *get_message_content_for_whisper(void)
|
||||
{
|
||||
return message_content_for_whisper;
|
||||
}
|
||||
|
||||
/* Get the audio file_format use */
|
||||
|
||||
char *get_file_format(format_t file_type)
|
||||
{
|
||||
switch (file_type) {
|
||||
case FORMAT_M4A:
|
||||
return "m4a";
|
||||
case FORMAT_MP3:
|
||||
return "mp3";
|
||||
case FORMAT_WEBM:
|
||||
return "webm";
|
||||
case FORMAT_MP4:
|
||||
return "mp4";
|
||||
case FORMAT_MPGA:
|
||||
return "mpga";
|
||||
case FORMAT_WAV:
|
||||
return "wav";
|
||||
case FORMAT_MPEG:
|
||||
return "mpeg";
|
||||
default:
|
||||
return "wav";
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
# **OpenAI Component**
|
||||
|
||||
The ESP-OpenAI component currently offers support for two primary features: ChatGPT and Whisper AI.
|
||||
|
||||
ChatGPT is a powerful conversational AI model that excels in interactive conversations. It generates natural and coherent responses based on the context of the conversation, making it suitable for various applications like chatbots, virtual assistants, and customer support systems.
|
||||
|
||||
Whisper AI, developed by OpenAI, is an automatic speech recognition (ASR) system. It converts spoken language into written text and finds applications in transcription services, voice assistants, and audio analysis.
|
||||
|
||||
> Note: This is an experimental component, APIs may change in future
|
||||
@@ -1,7 +0,0 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
espressif/json_parser: "^1.0.2"
|
||||
## Required IDF version
|
||||
idf:
|
||||
version: ">=5.0.0"
|
||||
version: "0.0.1"
|
||||
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: CC0-1.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
#define OPENAI_API_KEY_MAX_LEN 256
|
||||
#define MAX_RESPONSE_TOKEN (CONFIG_MAX_TOKEN)
|
||||
#define MAX_HTTP_RECV_BUFFER (1 * 1024 * 1024 + 1024)
|
||||
#define MESSAGE_CONTENT_SIZE (CONFIG_MESSAGE_CONTENT_SIZE)
|
||||
|
||||
/**
|
||||
* @brief region of server
|
||||
*/
|
||||
typedef enum {
|
||||
REGION_OpenAI,
|
||||
REGION_Espressif,
|
||||
REGION_Max,
|
||||
} region_t;
|
||||
|
||||
/**
|
||||
* @brief audio file format supported
|
||||
*/
|
||||
typedef enum {
|
||||
FORMAT_M4A,
|
||||
FORMAT_MP3,
|
||||
FORMAT_WEBM,
|
||||
FORMAT_MP4,
|
||||
FORMAT_MPGA,
|
||||
FORMAT_WAV,
|
||||
FORMAT_MPEG,
|
||||
} format_t;
|
||||
|
||||
/**
|
||||
* @brief The audio file format to use.
|
||||
*/
|
||||
extern format_t file_type;
|
||||
|
||||
/**
|
||||
* @brief OpenAI API Authentication key.
|
||||
*/
|
||||
extern char OPENAI_API_KEY[OPENAI_API_KEY_MAX_LEN];
|
||||
|
||||
/**
|
||||
* @brief Set the OpenAI API key to use for OpenAI services.
|
||||
*
|
||||
* @param key The API key to set. Must be less than OPENAI_API_KEY_MAX_LEN characters long.
|
||||
*/
|
||||
void set_api_key(const char *key);
|
||||
|
||||
/**
|
||||
* @brief Set the region to use for AI services.
|
||||
*
|
||||
* @param server The server region to set.
|
||||
*/
|
||||
void set_server(const region_t server);
|
||||
|
||||
/**
|
||||
* @brief Set the audio file format to use.
|
||||
*
|
||||
* @param type The audio file format to set.
|
||||
*/
|
||||
void set_audio_type(const format_t type);
|
||||
|
||||
/**
|
||||
* @brief Get the string representation of the audio file format.
|
||||
*
|
||||
* @param file_type The audio file format.
|
||||
* @return The string representation of the audio file format.
|
||||
*/
|
||||
char *get_file_format(format_t file_type);
|
||||
|
||||
/**
|
||||
* @brief Get the message content for the last response from ChatGPT.
|
||||
*
|
||||
* @return The message content for the last response.
|
||||
*/
|
||||
char *get_message_content_for_chatgpt();
|
||||
|
||||
/**
|
||||
* @brief Get the message content for the last response from Whisper AI.
|
||||
*
|
||||
* @return The message content for the last response.
|
||||
*/
|
||||
char *get_message_content_for_whisper();
|
||||
|
||||
/**
|
||||
* @brief Create a ChatGPT request for the given content.
|
||||
*
|
||||
* @param content The content of the request.
|
||||
* @return ESP_OK on success, or an error code otherwise.
|
||||
*/
|
||||
esp_err_t create_chatgpt_request(const char *content);
|
||||
|
||||
/**
|
||||
* @brief Create a Whisper AI request from the recorded audio.
|
||||
*
|
||||
* @param audio The recorded audio to use for the request.
|
||||
* @param audio_len The length of the recorded audio.
|
||||
* @return ESP_OK on success, or an error code otherwise.
|
||||
*/
|
||||
esp_err_t create_whisper_request_from_record(uint8_t *audio, int audio_len);
|
||||
@@ -0,0 +1,9 @@
|
||||
# For more information about build system see
|
||||
# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
|
||||
# The following five lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
add_compile_options(-fdiagnostics-color=always)
|
||||
project(factory_nvs)
|
||||
@@ -0,0 +1,18 @@
|
||||
## TinyUF2 NVS: Adding USB capabilities to ESP-Box
|
||||
|
||||
This standalone project provides support for dumping NVS key-value pairs, allowing users to access and modify the NVS data. They can retrieve the NVS data, make necessary changes, and write the updated values back to the NVS using.
|
||||
|
||||
## Build
|
||||
|
||||
Run `idf.py build` to build and flash the project.
|
||||
|
||||
## Flash
|
||||
|
||||
Since this project functions as a "factory app" for chatgpt_demo, we exclusively employ the "esptool" to flash the binaries. Checkout the [partition table](../partitions.csv)
|
||||
|
||||
```bash
|
||||
python -m esptool -p /dev/ttyACM0 --chip esp32s3 -b 460800 --before default_reset --after hard_reset write_flash --flash_mode dio --flash_size 16MB --flash_freq 80m 0x700000 build/factory_nvs.bin
|
||||
|
||||
```
|
||||
|
||||
Check the [original implementation of Tinyuf2](https://github.com/espressif/esp-iot-solution/tree/master/components/usb/esp_tinyuf2) for more information. For more details of follow the [chatgpt_demo](../README.md) project.
|
||||
@@ -0,0 +1,16 @@
|
||||
set(UI_DIR ./ui)
|
||||
file(GLOB_RECURSE UI_SRCS ${UI_DIR}/*.c)
|
||||
|
||||
set(APP_DIR ./app)
|
||||
file(GLOB_RECURSE APP_SRCS ${APP_DIR}/*.c)
|
||||
|
||||
idf_component_register(
|
||||
SRCS
|
||||
"main.c"
|
||||
${UI_SRCS}
|
||||
${APP_SRCS}
|
||||
INCLUDE_DIRS
|
||||
"."
|
||||
${UI_DIR}
|
||||
${APP_DIR}
|
||||
)
|
||||
@@ -0,0 +1,19 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config ESP_WIFI_SSID
|
||||
string "WiFi SSID"
|
||||
default "My Network SSID"
|
||||
help
|
||||
SSID (network name) for the example to connect to.
|
||||
config ESP_WIFI_PASSWORD
|
||||
string "WiFi Password"
|
||||
default "My Password"
|
||||
help
|
||||
WiFi password (WPA or WPA2) for the example to use.
|
||||
config OPENAI_API_KEY
|
||||
string "OpenAI Key"
|
||||
default "sk-xxxxxxxx"
|
||||
help
|
||||
OpenAI api key for the example to use.
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,19 @@
|
||||
/* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
#include "hal/usb_phy_ll.h"
|
||||
#include "lvgl.h"
|
||||
|
||||
static char *TAG = "NVS: ui-events";
|
||||
|
||||
void EventBtnSetupClick(lv_event_t * e)
|
||||
{
|
||||
ESP_LOGI(TAG, "btn click!");
|
||||
// Configure USB PHY, Change back to USB-Serial-Jtag
|
||||
usb_phy_ll_int_jtag_enable(&USB_SERIAL_JTAG);
|
||||
esp_restart();
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
## IDF Component Manager Manifest File
|
||||
dependencies:
|
||||
espressif/esp_tinyuf2: "^0.1.0"
|
||||
espressif/esp-box: "~2.2.0"
|
||||
## Required IDF version
|
||||
idf:
|
||||
version: ">=5.0"
|
||||
# # Put list of dependencies here
|
||||
# # For components maintained by Espressif:
|
||||
# component: "~1.0.0"
|
||||
# # For 3rd party components:
|
||||
# username/component: ">=1.0.0,<2.0.0"
|
||||
# username2/component2:
|
||||
# version: "~1.0.0"
|
||||
# # For transient dependencies `public` flag can be set.
|
||||
# # `public` flag doesn't have an effect dependencies of the `main` component.
|
||||
# # All dependencies of `main` are public by default.
|
||||
# public: true
|
||||
@@ -0,0 +1,156 @@
|
||||
/* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "esp_tinyuf2.h"
|
||||
#include "ui.h"
|
||||
#include "bsp/esp-bsp.h"
|
||||
#include "esp_ota_ops.h"
|
||||
|
||||
#define NVS_MODIFIED_BIT BIT0
|
||||
#define SSID_SIZE 32
|
||||
#define PASSWORD_SIZE 64
|
||||
#define KEY_SIZE 64
|
||||
|
||||
static const char *TAG = "ChatGPT_NVS";
|
||||
|
||||
static EventGroupHandle_t s_event_group;
|
||||
static nvs_handle_t my_handle;
|
||||
static size_t buf_len_long;
|
||||
|
||||
static void uf2_nvs_modified_cb()
|
||||
{
|
||||
ESP_LOGI(TAG, "uf2 nvs modified");
|
||||
xEventGroupSetBits(s_event_group, NVS_MODIFIED_BIT);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
const esp_partition_t *update_partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_OTA_0, NULL);
|
||||
ESP_LOGI(TAG, "Switch to partition OTA_0");
|
||||
esp_ota_set_boot_partition(update_partition);
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
const char *uf2_nvs_partition = "nvs";
|
||||
const char *uf2_nvs_namespace = "configuration";
|
||||
|
||||
char ssid[SSID_SIZE] = {0};
|
||||
char password[PASSWORD_SIZE] = {0};
|
||||
char key[KEY_SIZE] = {0};
|
||||
|
||||
s_event_group = xEventGroupCreate();
|
||||
|
||||
// Initialize NVS
|
||||
err = nvs_flash_init();
|
||||
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
err = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(err);
|
||||
|
||||
err = nvs_open_from_partition(uf2_nvs_partition, uf2_nvs_namespace, NVS_READWRITE, &my_handle);
|
||||
if (err != ESP_OK) {
|
||||
printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
|
||||
} else {
|
||||
buf_len_long = sizeof(ssid);
|
||||
err = nvs_get_str(my_handle, "ssid", ssid, &buf_len_long);
|
||||
if (err != ESP_OK || buf_len_long == 0) {
|
||||
ESP_ERROR_CHECK(nvs_set_str(my_handle, "ssid", CONFIG_ESP_WIFI_SSID));
|
||||
ESP_ERROR_CHECK(nvs_commit(my_handle));
|
||||
ESP_LOGI(TAG, "no ssid, give a init value to nvs");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "stored ssid:%s", ssid);
|
||||
}
|
||||
|
||||
buf_len_long = sizeof(password);
|
||||
err = nvs_get_str(my_handle, "password", password, &buf_len_long);
|
||||
if (err != ESP_OK || buf_len_long == 0) {
|
||||
ESP_ERROR_CHECK(nvs_set_str(my_handle, "password", CONFIG_ESP_WIFI_PASSWORD));
|
||||
ESP_ERROR_CHECK(nvs_commit(my_handle));
|
||||
ESP_LOGI(TAG, "no password, give a init value to nvs");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "stored password:%s", password);
|
||||
}
|
||||
|
||||
buf_len_long = sizeof(key);
|
||||
err = nvs_get_str(my_handle, "ChatGPT_key", key, &buf_len_long);
|
||||
if (err != ESP_OK || buf_len_long == 0) {
|
||||
ESP_ERROR_CHECK(nvs_set_str(my_handle, "ChatGPT_key", CONFIG_OPENAI_API_KEY));
|
||||
ESP_ERROR_CHECK(nvs_commit(my_handle));
|
||||
ESP_LOGI(TAG, "no ChatGPT key, give a init value to key");
|
||||
} else {
|
||||
ESP_LOGI(TAG, "stored ChatGPT key:%s", key);
|
||||
}
|
||||
}
|
||||
nvs_close(my_handle);
|
||||
|
||||
/* install UF2 NVS */
|
||||
tinyuf2_nvs_config_t nvs_config = DEFAULT_TINYUF2_NVS_CONFIG();
|
||||
nvs_config.part_name = uf2_nvs_partition;
|
||||
nvs_config.namespace_name = uf2_nvs_namespace;
|
||||
nvs_config.modified_cb = uf2_nvs_modified_cb;
|
||||
|
||||
ESP_ERROR_CHECK(esp_tinyuf2_install(NULL, &nvs_config));
|
||||
|
||||
bsp_i2c_init();
|
||||
bsp_display_start();
|
||||
bsp_display_backlight_on();
|
||||
ui_init();
|
||||
|
||||
while (1) {
|
||||
EventBits_t bits = xEventGroupWaitBits(s_event_group, NVS_MODIFIED_BIT,
|
||||
pdTRUE, pdFALSE, portMAX_DELAY);
|
||||
|
||||
if (bits & NVS_MODIFIED_BIT) {
|
||||
esp_err_t err = nvs_open_from_partition(uf2_nvs_partition, uf2_nvs_namespace, NVS_READONLY, &my_handle);
|
||||
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to open NVS partition: %s", esp_err_to_name(err));
|
||||
// Handle the error or take appropriate action
|
||||
return;
|
||||
}
|
||||
|
||||
size_t buf_len_long = sizeof(ssid);
|
||||
err = nvs_get_str(my_handle, "ssid", ssid, &buf_len_long);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to read 'ssid' from NVS: %s", esp_err_to_name(err));
|
||||
nvs_close(my_handle);
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "SSID", ssid);
|
||||
|
||||
buf_len_long = sizeof(password);
|
||||
err = nvs_get_str(my_handle, "password", password, &buf_len_long);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to read 'password' from NVS: %s", esp_err_to_name(err));
|
||||
nvs_close(my_handle);
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "Password", password);
|
||||
|
||||
buf_len_long = sizeof(key);
|
||||
err = nvs_get_str(my_handle, "ChatGPT_key", key, &buf_len_long);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to read 'ChatGPT_key' from NVS: %s", esp_err_to_name(err));
|
||||
nvs_close(my_handle);
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "OpenAI Key", key);
|
||||
|
||||
|
||||
nvs_close(my_handle);
|
||||
}
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user