首页 > 其他分享 >构建交互式聊天界面-2

构建交互式聊天界面-2

时间:2024-12-05 22:20:56浏览次数:4  
标签:const messageList item useState 聊天 交互式 import 界面 newMessageList

1. 前情回顾

基于之前的需求,我们的聊天中包含一些简单的交互功能,例如语音转文本:

  1. 用户点击语音识别按钮,前端进行语音转文字操作,此时页面展示“Please Talk, I am listening”的消息,消息的左侧包含动画效果
  2. 再次点击语音识别按钮,将转换后的文字展示出来,供用户确认
  3. 用户点击确认后,将发送确认的文本
  4. 用户点击取消后,取消所有的消息展示

我们将之前的这几篇结合起来实现该需求:

react-chat-element 实战小计

语音转文字

雪碧图

2. 功能实现

  • loading动画

使用 gka 生成雪碧图,建议将该效果封装为组件

  1. 安装 gka 工具

    npm install gka -g
  2. 生成雪碧图:使用 gka 处理你的动画帧图片,生成雪碧图和 CSS 文件。

    gka dir path/to/your/images -o path/to/output -u -m -s

    这里,path/to/your/images 是包含你所有帧图片的目录,path/to/output 是输出目录。-u 选项用于相同图片复用优化,-m 用于图片压缩,-s 用于合图优化

  3. 编写组件代码:在 LoadingSpinner.js 中,引入生成的雪碧图和 CSS 文件,并创建一个组件,该组件使用 div 来显示雪碧图,并通过修改 div 的样式来调整动画的大小

    import React from 'react';
    import spriteSheet from './path/to/output/sprites.png'; // 雪碧图路径
    import './path/to/output/gka.css'; // gka 生成的 CSS 文件
    
    const LoadingSpinner = ({ size = '100px' }) => {
      return (
        <div className="gka-base" style={{ width: size, height: size, backgroundImage: `url(${spriteSheet})` }}></div>
      );
    };
    
    export default LoadingSpinner;

    在这个组件中,size 是一个可选 props,允许动态设置组件的大小。

  • 语音录入时展示 "Listening Message"

import { useEffect, useState } from 'react';
import { MessageBox } from 'react-chat-elements';
import 'react-chat-elements/dist/main.css';
import AISVG from '@/assets/imgs/AI.svg';
import UserSVG from '@/assets/imgs/user.svg';
import LoadingSpinner from '../LoadingSpinner';

const MessageList = () => {
  const [messageList, setMessageList] = useState([]);
  const [maskVisible, setMaskVisible] = useState(false);
  const [loadingTimer, setLoadingTimer] = useState(null);
  const [textToConfirm, setTextToConfirm] = useState('');

  useEffect(() => {
    scrollToBottom();
  }, [messageList]);

  const scrollToBottom = () => {
    const msgElement = document.getElementById('message-list');
    const scrollTop = msgElement.scrollTop;
    const scrollHeight = msgElement.scrollHeight;
    const clientHeight = msgElement.clientHeight;
    msgElement.scrollTop = scrollHeight - clientHeight;
  };

  const handleOpenFile = async (e, item) => {
    // 文件点击逻辑
  };
    
  const addListeningMessgae = () => {
    const newMessageList = messageList?.filter((item) => item.key !== 'speech2text');
    const newMessage = {
      key: 'speech2text',
      type: 'text',
      content: (
        <div className="listening-item">
          <div className="listening-item-text">
            <LoadingSpinner size="30px" />
            {'Please talk, I am listening...'}
          </div>
        </div>
      ),
      data: {
        listening: true
      }
    };
    newMessageList.push(newMessage);
    setMessageList(newMessageList);
  };

  return (
    <>
      <div className="message-list" id="message-list" onScroll={() => scrollToBottom()}>
            <MessageBox
              avatar={AISVG}
              position="left"
              type="text"
              text="Hello, I am Univers AI. I am the first professional AI in the sustainable industry, dedicated to helping you optimize your building systems."
              className="message-item message-item-left"
            />
            <div className="init-list">
              {!messageList?.length &&
                initContents.map((item, index) => (
                  <InitComponent title={item?.title} content={item?.content} key={item?.key} index={index} tabKey={item?.key} />
                ))}
            </div>
            {messageList.map((item) => (
              <MessageBox
                key={item?.key}
                avatar={item?.isBot ? UserSVG : AISVG}
                position={item?.isBot ? 'right' : 'left'}
                type={item?.type}
                text={item?.type === 'text' ? item?.content : item?.text}
                data={item?.data}
                onOpen={item?.type === 'photo' || item?.type === 'file' ? (e) => handleOpenFile(e, item) : null}
                onDownload={item?.type === 'photo' || item?.type === 'file' ? (e) => handleOpenFile(e, item) : null}
              />
            ))}
        )}
      </div>
    </>
  );
};
export default MessageList;
  • 语音录入停止后展示"Text Confirm Message"

