* @Author: luozheng 1732036298@qq.com
* @Date: 2024-06-20 15:14:43
* @LastEditors: luozheng 1732036298@qq.com
- * @LastEditTime: 2024-09-21 11:07:14
+ * @LastEditTime: 2024-09-26 16:45:56
* @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/include/AiVoiceModel.h
*/
#ifndef AI_VOICE_MODEL_H
void CancelCurAIChat(void);
int GetAIResponseType(void);
std::string GetErrnote(void);
+ void SetErrnote(std::string str);
void SetCurView(int16_t viewNum);
int GetCurView(void);
void ai_stop_screen60s_timer(void);
void reset_ai_screen60s_timer_time();
+ void start_listening_timer(uint32_t interval = 1000);
+ void stop_listening_timer(void);
+
void SetSelectAiModel(int index);
int GetSelectAiModel(void);
* @Author: luozheng 1732036298@qq.com
* @Date: 2024-06-29 17:26:19
* @LastEditors: luozheng 1732036298@qq.com
- * @LastEditTime: 2024-07-16 10:14:28
+ * @LastEditTime: 2024-09-26 15:21:21
* @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/include/AivoiceChatContentListItemView.h
*/
void ResetItemView(int viewHeight, bool isAiAnswerFlag);
private:
- UILabelExt chatContentLabel;
+ UILabel chatContentLabel;
UIImageView chatContentImage;
UIScrollView chatContentScrollView;
int m_viewHeight;
* @Author: luozheng 1732036298@qq.com
* @Date: 2024-06-22 16:46:26
* @LastEditors: luozheng 1732036298@qq.com
- * @LastEditTime: 2024-09-06 17:37:55
+ * @LastEditTime: 2024-09-25 20:34:17
* @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/include/AivoiceListeningView.h
*/
static constexpr int16_t AIVOICE_LISTENING_IMAGE_ANIMATOR_VIEW_W = 240;
static constexpr int16_t AIVOICE_LISTENING_IMAGE_ANIMATOR_VIEW_H = 60;
static constexpr int16_t AIVOICE_LISTENING_IMAGE_ANIMATOR_VIEW_NUM_FRAMES = 40; // 图片帧数
- static constexpr int16_t AIVOICE_LISTENING_IMAGE_ANIMATOR_DELAY = 70; // 图片更新间隔
+ static constexpr int16_t AIVOICE_LISTENING_IMAGE_ANIMATOR_DELAY = 70; // 图片更新间隔
static constexpr char *AIVoiceListeningImagePaths = "/user/res/AIVoice/AIVoiceListening/";
class AivoiceListeningView
{
~AivoiceListeningView();
static AivoiceListeningView *GetInstance(void);
UIScrollView *CreateAivoiceListeningView(void);
+ UILabelExt *GetShowtimeoutLabel(void);
private:
void ClearAll(void);
UIImageAnimatorView *AiVoiceListeningImageAnimatorView{nullptr};
ImageAnimatorInfo AiVoiceListeningImageInfo[AIVOICE_LISTENING_IMAGE_ANIMATOR_VIEW_NUM_FRAMES];
const ImageInfo **AiVoiceListeningPathsArray{nullptr};
+ UILabelExt *showtimeout{nullptr};
};
}
#endif
* @Author: luozheng 1732036298@qq.com
* @Date: 2024-06-20 15:14:50
* @LastEditors: luozheng 1732036298@qq.com
- * @LastEditTime: 2024-09-21 11:13:21
+ * @LastEditTime: 2024-09-26 17:54:07
* @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/src/AiVoiceModel.cpp
*/
#include "aivoice/include/AiVoiceModel.h"
static int Time = THIRTY_TIME;
static int AiModelConnectTimeout = 5;
- AiVoiceModel::AiVoiceModel()
+ AiVoiceModel::AiVoiceModel()
{
CreateDirectory("/user/userdata/AiRecording/");
}
return instance;
}
- bool AiVoiceModel::CreateDirectory(const char* path)
+ bool AiVoiceModel::CreateDirectory(const char *path)
{
- if (access(path, F_OK) == -1) { // 如果路径不存在
+ if (access(path, F_OK) == -1)
+ { // 如果路径不存在
WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Directory %s not exist, creating directory\n", path);
- if (mkdir(path, 0777)!= 0) { // 尝试创建目录,如果创建失败
+ if (mkdir(path, 0777) != 0)
+ { // 尝试创建目录,如果创建失败
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Create directory %s failed\n", path);
return false;
}
- } else { // 如果路径存在
+ }
+ else
+ { // 如果路径存在
WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Directory %s already exists\n", path);
}
return true;
return true;
}
+ /*跳转到AI聆听界面界面*/
bool AiVoiceModel::ChangeToAIVoiceListeningView(bool value)
{
WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::ChangeToReturnResultTextView");
return errnote;
}
+ void AiVoiceModel::SetErrnote(std::string str)
+ {
+ errnote = str;
+ }
+
/*设置当前哪个子视图是可见的*/
void AiVoiceModel::SetCurView(int16_t viewNum)
{
{
AIResponseType = type;
errnote = str;
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AIResponseType = %d,errnote = %s\n", AIResponseType, errnote.c_str());
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AIResponseType = %d,errnote = %s\n", AIResponseType, errnote.c_str());
+ //如果是:AI录音解析错误或AI 回应错误 ->跳转AI回应错误界面
if (AIResponseType == AiVoiceModel::AI_RECORDING_PARSING_ERROR || AIResponseType == AiVoiceModel::AI_RESPONSE_ERROR)
{
SendMsgToUIService(UI_AI_JUMP_TO_RESPONDERR_VIEW, 0, (void *)errnote.c_str(), errnote.length());
{
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AIVoice_TimerCallbackProc,Time = %d", Time);
Time -= 1;
- if (Time == 30)
+ if (Time == 30) //等待一秒,确保录音停止,发送录音准备就绪指令
{
AiVoiceModel::GetInstance().CheckFileAndSendAIIsReady();
- AiVoiceModel::GetInstance().AIVoice_StopTimer();
- return;
+ // AiVoiceModel::GetInstance().AIVoice_StopTimer();
+ // return;
}
if (Time < 0) // 如果思考时间超时30s,进入连接超时界面
{
AiVoiceModel::GetInstance().AIVoice_StopTimer();
-
- AiVoiceView *view_ = AiVoiceView::GetInstance();
- AiVoicePresenter *p_AiVoicePresenter = AiVoicePresenter::GetInstance();
- if (view_ != nullptr && p_AiVoicePresenter != nullptr)
- {
- if ((view_->GetAiVoiceScrollView(AIVOICE_THINKING_VIEWID) != nullptr) &&
- (view_->GetAiVoiceScrollView(AIVOICE_THINKING_VIEWID)->IsVisible()))
- {
- p_AiVoicePresenter->ChangeViewAndLogicOperator(AIVOICE_THINKING_VIEWID, AIVOICE_CONNECT_TIMEOUT_VIEWID);
- }
- }
+ AiVoiceModel::GetInstance().SetErrnote("The connection timed out. Please restart the conversation");
+ std::string str = AiVoiceModel::GetInstance().GetErrnote();
+ SendMsgToUIService(UI_AI_JUMP_TO_RESPONDERR_VIEW, 0, (void *)str.c_str(), str.length());
+ ScreenTurnOn(5 * 1000); // 有消息来就亮屏5秒
}
}
return;
}
}
+ static osTimerId_t g_listeningEndHandle = nullptr;
+ static uint8_t LISTENING_TIMEOUT = 15; // 15s钟无操作关闭该视图
+ static void AIListeningCallbackProc(int data)
+ {
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AIListeningCallbackProc %d", LISTENING_TIMEOUT);
+ if (LISTENING_TIMEOUT <= 0)
+ {
+ AiVoiceModel::GetInstance().StopListenAndRecordingUserQuestion(); //停止聆听用户问题
+ AiVoiceModel::GetInstance().stop_listening_timer(); //停止聆听定时器
+ if (AiVoiceView::GetInstance() && AivoiceListeningView::GetInstance() )
+ {
+ AivoiceListeningView::GetInstance()->GetShowtimeoutLabel()->SetText("");
+ AivoiceListeningView::GetInstance()->GetShowtimeoutLabel()->Invalidate();
+ AiVoiceView::GetInstance()->ChangeView(AIVOICE_LISTENING_VIEWID, AIVOICE_THINKING_VIEWID); // 切换到思考中界面
+
+ AiVoiceModel::GetInstance().AIVoice_StartTimer();
+ }
+ }
+ else
+ {
+ if (AivoiceListeningView::GetInstance())
+ {
+ AivoiceListeningView::GetInstance()->GetShowtimeoutLabel()->SetText(std::to_string(LISTENING_TIMEOUT).c_str());
+ AivoiceListeningView::GetInstance()->GetShowtimeoutLabel()->Invalidate();
+ }
+ }
+ LISTENING_TIMEOUT--;
+ }
+ static void AIListeningCallback(int data)
+ {
+ GraphicService::GetInstance()->PostGraphicEvent(std::bind(AIListeningCallbackProc, data));
+ }
+ // 开启一个AI录音的定时器
+ void AiVoiceModel::start_listening_timer(uint32_t interval)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::start_listening_timer");
+ /* -------------------------- 1.检查定时器是否已经存在,如果存在则返回 ------------------------- */
+ if (g_listeningEndHandle != nullptr)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Timer already exists!!");
+ return;
+ }
+ /* --------------------------------- 2.创建定时器 -------------------------------- */
+ g_listeningEndHandle = osTimerNew((osTimerFunc_t)AIListeningCallback, osTimerPeriodic, nullptr, nullptr);
+ // 检查定时器创建是否成功
+ if (g_listeningEndHandle == nullptr)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Timer create failed!!");
+ return;
+ }
+ /* ----------------------------- 3.将毫秒转换为系统时钟节拍数 ---------------------------- */
+ int tick = osMs2Tick(interval);
+ /* --------------------------------- 4.启动定时器 -------------------------------- */
+ osStatus_t ret = osTimerStart(g_listeningEndHandle, tick);
+ /* -------------------- 5.检查定时器启动是否成功,如果启动失败,删除定时器并置为 nullptr -------------------- */
+ if (ret != osOK)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "osTimerDelete failed, ret = %lx!!", ret);
+ if (g_listeningEndHandle != nullptr)
+ {
+ ret = osTimerDelete(g_listeningEndHandle);
+ }
+ g_listeningEndHandle = nullptr;
+ return;
+ }
+ }
+
+ // 停止一个AI录音的定时器
+ void AiVoiceModel::stop_listening_timer(void)
+ {
+ // 检查定时器是否存在
+ if (g_listeningEndHandle != nullptr)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AiVoiceModel::stop_listening_timer");
+ osTimerStop(g_listeningEndHandle);
+ // 删除定时器并置为 nullptr
+ osStatus_t ret = osTimerDelete(g_listeningEndHandle);
+ if (ret != osOK)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "osTimerDelete failed, ret = %lx!!", ret);
+ }
+ g_listeningEndHandle = nullptr;
+ LISTENING_TIMEOUT = 15;
+ }
+ }
// 设置选择的ai模型
void AiVoiceModel::SetSelectAiModel(int index)
{
* @Author: luozheng 1732036298@qq.com
* @Date: 2024-06-20 15:11:17
* @LastEditors: luozheng 1732036298@qq.com
- * @LastEditTime: 2024-09-07 12:30:56
+ * @LastEditTime: 2024-09-26 16:16:49
* @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/src/AiVoicePresenter.cpp
*/
#include "AppViewIDs.h"
ScreenAlwaysOnCtr(CANCEL_SCREEN_ALWAYS_ON);
model->StatusResume();
model->ai_stop_screen60s_timer();
+ model->stop_listening_timer();
}
/*调转到返回结果界面*/
WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AiVoicePresenter::JumpToReturnResultTextView");
if (view_->GetAiVoiceScrollView(AIVOICE_THINKING_VIEWID) != nullptr && view_->GetAiVoiceScrollView(AIVOICE_THINKING_VIEWID)->IsVisible())
{
- // view_->ChangeView(AIVOICE_THINKING_VIEWID, AIVOICE_RETURN_RESULT_TEXT_VIEWID); // 思考中界面->返回结果
ChangeViewAndLogicOperator(AIVOICE_THINKING_VIEWID, AIVOICE_RETURN_RESULT_TEXT_VIEWID);
}
else
if ((view_->GetAiVoiceScrollView(AIVOICE_THINKING_VIEWID) != nullptr) &&
(view_->GetAiVoiceScrollView(AIVOICE_THINKING_VIEWID)->IsVisible()))
{
- ChangeViewAndLogicOperator(AiVoiceModel::GetInstance().GetCurView(), AIVOICE_CONNECT_TIMEOUT_VIEWID);
+ ChangeViewAndLogicOperator(AIVOICE_THINKING_VIEWID, AIVOICE_CONNECT_TIMEOUT_VIEWID);
AivoiceConnectTimeoutView *p_AivoiceConnectTimeoutView = AivoiceConnectTimeoutView::GetInstance();
if (p_AivoiceConnectTimeoutView)
{
case AIVOICE_LISTENING_VIEWID:
model->StopListenAndRecordingUserQuestion();
+ model->stop_listening_timer();
if (showView == AIVOICE_THINKING_VIEWID) // 聆听中->思考中界面
{
// osal_msleep(500);
* @Author: luozheng 1732036298@qq.com
* @Date: 2024-05-07 11:25:58
* @LastEditors: luozheng 1732036298@qq.com
- * @LastEditTime: 2024-09-07 12:12:53
+ * @LastEditTime: 2024-09-26 15:37:15
* @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/AiVoice/src/AiVoiceView.cpp
*/
#include "aivoice/include/AiVoicePresenter.h"
container_->SetPosition(0, 0, Screen::GetInstance().GetWidth(), Screen::GetInstance().GetHeight());
container_->SetTouchable(true);
container_->SetDraggable(true);
+ container_->SetOnClickListener(presenter_);
if (!viewInitStatus)
{
AiVoiceScrollView[thisView] = p_AivoiceListeningView->CreateAivoiceListeningView();
container_->Add(AiVoiceScrollView[thisView]);
}
+ AiVoiceModel::GetInstance().start_listening_timer();
return true;
}
* @Author: luozheng 1732036298@qq.com
* @Date: 2024-06-29 17:27:25
* @LastEditors: luozheng 1732036298@qq.com
- * @LastEditTime: 2024-07-16 11:19:28
+ * @LastEditTime: 2024-09-26 18:16:34
* @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/aivoice/src/AivoiceChatContentListItemView.cpp
*/
void AivoiceChatContentListItemView::ResetItemView(int viewHeight, bool isAiAnswerFlag)
{
- Resize(ITEM_VIEW_W, viewHeight + ITEM_VIEW_H);
+ if (viewHeight < 120 * CHATCONTENTLABEL_LINE_HEIGHT + 30) // itemView最高为120 * label行高
+ Resize(ITEM_VIEW_W, viewHeight + ITEM_VIEW_H);
chatContentImage.SetPosition(isAiAnswerFlag ? QUESTION_CHATCONTENTIMAGE_X : ANSWER_CHATCONTENTIMAGE_X, 0, 70, 30);
chatContentImage.SetSrc(isAiAnswerFlag ? ANSWER_ITEM_IMAGE_SRC : QUESTION_ITEM_IMAGE_SRC);
chatContentScrollView.SetPosition(isAiAnswerFlag ? QUESTION_CHATCONTENTSCROLLVIEW_X : ANSWER_CHATCONTENTSCROLLVIEW_X, 0);
- chatContentScrollView.Resize(isAiAnswerFlag ? QUESTION_CHATCONTENTSCROLLVIEW_W : ANSWER_CHATCONTENTSCROLLVIEW_W, GetHeight() - 30);
+ if (viewHeight < 120 * CHATCONTENTLABEL_LINE_HEIGHT + 30) // scrollviewView最高为120 * label行高
+ chatContentScrollView.Resize(isAiAnswerFlag ? QUESTION_CHATCONTENTSCROLLVIEW_W : ANSWER_CHATCONTENTSCROLLVIEW_W, GetHeight() - 30);
chatContentScrollView.SetStyle(STYLE_BACKGROUND_COLOR, isAiAnswerFlag ? ANSWER_ITEM_VIEW_COLOR : QUESTION_ITEM_VIEW_COLOR);
- chatContentLabel.Resize(isAiAnswerFlag ? QUESTION_CHATCONTENTLABEL_W : ANSWER_CHATCONTENTLABEL_W, viewHeight);
+ if (viewHeight < 120 * CHATCONTENTLABEL_LINE_HEIGHT) // label最高为120 * label行高
+ {
+ chatContentLabel.Resize(isAiAnswerFlag ? QUESTION_CHATCONTENTLABEL_W : ANSWER_CHATCONTENTLABEL_W, viewHeight);
+ }
+ else
+ {
+ chatContentLabel.SetLineBreakMode(isAiAnswerFlag ? UILabel::LINE_BREAK_ELLIPSIS : UILabel::LINE_BREAK_WRAP);//超过高度在末尾用省略号替换
+ }
}
void AivoiceChatContentListItemView::SetUpChild()
* @Author: luozheng 1732036298@qq.com
* @Date: 2024-05-07 11:25:58
* @LastEditors: luozheng 1732036298@qq.com
- * @LastEditTime: 2024-09-06 17:17:03
+ * @LastEditTime: 2024-09-26 15:39:03
* @FilePath: /FD230/code/sdk/application/wearable/fd230app/nativeui/AiVoice/src/AivoiceListeningView.cpp
*/
#include "aivoice/include/AiVoicePresenter.h"
FreeImageInfoArray(AiVoiceListeningPathsArray, AIVoiceListeningImagePaths, AIVOICE_LISTENING_IMAGE_ANIMATOR_VIEW_NUM_FRAMES);
}
+ if (showtimeout != nullptr)
+ {
+ delete showtimeout;
+ showtimeout = nullptr;
+ }
+
if (finishSpeak != nullptr)
{
delete finishSpeak;
WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::finishSpeak is nullptr!");
return false;
}
+ /* -------------------------------------------------------------------------- */
+ showtimeout = new UILabelExt();
+ if (showtimeout == nullptr)
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::showtimeout is nullptr!");
+ return false;
+ }
+ showtimeout->SetPosition(60, 258, 240, 60);
+ showtimeout->SetStyle(STYLE_TEXT_FONT, 50);
+ showtimeout->SetStyle(STYLE_LINE_HEIGHT, 60);
+ showtimeout->SetLineBreakMode(UILabel::LINE_BREAK_ELLIPSIS);
+ showtimeout->SetAlign(TEXT_ALIGNMENT_CENTER, TEXT_ALIGNMENT_CENTER);
+ showtimeout->SetFont(DEFAULT_VECTOR_FONT_FILENAME, 50);
return true;
}
UIScrollView *AivoiceListeningView::CreateAivoiceListeningView(void)
{
WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::CreateAivoiceListeningView");
+#if 0
if (scrollView == nullptr)
{
if (!CreateAivoiceListeningScrollView() || !CreateAivoiceListeningLabel() ||
scrollView->Add(finishSpeakButton);
scrollView->Add(finishSpeak);
}
- return scrollView;
+#else
+ if (!CreateAivoiceListeningScrollView())
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::CreateAivoiceListeningScrollView fail!!");
+ }
+ if (!CreateAivoiceListeningLabel())
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::CreateAivoiceListeningLabel fail!!");
+ }
+ if (!CreateAivoiceListeningButton())
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::CreateAivoiceListeningButton fail!!");
+ }
+ if (!CreateAivoiceListeningImageAnimator())
+ {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "AivoiceListeningView::CreateAivoiceListeningImageAnimator fail!!");
+ }
+ if (scrollView == nullptr)
+ {
+ return nullptr;
+ }
+ else
+ {
+ if (title)
+ {
+ scrollView->Add(title);
+ }
+ if (AiVoiceListeningImageAnimatorView)
+ {
+ scrollView->Add(AiVoiceListeningImageAnimatorView);
+ }
+ if (showtimeout)
+ {
+ showtimeout->SetX((scrollView->GetWidth() - showtimeout->GetWidth()) / 2);
+ scrollView->Add(showtimeout);
+ }
+ if (finishSpeakButton)
+ {
+ scrollView->Add(finishSpeakButton);
+ }
+ if (finishSpeak)
+ {
+ scrollView->Add(finishSpeak);
+ }
+ return scrollView;
+ }
+#endif
+ }
+
+ UILabelExt *AivoiceListeningView::GetShowtimeoutLabel(void)
+ {
+ return showtimeout;
}
}
\ No newline at end of file
std::bind(&OHOS::AiVoiceModel::ChangeToAIVoiceListeningView, &OHOS::AiVoiceModel::GetInstance(), state));
}
- // 处理更新查询AI模型是否连接成功的状态
+ // 处理跳转AI回应错误界面
void HandleAiJumpToRespondErrMessage(Request *request)
{
WEARABLE_LOGI(WEARABLE_LOG_MODULE_UI_SERVICE, "HandleAiJumpToRespondErrMessage");
};
/** Maximum number of lines */
- static constexpr uint16_t MAX_LINE_COUNT = 50;
+ static constexpr uint16_t MAX_LINE_COUNT = 120;//原50行,现修改为120行
static TextLine textLine_[MAX_LINE_COUNT];
static constexpr int16_t TEXT_ELLIPSIS_DOT_NUM = 3;