gec6818客户端
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include<stdlib.h>
#include <linux/input.h>
// 添加字库接口
#include "font.h"
// 刷颜色
void show_color(int *lcd, int color)
{
for (int y = 0; y < 480; y++)
{
for (int x = 0; x < 800; x++)
{
*(lcd + y * 800 + x) = color;
}
}
}
// 映射LCD设备
void *mmap_lcd()
{ // 1.打开LCD设备
int fd = open("/dev/fb0", O_RDWR);
if (fd < 0)
{
printf("打开LCD设备失败\n");
return NULL;
}
else
{
printf("打开LCD设备成功\n");
}
// 2.把硬件设备LCD的地址映射到应用层中
void *p = mmap(NULL, 800 * 480 * 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (p == MAP_FAILED)
{
printf("映射失败\n");
return NULL;
}
else
{
printf("映射成功\n");
return p;
}
}
// 初始化字库
font *init_font(int size)
{
// 3.加载字库文件
font *f = fontLoad("/usr/share/fonts/DroidSansFallback.ttf");
if (f == NULL)
{
printf("加载字库失败\n");
return NULL;
}
// 4.设置字体大小
fontSetSize(f, size);
}
// 显示汉字 框长 框高 框背景色 汉字框中距离 汉字文本 汉字颜色 换行 映射设备 框在lcd位置
void show_text(u32 b_w, u32 b_h, u32 b_color,font *f, s32 t_x, s32 t_y, char *text, u32 t_color, s32 maxWidth,unsigned int *lcd, int px, int py)
{
// 创建一个字体输出框 ,并设置为绿色
bitmap *bm = createBitmapWithInit(b_w, b_h, 4, b_color);
// 放入文件到画框中
fontPrint(f, bm, t_x, t_y, text, t_color, maxWidth);
show_font_to_lcd(lcd, px, py, bm);
// 销毁画板
destroyBitmap(bm);
}
void LCD()
{
// 1.映射LCD设备
int *lcd = mmap_lcd();
// 刷颜色
show_color(lcd, 0xdddddd);
// 2.初始化字库
font *f = init_font(50);
show_text(780, 50, getColor(0, 255, 255, 255), f, 0, 0, "问题显示", 0x0,780, lcd,10,10);
show_text(780,340, getColor(0, 255, 255, 255), f, 0, 0, "答案显示", 0x0,780, lcd,10,70);
show_text(200, 50, getColor(0, 255, 255, 255), f,25, 0, "语音输入", 0x0, 0, lcd,10,420);
show_text(200, 50, getColor(0, 255, 255, 255), f,25, 0, "语义理解", 0x0, 0, lcd,300,420);
show_text(200, 50, getColor(0, 255, 255, 255), f,25, 0, "历史记录", 0x0, 0, lcd,590,420);
}
//触摸屏模块
int cmp(int *x, int *y)
{
int fd = open("/dev/input/event0", O_RDWR);
if (fd < 0)
{
printf("打开触摸屏失败\n");
return -1;
}
printf("点击触摸屏选择录制\n");
struct input_event ev;
int temp_x = 0, temp_y = 0;
while (1)
{
if (read(fd, &ev, sizeof(ev)) < 0) {
perror("读取触摸屏设备失败");
close(fd);
return -1;
}
if (ev.type == EV_ABS)
{
if (ev.code == ABS_X)
{
temp_x = ev.value * 800 / 1024;
}
else if (ev.code == ABS_Y)
{
temp_y = ev.value * 480 / 600;
}
if (temp_x != 0 && temp_y != 0)
{
*x = temp_x;
*y = temp_y;
break;
}
}
}
printf("x=%d, y=%d\n", *x, *y);
close(fd);
return 0;
}
//客户端发送音频文件
int Get_Speech_Text(char *name, char *text)
{
// 1.创建客户端通信对象
int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
// 2.链接服务器
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET; // IPV4
server_addr.sin_port = htons(1204); // 设置端口
server_addr.sin_addr.s_addr = inet_addr("192.168.46.62");
if (connect(tcp_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
{
printf("连接失败\n");
return -1;
}
// 1.打开文件
int fd = open(name, O_RDWR);
if (fd < 0)
{
printf("打开文件失败\n");
return -1;
}
while (1) // 不断把本地音频数据发送给服务器
{
// 2.读取文件的内容
char buf[4096] = {0};
int size = read(fd, buf, 4096);
if (size <= 0)
{
printf("发送文件完毕,等待识别....\n");
break;
}
// 3.发送到网络中
write(tcp_socket, buf, size);
}
// 读取服务器返回的语义
char msg[4096] = {0};
read(tcp_socket, msg, 4096);
// 保存语义
strcpy(text, msg);
// 关闭通信
close(tcp_socket);
close(fd);
}
int Get_Speech_Answer(char *question, char *answer)
{
// 1.创建网络通信对象
int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
// 2.链接服务器
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(1204);
server_addr.sin_addr.s_addr = inet_addr("192.168.46.62");
if (connect(tcp_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
{
printf("链接服务器失败\n");
return -1;
}
else
{
printf("链接服务器成功\n");
}
printf("\n\n问题是:%s\n\n", question);
// 把问题发送给服务器
write(tcp_socket, question, strlen(question));
printf("发送问题完毕,等待识别....\n");
// 读取服务器返回的语义
char msg[4096] = {0};
read(tcp_socket, msg, 4096);
// 保存语义
strcpy(answer, msg);
close(tcp_socket);
// 读取服务器返回的答案
//read(tcp_socket, answer, sizeof(answer));
//printf("答案:%s\n", answer);
// 显示答案
//show_text(780,340, getColor(0, 255, 255, 255), f, 0, 0, answer, 0x0,780, lcd,10,70);
}
char *Choose_part(char *part)
{
// 1.创建网络通信对象
int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
// 2.链接服务器
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(1204);
server_addr.sin_addr.s_addr = inet_addr("192.168.46.62");
if (connect(tcp_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
{
printf("链接服务器失败\n");
return NULL;
}
else
{
printf("链接服务器成功\n");
}
printf("功能模块确认中\n");
write(tcp_socket, part, strlen(part));
printf("发送完毕,等待服务器响应....\n");
}
int main()
{
//初始化lcd
LCD();
font *f = init_font(50);
font *f1 = init_font(25);
int *lcd = mmap_lcd();
while (1)
{
int x = 0, y = 0;
char text2[1024];
char answer[4096] = {0};
char text[1024] = {0};
cmp(&x,&y);
printf("%d,%d\n",x,y);
//语音输入
if (x>10 && x<210 && y>420 && y<470)
{
//选择功能块
char part1[1024] = "1";
Choose_part(part1);
//执行对应功能
printf("开始录音\n");
system("arecord -d 5 -r 16000 -c 1 -f S16_LE -t wav test.wav");
printf("录音完成\n\n");
printf("传输文件\n");
//char text[4096] = {0};
Get_Speech_Text("test.wav", text); // 获取音频文件的语义
printf("结果:%s\n", text);
//char text2[1024] = {0};
show_text(780, 50, getColor(0, 255, 255, 255), f, 0, 0,text, 0x0,780, lcd,10,10);
strcpy(text2,text);
}
//语义分析
else if (x>300 && x<500 && y>420 && y<470)
{
//选择功能块
char part2[1024] = "2";
Choose_part(part2);
//执行对应功能
//char text[1024]="介绍一下无畏契约";
Get_Speech_Answer(text2, answer);
printf("答案是:%s\n\n",answer);
show_text(780,340, getColor(0, 255, 255, 255), f1, 0, 0, answer, 0x0,780, lcd,10,70);
}
else if (x>590 && x<790 && y>420 && y<470)
{
//选择功能块
char part3[1024] = "3";
Choose_part(part3);
//执行对应功能
printf("开始播放\n");
system("aplay test.wav");
printf("播放完成\n\n");
}
}
return 0;
}
主机服务端
/*
* 语音听写(iFly Auto Transform)技术能够实时地将语音转换成对应的文字。
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include "msp_cmn.h"
#include "msp_errors.h"
#include "qisr.h"
#define BUFFER_SIZE 4096
#define FRAME_LEN 640
#define HINTS_SIZE 100
// 识别音频文件
void run_iat(const char *audio_file, const char *session_begin_params, char *text)
{
const char *session_id = NULL;
char rec_result[BUFFER_SIZE] = {0};
char hints[HINTS_SIZE] = {0}; // hints为结束本次会话的原因描述,由用户自定义
unsigned int total_len = 0;
int aud_stat = MSP_AUDIO_SAMPLE_CONTINUE; // 音频状态
int ep_stat = MSP_EP_LOOKING_FOR_SPEECH; // 端点检测
int rec_stat = MSP_REC_STATUS_SUCCESS; // 识别状态
int errcode = MSP_SUCCESS;
FILE *f_pcm = NULL;
char *p_pcm = NULL;
long pcm_count = 0;
long pcm_size = 0;
long read_size = 0;
if (NULL == audio_file)
goto iat_exit;
f_pcm = fopen(audio_file, "rb");
if (NULL == f_pcm)
{
printf("\nopen [%s] failed! \n", audio_file);
goto iat_exit;
}
fseek(f_pcm, 0, SEEK_END);
pcm_size = ftell(f_pcm); // 获取音频文件大小
fseek(f_pcm, 0, SEEK_SET);
p_pcm = (char *)malloc(pcm_size);
if (NULL == p_pcm)
{
printf("\nout of memory! \n");
goto iat_exit;
}
read_size = fread((void *)p_pcm, 1, pcm_size, f_pcm); // 读取音频文件内容
if (read_size != pcm_size)
{
printf("\nread [%s] error!\n", audio_file);
goto iat_exit;
}
printf("\n开始语音听写 ...\n");
session_id = QISRSessionBegin(NULL, session_begin_params, &errcode); // 听写不需要语法,第一个参数为NULL
if (MSP_SUCCESS != errcode)
{
printf("\nQISRSessionBegin failed! error code:%d\n", errcode);
goto iat_exit;
}
while (1)
{
unsigned int len = 10 * FRAME_LEN; // 每次写入200ms音频(16k,16bit):1帧音频20ms,10帧=200ms。16k采样率的16位音频,一帧的大小为640Byte
int ret = 0;
if (pcm_size < 2 * len)
len = pcm_size;
if (len <= 0)
break;
aud_stat = MSP_AUDIO_SAMPLE_CONTINUE;
if (0 == pcm_count)
aud_stat = MSP_AUDIO_SAMPLE_FIRST;
printf(">");
ret = QISRAudioWrite(session_id, (const void *)&p_pcm[pcm_count], len, aud_stat, &ep_stat, &rec_stat);
if (MSP_SUCCESS != ret)
{
printf("\nQISRAudioWrite failed! error code:%d\n", ret);
goto iat_exit;
}
pcm_count += (long)len;
pcm_size -= (long)len;
if (MSP_REC_STATUS_SUCCESS == rec_stat) // 已经有部分听写结果
{
const char *rslt = QISRGetResult(session_id, &rec_stat, 0, &errcode);
if (MSP_SUCCESS != errcode)
{
printf("\nQISRGetResult failed! error code: %d\n", errcode);
goto iat_exit;
}
if (NULL != rslt)
{
unsigned int rslt_len = strlen(rslt);
total_len += rslt_len;
if (total_len >= BUFFER_SIZE)
{
printf("\nno enough buffer for rec_result !\n");
goto iat_exit;
}
strncat(rec_result, rslt, rslt_len);
}
}
if (MSP_EP_AFTER_SPEECH == ep_stat)
break;
usleep(200 * 1000); // 模拟人说话时间间隙。200ms对应10帧的音频
}
errcode = QISRAudioWrite(session_id, NULL, 0, MSP_AUDIO_SAMPLE_LAST, &ep_stat, &rec_stat);
if (MSP_SUCCESS != errcode)
{
printf("\nQISRAudioWrite failed! error code:%d \n", errcode);
goto iat_exit;
}
while (MSP_REC_STATUS_COMPLETE != rec_stat)
{
const char *rslt = QISRGetResult(session_id, &rec_stat, 0, &errcode);
if (MSP_SUCCESS != errcode)
{
printf("\nQISRGetResult failed, error code: %d\n", errcode);
goto iat_exit;
}
if (NULL != rslt)
{
unsigned int rslt_len = strlen(rslt);
total_len += rslt_len;
if (total_len >= BUFFER_SIZE)
{
printf("\nno enough buffer for rec_result !\n");
goto iat_exit;
}
strncat(rec_result, rslt, rslt_len);
}
usleep(150 * 1000); // 防止频繁占用CPU
}
printf("\n语音听写结束\n");
// printf("%s\n", rec_result);
strcpy(text, rec_result); // 保存识别结果
iat_exit:
if (NULL != f_pcm)
{
fclose(f_pcm);
f_pcm = NULL;
}
if (NULL != p_pcm)
{
free(p_pcm);
p_pcm = NULL;
}
QISRSessionEnd(session_id, hints);
}
// 全局变量,所有函数都可以使用
int new_socket = 0;
// 通过服务器socket 获取客户端发送的音频文件
char *Get_Network_File(int tcp_socket)
{
// 接收客户端的链接请求
printf("等待客户端发生识别文件.....\n");
new_socket = accept(tcp_socket, NULL, NULL);
if (new_socket < 0)
{
printf("客户端链接失败\n");
return NULL;
}
// 不断接收客户端的发送的内容
// 1.打开文件
int fd = open("test.wav", O_RDWR | O_CREAT | O_TRUNC, 0777);
if (fd < 0)
{
printf("创建文件失败\n");
return NULL;
}
int down_size = 0;
while (1) // 不断读取客户端发送过来的数据
{
// 2.读取文件的内容
char buf[4096] = {0};
int size = read(new_socket, buf, 4096);
// 3.发送到网络中
write(fd, buf, size);
down_size += size; // 记录当前接收的总大小
if (down_size >= 160996)
{
printf("接收完毕开始识别.....\n");
close(fd);
break;
}
}
// 返回识别的文件名
return "test.wav";
}
// 调用ChatGLM函数,qustion 问题, answer 答案
int ChatGLM(char *qustion, char *answer)
{
// 定义一个缓存区
char cmd[1024] = {0};
sprintf(cmd, "python3 ChatGLM_rebot.py %s", qustion);
// 加载python脚本
FILE *fp = popen(cmd, "r");
if (fp == NULL)
{
printf("加载脚本失败\n");
return -1;
}
char buf[4096] = {0};
// 不断读取脚本返回的数据
while (1)
{
// 读取脚本返回的数据 到 buf 中
char *ret = fgets(buf, sizeof(buf), fp);
if (ret == NULL)
{
break;
}
}
// 处理前面的无关信息
char *p = strstr(buf, "content=");
// 处理后面的无关信息
char *q = strstr(buf, "role=");
*(q - 2) = '\0';
// 输出处理后的数据
strcpy(answer, p + 8); // 存储答案
// 关闭文件流
pclose(fp);
}
char *Get_Network_Text(int tcp_socket,char *buf)
{
new_socket = accept(tcp_socket, NULL, NULL);
printf("服务器连接 %d\n",new_socket);
char recv_buf[1024] = {0};
read(new_socket, recv_buf, 1024);
printf("接收到的数据内容:%s\n",recv_buf);
strcpy(buf,recv_buf);
}
int main(int argc, char *argv[])
{
int ret = MSP_SUCCESS;
const char *login_params = "appid = 07bf224a, work_dir = ."; // 登录参数,appid与msc库绑定,请勿随意改动
/*
* sub: 请求业务类型
* domain: 领域
* language: 语言
* accent: 方言
* sample_rate: 音频采样率
* result_type: 识别结果格式
* result_encoding: 结果编码格式
*
*/
const char *session_begin_params = "sub = iat, domain = iat, language = zh_cn, accent = mandarin, sample_rate = 16000, result_type = plain, result_encoding = utf8";
/* 用户登录 */
ret = MSPLogin(NULL, NULL, login_params); // 第一个参数是用户名,第二个参数是密码,均传NULL即可,第三个参数是登录参数
if (MSP_SUCCESS != ret)
{
printf("MSPLogin failed , Error code %d.\n", ret);
goto exit; // 登录失败,退出登录
}
// 绑定网络服务器地址信息
int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(1112);
server_addr.sin_addr.s_addr = inet_addr("192.168.46.54");
if (bind(tcp_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
{
printf("绑定服务器失败\n");
return -1;
}
// 设置监听模型
if (listen(tcp_socket, 5) < 0)
{
printf("监听失败\n");
return -1;
}
while (1)
{
char buf[1024] ={0};
char part1[1024] = "1";
char part2[1024] = "2";
Get_Network_Text(tcp_socket,buf);
printf("buf:%s\n",buf);
if((strcmp(buf,part1)) == 0)
{
// 获取网络识别文件
char *file = Get_Network_File(tcp_socket);
char text[4096] = {0};
run_iat(file, session_begin_params, text); // iflytek02音频内容为“中美数控”;如果上传了用户词表,识别结果为:“中美速控”。
// 把识别后的内容发生给客户端
write(new_socket, text, strlen(text));
printf("识别结果:%s\n", text);
// 关闭客户端对象
close(new_socket);
}
else if((strcmp(buf,part2)) == 0)
{
char buf[1024] ={0};
char msg[1024] ={0};
char answer[1024] = {0};
printf("开始运行\n");
// 获取网络识别文件
Get_Network_Text(tcp_socket,buf);
printf("%s",buf);
// 调用模型
ChatGLM(buf, answer);
// 把识别后的内容发生给客户端
strcpy(msg,answer);
write(new_socket, msg, strlen(msg));
printf("发送内容为:%s",msg);
// 关闭客户端对象
close(new_socket);
}
else
{
printf("未接收到命令\n");
break;
}
}
exit:
MSPLogout(); // 退出登录
return 0;
}
ChatGLM模型
from zhipuai import ZhipuAI
#获取用户输入的命令行参数
import sys
#判断用户输入的参数是否为 2
if len(sys.argv) != 2:
print("请输入一个问题")
sys.exit()
#获取用户输入的第一个参数
Problem = sys.argv[1]
client = ZhipuAI(api_key="1edc2f094de9d45c0f6cac2a39a52bf1.4v6s1XgdCDh74AXB") #填写自己的API_KEY
response = client.chat.completions.create(
model="glm-4-flash",
messages=[
{
"role": "system",
"content": "你是一个乐于解答各种问题的助手,你的任务是为用户提供专业、准确、有见地的建议。"
},
{
"role": "user",
"content": Problem
}
],
top_p= 0.7,
temperature= 0.95,
max_tokens=400, #最大的返回字数
tools = [{"type":"web_search","web_search":{"search_result":True}}],
)
print(response.choices[0].message) #一次性输出所有结果
*本项目调用gec6818开发板的汉字库