const addConfirmMessage = () => {
    const newMessageList = messageList?.filter((item) => item.key !== 'speech2text');
    const newMessage = {
      key: 'speech2text',
      type: 'text',
      content: (
        <div className="listening-item">
          <div className="listening-item-text">
            <LoadingSpinner size="30px" />
            {textToConfirm || 'Please talk, I am listening...'}
          </div>
          {!speaking && renderOptions()}
        </div>
      ),
      data: {
        listening: true
      }
    };
    newMessageList.push(newMessage);
    setMessageList(newMessageList);
  };

const renderOptions = () => {
    return (
      <div className="listening-item-options">
        <div className="listening-item-options-item reject" onClick={rejectText}>
          ×
        </div>
        <div className="listening-item-options-item confirm" onClick={confirmText}>
          √
        </div>
      </div>
    );
  };

  const rejectText = () => {
    // 停止语音识别
    recognizer?.stopContinuousRecognitionAsync();
    const newMessageList = messageList.filter((item) => item.key !== 'speech2text');
    setMessageList(newMessageList);
    setTextToConfirm('');
  };

  const confirmText = () => {
     // 停止语音识别
    recognizer?.stopContinuousRecognitionAsync();
    const newMessageList = [...messageList];
    newMessageList[newMessageList.length - 1] = {
      key: uuid(),
      type: 'text',
      content: textToConfirm
    };
    setMessageList(newMessageList);
    setTextToConfirm('');
  };

效果展示

3. 文字打字机效果

  1. 定义组件:在组件中,使用状态来存储当前显示的文本,并使用一个副作用来逐步更新这个状态,模拟打字机的打字效果。

  2. 实现打字机逻辑:在 useEffect 中,使用 setInterval 来逐字显示文本,直到文本完成。

  3. 清理定时器:确保在组件卸载时清除定时器,避免内存泄漏。

import React, { useState, useEffect } from 'react';

function Typewriter({ text, typingSpeed }) {
  const [displayText, setDisplayText] = useState('');
  const [currentIndex, setCurrentIndex] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      if (currentIndex < text.length) {
        setDisplayText((prevText) => prevText + text[currentIndex]);
        setCurrentIndex((prevIndex) => prevIndex + 1);
      } else {
        clearInterval(interval);
      }
    }, typingSpeed);
    return () => {
      clearInterval(interval);
    };
  }, [text, typingSpeed, currentIndex]);

  return <div>{displayText}</div>;
}

export default Typewriter;

 

标签:const,messageList,item,useState,聊天,交互式,import,界面,newMessageList
From: https://www.cnblogs.com/little-sheep10/p/18585231

