开源项目——小Q聊天机器人V1.4
小Q聊天机器人V1.0 http://blog.csdn.net/baiyuliang2013/article/details/51386281
小Q聊天机器人V1.1 http://blog.csdn.net/baiyuliang2013/article/details/51395163
小Q聊天机器人V1.2 http://blog.csdn.net/baiyuliang2013/article/details/51424971
小Q聊天机器人V1.3 http://blog.csdn.net/baiyuliang2013/article/details/51443156
小Q聊天机器人V1.4 http://blog.csdn.net/baiyuliang2013/article/details/51454161
小Q聊天机器人V1.5 http://blog.csdn.net/baiyuliang2013/article/details/51461008
GitHub:https://github.com/baiyuliang/QRobot
应用市场已上线,扫码体验:
注意:发送消息后如果小Q没回答,或回答“亲爱的,当天请求次数已用完”,表示当天的api调用次数已经超过限制次数,大家可以自己申请apikey用于测试!(音乐和位置功能不受影响)
V1.4版本中,对来聊天界面不同消息布局进行了优化,使得聊天消息类型的扩展性更强!1.4之前的版本我们知道,我是将各种消息类型布局全部集中在了一个xml中,这种方式对少量消息类型的应用还可以,如果消息类型过多,那么这种方式就显得很low了,而且影响性能!1.4版本中,将各种消息类型逐一拆分(并且发送和接收一一对应),在adapter中根据消息类型去加载不同view:
同时使用了通用ViewHolder,我们可以比较下1.4之前版本和1.4版本中adapter的getview部分:
1.4之前:
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHodler hodler;
if (convertView == null) {
hodler = new ViewHodler();
convertView = LayoutInflater.from(mContext).inflate(R.layout.chat_lv_item, null);
hodler.rl_chat = (RelativeLayout) convertView.findViewById(R.id.rl_chat);//聊天布局
//接收的消息
hodler.fromIcon = (CircleImageView) convertView.findViewById(R.id.chatfrom_icon);//他人头像
hodler.toIcon = (CircleImageView) convertView.findViewById(R.id.chatto_icon);//自己头像
hodler.fromContainer = (LinearLayout) convertView.findViewById(R.id.chart_from_container);
hodler.fromText = (TextView) convertView.findViewById(R.id.chatfrom_content);//文本
hodler.fromImg = (ImageView) convertView.findViewById(R.id.chatfrom_img);//图片
hodler.fromLocation = (ImageView) convertView.findViewById(R.id.chatfrom_location);//位置
hodler.ll_music = (LinearLayout) convertView.findViewById(R.id.ll_music);//音乐
hodler.iv_music= (ImageView) convertView.findViewById(R.id.iv_music);
hodler.pb_music=(ProgressBar)convertView.findViewById(R.id.pb_music);
hodler.tv_song_name = (TextView) convertView.findViewById(R.id.tv_song_name);//音乐名
hodler.tv_song_author = (TextView) convertView.findViewById(R.id.tv_song_author);//音乐作者
hodler.progress_load = (ProgressBar) convertView.findViewById(R.id.progress_load);//ProgressBar
//发送的消息
hodler.toContainer = (RelativeLayout) convertView.findViewById(R.id.chart_to_container);
hodler.toText = (TextView) convertView.findViewById(R.id.chatto_content);//文本
hodler.toImg = (ImageView) convertView.findViewById(R.id.chatto_img);//图片
hodler.toLocation = (ImageView) convertView.findViewById(R.id.chatto_location);//位置
//时间
hodler.time = (TextView) convertView.findViewById(R.id.chat_time);
convertView.setTag(hodler);
} else {
hodler = (ViewHodler) convertView.getTag();
}
final Msg msg = list.get(position);
if (msg.getIsComing() == 0) {// 收到消息 from显示
hodler.toContainer.setVisibility(View.GONE);//隐藏右侧布局
hodler.fromContainer.setVisibility(View.VISIBLE);
hodler.time.setText(msg.getDate());
if (msg.getType().equals(Const.MSG_TYPE_TEXT)) {//文本类型
hodler.fromText.setVisibility(View.VISIBLE);//文本
hodler.fromImg.setVisibility(View.GONE);//图片
hodler.fromLocation.setVisibility(View.GONE);//位置
hodler.ll_music.setVisibility(View.GONE);//音乐
hodler.progress_load.setVisibility(View.GONE);
SpannableStringBuilder sb = ExpressionUtil.prase(mContext, hodler.fromText, msg.getContent());// 对内容做处理
hodler.fromText.setText(sb);
Linkify.addLinks(hodler.fromText, Linkify.ALL);//增加文本链接类型
} else if (msg.getType().equals(Const.MSG_TYPE_IMG)) {//图片类型
hodler.fromText.setVisibility(View.GONE);//文本
hodler.fromImg.setVisibility(View.VISIBLE);//图片
hodler.fromLocation.setVisibility(View.GONE);//位置
hodler.ll_music.setVisibility(View.GONE);//音乐
hodler.progress_load.setVisibility(View.GONE);
finalImageLoader.display(hodler.fromImg, msg.getContent());//加载图片
} else if (msg.getType().equals(Const.MSG_TYPE_LOCATION)) {//位置类型
hodler.fromText.setVisibility(View.GONE);//文本
hodler.fromImg.setVisibility(View.GONE);//图片
hodler.fromLocation.setVisibility(View.VISIBLE);//位置
hodler.ll_music.setVisibility(View.GONE);//音乐
hodler.progress_load.setVisibility(View.GONE);
finalImageLoader.display(hodler.fromLocation, msg.getContent());//加载网络图片
} else if (msg.getType().equals(Const.MSG_TYPE_MUSIC)) {//音乐类型
hodler.fromText.setVisibility(View.GONE);//文本
hodler.fromImg.setVisibility(View.GONE);//图片
hodler.fromLocation.setVisibility(View.GONE);//位置
hodler.ll_music.setVisibility(View.VISIBLE);//音乐
hodler.progress_load.setVisibility(View.GONE);
if(!TextUtils.isEmpty(msg.getBak1())&&msg.getBak1().equals("1")){
hodler.pb_music.setVisibility(View.VISIBLE);
hodler.iv_music.setVisibility(View.GONE);
}else{
hodler.pb_music.setVisibility(View.GONE);
hodler.iv_music.setVisibility(View.VISIBLE);
}
String[] musicinfo = msg.getContent().split(",");
if (musicinfo.length==3) {//音乐链接,歌曲名,作者
hodler.tv_song_name.setText(musicinfo[1]);
hodler.tv_song_author.setText(musicinfo[2]);
}
}
} else {// 发送消息 to显示(目前发送消息只能发送文本类型,后期将会增加其它类型)
hodler.toContainer.setVisibility(View.VISIBLE);
hodler.fromContainer.setVisibility(View.GONE);
hodler.time.setText(msg.getDate());
if (msg.getType().equals(Const.MSG_TYPE_TEXT)) {//文本类型
hodler.toText.setVisibility(View.VISIBLE);//文本
hodler.toImg.setVisibility(View.GONE);//图片
hodler.toLocation.setVisibility(View.GONE);//位置
SpannableStringBuilder sb = ExpressionUtil.prase(mContext, hodler.toText, msg.getContent());// 对内容做处理
hodler.toText.setText(sb);
Linkify.addLinks(hodler.toText, Linkify.ALL);
} else if (msg.getType().equals(Const.MSG_TYPE_IMG)) {//图片类型
hodler.toText.setVisibility(View.GONE);//文本
hodler.toImg.setVisibility(View.VISIBLE);//图片
hodler.toLocation.setVisibility(View.GONE);//位置
finalImageLoader.display(hodler.toImg, msg.getContent());//加载图片
} else if (msg.getType().equals(Const.MSG_TYPE_LOCATION)) {//位置类型
hodler.toText.setVisibility(View.GONE);//文本
hodler.toImg.setVisibility(View.GONE);//图片
hodler.toLocation.setVisibility(View.VISIBLE);//位置
finalImageLoader.display(hodler.toLocation, msg.getContent());//加载网络图片
}
}
// 文本点击
hodler.fromText.setOnClickListener(new onClick(position));
hodler.fromText.setOnLongClickListener(new onLongCilck(position));
hodler.toText.setOnClickListener(new onClick(position));
hodler.toText.setOnLongClickListener(new onLongCilck(position));
//图片点击
hodler.fromImg.setOnClickListener(new onClick(position));
hodler.fromImg.setOnLongClickListener(new onLongCilck(position));
hodler.toImg.setOnClickListener(new onClick(position));
hodler.toImg.setOnLongClickListener(new onLongCilck(position));
//位置
hodler.fromLocation.setOnClickListener(new onClick(position));
hodler.fromLocation.setOnLongClickListener(new onLongCilck(position));
hodler.toLocation.setOnClickListener(new onClick(position));
hodler.toLocation.setOnLongClickListener(new onLongCilck(position));
//音乐
hodler.ll_music.setOnClickListener(new onClick(position));
hodler.ll_music.setOnLongClickListener(new onLongCilck(position));
return convertView;
}
class ViewHodler {
RelativeLayout rl_chat;
CircleImageView fromIcon, toIcon;
ImageView fromImg, fromLocation, toImg, toLocation;
TextView fromText, toText, time;
LinearLayout fromContainer;
RelativeLayout toContainer;
ProgressBar progress_load;
//音乐
LinearLayout ll_music;
ImageView iv_music;
ProgressBar pb_music;
TextView tv_song_name, tv_song_author;
}
1.4版本:
final Msg msg = list.get(position);
if (convertView == null) {
convertView = createViewByType(msg, position);
}
CircleImageView head_view = ViewHolder.get(convertView, R.id.head_view);//头像
TextView chat_time = ViewHolder.get(convertView, R.id.chat_time);//时间
TextView tv_text = ViewHolder.get(convertView, R.id.tv_text);//文本
ImageView iv_image = ViewHolder.get(convertView, R.id.iv_image);//图片
ImageView iv_location = ViewHolder.get(convertView, R.id.iv_location);//位置
LinearLayout layout_voice = ViewHolder.get(convertView, R.id.layout_voice);//语音 语音播放按钮父控件
ImageView iv_voice = ViewHolder.get(convertView, R.id.iv_voice);//动画
ImageView iv_fy = ViewHolder.get(convertView, R.id.iv_fy);//翻译按钮
final TextView tv_fy = ViewHolder.get(convertView, R.id.tv_fy);//翻译内容
LinearLayout ll_music = (LinearLayout) convertView.findViewById(R.id.ll_music);//音乐
ImageView iv_music = (ImageView) convertView.findViewById(R.id.iv_music);
ProgressBar pb_music = (ProgressBar) convertView.findViewById(R.id.pb_music);
TextView tv_song_name = (TextView) convertView.findViewById(R.id.tv_song_name);//音乐名
TextView tv_song_author = (TextView) convertView.findViewById(R.id.tv_song_author);//音乐作者
chat_time.setText(msg.getDate());//时间
switch (msg.getType()) {
case Const.MSG_TYPE_TEXT://文本
tv_text.setText(msg.getContent());
tv_text.setOnClickListener(new onClick(position));
tv_text.setOnLongClickListener(new onLongCilck(position));
break;
case Const.MSG_TYPE_IMG://图片
finalImageLoader.display(iv_image, msg.getContent());
iv_image.setOnClickListener(new onClick(position));
iv_image.setOnLongClickListener(new onLongCilck(position));
break;
case Const.MSG_TYPE_LOCATION://位置
finalImageLoader.display(iv_location, msg.getContent());
iv_location.setOnClickListener(new onClick(position));
iv_location.setOnLongClickListener(new onLongCilck(position));
break;
case Const.MSG_TYPE_VOICE://语音
final String[] _content = msg.getContent().split(Const.SPILT);
tv_fy.setText(_content[1]);
tv_fy.setVisibility(View.GONE);
layout_voice.setOnClickListener(new RecordPlayClickListener(mContext, iv_voice, _content[0]));
iv_fy.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (tv_fy.getVisibility() == View.GONE) {
tv_fy.setVisibility(View.VISIBLE);
}else{
tv_fy.setVisibility(View.GONE);
}
}
});
layout_voice.setOnLongClickListener(new onLongCilck(position));
break;
case Const.MSG_TYPE_MUSIC://音乐
if (!TextUtils.isEmpty(msg.getBak1()) && msg.getBak1().equals("1")) {
pb_music.setVisibility(View.VISIBLE);
iv_music.setVisibility(View.GONE);
} else {
pb_music.setVisibility(View.GONE);
iv_music.setVisibility(View.VISIBLE);
}
String[] musicinfo = msg.getContent().split(Const.SPILT);
if (musicinfo.length == 3) {//音乐链接,歌曲名,作者
tv_song_name.setText(musicinfo[1]);
tv_song_author.setText(musicinfo[2]);
}
ll_music.setOnClickListener(new onClick(position));
ll_music.setOnLongClickListener(new onLongCilck(position));
break;
}
return convertView;
就拿代码行数来说就非常直观,而且1.4版本中还增加了语音消息类型!代码简洁,逻辑更加清晰,扩展也更加容易,这也算的上IM应用的标准写法啦!
好了,接下来看看1.4版本中增加了哪些功能:
1.增加语音聊天功能及语音翻译功能:
1.4之前是录音完毕后转为文字并放进输入框,手动发送,而1.4版本中录音完毕后,可以转为语音形式自动发送,可点击播放,也可点击翻译按钮翻译成文字形式,类似QQ,看效果图:
看完你肯定会想问我是如何实现的,是直接识别音频文件并将音频文件转为文字吗?这么高大上?——哈哈,非也,其实我是取巧!在使用讯飞语音(录音)的参数设置代码中,看到如下代码:
mIat.setParameter(SpeechConstant.ASR_AUDIO_PATH, Const.FILE_VOICE_CACHE + "iat.wav");
这个文件就是每次说话时,自动生成的音频文件,那么你刚说完的话,直接取这个音频文件播放不就可以了吗?!当然,你需要复制这个文件或者说移动这个文件,并修改文件名,否则你原封不动的话,下次录音不久吧上次录音的文件覆盖掉了吗?
/**
* 移动文件
* @param oldPath
* @param newPath
* @return
*/
public static boolean copyFile(String oldPath, String newPath) {
File oldFile = new File(oldPath);
if (!oldFile.exists()) {
return false;
}
if(oldFile.renameTo(new File(newPath))){
return true;
}else{
return false;
}
}
音频文件路径有了,而语音识别后的文本也是讯飞直接识别后生成的,现在音频文件路径和对应的语音识别文本都有了,将其存储起来,那么所谓的语音聊天,语音翻译实现也就顺理成章了!(哎,还以为是多么高大上呢,原来是投机取巧啊^^)
2.增加录音发送形式和回复自动朗读设置:
录音以语音形式发送,即录音完毕,直接以语音形式发送;
录音以文字形式发送,即录音完毕,转为文字形式手动发送;
回复内容直接朗读,即文本形式的回复直接朗读出来!
开源项目——小Q聊天机器人V1.4的更多相关文章
- 开源项目——小Q聊天机器人V1.3
小Q聊天机器人V1.0 http://blog.csdn.net/baiyuliang2013/article/details/51386281 小Q聊天机器人V1.1 http://blog.csd ...
- 开源项目——小Q聊天机器人V1.0
小Q聊天机器人V1.0 http://blog.csdn.net/baiyuliang2013/article/details/51386281 小Q聊天机器人V1.1 http://blog.csd ...
- 开源项目——小Q聊天机器人V1.2
小Q聊天机器人V1.0 http://blog.csdn.net/baiyuliang2013/article/details/51386281 小Q聊天机器人V1.1 http://blog.csd ...
- 开源项目——小Q聊天机器人V1.1
小Q聊天机器人V1.0 http://blog.csdn.net/baiyuliang2013/article/details/51386281 小Q聊天机器人V1.1 http://blog.csd ...
- 开源项目——小Q聊天机器人V1.5
小Q聊天机器人V1.0 http://blog.csdn.net/baiyuliang2013/article/details/51386281 小Q聊天机器人V1.1 http://blog.csd ...
- QQ 聊天机器人小薇 2.1.0 发布!
本次发布加入了支持茉莉机器人,并且更容易搭建开发环境,在线显示登录二维码~ 简介 XiaoV(小薇)是一个用 Java 写的 QQ 聊天机器人 Web 服务,可以用于社群互动: 监听多个 QQ 群消息 ...
- Python进阶开发之网络编程,socket实现在线聊天机器人
系列文章 √第一章 元类编程,已完成 ; √第二章 网络编程,已完成 ; 本文目录 什么是socket?创建socket客户端创建socket服务端socket工作流程图解socket公共函数汇总实战 ...
- 打造一个高逼格的android开源项目——小白全攻略 (转)
转自:打造一个高逼格的android开源项目 小引子 在平时的开发过程中,我们经常会查阅很多的资料,最常参考的是 github 的开源项目.通常在项目的主页面能看到项目的简介和基本使用,并且时不时能看 ...
- TensorFlow 聊天机器人开源项目评测第一期:DeepQA
聊天机器人开源项目评测第一期:DeepQA https://github.com/Conchylicultor/DeepQA 用 i5 的笔记本早上运行到下午,跑了 3 轮的结果,最后效果并不理想.官 ...
随机推荐
- Postgres中postmaster代码解析(中)
今天我们对postmaster的以下细节进行讨论: backend的启动和client的连接请求的认证 客户端取消查询时的处理 接受pg_ctl的shutdown请求进行shutdown处理 2.与前 ...
- PHP查看本地文件夹及删除文件夹操作
查看文件夹(包括文件夹内所有的文件夹和文件) function descdir($dir){ if(is_dir($dir)){ if($dh=opendir($dir)){ while(($file ...
- python中读取文件数据时要注意文件路径
我们在用python进行数据处理时往往需要将文件中的数据取出来做一些处理,这时我们应该注意数据文件的路径.文件路径不对,回报如下错误: FileNotFoundError: File b'..Adve ...
- 从零开始搭建口袋妖怪管理系统(2)-借助ngRoute实现详情页面跳转
一.目标 上一次我们用Angular1.x完成了简单的口袋妖怪展示列表页面,现在我们想要了解口袋妖怪更多的信息,但是发现原有单行表格可能容纳不下口袋妖怪的所有信息,所以现在我们需要一个口袋妖怪详情界面 ...
- BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext
这个坑爹的玩意 有几个出现错误的原因 服务器 1.服务器重复启动同一个部署 这个时候要停止然后启动 电脑差的 重启电脑 重启服务器就好了 代码 2.bean工厂不知道哪里关闭 3.bean工厂没有找到 ...
- 微信内置浏览器 如何小窗不全屏播放视频?也可以尝试canvas.
设置属性: <video height="100%" width="100%" autoplay="autoplay" control ...
- Lucene——Field.Store(存储域选项)及Field.Index(索引选项)
Field.Store.YES或者NO(存储域选项) 设置为YES表示或把这个域中的内容完全存储到文件中,方便进行文本的还原 设置为NO表示把这个域的内容不存储到文件中,但是可以被索引,此时内容无法完 ...
- echarts——各个配置项详细说明总结
前 言 最近做了个关于各种图表的项目,用到了echarts , 关于各个配置项刚开始用好多都不懂,有些地方需要改不知道改哪个参数,就在网上查了各种,总结规整了一下,跟大家分享学习一下.(e ...
- Java面试18|关于进程、线程与协程
1.IPC(Inter-Process Communication,进程间通信)与线程通信的几种方式 # 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进 ...
- MongoDB 连接
启动 MongoDB服务 在前面的教程中,我们已经讨论了如何启动MongoDB服务,你只需要在MongoDB安装目录的bin目录下执行'mongod'即可. 执行启动操作后,mongodb在输出一些必 ...