相关文章

  • Charts 教程:创建交互式图表的基础
    ECharts是一个开源的、基于JavaScript的数据可视化库,它可以帮助你快速创建交互式的图表。无论是简单的柱状图、折线图,还是复杂的地图和关系图,ECharts都能够轻松应对。本文将带你了解如何在你的网页中使用ECharts创建图表,并介绍一些基本概念和常见的配置项。1.什么是E......
  • 界面控件DevExpress WinForms中文教程:Data Grid - Best Fit选项
    DevExpressWinForms拥有180+组件和UI库,能为WindowsForms平台创建具有影响力的业务解决方案。DevExpressWinForms能完美构建流畅、美观且易于使用的应用程序,无论是Office风格的界面,还是分析处理大批量的业务数据,它都能轻松胜任!本文主要介绍如何使用DevExpressWinFormsDataGr......
  • Qt编写嵌入式linux输入法/支持自定义词语和繁体/支持wayland和watson/纯QWidget/界面
    一、功能特点纯QWidget编写,原创输入法机制,没有任何第三方动态库的依赖。支持各种Qt版本,包括Qt4、Qt5、Qt6及后续版本。支持各种编译器,包括mingw、msvc、gcc、clang、wasm等。支持各种目标平台,包括windows、linux、macos、android、嵌入式linux等。支持任意控件输入,包括文本......
  • PyQt设计界面优化 #qss #ui设计 #QMainWindow
    思维导图 通过qss实现ui界面设计优化 Qss是Qt程序界面中用来设置控件的背景图片、大小、字体颜色、字体类型、按钮状态变化等属性,它是用来美化UI界面。实现界面和程序的分离,快速切换界面。首先我们在Pytchram创建一个新目录  然后将我们所需要的图片打包到文件......
  • Linux无图形界面环境使用Python+Selenium实践 (转载)
    原文链接:https://developer.aliyun.com/article/1511623简介: 在Linux上使用Selenium和Python来控制浏览器进行自动化测试或者网页数据抓取是常见的需求。本文将介绍如何在Linux无图形界面环境下使用Selenium与Firefox浏览器以headless模式运行,并提供geckodriver、Xvfb和pyvirtu......
  • 国标GB28181设备管理软件LiteGBS国标GB28181公网直播摄像头网页界面无法访问怎么办?
    随着智能化升级、云化与大数据应用与技术的不断深入,视频监控技术有望在公共安全、城市管理、企业安防等领域发挥更加重要的作用,提供更优质的视频智能解决方案。那么当遇到摄像头网页界面无法访问时,应该怎么办呢?问题排查1、设备供电是否正常观察刚上电的时候IPC红外灯是否亮,如......
  • 11Labs 推出 Conversational AI,可定制交互式语音智能体;Recall.ai:视频会议智能体通用 A
       开发者朋友们大家好: 这里是「RTE开发者日报」,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享RTE(Real-TimeEngagement)领域内「有话题的新闻」、「有态度的观点」、「有意思的数据」、「有思考的文章」、「有看点的会议」,但内容仅代表编......
  • 兰亭妙微 UI:雕琢医疗界面,绘就健康新篇
    在医疗数字化的浪潮中,界面设计成为连接医患、传递健康的关键桥梁。兰亭妙微UI设计公司,以匠心独运之笔,为医疗行业勾勒出未来的蓝图。我们深入洞察医疗场景,从患者的便捷就医到医生的高效诊疗,每一处交互都精心打磨。简洁直观的操作流程,让患者在病痛中不再为复杂的挂号、问诊步骤......
  • uniapp精仿微信源码,基于SumerUI和Uniapp前端框架的一款仿微信APP应用,界面漂亮颜值高,视
    uniapp精仿微信源码,基于SumerUI和Uniapp前端框架的一款仿微信APP应用,界面漂亮颜值高,视频商城小工具等,朋友圈视频号即时聊天用于视频,商城,直播,聊天,等等场景,源码分享sumer-weixin介绍uniapp精仿微信,基于SumerUI3.0和Uniapp前端框架的一款仿微信APP应用,界面漂亮颜值高,视频......
  • 基于jQuery UI的仿PhotoShop界面屏幕标尺插件
    在线演示 下载 jQueryUI.Ruler是一款基于Jquery.UI的仿Photoshop界面的屏幕标尺插件。该插件可以在一个DOM元素上使用屏幕标尺,这个元素可以是body元素,也可以是一个div元素。它的特点有:支持多种尺寸单位:px,mm,cm,in。支持三种刻度模式:major,minor,micro。支持鼠标......