Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
PaddlePaddle
DeepSpeech
提交
1aa7495d
D
DeepSpeech
项目概览
PaddlePaddle
/
DeepSpeech
大约 2 年 前同步成功
通知
210
Star
8425
Fork
1598
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
245
列表
看板
标记
里程碑
合并请求
3
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
DeepSpeech
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
245
Issue
245
列表
看板
标记
里程碑
合并请求
3
合并请求
3
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
“e71bf9f72a95d5415c1c860180c0066746bc7de0”上不存在“paddle/fluid/lite/api/paddle_use_passes.h”
未验证
提交
1aa7495d
编写于
3月 14, 2023
作者:
小湉湉
提交者:
GitHub
3月 14, 2023
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
[TTS]Add license and reformat for TTSCppFrontend (#3030)
上级
259f4936
变更
13
隐藏空白更改
内联
并排
Showing
13 changed file
with
1323 addition
and
848 deletion
+1323
-848
demos/TTSArmLinux/src/Predictor.hpp
demos/TTSArmLinux/src/Predictor.hpp
+87
-73
demos/TTSArmLinux/src/main.cc
demos/TTSArmLinux/src/main.cc
+60
-26
demos/TTSCppFrontend/README.md
demos/TTSCppFrontend/README.md
+1
-0
demos/TTSCppFrontend/front_demo/front_demo.cpp
demos/TTSCppFrontend/front_demo/front_demo.cpp
+34
-20
demos/TTSCppFrontend/front_demo/gentools/gen_dict_paddlespeech.py
...SCppFrontend/front_demo/gentools/gen_dict_paddlespeech.py
+50
-26
demos/TTSCppFrontend/front_demo/gentools/genid.py
demos/TTSCppFrontend/front_demo/gentools/genid.py
+15
-2
demos/TTSCppFrontend/front_demo/gentools/word2phones.py
demos/TTSCppFrontend/front_demo/gentools/word2phones.py
+23
-5
demos/TTSCppFrontend/src/base/type_conv.cpp
demos/TTSCppFrontend/src/base/type_conv.cpp
+20
-10
demos/TTSCppFrontend/src/base/type_conv.h
demos/TTSCppFrontend/src/base/type_conv.h
+18
-5
demos/TTSCppFrontend/src/front/front_interface.cpp
demos/TTSCppFrontend/src/front/front_interface.cpp
+586
-389
demos/TTSCppFrontend/src/front/front_interface.h
demos/TTSCppFrontend/src/front/front_interface.h
+159
-117
demos/TTSCppFrontend/src/front/text_normalize.cpp
demos/TTSCppFrontend/src/front/text_normalize.cpp
+218
-138
demos/TTSCppFrontend/src/front/text_normalize.h
demos/TTSCppFrontend/src/front/text_normalize.h
+52
-37
未找到文件。
demos/TTSArmLinux/src/Predictor.hpp
浏览文件 @
1aa7495d
// Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
//
// 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.
#include <algorithm>
#include <algorithm>
#include <chrono>
#include <chrono>
#include <iostream>
#include <fstream>
#include <fstream>
#include <iostream>
#include <memory>
#include <memory>
#include <string>
#include <string>
#include <vector>
#include <vector>
...
@@ -10,24 +23,28 @@
...
@@ -10,24 +23,28 @@
using
namespace
paddle
::
lite_api
;
using
namespace
paddle
::
lite_api
;
class
PredictorInterface
{
class
PredictorInterface
{
public:
public:
virtual
~
PredictorInterface
()
=
0
;
virtual
~
PredictorInterface
()
=
0
;
virtual
bool
Init
(
virtual
bool
Init
(
const
std
::
string
&
AcousticModelPath
,
const
std
::
string
&
AcousticModelPath
,
const
std
::
string
&
VocoderPath
,
const
std
::
string
&
VocoderPath
,
PowerMode
cpuPowerMode
,
PowerMode
cpuPowerMode
,
int
cpuThreadNum
,
int
cpuThreadNum
,
// WAV采样率(必须与模型输出匹配)
// WAV采样率(必须与模型输出匹配)
// 如果播放速度和音调异常,请修改采样率
// 如果播放速度和音调异常,请修改采样率
// 常见采样率:16000, 24000, 32000, 44100, 48000, 96000
// 常见采样率:16000, 24000, 32000, 44100, 48000, 96000
uint32_t
wavSampleRate
)
=
0
;
uint32_t
wavSampleRate
virtual
std
::
shared_ptr
<
PaddlePredictor
>
LoadModel
(
)
=
0
;
const
std
::
string
&
modelPath
,
virtual
std
::
shared_ptr
<
PaddlePredictor
>
LoadModel
(
const
std
::
string
&
modelPath
,
int
cpuThreadNum
,
PowerMode
cpuPowerMode
)
=
0
;
int
cpuThreadNum
,
PowerMode
cpuPowerMode
)
=
0
;
virtual
void
ReleaseModel
()
=
0
;
virtual
void
ReleaseModel
()
=
0
;
virtual
bool
RunModel
(
const
std
::
vector
<
int64_t
>
&
phones
)
=
0
;
virtual
bool
RunModel
(
const
std
::
vector
<
int64_t
>
&
phones
)
=
0
;
virtual
std
::
unique_ptr
<
const
Tensor
>
GetAcousticModelOutput
(
const
std
::
vector
<
int64_t
>
&
phones
)
=
0
;
virtual
std
::
unique_ptr
<
const
Tensor
>
GetAcousticModelOutput
(
virtual
std
::
unique_ptr
<
const
Tensor
>
GetVocoderOutput
(
std
::
unique_ptr
<
const
Tensor
>
&&
amOutput
)
=
0
;
const
std
::
vector
<
int64_t
>
&
phones
)
=
0
;
virtual
void
VocoderOutputToWav
(
std
::
unique_ptr
<
const
Tensor
>
&&
vocOutput
)
=
0
;
virtual
std
::
unique_ptr
<
const
Tensor
>
GetVocoderOutput
(
std
::
unique_ptr
<
const
Tensor
>
&&
amOutput
)
=
0
;
virtual
void
VocoderOutputToWav
(
std
::
unique_ptr
<
const
Tensor
>
&&
vocOutput
)
=
0
;
virtual
void
SaveFloatWav
(
float
*
floatWav
,
int64_t
size
)
=
0
;
virtual
void
SaveFloatWav
(
float
*
floatWav
,
int64_t
size
)
=
0
;
virtual
bool
IsLoaded
()
=
0
;
virtual
bool
IsLoaded
()
=
0
;
virtual
float
GetInferenceTime
()
=
0
;
virtual
float
GetInferenceTime
()
=
0
;
...
@@ -45,23 +62,22 @@ PredictorInterface::~PredictorInterface() {}
...
@@ -45,23 +62,22 @@ PredictorInterface::~PredictorInterface() {}
// WavDataType: WAV数据类型
// WavDataType: WAV数据类型
// 可在 int16_t 和 float 之间切换,
// 可在 int16_t 和 float 之间切换,
// 用于生成 16-bit PCM 或 32-bit IEEE float 格式的 WAV
// 用于生成 16-bit PCM 或 32-bit IEEE float 格式的 WAV
template
<
typename
WavDataType
>
template
<
typename
WavDataType
>
class
Predictor
:
public
PredictorInterface
{
class
Predictor
:
public
PredictorInterface
{
public:
public:
virtual
bool
Init
(
bool
Init
(
const
std
::
string
&
AcousticModelPath
,
const
std
::
string
&
AcousticModelPath
,
const
std
::
string
&
VocoderPath
,
const
std
::
string
&
VocoderPath
,
PowerMode
cpuPowerMode
,
PowerMode
cpuPowerMode
,
int
cpuThreadNum
,
int
cpuThreadNum
,
// WAV采样率(必须与模型输出匹配)
// WAV采样率(必须与模型输出匹配)
// 如果播放速度和音调异常,请修改采样率
// 如果播放速度和音调异常,请修改采样率
// 常见采样率:16000, 24000, 32000, 44100, 48000, 96000
// 常见采样率:16000, 24000, 32000, 44100, 48000, 96000
uint32_t
wavSampleRate
)
override
{
uint32_t
wavSampleRate
)
override
{
// Release model if exists
// Release model if exists
ReleaseModel
();
ReleaseModel
();
acoustic_model_predictor_
=
LoadModel
(
AcousticModelPath
,
cpuThreadNum
,
cpuPowerMode
);
acoustic_model_predictor_
=
LoadModel
(
AcousticModelPath
,
cpuThreadNum
,
cpuPowerMode
);
if
(
acoustic_model_predictor_
==
nullptr
)
{
if
(
acoustic_model_predictor_
==
nullptr
)
{
return
false
;
return
false
;
}
}
...
@@ -80,7 +96,10 @@ public:
...
@@ -80,7 +96,10 @@ public:
ReleaseWav
();
ReleaseWav
();
}
}
virtual
std
::
shared_ptr
<
PaddlePredictor
>
LoadModel
(
const
std
::
string
&
modelPath
,
int
cpuThreadNum
,
PowerMode
cpuPowerMode
)
override
{
std
::
shared_ptr
<
PaddlePredictor
>
LoadModel
(
const
std
::
string
&
modelPath
,
int
cpuThreadNum
,
PowerMode
cpuPowerMode
)
override
{
if
(
modelPath
.
empty
())
{
if
(
modelPath
.
empty
())
{
return
nullptr
;
return
nullptr
;
}
}
...
@@ -94,12 +113,12 @@ public:
...
@@ -94,12 +113,12 @@ public:
return
CreatePaddlePredictor
<
MobileConfig
>
(
config
);
return
CreatePaddlePredictor
<
MobileConfig
>
(
config
);
}
}
v
irtual
v
oid
ReleaseModel
()
override
{
void
ReleaseModel
()
override
{
acoustic_model_predictor_
=
nullptr
;
acoustic_model_predictor_
=
nullptr
;
vocoder_predictor_
=
nullptr
;
vocoder_predictor_
=
nullptr
;
}
}
virtual
bool
RunModel
(
const
std
::
vector
<
int64_t
>
&
phones
)
override
{
bool
RunModel
(
const
std
::
vector
<
int64_t
>
&
phones
)
override
{
if
(
!
IsLoaded
())
{
if
(
!
IsLoaded
())
{
return
false
;
return
false
;
}
}
...
@@ -115,12 +134,13 @@ public:
...
@@ -115,12 +134,13 @@ public:
// 计算用时
// 计算用时
std
::
chrono
::
duration
<
float
>
duration
=
end
-
start
;
std
::
chrono
::
duration
<
float
>
duration
=
end
-
start
;
inference_time_
=
duration
.
count
()
*
1000
;
// 单位:毫秒
inference_time_
=
duration
.
count
()
*
1000
;
// 单位:毫秒
return
true
;
return
true
;
}
}
virtual
std
::
unique_ptr
<
const
Tensor
>
GetAcousticModelOutput
(
const
std
::
vector
<
int64_t
>
&
phones
)
override
{
std
::
unique_ptr
<
const
Tensor
>
GetAcousticModelOutput
(
const
std
::
vector
<
int64_t
>
&
phones
)
override
{
auto
phones_handle
=
acoustic_model_predictor_
->
GetInput
(
0
);
auto
phones_handle
=
acoustic_model_predictor_
->
GetInput
(
0
);
phones_handle
->
Resize
({
static_cast
<
int64_t
>
(
phones
.
size
())});
phones_handle
->
Resize
({
static_cast
<
int64_t
>
(
phones
.
size
())});
phones_handle
->
CopyFromCpu
(
phones
.
data
());
phones_handle
->
CopyFromCpu
(
phones
.
data
());
...
@@ -139,7 +159,8 @@ public:
...
@@ -139,7 +159,8 @@ public:
return
am_output_handle
;
return
am_output_handle
;
}
}
virtual
std
::
unique_ptr
<
const
Tensor
>
GetVocoderOutput
(
std
::
unique_ptr
<
const
Tensor
>
&&
amOutput
)
override
{
std
::
unique_ptr
<
const
Tensor
>
GetVocoderOutput
(
std
::
unique_ptr
<
const
Tensor
>
&&
amOutput
)
override
{
auto
mel_handle
=
vocoder_predictor_
->
GetInput
(
0
);
auto
mel_handle
=
vocoder_predictor_
->
GetInput
(
0
);
// [?, 80]
// [?, 80]
auto
dims
=
amOutput
->
shape
();
auto
dims
=
amOutput
->
shape
();
...
@@ -161,7 +182,8 @@ public:
...
@@ -161,7 +182,8 @@ public:
return
voc_output_handle
;
return
voc_output_handle
;
}
}
virtual
void
VocoderOutputToWav
(
std
::
unique_ptr
<
const
Tensor
>
&&
vocOutput
)
override
{
void
VocoderOutputToWav
(
std
::
unique_ptr
<
const
Tensor
>
&&
vocOutput
)
override
{
// 获取输出Tensor的数据
// 获取输出Tensor的数据
int64_t
output_size
=
1
;
int64_t
output_size
=
1
;
for
(
auto
dim
:
vocOutput
->
shape
())
{
for
(
auto
dim
:
vocOutput
->
shape
())
{
...
@@ -172,39 +194,31 @@ public:
...
@@ -172,39 +194,31 @@ public:
SaveFloatWav
(
output_data
,
output_size
);
SaveFloatWav
(
output_data
,
output_size
);
}
}
v
irtual
v
oid
SaveFloatWav
(
float
*
floatWav
,
int64_t
size
)
override
;
void
SaveFloatWav
(
float
*
floatWav
,
int64_t
size
)
override
;
virtual
bool
IsLoaded
()
override
{
bool
IsLoaded
()
override
{
return
acoustic_model_predictor_
!=
nullptr
&&
vocoder_predictor_
!=
nullptr
;
return
acoustic_model_predictor_
!=
nullptr
&&
vocoder_predictor_
!=
nullptr
;
}
}
virtual
float
GetInferenceTime
()
override
{
float
GetInferenceTime
()
override
{
return
inference_time_
;
}
return
inference_time_
;
}
const
std
::
vector
<
WavDataType
>
&
GetWav
()
{
const
std
::
vector
<
WavDataType
>
&
GetWav
()
{
return
wav_
;
}
return
wav_
;
}
virtual
int
GetWavSize
()
override
{
int
GetWavSize
()
override
{
return
wav_
.
size
()
*
sizeof
(
WavDataType
);
}
return
wav_
.
size
()
*
sizeof
(
WavDataType
);
}
// 获取WAV持续时间(单位:毫秒)
// 获取WAV持续时间(单位:毫秒)
virtual
float
GetWavDuration
()
override
{
float
GetWavDuration
()
override
{
return
static_cast
<
float
>
(
GetWavSize
())
/
sizeof
(
WavDataType
)
/
static_cast
<
float
>
(
wav_sample_rate_
)
*
1000
;
return
static_cast
<
float
>
(
GetWavSize
())
/
sizeof
(
WavDataType
)
/
static_cast
<
float
>
(
wav_sample_rate_
)
*
1000
;
}
}
// 获取RTF(合成时间 / 音频时长)
// 获取RTF(合成时间 / 音频时长)
virtual
float
GetRTF
()
override
{
float
GetRTF
()
override
{
return
GetInferenceTime
()
/
GetWavDuration
();
}
return
GetInferenceTime
()
/
GetWavDuration
();
}
virtual
void
ReleaseWav
()
override
{
void
ReleaseWav
()
override
{
wav_
.
clear
();
}
wav_
.
clear
();
}
virtual
bool
WriteWavToFile
(
const
std
::
string
&
wavPath
)
override
{
bool
WriteWavToFile
(
const
std
::
string
&
wavPath
)
override
{
std
::
ofstream
fout
(
wavPath
,
std
::
ios
::
binary
);
std
::
ofstream
fout
(
wavPath
,
std
::
ios
::
binary
);
if
(
!
fout
.
is_open
())
{
if
(
!
fout
.
is_open
())
{
return
false
;
return
false
;
...
@@ -216,18 +230,20 @@ public:
...
@@ -216,18 +230,20 @@ public:
header
.
data_size
=
GetWavSize
();
header
.
data_size
=
GetWavSize
();
header
.
size
=
sizeof
(
header
)
-
8
+
header
.
data_size
;
header
.
size
=
sizeof
(
header
)
-
8
+
header
.
data_size
;
header
.
sample_rate
=
wav_sample_rate_
;
header
.
sample_rate
=
wav_sample_rate_
;
header
.
byte_rate
=
header
.
sample_rate
*
header
.
num_channels
*
header
.
bits_per_sample
/
8
;
header
.
byte_rate
=
header
.
sample_rate
*
header
.
num_channels
*
header
.
bits_per_sample
/
8
;
header
.
block_align
=
header
.
num_channels
*
header
.
bits_per_sample
/
8
;
header
.
block_align
=
header
.
num_channels
*
header
.
bits_per_sample
/
8
;
fout
.
write
(
reinterpret_cast
<
const
char
*>
(
&
header
),
sizeof
(
header
));
fout
.
write
(
reinterpret_cast
<
const
char
*>
(
&
header
),
sizeof
(
header
));
// 写入wav数据
// 写入wav数据
fout
.
write
(
reinterpret_cast
<
const
char
*>
(
wav_
.
data
()),
header
.
data_size
);
fout
.
write
(
reinterpret_cast
<
const
char
*>
(
wav_
.
data
()),
header
.
data_size
);
fout
.
close
();
fout
.
close
();
return
true
;
return
true
;
}
}
protected:
protected:
struct
WavHeader
{
struct
WavHeader
{
// RIFF 头
// RIFF 头
char
riff
[
4
]
=
{
'R'
,
'I'
,
'F'
,
'F'
};
char
riff
[
4
]
=
{
'R'
,
'I'
,
'F'
,
'F'
};
...
@@ -250,19 +266,17 @@ protected:
...
@@ -250,19 +266,17 @@ protected:
};
};
enum
WavAudioFormat
{
enum
WavAudioFormat
{
WAV_FORMAT_16BIT_PCM
=
1
,
// 16-bit PCM 格式
WAV_FORMAT_16BIT_PCM
=
1
,
// 16-bit PCM 格式
WAV_FORMAT_32BIT_FLOAT
=
3
// 32-bit IEEE float 格式
WAV_FORMAT_32BIT_FLOAT
=
3
// 32-bit IEEE float 格式
};
};
protected:
protected:
// 返回值通过模板特化由 WavDataType 决定
// 返回值通过模板特化由 WavDataType 决定
inline
uint16_t
GetWavAudioFormat
();
inline
uint16_t
GetWavAudioFormat
();
inline
float
Abs
(
float
number
)
{
inline
float
Abs
(
float
number
)
{
return
(
number
<
0
)
?
-
number
:
number
;
}
return
(
number
<
0
)
?
-
number
:
number
;
}
protected:
protected:
float
inference_time_
=
0
;
float
inference_time_
=
0
;
uint32_t
wav_sample_rate_
=
0
;
uint32_t
wav_sample_rate_
=
0
;
std
::
vector
<
WavDataType
>
wav_
;
std
::
vector
<
WavDataType
>
wav_
;
...
@@ -270,36 +284,36 @@ protected:
...
@@ -270,36 +284,36 @@ protected:
std
::
shared_ptr
<
PaddlePredictor
>
vocoder_predictor_
=
nullptr
;
std
::
shared_ptr
<
PaddlePredictor
>
vocoder_predictor_
=
nullptr
;
};
};
template
<
>
template
<
>
uint16_t
Predictor
<
int16_t
>::
GetWavAudioFormat
()
{
uint16_t
Predictor
<
int16_t
>::
GetWavAudioFormat
()
{
return
Predictor
::
WAV_FORMAT_16BIT_PCM
;
return
Predictor
::
WAV_FORMAT_16BIT_PCM
;
}
}
template
<
>
template
<
>
uint16_t
Predictor
<
float
>::
GetWavAudioFormat
()
{
uint16_t
Predictor
<
float
>::
GetWavAudioFormat
()
{
return
Predictor
::
WAV_FORMAT_32BIT_FLOAT
;
return
Predictor
::
WAV_FORMAT_32BIT_FLOAT
;
}
}
// 保存 16-bit PCM 格式 WAV
// 保存 16-bit PCM 格式 WAV
template
<
>
template
<
>
void
Predictor
<
int16_t
>::
SaveFloatWav
(
float
*
floatWav
,
int64_t
size
)
{
void
Predictor
<
int16_t
>::
SaveFloatWav
(
float
*
floatWav
,
int64_t
size
)
{
wav_
.
resize
(
size
);
wav_
.
resize
(
size
);
float
maxSample
=
0.01
;
float
maxSample
=
0.01
;
// 寻找最大采样值
// 寻找最大采样值
for
(
int64_t
i
=
0
;
i
<
size
;
i
++
)
{
for
(
int64_t
i
=
0
;
i
<
size
;
i
++
)
{
float
sample
=
Abs
(
floatWav
[
i
]);
float
sample
=
Abs
(
floatWav
[
i
]);
if
(
sample
>
maxSample
)
{
if
(
sample
>
maxSample
)
{
maxSample
=
sample
;
maxSample
=
sample
;
}
}
}
}
// 把采样值缩放到 int_16 范围
// 把采样值缩放到 int_16 范围
for
(
int64_t
i
=
0
;
i
<
size
;
i
++
)
{
for
(
int64_t
i
=
0
;
i
<
size
;
i
++
)
{
wav_
[
i
]
=
floatWav
[
i
]
*
32767.0
f
/
maxSample
;
wav_
[
i
]
=
floatWav
[
i
]
*
32767.0
f
/
maxSample
;
}
}
}
}
// 保存 32-bit IEEE float 格式 WAV
// 保存 32-bit IEEE float 格式 WAV
template
<
>
template
<
>
void
Predictor
<
float
>::
SaveFloatWav
(
float
*
floatWav
,
int64_t
size
)
{
void
Predictor
<
float
>::
SaveFloatWav
(
float
*
floatWav
,
int64_t
size
)
{
wav_
.
resize
(
size
);
wav_
.
resize
(
size
);
std
::
copy_n
(
floatWav
,
size
,
wav_
.
data
());
std
::
copy_n
(
floatWav
,
size
,
wav_
.
data
());
...
...
demos/TTSArmLinux/src/main.cc
浏览文件 @
1aa7495d
// Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
//
// 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.
#include <front/front_interface.h>
#include <gflags/gflags.h>
#include <glog/logging.h>
#include <paddle_api.h>
#include <cstdlib>
#include <cstdlib>
#include <iostream>
#include <iostream>
#include <map>
#include <memory>
#include <memory>
#include <string>
#include <string>
#include <map>
#include <glog/logging.h>
#include <gflags/gflags.h>
#include <paddle_api.h>
#include <front/front_interface.h>
#include "Predictor.hpp"
#include "Predictor.hpp"
using
namespace
paddle
::
lite_api
;
using
namespace
paddle
::
lite_api
;
DEFINE_string
(
sentence
,
"你好,欢迎使用语音合成服务"
,
"Text to be synthesized (Chinese only. English will crash the program.)"
);
DEFINE_string
(
sentence
,
"你好,欢迎使用语音合成服务"
,
"Text to be synthesized (Chinese only. English will crash the program.)"
);
DEFINE_string
(
front_conf
,
"./front.conf"
,
"Front configuration file"
);
DEFINE_string
(
front_conf
,
"./front.conf"
,
"Front configuration file"
);
DEFINE_string
(
acoustic_model
,
"./models/cpu/fastspeech2_csmsc_arm.nb"
,
"Acoustic model .nb file"
);
DEFINE_string
(
acoustic_model
,
DEFINE_string
(
vocoder
,
"./models/cpu/fastspeech2_csmsc_arm.nb"
,
"vocoder .nb file"
);
"./models/cpu/fastspeech2_csmsc_arm.nb"
,
"Acoustic model .nb file"
);
DEFINE_string
(
vocoder
,
"./models/cpu/fastspeech2_csmsc_arm.nb"
,
"vocoder .nb file"
);
DEFINE_string
(
output_wav
,
"./output/tts.wav"
,
"Output WAV file"
);
DEFINE_string
(
output_wav
,
"./output/tts.wav"
,
"Output WAV file"
);
DEFINE_string
(
wav_bit_depth
,
"16"
,
"WAV bit depth, 16 (16-bit PCM) or 32 (32-bit IEEE float)"
);
DEFINE_string
(
wav_bit_depth
,
DEFINE_string
(
wav_sample_rate
,
"24000"
,
"WAV sample rate, should match the output of the vocoder"
);
"16"
,
"WAV bit depth, 16 (16-bit PCM) or 32 (32-bit IEEE float)"
);
DEFINE_string
(
wav_sample_rate
,
"24000"
,
"WAV sample rate, should match the output of the vocoder"
);
DEFINE_string
(
cpu_thread
,
"1"
,
"CPU thread numbers"
);
DEFINE_string
(
cpu_thread
,
"1"
,
"CPU thread numbers"
);
int
main
(
int
argc
,
char
*
argv
[])
{
int
main
(
int
argc
,
char
*
argv
[])
{
...
@@ -53,7 +78,7 @@ int main(int argc, char *argv[]) {
...
@@ -53,7 +78,7 @@ int main(int argc, char *argv[]) {
// 繁体转简体
// 繁体转简体
std
::
wstring
sentence_simp
;
std
::
wstring
sentence_simp
;
front_inst
->
Trand2Simp
(
ws_sentence
,
sentence_simp
);
front_inst
->
Trand2Simp
(
ws_sentence
,
&
sentence_simp
);
ws_sentence
=
sentence_simp
;
ws_sentence
=
sentence_simp
;
std
::
string
s_sentence
;
std
::
string
s_sentence
;
...
@@ -63,28 +88,30 @@ int main(int argc, char *argv[]) {
...
@@ -63,28 +88,30 @@ int main(int argc, char *argv[]) {
// 根据标点进行分句
// 根据标点进行分句
LOG
(
INFO
)
<<
"Start to segment sentences by punctuation"
;
LOG
(
INFO
)
<<
"Start to segment sentences by punctuation"
;
front_inst
->
SplitByPunc
(
ws_sentence
,
sentence_part
);
front_inst
->
SplitByPunc
(
ws_sentence
,
&
sentence_part
);
LOG
(
INFO
)
<<
"Segment sentences through punctuation successfully"
;
LOG
(
INFO
)
<<
"Segment sentences through punctuation successfully"
;
// 分句后获取音素id
// 分句后获取音素id
LOG
(
INFO
)
<<
"Start to get the phoneme and tone id sequence of each sentence"
;
LOG
(
INFO
)
for
(
int
i
=
0
;
i
<
sentence_part
.
size
();
i
++
)
{
<<
"Start to get the phoneme and tone id sequence of each sentence"
;
for
(
int
i
=
0
;
i
<
sentence_part
.
size
();
i
++
)
{
LOG
(
INFO
)
<<
"Raw sentence is: "
<<
ppspeech
::
wstring2utf8string
(
sentence_part
[
i
]);
LOG
(
INFO
)
<<
"Raw sentence is: "
front_inst
->
SentenceNormalize
(
sentence_part
[
i
]);
<<
ppspeech
::
wstring2utf8string
(
sentence_part
[
i
]);
front_inst
->
SentenceNormalize
(
&
sentence_part
[
i
]);
s_sentence
=
ppspeech
::
wstring2utf8string
(
sentence_part
[
i
]);
s_sentence
=
ppspeech
::
wstring2utf8string
(
sentence_part
[
i
]);
LOG
(
INFO
)
<<
"After normalization sentence is: "
<<
s_sentence
;
LOG
(
INFO
)
<<
"After normalization sentence is: "
<<
s_sentence
;
if
(
0
!=
front_inst
->
GetSentenceIds
(
s_sentence
,
phoneids
,
toneids
))
{
if
(
0
!=
front_inst
->
GetSentenceIds
(
s_sentence
,
&
phoneids
,
&
toneids
))
{
LOG
(
ERROR
)
<<
"TTS inst get sentence phoneids and toneids failed"
;
LOG
(
ERROR
)
<<
"TTS inst get sentence phoneids and toneids failed"
;
return
-
1
;
return
-
1
;
}
}
}
}
LOG
(
INFO
)
<<
"The phoneids of the sentence is: "
<<
limonp
::
Join
(
phoneids
.
begin
(),
phoneids
.
end
(),
" "
);
LOG
(
INFO
)
<<
"The phoneids of the sentence is: "
LOG
(
INFO
)
<<
"The toneids of the sentence is: "
<<
limonp
::
Join
(
toneids
.
begin
(),
toneids
.
end
(),
" "
);
<<
limonp
::
Join
(
phoneids
.
begin
(),
phoneids
.
end
(),
" "
);
LOG
(
INFO
)
<<
"The toneids of the sentence is: "
<<
limonp
::
Join
(
toneids
.
begin
(),
toneids
.
end
(),
" "
);
LOG
(
INFO
)
<<
"Get the phoneme id sequence of each sentence successfully"
;
LOG
(
INFO
)
<<
"Get the phoneme id sequence of each sentence successfully"
;
/////////////////////////// 后端:音素转音频 ///////////////////////////
/////////////////////////// 后端:音素转音频 ///////////////////////////
...
@@ -99,13 +126,19 @@ int main(int argc, char *argv[]) {
...
@@ -99,13 +126,19 @@ int main(int argc, char *argv[]) {
// CPU电源模式
// CPU电源模式
const
PowerMode
cpuPowerMode
=
PowerMode
::
LITE_POWER_HIGH
;
const
PowerMode
cpuPowerMode
=
PowerMode
::
LITE_POWER_HIGH
;
if
(
!
predictor
->
Init
(
FLAGS_acoustic_model
,
FLAGS_vocoder
,
cpuPowerMode
,
cpuThreadNum
,
wavSampleRate
))
{
if
(
!
predictor
->
Init
(
FLAGS_acoustic_model
,
FLAGS_vocoder
,
cpuPowerMode
,
cpuThreadNum
,
wavSampleRate
))
{
LOG
(
ERROR
)
<<
"predictor init failed"
<<
std
::
endl
;
LOG
(
ERROR
)
<<
"predictor init failed"
<<
std
::
endl
;
return
-
1
;
return
-
1
;
}
}
std
::
vector
<
int64_t
>
phones
(
phoneids
.
size
());
std
::
vector
<
int64_t
>
phones
(
phoneids
.
size
());
std
::
transform
(
phoneids
.
begin
(),
phoneids
.
end
(),
phones
.
begin
(),
[](
int
x
)
{
return
static_cast
<
int64_t
>
(
x
);
});
std
::
transform
(
phoneids
.
begin
(),
phoneids
.
end
(),
phones
.
begin
(),
[](
int
x
)
{
return
static_cast
<
int64_t
>
(
x
);
});
if
(
!
predictor
->
RunModel
(
phones
))
{
if
(
!
predictor
->
RunModel
(
phones
))
{
LOG
(
ERROR
)
<<
"predictor run model failed"
<<
std
::
endl
;
LOG
(
ERROR
)
<<
"predictor run model failed"
<<
std
::
endl
;
...
@@ -113,7 +146,8 @@ int main(int argc, char *argv[]) {
...
@@ -113,7 +146,8 @@ int main(int argc, char *argv[]) {
}
}
LOG
(
INFO
)
<<
"Inference time: "
<<
predictor
->
GetInferenceTime
()
<<
" ms, "
LOG
(
INFO
)
<<
"Inference time: "
<<
predictor
->
GetInferenceTime
()
<<
" ms, "
<<
"WAV size (without header): "
<<
predictor
->
GetWavSize
()
<<
" bytes, "
<<
"WAV size (without header): "
<<
predictor
->
GetWavSize
()
<<
" bytes, "
<<
"WAV duration: "
<<
predictor
->
GetWavDuration
()
<<
" ms, "
<<
"WAV duration: "
<<
predictor
->
GetWavDuration
()
<<
" ms, "
<<
"RTF: "
<<
predictor
->
GetRTF
()
<<
std
::
endl
;
<<
"RTF: "
<<
predictor
->
GetRTF
()
<<
std
::
endl
;
...
...
demos/TTSCppFrontend/README.md
浏览文件 @
1aa7495d
...
@@ -38,6 +38,7 @@ If the download speed is too slow, you can open [third-party/CMakeLists.txt](thi
...
@@ -38,6 +38,7 @@ If the download speed is too slow, you can open [third-party/CMakeLists.txt](thi
```
```
## Run
## Run
You can change
`--phone2id_path`
in
`./front_demo/front.conf`
to the
`phone_id_map.txt`
of your own acoustic model.
```
```
./run_front_demo.sh
./run_front_demo.sh
...
...
demos/TTSCppFrontend/front_demo/front_demo.cpp
浏览文件 @
1aa7495d
#include <string>
// Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
//#include "utils/dir_utils.h"
//
#include "front/front_interface.h"
// Licensed under the Apache License, Version 2.0 (the "License");
#include <glog/logging.h>
// 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.
#include <gflags/gflags.h>
#include <gflags/gflags.h>
#include <glog/logging.h>
#include <map>
#include <map>
#include <string>
#include "front/front_interface.h"
DEFINE_string
(
sentence
,
"你好,欢迎使用语音合成服务"
,
"Text to be synthesized"
);
DEFINE_string
(
sentence
,
"你好,欢迎使用语音合成服务"
,
"Text to be synthesized"
);
DEFINE_string
(
front_conf
,
"./front_demo/front.conf"
,
"Front conf file"
);
DEFINE_string
(
front_conf
,
"./front_demo/front.conf"
,
"Front conf file"
);
//DEFINE_string(seperate_tone, "true", "If true, get phoneids and tonesid");
//
DEFINE_string(seperate_tone, "true", "If true, get phoneids and tonesid");
int
main
(
int
argc
,
char
**
argv
)
{
int
main
(
int
argc
,
char
**
argv
)
{
gflags
::
ParseCommandLineFlags
(
&
argc
,
&
argv
,
true
);
gflags
::
ParseCommandLineFlags
(
&
argc
,
&
argv
,
true
);
// 实例化文本前端引擎
// 实例化文本前端引擎
ppspeech
::
FrontEngineInterface
*
front_inst
=
nullptr
;
ppspeech
::
FrontEngineInterface
*
front_inst
=
nullptr
;
front_inst
=
new
ppspeech
::
FrontEngineInterface
(
FLAGS_front_conf
);
front_inst
=
new
ppspeech
::
FrontEngineInterface
(
FLAGS_front_conf
);
if
((
!
front_inst
)
||
(
front_inst
->
init
()))
{
if
((
!
front_inst
)
||
(
front_inst
->
init
()))
{
LOG
(
ERROR
)
<<
"Creater tts engine failed!"
;
LOG
(
ERROR
)
<<
"Creater tts engine failed!"
;
...
@@ -28,7 +41,7 @@ int main(int argc, char** argv) {
...
@@ -28,7 +41,7 @@ int main(int argc, char** argv) {
// 繁体转简体
// 繁体转简体
std
::
wstring
sentence_simp
;
std
::
wstring
sentence_simp
;
front_inst
->
Trand2Simp
(
ws_sentence
,
sentence_simp
);
front_inst
->
Trand2Simp
(
ws_sentence
,
&
sentence_simp
);
ws_sentence
=
sentence_simp
;
ws_sentence
=
sentence_simp
;
std
::
string
s_sentence
;
std
::
string
s_sentence
;
...
@@ -38,28 +51,29 @@ int main(int argc, char** argv) {
...
@@ -38,28 +51,29 @@ int main(int argc, char** argv) {
// 根据标点进行分句
// 根据标点进行分句
LOG
(
INFO
)
<<
"Start to segment sentences by punctuation"
;
LOG
(
INFO
)
<<
"Start to segment sentences by punctuation"
;
front_inst
->
SplitByPunc
(
ws_sentence
,
sentence_part
);
front_inst
->
SplitByPunc
(
ws_sentence
,
&
sentence_part
);
LOG
(
INFO
)
<<
"Segment sentences through punctuation successfully"
;
LOG
(
INFO
)
<<
"Segment sentences through punctuation successfully"
;
// 分句后获取音素id
// 分句后获取音素id
LOG
(
INFO
)
<<
"Start to get the phoneme and tone id sequence of each sentence"
;
LOG
(
INFO
)
for
(
int
i
=
0
;
i
<
sentence_part
.
size
();
i
++
)
{
<<
"Start to get the phoneme and tone id sequence of each sentence"
;
for
(
int
i
=
0
;
i
<
sentence_part
.
size
();
i
++
)
{
LOG
(
INFO
)
<<
"Raw sentence is: "
<<
ppspeech
::
wstring2utf8string
(
sentence_part
[
i
]);
LOG
(
INFO
)
<<
"Raw sentence is: "
front_inst
->
SentenceNormalize
(
sentence_part
[
i
]);
<<
ppspeech
::
wstring2utf8string
(
sentence_part
[
i
]);
front_inst
->
SentenceNormalize
(
&
sentence_part
[
i
]);
s_sentence
=
ppspeech
::
wstring2utf8string
(
sentence_part
[
i
]);
s_sentence
=
ppspeech
::
wstring2utf8string
(
sentence_part
[
i
]);
LOG
(
INFO
)
<<
"After normalization sentence is: "
<<
s_sentence
;
LOG
(
INFO
)
<<
"After normalization sentence is: "
<<
s_sentence
;
if
(
0
!=
front_inst
->
GetSentenceIds
(
s_sentence
,
phoneids
,
toneids
))
{
if
(
0
!=
front_inst
->
GetSentenceIds
(
s_sentence
,
&
phoneids
,
&
toneids
))
{
LOG
(
ERROR
)
<<
"TTS inst get sentence phoneids and toneids failed"
;
LOG
(
ERROR
)
<<
"TTS inst get sentence phoneids and toneids failed"
;
return
-
1
;
return
-
1
;
}
}
}
}
LOG
(
INFO
)
<<
"The phoneids of the sentence is: "
<<
limonp
::
Join
(
phoneids
.
begin
(),
phoneids
.
end
(),
" "
);
LOG
(
INFO
)
<<
"The phoneids of the sentence is: "
LOG
(
INFO
)
<<
"The toneids of the sentence is: "
<<
limonp
::
Join
(
toneids
.
begin
(),
toneids
.
end
(),
" "
);
<<
limonp
::
Join
(
phoneids
.
begin
(),
phoneids
.
end
(),
" "
);
LOG
(
INFO
)
<<
"The toneids of the sentence is: "
<<
limonp
::
Join
(
toneids
.
begin
(),
toneids
.
end
(),
" "
);
LOG
(
INFO
)
<<
"Get the phoneme id sequence of each sentence successfully"
;
LOG
(
INFO
)
<<
"Get the phoneme id sequence of each sentence successfully"
;
return
EXIT_SUCCESS
;
return
EXIT_SUCCESS
;
}
}
demos/TTSCppFrontend/front_demo/gentools/gen_dict_paddlespeech.py
浏览文件 @
1aa7495d
# !/usr/bin/env python3
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
# -*- coding: utf-8 -*-
########################################################################
#
#
# Copyright 2021 liangyunming(liangyunming@baidu.com)
# 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
#
#
# Execute the script when PaddleSpeech has been installed
# http://www.apache.org/licenses/LICENSE-2.0
# PaddleSpeech: https://github.com/PaddlePaddle/PaddleSpeech
#
# 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.
import
argparse
import
argparse
import
configparser
import
configparser
from
paddlespeech.t2s.frontend.zh_frontend
import
Frontend
from
paddlespeech.t2s.frontend.zh_frontend
import
Frontend
def
get_phone
(
frontend
,
word
,
merge_sentences
=
True
,
print_info
=
False
,
robot
=
False
,
get_tone_ids
=
False
):
def
get_phone
(
frontend
,
word
,
merge_sentences
=
True
,
print_info
=
False
,
robot
=
False
,
get_tone_ids
=
False
):
phonemes
=
frontend
.
get_phonemes
(
word
,
merge_sentences
,
print_info
,
robot
)
phonemes
=
frontend
.
get_phonemes
(
word
,
merge_sentences
,
print_info
,
robot
)
# Some optimizations
# Some optimizations
phones
,
tones
=
frontend
.
_get_phone_tone
(
phonemes
[
0
],
get_tone_ids
)
phones
,
tones
=
frontend
.
_get_phone_tone
(
phonemes
[
0
],
get_tone_ids
)
...
@@ -22,7 +31,10 @@ def get_phone(frontend, word, merge_sentences=True, print_info=False, robot=Fals
...
@@ -22,7 +31,10 @@ def get_phone(frontend, word, merge_sentences=True, print_info=False, robot=Fals
return
phones
,
tones
return
phones
,
tones
def
gen_word2phone_dict
(
frontend
,
jieba_words_dict
,
word2phone_dict
,
get_tone
=
False
):
def
gen_word2phone_dict
(
frontend
,
jieba_words_dict
,
word2phone_dict
,
get_tone
=
False
):
with
open
(
jieba_words_dict
,
"r"
)
as
f1
,
open
(
word2phone_dict
,
"w+"
)
as
f2
:
with
open
(
jieba_words_dict
,
"r"
)
as
f1
,
open
(
word2phone_dict
,
"w+"
)
as
f2
:
for
line
in
f1
.
readlines
():
for
line
in
f1
.
readlines
():
word
=
line
.
split
(
" "
)[
0
]
word
=
line
.
split
(
" "
)[
0
]
...
@@ -30,9 +42,9 @@ def gen_word2phone_dict(frontend, jieba_words_dict, word2phone_dict, get_tone=Fa
...
@@ -30,9 +42,9 @@ def gen_word2phone_dict(frontend, jieba_words_dict, word2phone_dict, get_tone=Fa
phone_str
=
""
phone_str
=
""
if
tone
:
if
tone
:
assert
(
len
(
phone
)
==
len
(
tone
))
assert
(
len
(
phone
)
==
len
(
tone
))
for
i
in
range
(
len
(
tone
)):
for
i
in
range
(
len
(
tone
)):
phone_tone
=
phone
[
i
]
+
tone
[
i
]
phone_tone
=
phone
[
i
]
+
tone
[
i
]
phone_str
+=
(
" "
+
phone_tone
)
phone_str
+=
(
" "
+
phone_tone
)
phone_str
=
phone_str
.
strip
(
"sp0"
).
strip
(
" "
)
phone_str
=
phone_str
.
strip
(
"sp0"
).
strip
(
" "
)
else
:
else
:
...
@@ -45,43 +57,55 @@ def gen_word2phone_dict(frontend, jieba_words_dict, word2phone_dict, get_tone=Fa
...
@@ -45,43 +57,55 @@ def gen_word2phone_dict(frontend, jieba_words_dict, word2phone_dict, get_tone=Fa
def
main
():
def
main
():
parser
=
argparse
.
ArgumentParser
(
parser
=
argparse
.
ArgumentParser
(
description
=
"Generate dictionary"
)
description
=
"Generate dictionary"
)
parser
.
add_argument
(
parser
.
add_argument
(
"--config"
,
type
=
str
,
default
=
"./config.ini"
,
help
=
"config file."
)
"--config"
,
type
=
str
,
default
=
"./config.ini"
,
help
=
"config file."
)
parser
.
add_argument
(
parser
.
add_argument
(
"--am_type"
,
type
=
str
,
default
=
"fastspeech2"
,
help
=
"fastspeech2 or speedyspeech"
)
"--am_type"
,
type
=
str
,
default
=
"fastspeech2"
,
help
=
"fastspeech2 or speedyspeech"
)
args
=
parser
.
parse_args
()
args
=
parser
.
parse_args
()
# Read config
# Read config
cf
=
configparser
.
ConfigParser
()
cf
=
configparser
.
ConfigParser
()
cf
.
read
(
args
.
config
)
cf
.
read
(
args
.
config
)
jieba_words_dict_file
=
cf
.
get
(
"jieba"
,
"jieba_words_dict"
)
# get words dict
jieba_words_dict_file
=
cf
.
get
(
"jieba"
,
"jieba_words_dict"
)
# get words dict
am_type
=
args
.
am_type
am_type
=
args
.
am_type
if
(
am_type
==
"fastspeech2"
):
if
(
am_type
==
"fastspeech2"
):
phone2id_dict_file
=
cf
.
get
(
am_type
,
"phone2id_dict"
)
phone2id_dict_file
=
cf
.
get
(
am_type
,
"phone2id_dict"
)
word2phone_dict_file
=
cf
.
get
(
am_type
,
"word2phone_dict"
)
word2phone_dict_file
=
cf
.
get
(
am_type
,
"word2phone_dict"
)
frontend
=
Frontend
(
phone_vocab_path
=
phone2id_dict_file
)
frontend
=
Frontend
(
phone_vocab_path
=
phone2id_dict_file
)
print
(
"frontend done!"
)
print
(
"frontend done!"
)
gen_word2phone_dict
(
frontend
,
jieba_words_dict_file
,
word2phone_dict_file
,
get_tone
=
False
)
gen_word2phone_dict
(
frontend
,
elif
(
am_type
==
"speedyspeech"
):
jieba_words_dict_file
,
word2phone_dict_file
,
get_tone
=
False
)
elif
(
am_type
==
"speedyspeech"
):
phone2id_dict_file
=
cf
.
get
(
am_type
,
"phone2id_dict"
)
phone2id_dict_file
=
cf
.
get
(
am_type
,
"phone2id_dict"
)
tone2id_dict_file
=
cf
.
get
(
am_type
,
"tone2id_dict"
)
tone2id_dict_file
=
cf
.
get
(
am_type
,
"tone2id_dict"
)
word2phone_dict_file
=
cf
.
get
(
am_type
,
"word2phone_dict"
)
word2phone_dict_file
=
cf
.
get
(
am_type
,
"word2phone_dict"
)
frontend
=
Frontend
(
phone_vocab_path
=
phone2id_dict_file
,
tone_vocab_path
=
tone2id_dict_file
)
frontend
=
Frontend
(
phone_vocab_path
=
phone2id_dict_file
,
tone_vocab_path
=
tone2id_dict_file
)
print
(
"frontend done!"
)
print
(
"frontend done!"
)
gen_word2phone_dict
(
frontend
,
jieba_words_dict_file
,
word2phone_dict_file
,
get_tone
=
True
)
gen_word2phone_dict
(
frontend
,
jieba_words_dict_file
,
word2phone_dict_file
,
get_tone
=
True
)
else
:
else
:
print
(
"Please set correct am type, fastspeech2 or speedyspeech."
)
print
(
"Please set correct am type, fastspeech2 or speedyspeech."
)
if
__name__
==
"__main__"
:
if
__name__
==
"__main__"
:
main
()
main
()
demos/TTSCppFrontend/front_demo/gentools/genid.py
浏览文件 @
1aa7495d
#from parakeet.frontend.vocab import Vocab
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# 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.
PHONESFILE
=
"./dict/phones.txt"
PHONESFILE
=
"./dict/phones.txt"
PHONES_ID_FILE
=
"./dict/phonesid.dict"
PHONES_ID_FILE
=
"./dict/phonesid.dict"
TONESFILE
=
"./dict/tones.txt"
TONESFILE
=
"./dict/tones.txt"
TONES_ID_FILE
=
"./dict/tonesid.dict"
TONES_ID_FILE
=
"./dict/tonesid.dict"
def
GenIdFile
(
file
,
idfile
):
def
GenIdFile
(
file
,
idfile
):
id
=
2
id
=
2
with
open
(
file
,
'r'
)
as
f1
,
open
(
idfile
,
"w+"
)
as
f2
:
with
open
(
file
,
'r'
)
as
f1
,
open
(
idfile
,
"w+"
)
as
f2
:
...
@@ -16,7 +29,7 @@ def GenIdFile(file, idfile):
...
@@ -16,7 +29,7 @@ def GenIdFile(file, idfile):
f2
.
write
(
phone
+
" "
+
str
(
id
)
+
"
\n
"
)
f2
.
write
(
phone
+
" "
+
str
(
id
)
+
"
\n
"
)
id
+=
1
id
+=
1
if
__name__
==
"__main__"
:
if
__name__
==
"__main__"
:
GenIdFile
(
PHONESFILE
,
PHONES_ID_FILE
)
GenIdFile
(
PHONESFILE
,
PHONES_ID_FILE
)
GenIdFile
(
TONESFILE
,
TONES_ID_FILE
)
GenIdFile
(
TONESFILE
,
TONES_ID_FILE
)
demos/TTSCppFrontend/front_demo/gentools/word2phones.py
浏览文件 @
1aa7495d
from
pypinyin
import
lazy_pinyin
,
Style
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# 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.
import
re
import
re
from
pypinyin
import
lazy_pinyin
from
pypinyin
import
Style
worddict
=
"./dict/jieba_part.dict.utf8"
worddict
=
"./dict/jieba_part.dict.utf8"
newdict
=
"./dict/word_phones.dict"
newdict
=
"./dict/word_phones.dict"
def
GenPhones
(
initials
,
finals
,
seperate
=
True
):
def
GenPhones
(
initials
,
finals
,
seperate
=
True
):
phones
=
[]
phones
=
[]
...
@@ -14,9 +30,9 @@ def GenPhones(initials, finals, seperate=True):
...
@@ -14,9 +30,9 @@ def GenPhones(initials, finals, seperate=True):
elif
c
in
[
'zh'
,
'ch'
,
'sh'
,
'r'
]:
elif
c
in
[
'zh'
,
'ch'
,
'sh'
,
'r'
]:
v
=
re
.
sub
(
'i'
,
'iii'
,
v
)
v
=
re
.
sub
(
'i'
,
'iii'
,
v
)
if
c
:
if
c
:
if
seperate
==
True
:
if
seperate
is
True
:
phones
.
append
(
c
+
'0'
)
phones
.
append
(
c
+
'0'
)
elif
seperate
==
False
:
elif
seperate
is
False
:
phones
.
append
(
c
)
phones
.
append
(
c
)
else
:
else
:
print
(
"Not sure whether phone and tone need to be separated"
)
print
(
"Not sure whether phone and tone need to be separated"
)
...
@@ -28,8 +44,10 @@ def GenPhones(initials, finals, seperate=True):
...
@@ -28,8 +44,10 @@ def GenPhones(initials, finals, seperate=True):
with
open
(
worddict
,
"r"
)
as
f1
,
open
(
newdict
,
"w+"
)
as
f2
:
with
open
(
worddict
,
"r"
)
as
f1
,
open
(
newdict
,
"w+"
)
as
f2
:
for
line
in
f1
.
readlines
():
for
line
in
f1
.
readlines
():
word
=
line
.
split
(
" "
)[
0
]
word
=
line
.
split
(
" "
)[
0
]
initials
=
lazy_pinyin
(
word
,
neutral_tone_with_five
=
True
,
style
=
Style
.
INITIALS
)
initials
=
lazy_pinyin
(
finals
=
lazy_pinyin
(
word
,
neutral_tone_with_five
=
True
,
style
=
Style
.
FINALS_TONE3
)
word
,
neutral_tone_with_five
=
True
,
style
=
Style
.
INITIALS
)
finals
=
lazy_pinyin
(
word
,
neutral_tone_with_five
=
True
,
style
=
Style
.
FINALS_TONE3
)
phones
=
GenPhones
(
initials
,
finals
,
True
)
phones
=
GenPhones
(
initials
,
finals
,
True
)
...
...
demos/TTSCppFrontend/src/base/type_conv.cpp
浏览文件 @
1aa7495d
// Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
//
// 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.
#include "base/type_conv.h"
#include "base/type_conv.h"
namespace
ppspeech
{
namespace
ppspeech
{
// wstring to string
// wstring to string
std
::
string
wstring2utf8string
(
const
std
::
wstring
&
str
)
std
::
string
wstring2utf8string
(
const
std
::
wstring
&
str
)
{
{
static
std
::
wstring_convert
<
std
::
codecvt_utf8
<
wchar_t
>>
strCnv
;
static
std
::
wstring_convert
<
std
::
codecvt_utf8
<
wchar_t
>
>
strCnv
;
return
strCnv
.
to_bytes
(
str
);
return
strCnv
.
to_bytes
(
str
);
}
}
// string to wstring
std
::
wstring
utf8string2wstring
(
const
std
::
string
&
str
)
{
static
std
::
wstring_convert
<
std
::
codecvt_utf8
<
wchar_t
>
>
strCnv
;
return
strCnv
.
from_bytes
(
str
);
}
// string to wstring
std
::
wstring
utf8string2wstring
(
const
std
::
string
&
str
)
{
static
std
::
wstring_convert
<
std
::
codecvt_utf8
<
wchar_t
>>
strCnv
;
return
strCnv
.
from_bytes
(
str
);
}
}
}
// namespace ppspeech
demos/TTSCppFrontend/src/base/type_conv.h
浏览文件 @
1aa7495d
// Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
//
// 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.
#ifndef BASE_TYPE_CONVC_H
#ifndef BASE_TYPE_CONVC_H
#define BASE_TYPE_CONVC_H
#define BASE_TYPE_CONVC_H
#include <string>
#include <locale>
#include <codecvt>
#include <codecvt>
#include <locale>
#include <string>
namespace
ppspeech
{
namespace
ppspeech
{
// wstring to string
// wstring to string
std
::
string
wstring2utf8string
(
const
std
::
wstring
&
str
);
std
::
string
wstring2utf8string
(
const
std
::
wstring
&
str
);
// string to wstring
std
::
wstring
utf8string2wstring
(
const
std
::
string
&
str
);
// string to wstring
std
::
wstring
utf8string2wstring
(
const
std
::
string
&
str
);
}
}
#endif // BASE_TYPE_CONVC_H
#endif // BASE_TYPE_CONVC_H
\ No newline at end of file
demos/TTSCppFrontend/src/front/front_interface.cpp
浏览文件 @
1aa7495d
// Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
//
// 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.
#include "front/front_interface.h"
#include "front/front_interface.h"
namespace
ppspeech
{
namespace
ppspeech
{
...
@@ -5,96 +18,123 @@ namespace ppspeech {
...
@@ -5,96 +18,123 @@ namespace ppspeech {
int
FrontEngineInterface
::
init
()
{
int
FrontEngineInterface
::
init
()
{
if
(
_initialed
)
{
if
(
_initialed
)
{
return
0
;
return
0
;
}
}
if
(
0
!=
ReadConfFile
())
{
if
(
0
!=
ReadConfFile
())
{
LOG
(
ERROR
)
<<
"Read front conf file failed"
;
LOG
(
ERROR
)
<<
"Read front conf file failed"
;
return
-
1
;
return
-
1
;
}
}
_jieba
=
new
cppjieba
::
Jieba
(
_jieba_dict_path
,
_jieba_hmm_path
,
_jieba_user_dict_path
,
_jieba
=
new
cppjieba
::
Jieba
(
_jieba_dict_path
,
_jieba_idf_path
,
_jieba_stop_word_path
);
_jieba_hmm_path
,
_jieba_user_dict_path
,
_punc
=
{
","
,
"。"
,
"、"
,
"?"
,
":"
,
";"
,
"~"
,
"!"
,
_jieba_idf_path
,
","
,
"."
,
"?"
,
"!"
,
":"
,
";"
,
"/"
,
"
\\
"
};
_jieba_stop_word_path
);
_punc_omit
=
{
"“"
,
"”"
,
"
\"
"
,
"
\"
"
};
_punc
=
{
","
,
"。"
,
"、"
,
"?"
,
":"
,
";"
,
"~"
,
"!"
,
","
,
"."
,
"?"
,
"!"
,
":"
,
";"
,
"/"
,
"
\\
"
};
_punc_omit
=
{
"“"
,
"”"
,
"
\"
"
,
"
\"
"
};
// 需要儿化音处理的词语
// 需要儿化音处理的词语
must_erhua
=
{
"小院儿"
,
"胡同儿"
,
"范儿"
,
"老汉儿"
,
"撒欢儿"
,
"寻老礼儿"
,
"妥妥儿"
};
must_erhua
=
{
not_erhua
=
{
"小院儿"
,
"胡同儿"
,
"范儿"
,
"老汉儿"
,
"撒欢儿"
,
"寻老礼儿"
,
"妥妥儿"
};
"虐儿"
,
"为儿"
,
"护儿"
,
"瞒儿"
,
"救儿"
,
"替儿"
,
"有儿"
,
"一儿"
,
"我儿"
,
"俺儿"
,
"妻儿"
,
not_erhua
=
{
"虐儿"
,
"为儿"
,
"护儿"
,
"瞒儿"
,
"救儿"
,
"替儿"
,
"拐儿"
,
"聋儿"
,
"乞儿"
,
"患儿"
,
"幼儿"
,
"孤儿"
,
"婴儿"
,
"婴幼儿"
,
"连体儿"
,
"脑瘫儿"
,
"有儿"
,
"一儿"
,
"我儿"
,
"俺儿"
,
"妻儿"
,
"拐儿"
,
"流浪儿"
,
"体弱儿"
,
"混血儿"
,
"蜜雪儿"
,
"舫儿"
,
"祖儿"
,
"美儿"
,
"应采儿"
,
"可儿"
,
"侄儿"
,
"聋儿"
,
"乞儿"
,
"患儿"
,
"幼儿"
,
"孤儿"
,
"婴儿"
,
"孙儿"
,
"侄孙儿"
,
"女儿"
,
"男儿"
,
"红孩儿"
,
"花儿"
,
"虫儿"
,
"马儿"
,
"鸟儿"
,
"猪儿"
,
"猫儿"
,
"婴幼儿"
,
"连体儿"
,
"脑瘫儿"
,
"流浪儿"
,
"体弱儿"
,
"混血儿"
,
"狗儿"
"蜜雪儿"
,
"舫儿"
,
"祖儿"
,
"美儿"
,
"应采儿"
,
"可儿"
,
};
"侄儿"
,
"孙儿"
,
"侄孙儿"
,
"女儿"
,
"男儿"
,
"红孩儿"
,
"花儿"
,
"虫儿"
,
"马儿"
,
"鸟儿"
,
"猪儿"
,
"猫儿"
,
must_not_neural_tone_words
=
{
"男子"
,
"女子"
,
"分子"
,
"原子"
,
"量子"
,
"莲子"
,
"石子"
,
"瓜子"
,
"电子"
};
"狗儿"
};
must_not_neural_tone_words
=
{
"男子"
,
"女子"
,
"分子"
,
"原子"
,
"量子"
,
"莲子"
,
"石子"
,
"瓜子"
,
"电子"
};
// 需要轻声处理的词语
// 需要轻声处理的词语
must_neural_tone_words
=
{
must_neural_tone_words
=
{
"麻烦"
,
"麻利"
,
"鸳鸯"
,
"高粱"
,
"骨头"
,
"骆驼"
,
"马虎"
,
"首饰"
,
"馒头"
,
"馄饨"
,
"风筝"
,
"麻烦"
,
"麻利"
,
"鸳鸯"
,
"高粱"
,
"骨头"
,
"骆驼"
,
"马虎"
,
"首饰"
,
"馒头"
,
"难为"
,
"队伍"
,
"阔气"
,
"闺女"
,
"门道"
,
"锄头"
,
"铺盖"
,
"铃铛"
,
"铁匠"
,
"钥匙"
,
"里脊"
,
"馄饨"
,
"风筝"
,
"难为"
,
"队伍"
,
"阔气"
,
"闺女"
,
"门道"
,
"锄头"
,
"铺盖"
,
"里头"
,
"部分"
,
"那么"
,
"道士"
,
"造化"
,
"迷糊"
,
"连累"
,
"这么"
,
"这个"
,
"运气"
,
"过去"
,
"铃铛"
,
"铁匠"
,
"钥匙"
,
"里脊"
,
"里头"
,
"部分"
,
"那么"
,
"道士"
,
"造化"
,
"软和"
,
"转悠"
,
"踏实"
,
"跳蚤"
,
"跟头"
,
"趔趄"
,
"财主"
,
"豆腐"
,
"讲究"
,
"记性"
,
"记号"
,
"迷糊"
,
"连累"
,
"这么"
,
"这个"
,
"运气"
,
"过去"
,
"软和"
,
"转悠"
,
"踏实"
,
"认识"
,
"规矩"
,
"见识"
,
"裁缝"
,
"补丁"
,
"衣裳"
,
"衣服"
,
"衙门"
,
"街坊"
,
"行李"
,
"行当"
,
"跳蚤"
,
"跟头"
,
"趔趄"
,
"财主"
,
"豆腐"
,
"讲究"
,
"记性"
,
"记号"
,
"认识"
,
"蛤蟆"
,
"蘑菇"
,
"薄荷"
,
"葫芦"
,
"葡萄"
,
"萝卜"
,
"荸荠"
,
"苗条"
,
"苗头"
,
"苍蝇"
,
"芝麻"
,
"规矩"
,
"见识"
,
"裁缝"
,
"补丁"
,
"衣裳"
,
"衣服"
,
"衙门"
,
"街坊"
,
"行李"
,
"舒服"
,
"舒坦"
,
"舌头"
,
"自在"
,
"膏药"
,
"脾气"
,
"脑袋"
,
"脊梁"
,
"能耐"
,
"胳膊"
,
"胭脂"
,
"行当"
,
"蛤蟆"
,
"蘑菇"
,
"薄荷"
,
"葫芦"
,
"葡萄"
,
"萝卜"
,
"荸荠"
,
"苗条"
,
"胡萝"
,
"胡琴"
,
"胡同"
,
"聪明"
,
"耽误"
,
"耽搁"
,
"耷拉"
,
"耳朵"
,
"老爷"
,
"老实"
,
"老婆"
,
"苗头"
,
"苍蝇"
,
"芝麻"
,
"舒服"
,
"舒坦"
,
"舌头"
,
"自在"
,
"膏药"
,
"脾气"
,
"老头"
,
"老太"
,
"翻腾"
,
"罗嗦"
,
"罐头"
,
"编辑"
,
"结实"
,
"红火"
,
"累赘"
,
"糨糊"
,
"糊涂"
,
"脑袋"
,
"脊梁"
,
"能耐"
,
"胳膊"
,
"胭脂"
,
"胡萝"
,
"胡琴"
,
"胡同"
,
"聪明"
,
"精神"
,
"粮食"
,
"簸箕"
,
"篱笆"
,
"算计"
,
"算盘"
,
"答应"
,
"笤帚"
,
"笑语"
,
"笑话"
,
"窟窿"
,
"耽误"
,
"耽搁"
,
"耷拉"
,
"耳朵"
,
"老爷"
,
"老实"
,
"老婆"
,
"老头"
,
"老太"
,
"窝囊"
,
"窗户"
,
"稳当"
,
"稀罕"
,
"称呼"
,
"秧歌"
,
"秀气"
,
"秀才"
,
"福气"
,
"祖宗"
,
"砚台"
,
"翻腾"
,
"罗嗦"
,
"罐头"
,
"编辑"
,
"结实"
,
"红火"
,
"累赘"
,
"糨糊"
,
"糊涂"
,
"码头"
,
"石榴"
,
"石头"
,
"石匠"
,
"知识"
,
"眼睛"
,
"眯缝"
,
"眨巴"
,
"眉毛"
,
"相声"
,
"盘算"
,
"精神"
,
"粮食"
,
"簸箕"
,
"篱笆"
,
"算计"
,
"算盘"
,
"答应"
,
"笤帚"
,
"笑语"
,
"白净"
,
"痢疾"
,
"痛快"
,
"疟疾"
,
"疙瘩"
,
"疏忽"
,
"畜生"
,
"生意"
,
"甘蔗"
,
"琵琶"
,
"琢磨"
,
"笑话"
,
"窟窿"
,
"窝囊"
,
"窗户"
,
"稳当"
,
"稀罕"
,
"称呼"
,
"秧歌"
,
"秀气"
,
"琉璃"
,
"玻璃"
,
"玫瑰"
,
"玄乎"
,
"狐狸"
,
"状元"
,
"特务"
,
"牲口"
,
"牙碜"
,
"牌楼"
,
"爽快"
,
"秀才"
,
"福气"
,
"祖宗"
,
"砚台"
,
"码头"
,
"石榴"
,
"石头"
,
"石匠"
,
"知识"
,
"爱人"
,
"热闹"
,
"烧饼"
,
"烟筒"
,
"烂糊"
,
"点心"
,
"炊帚"
,
"灯笼"
,
"火候"
,
"漂亮"
,
"滑溜"
,
"眼睛"
,
"眯缝"
,
"眨巴"
,
"眉毛"
,
"相声"
,
"盘算"
,
"白净"
,
"痢疾"
,
"痛快"
,
"溜达"
,
"温和"
,
"清楚"
,
"消息"
,
"浪头"
,
"活泼"
,
"比方"
,
"正经"
,
"欺负"
,
"模糊"
,
"槟榔"
,
"疟疾"
,
"疙瘩"
,
"疏忽"
,
"畜生"
,
"生意"
,
"甘蔗"
,
"琵琶"
,
"琢磨"
,
"琉璃"
,
"棺材"
,
"棒槌"
,
"棉花"
,
"核桃"
,
"栅栏"
,
"柴火"
,
"架势"
,
"枕头"
,
"枇杷"
,
"机灵"
,
"本事"
,
"玻璃"
,
"玫瑰"
,
"玄乎"
,
"狐狸"
,
"状元"
,
"特务"
,
"牲口"
,
"牙碜"
,
"牌楼"
,
"木头"
,
"木匠"
,
"朋友"
,
"月饼"
,
"月亮"
,
"暖和"
,
"明白"
,
"时候"
,
"新鲜"
,
"故事"
,
"收拾"
,
"爽快"
,
"爱人"
,
"热闹"
,
"烧饼"
,
"烟筒"
,
"烂糊"
,
"点心"
,
"炊帚"
,
"灯笼"
,
"收成"
,
"提防"
,
"挖苦"
,
"挑剔"
,
"指甲"
,
"指头"
,
"拾掇"
,
"拳头"
,
"拨弄"
,
"招牌"
,
"招呼"
,
"火候"
,
"漂亮"
,
"滑溜"
,
"溜达"
,
"温和"
,
"清楚"
,
"消息"
,
"浪头"
,
"活泼"
,
"抬举"
,
"护士"
,
"折腾"
,
"扫帚"
,
"打量"
,
"打算"
,
"打点"
,
"打扮"
,
"打听"
,
"打发"
,
"扎实"
,
"比方"
,
"正经"
,
"欺负"
,
"模糊"
,
"槟榔"
,
"棺材"
,
"棒槌"
,
"棉花"
,
"核桃"
,
"扁担"
,
"戒指"
,
"懒得"
,
"意识"
,
"意思"
,
"情形"
,
"悟性"
,
"怪物"
,
"思量"
,
"怎么"
,
"念头"
,
"栅栏"
,
"柴火"
,
"架势"
,
"枕头"
,
"枇杷"
,
"机灵"
,
"本事"
,
"木头"
,
"木匠"
,
"念叨"
,
"快活"
,
"忙活"
,
"志气"
,
"心思"
,
"得罪"
,
"张罗"
,
"弟兄"
,
"开通"
,
"应酬"
,
"庄稼"
,
"朋友"
,
"月饼"
,
"月亮"
,
"暖和"
,
"明白"
,
"时候"
,
"新鲜"
,
"故事"
,
"收拾"
,
"干事"
,
"帮手"
,
"帐篷"
,
"希罕"
,
"师父"
,
"师傅"
,
"巴结"
,
"巴掌"
,
"差事"
,
"工夫"
,
"岁数"
,
"收成"
,
"提防"
,
"挖苦"
,
"挑剔"
,
"指甲"
,
"指头"
,
"拾掇"
,
"拳头"
,
"拨弄"
,
"屁股"
,
"尾巴"
,
"少爷"
,
"小气"
,
"小伙"
,
"将就"
,
"对头"
,
"对付"
,
"寡妇"
,
"家伙"
,
"客气"
,
"招牌"
,
"招呼"
,
"抬举"
,
"护士"
,
"折腾"
,
"扫帚"
,
"打量"
,
"打算"
,
"打点"
,
"实在"
,
"官司"
,
"学问"
,
"学生"
,
"字号"
,
"嫁妆"
,
"媳妇"
,
"媒人"
,
"婆家"
,
"娘家"
,
"委屈"
,
"打扮"
,
"打听"
,
"打发"
,
"扎实"
,
"扁担"
,
"戒指"
,
"懒得"
,
"意识"
,
"意思"
,
"姑娘"
,
"姐夫"
,
"妯娌"
,
"妥当"
,
"妖精"
,
"奴才"
,
"女婿"
,
"头发"
,
"太阳"
,
"大爷"
,
"大方"
,
"情形"
,
"悟性"
,
"怪物"
,
"思量"
,
"怎么"
,
"念头"
,
"念叨"
,
"快活"
,
"忙活"
,
"大意"
,
"大夫"
,
"多少"
,
"多么"
,
"外甥"
,
"壮实"
,
"地道"
,
"地方"
,
"在乎"
,
"困难"
,
"嘴巴"
,
"志气"
,
"心思"
,
"得罪"
,
"张罗"
,
"弟兄"
,
"开通"
,
"应酬"
,
"庄稼"
,
"干事"
,
"嘱咐"
,
"嘟囔"
,
"嘀咕"
,
"喜欢"
,
"喇嘛"
,
"喇叭"
,
"商量"
,
"唾沫"
,
"哑巴"
,
"哈欠"
,
"哆嗦"
,
"帮手"
,
"帐篷"
,
"希罕"
,
"师父"
,
"师傅"
,
"巴结"
,
"巴掌"
,
"差事"
,
"工夫"
,
"咳嗽"
,
"和尚"
,
"告诉"
,
"告示"
,
"含糊"
,
"吓唬"
,
"后头"
,
"名字"
,
"名堂"
,
"合同"
,
"吆喝"
,
"岁数"
,
"屁股"
,
"尾巴"
,
"少爷"
,
"小气"
,
"小伙"
,
"将就"
,
"对头"
,
"对付"
,
"叫唤"
,
"口袋"
,
"厚道"
,
"厉害"
,
"千斤"
,
"包袱"
,
"包涵"
,
"匀称"
,
"勤快"
,
"动静"
,
"动弹"
,
"寡妇"
,
"家伙"
,
"客气"
,
"实在"
,
"官司"
,
"学问"
,
"学生"
,
"字号"
,
"嫁妆"
,
"功夫"
,
"力气"
,
"前头"
,
"刺猬"
,
"刺激"
,
"别扭"
,
"利落"
,
"利索"
,
"利害"
,
"分析"
,
"出息"
,
"媳妇"
,
"媒人"
,
"婆家"
,
"娘家"
,
"委屈"
,
"姑娘"
,
"姐夫"
,
"妯娌"
,
"妥当"
,
"凑合"
,
"凉快"
,
"冷战"
,
"冤枉"
,
"冒失"
,
"养活"
,
"关系"
,
"先生"
,
"兄弟"
,
"便宜"
,
"使唤"
,
"妖精"
,
"奴才"
,
"女婿"
,
"头发"
,
"太阳"
,
"大爷"
,
"大方"
,
"大意"
,
"大夫"
,
"佩服"
,
"作坊"
,
"体面"
,
"位置"
,
"似的"
,
"伙计"
,
"休息"
,
"什么"
,
"人家"
,
"亲戚"
,
"亲家"
,
"多少"
,
"多么"
,
"外甥"
,
"壮实"
,
"地道"
,
"地方"
,
"在乎"
,
"困难"
,
"嘴巴"
,
"交情"
,
"云彩"
,
"事情"
,
"买卖"
,
"主意"
,
"丫头"
,
"丧气"
,
"两口"
,
"东西"
,
"东家"
,
"世故"
,
"嘱咐"
,
"嘟囔"
,
"嘀咕"
,
"喜欢"
,
"喇嘛"
,
"喇叭"
,
"商量"
,
"唾沫"
,
"哑巴"
,
"不由"
,
"不在"
,
"下水"
,
"下巴"
,
"上头"
,
"上司"
,
"丈夫"
,
"丈人"
,
"一辈"
,
"那个"
,
"菩萨"
,
"哈欠"
,
"哆嗦"
,
"咳嗽"
,
"和尚"
,
"告诉"
,
"告示"
,
"含糊"
,
"吓唬"
,
"后头"
,
"父亲"
,
"母亲"
,
"咕噜"
,
"邋遢"
,
"费用"
,
"冤家"
,
"甜头"
,
"介绍"
,
"荒唐"
,
"大人"
,
"泥鳅"
,
"名字"
,
"名堂"
,
"合同"
,
"吆喝"
,
"叫唤"
,
"口袋"
,
"厚道"
,
"厉害"
,
"千斤"
,
"幸福"
,
"熟悉"
,
"计划"
,
"扑腾"
,
"蜡烛"
,
"姥爷"
,
"照顾"
,
"喉咙"
,
"吉他"
,
"弄堂"
,
"蚂蚱"
,
"包袱"
,
"包涵"
,
"匀称"
,
"勤快"
,
"动静"
,
"动弹"
,
"功夫"
,
"力气"
,
"前头"
,
"凤凰"
,
"拖沓"
,
"寒碜"
,
"糟蹋"
,
"倒腾"
,
"报复"
,
"逻辑"
,
"盘缠"
,
"喽啰"
,
"牢骚"
,
"咖喱"
,
"刺猬"
,
"刺激"
,
"别扭"
,
"利落"
,
"利索"
,
"利害"
,
"分析"
,
"出息"
,
"凑合"
,
"扫把"
,
"惦记"
"凉快"
,
"冷战"
,
"冤枉"
,
"冒失"
,
"养活"
,
"关系"
,
"先生"
,
"兄弟"
,
"便宜"
,
};
"使唤"
,
"佩服"
,
"作坊"
,
"体面"
,
"位置"
,
"似的"
,
"伙计"
,
"休息"
,
"什么"
,
"人家"
,
"亲戚"
,
"亲家"
,
"交情"
,
"云彩"
,
"事情"
,
"买卖"
,
"主意"
,
"丫头"
,
"丧气"
,
"两口"
,
"东西"
,
"东家"
,
"世故"
,
"不由"
,
"不在"
,
"下水"
,
"下巴"
,
"上头"
,
"上司"
,
"丈夫"
,
"丈人"
,
"一辈"
,
"那个"
,
"菩萨"
,
"父亲"
,
"母亲"
,
"咕噜"
,
"邋遢"
,
"费用"
,
"冤家"
,
"甜头"
,
"介绍"
,
"荒唐"
,
"大人"
,
"泥鳅"
,
"幸福"
,
"熟悉"
,
"计划"
,
"扑腾"
,
"蜡烛"
,
"姥爷"
,
"照顾"
,
"喉咙"
,
"吉他"
,
"弄堂"
,
"蚂蚱"
,
"凤凰"
,
"拖沓"
,
"寒碜"
,
"糟蹋"
,
"倒腾"
,
"报复"
,
"逻辑"
,
"盘缠"
,
"喽啰"
,
"牢骚"
,
"咖喱"
,
"扫把"
,
"惦记"
};
// 生成词典(词到音素的映射)
// 生成词典(词到音素的映射)
if
(
0
!=
GenDict
(
_word2phone_path
,
word_phone_map
))
{
if
(
0
!=
GenDict
(
_word2phone_path
,
&
word_phone_map
))
{
LOG
(
ERROR
)
<<
"Genarate word2phone dict failed"
;
LOG
(
ERROR
)
<<
"Genarate word2phone dict failed"
;
return
-
1
;
return
-
1
;
}
}
// 生成音素字典(音素到音素id的映射)
// 生成音素字典(音素到音素id的映射)
if
(
0
!=
GenDict
(
_phone2id_path
,
phone_id_map
))
{
if
(
0
!=
GenDict
(
_phone2id_path
,
&
phone_id_map
))
{
LOG
(
ERROR
)
<<
"Genarate phone2id dict failed"
;
LOG
(
ERROR
)
<<
"Genarate phone2id dict failed"
;
return
-
1
;
return
-
1
;
}
}
// 生成音调字典(音调到音调id的映射)
// 生成音调字典(音调到音调id的映射)
if
(
_seperate_tone
==
"true"
)
{
if
(
_seperate_tone
==
"true"
)
{
if
(
0
!=
GenDict
(
_tone2id_path
,
tone_id_map
))
{
if
(
0
!=
GenDict
(
_tone2id_path
,
&
tone_id_map
))
{
LOG
(
ERROR
)
<<
"Genarate tone2id dict failed"
;
LOG
(
ERROR
)
<<
"Genarate tone2id dict failed"
;
return
-
1
;
return
-
1
;
}
}
}
}
// 生成繁简字典(繁体到简体id的映射)
// 生成繁简字典(繁体到简体id的映射)
if
(
0
!=
GenDict
(
_trand2simp_path
,
trand_simp_map
))
{
if
(
0
!=
GenDict
(
_trand2simp_path
,
&
trand_simp_map
))
{
LOG
(
ERROR
)
<<
"Genarate trand2simp dict failed"
;
LOG
(
ERROR
)
<<
"Genarate trand2simp dict failed"
;
return
-
1
;
return
-
1
;
}
}
...
@@ -113,14 +153,14 @@ int FrontEngineInterface::ReadConfFile() {
...
@@ -113,14 +153,14 @@ int FrontEngineInterface::ReadConfFile() {
while
(
std
::
getline
(
is
,
line
))
{
while
(
std
::
getline
(
is
,
line
))
{
if
(
line
.
substr
(
0
,
2
)
==
"--"
)
{
if
(
line
.
substr
(
0
,
2
)
==
"--"
)
{
size_t
pos
=
line
.
find_first_of
(
"="
,
0
);
size_t
pos
=
line
.
find_first_of
(
"="
,
0
);
std
::
string
key
=
line
.
substr
(
2
,
pos
-
2
);
std
::
string
key
=
line
.
substr
(
2
,
pos
-
2
);
std
::
string
value
=
line
.
substr
(
pos
+
1
);
std
::
string
value
=
line
.
substr
(
pos
+
1
);
conf_map
[
key
]
=
value
;
conf_map
[
key
]
=
value
;
LOG
(
INFO
)
<<
"Key: "
<<
key
<<
"; Value: "
<<
value
;
LOG
(
INFO
)
<<
"Key: "
<<
key
<<
"; Value: "
<<
value
;
}
}
}
}
// jieba conf path
// jieba conf path
_jieba_dict_path
=
conf_map
[
"jieba_dict_path"
];
_jieba_dict_path
=
conf_map
[
"jieba_dict_path"
];
_jieba_hmm_path
=
conf_map
[
"jieba_hmm_path"
];
_jieba_hmm_path
=
conf_map
[
"jieba_hmm_path"
];
_jieba_user_dict_path
=
conf_map
[
"jieba_user_dict_path"
];
_jieba_user_dict_path
=
conf_map
[
"jieba_user_dict_path"
];
...
@@ -137,23 +177,26 @@ int FrontEngineInterface::ReadConfFile() {
...
@@ -137,23 +177,26 @@ int FrontEngineInterface::ReadConfFile() {
return
0
;
return
0
;
}
}
int
FrontEngineInterface
::
Trand2Simp
(
const
std
::
wstring
&
sentence
,
std
::
wstring
&
sentence_simp
)
{
int
FrontEngineInterface
::
Trand2Simp
(
const
std
::
wstring
&
sentence
,
//sentence_simp = sentence;
std
::
wstring
*
sentence_simp
)
{
for
(
int
i
=
0
;
i
<
sentence
.
length
();
i
++
)
{
// sentence_simp = sentence;
for
(
int
i
=
0
;
i
<
sentence
.
length
();
i
++
)
{
std
::
wstring
temp
(
1
,
sentence
[
i
]);
std
::
wstring
temp
(
1
,
sentence
[
i
]);
std
::
string
sigle_word
=
ppspeech
::
wstring2utf8string
(
temp
);
std
::
string
sigle_word
=
ppspeech
::
wstring2utf8string
(
temp
);
// 单个字是否在繁转简的字典里
// 单个字是否在繁转简的字典里
if
(
trand_simp_map
.
find
(
sigle_word
)
==
trand_simp_map
.
end
())
{
if
(
trand_simp_map
.
find
(
sigle_word
)
==
trand_simp_map
.
end
())
{
sentence_simp
+=
temp
;
sentence_simp
->
append
(
temp
);
}
else
{
}
else
{
sentence_simp
+=
(
ppspeech
::
utf8string2wstring
(
trand_simp_map
[
sigle_word
]));
sentence_simp
->
append
(
(
ppspeech
::
utf8string2wstring
(
trand_simp_map
[
sigle_word
])));
}
}
}
}
return
0
;
return
0
;
}
}
int
FrontEngineInterface
::
GenDict
(
const
std
::
string
&
dict_file
,
std
::
map
<
std
::
string
,
std
::
string
>
&
map
)
{
int
FrontEngineInterface
::
GenDict
(
const
std
::
string
&
dict_file
,
std
::
map
<
std
::
string
,
std
::
string
>
*
map
)
{
std
::
ifstream
is
(
dict_file
.
c_str
(),
std
::
ifstream
::
in
);
std
::
ifstream
is
(
dict_file
.
c_str
(),
std
::
ifstream
::
in
);
if
(
!
is
.
good
())
{
if
(
!
is
.
good
())
{
LOG
(
ERROR
)
<<
"Cannot open dict file: "
<<
dict_file
;
LOG
(
ERROR
)
<<
"Cannot open dict file: "
<<
dict_file
;
...
@@ -163,28 +206,32 @@ int FrontEngineInterface::GenDict(const std::string &dict_file, std::map<std::st
...
@@ -163,28 +206,32 @@ int FrontEngineInterface::GenDict(const std::string &dict_file, std::map<std::st
while
(
std
::
getline
(
is
,
line
))
{
while
(
std
::
getline
(
is
,
line
))
{
size_t
pos
=
line
.
find_first_of
(
" "
,
0
);
size_t
pos
=
line
.
find_first_of
(
" "
,
0
);
key
=
line
.
substr
(
0
,
pos
);
key
=
line
.
substr
(
0
,
pos
);
value
=
line
.
substr
(
pos
+
1
);
value
=
line
.
substr
(
pos
+
1
);
map
[
key
]
=
value
;
(
*
map
)[
key
]
=
value
;
}
}
return
0
;
return
0
;
}
}
int
FrontEngineInterface
::
GetSegResult
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
&
seg
,
int
FrontEngineInterface
::
GetSegResult
(
std
::
vector
<
std
::
string
>
&
seg_words
)
{
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
*
seg
,
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
::
iterator
iter
;
std
::
vector
<
std
::
string
>
*
seg_words
)
{
for
(
iter
=
seg
.
begin
();
iter
!=
seg
.
end
();
iter
++
)
{
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>::
iterator
iter
;
seg_words
.
push_back
((
*
iter
).
first
);
for
(
iter
=
seg
->
begin
();
iter
!=
seg
->
end
();
iter
++
)
{
seg_words
->
push_back
((
*
iter
).
first
);
}
}
return
0
;
return
0
;
}
}
int
FrontEngineInterface
::
GetSentenceIds
(
const
std
::
string
&
sentence
,
std
::
vector
<
int
>
&
phoneids
,
std
::
vector
<
int
>
&
toneids
)
{
int
FrontEngineInterface
::
GetSentenceIds
(
const
std
::
string
&
sentence
,
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
cut_result
;
//分词结果包含词和词性
std
::
vector
<
int
>
*
phoneids
,
if
(
0
!=
Cut
(
sentence
,
cut_result
))
{
std
::
vector
<
int
>
*
toneids
)
{
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
cut_result
;
//分词结果包含词和词性
if
(
0
!=
Cut
(
sentence
,
&
cut_result
))
{
LOG
(
ERROR
)
<<
"Cut sentence:
\"
"
<<
sentence
<<
"
\"
failed"
;
LOG
(
ERROR
)
<<
"Cut sentence:
\"
"
<<
sentence
<<
"
\"
failed"
;
return
-
1
;
return
-
1
;
}
}
if
(
0
!=
GetWordsIds
(
cut_result
,
phoneids
,
toneids
))
{
if
(
0
!=
GetWordsIds
(
cut_result
,
phoneids
,
toneids
))
{
LOG
(
ERROR
)
<<
"Get words phoneids failed"
;
LOG
(
ERROR
)
<<
"Get words phoneids failed"
;
return
-
1
;
return
-
1
;
...
@@ -192,81 +239,89 @@ int FrontEngineInterface::GetSentenceIds(const std::string &sentence, std::vecto
...
@@ -192,81 +239,89 @@ int FrontEngineInterface::GetSentenceIds(const std::string &sentence, std::vecto
return
0
;
return
0
;
}
}
int
FrontEngineInterface
::
GetWordsIds
(
const
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
&
cut_result
,
std
::
vector
<
int
>
&
phoneids
,
int
FrontEngineInterface
::
GetWordsIds
(
std
::
vector
<
int
>
&
toneids
)
{
const
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
&
cut_result
,
std
::
vector
<
int
>
*
phoneids
,
std
::
vector
<
int
>
*
toneids
)
{
std
::
string
word
;
std
::
string
word
;
std
::
string
pos
;
std
::
string
pos
;
std
::
vector
<
std
::
string
>
word_initials
;
std
::
vector
<
std
::
string
>
word_initials
;
std
::
vector
<
std
::
string
>
word_finals
;
std
::
vector
<
std
::
string
>
word_finals
;
std
::
string
phone
;
std
::
string
phone
;
for
(
int
i
=
0
;
i
<
cut_result
.
size
();
i
++
)
{
for
(
int
i
=
0
;
i
<
cut_result
.
size
();
i
++
)
{
word
=
cut_result
[
i
].
first
;
word
=
cut_result
[
i
].
first
;
pos
=
cut_result
[
i
].
second
;
pos
=
cut_result
[
i
].
second
;
if
(
std
::
find
(
_punc_omit
.
begin
(),
_punc_omit
.
end
(),
word
)
==
_punc_omit
.
end
())
{
// 非可忽略的标点
if
(
std
::
find
(
_punc_omit
.
begin
(),
_punc_omit
.
end
(),
word
)
==
_punc_omit
.
end
())
{
// 非可忽略的标点
word_initials
=
{};
word_initials
=
{};
word_finals
=
{};
word_finals
=
{};
phone
=
""
;
phone
=
""
;
// 判断是否在标点符号集合中
// 判断是否在标点符号集合中
if
(
std
::
find
(
_punc
.
begin
(),
_punc
.
end
(),
word
)
==
_punc
.
end
())
{
// 文字
if
(
std
::
find
(
_punc
.
begin
(),
_punc
.
end
(),
word
)
==
_punc
.
end
())
{
// 文字
// 获取字词的声母韵母列表
// 获取字词的声母韵母列表
if
(
0
!=
GetInitialsFinals
(
word
,
word_initials
,
word_finals
))
{
if
(
0
!=
LOG
(
ERROR
)
<<
"Genarate the word_initials and word_finals of "
<<
word
<<
" failed"
;
GetInitialsFinals
(
word
,
&
word_initials
,
&
word_finals
))
{
LOG
(
ERROR
)
<<
"Genarate the word_initials and word_finals of "
<<
word
<<
" failed"
;
return
-
1
;
return
-
1
;
}
}
// 对读音进行修改
// 对读音进行修改
if
(
0
!=
ModifyTone
(
word
,
pos
,
word_finals
))
{
if
(
0
!=
ModifyTone
(
word
,
pos
,
&
word_finals
))
{
LOG
(
ERROR
)
<<
"Failed to modify tone."
;
LOG
(
ERROR
)
<<
"Failed to modify tone."
;
}
}
// 对儿化音进行修改
// 对儿化音进行修改
std
::
vector
<
std
::
vector
<
std
::
string
>>
new_initals_finals
=
MergeErhua
(
word_initials
,
word_finals
,
word
,
pos
);
std
::
vector
<
std
::
vector
<
std
::
string
>>
new_initals_finals
=
MergeErhua
(
word_initials
,
word_finals
,
word
,
pos
);
word_initials
=
new_initals_finals
[
0
];
word_initials
=
new_initals_finals
[
0
];
word_finals
=
new_initals_finals
[
1
];
word_finals
=
new_initals_finals
[
1
];
// 将声母和韵母合并成音素
// 将声母和韵母合并成音素
assert
(
word_initials
.
size
()
==
word_finals
.
size
());
assert
(
word_initials
.
size
()
==
word_finals
.
size
());
std
::
string
temp_phone
;
std
::
string
temp_phone
;
for
(
int
j
=
0
;
j
<
word_initials
.
size
();
j
++
)
{
for
(
int
j
=
0
;
j
<
word_initials
.
size
();
j
++
)
{
if
(
word_initials
[
j
]
!=
""
)
{
if
(
word_initials
[
j
]
!=
""
)
{
temp_phone
=
word_initials
[
j
]
+
" "
+
word_finals
[
j
];
temp_phone
=
word_initials
[
j
]
+
" "
+
word_finals
[
j
];
}
else
{
}
else
{
temp_phone
=
word_finals
[
j
];
temp_phone
=
word_finals
[
j
];
}
}
if
(
j
==
0
)
{
if
(
j
==
0
)
{
phone
+=
temp_phone
;
phone
+=
temp_phone
;
}
else
{
}
else
{
phone
+=
(
" "
+
temp_phone
);
phone
+=
(
" "
+
temp_phone
);
}
}
}
}
}
else
{
// 标点符号
}
else
{
// 标点符号
if
(
_seperate_tone
==
"true"
)
{
if
(
_seperate_tone
==
"true"
)
{
phone
=
"sp0"
;
// speedyspeech
phone
=
"sp0"
;
// speedyspeech
}
else
{
}
else
{
phone
=
"sp"
;
// fastspeech2
phone
=
"sp"
;
// fastspeech2
}
}
}
}
// 音素到音素id
// 音素到音素id
if
(
0
!=
Phone2Phoneid
(
phone
,
phoneids
,
toneids
))
{
if
(
0
!=
Phone2Phoneid
(
phone
,
phoneids
,
toneids
))
{
LOG
(
ERROR
)
<<
"Genarate the phone id of "
<<
word
<<
" failed"
;
LOG
(
ERROR
)
<<
"Genarate the phone id of "
<<
word
<<
" failed"
;
return
-
1
;
return
-
1
;
}
}
}
}
}
}
return
0
;
return
0
;
}
}
int
FrontEngineInterface
::
Cut
(
const
std
::
string
&
sentence
,
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
&
cut_result
)
{
int
FrontEngineInterface
::
Cut
(
const
std
::
string
&
sentence
,
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
*
cut_result
)
{
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
cut_result_jieba
;
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
cut_result_jieba
;
// 结巴分词
// 结巴分词
_jieba
->
Tag
(
sentence
,
cut_result_jieba
);
_jieba
->
Tag
(
sentence
,
cut_result_jieba
);
// 对分词后结果进行整合
// 对分词后结果进行整合
if
(
0
!=
MergeforModify
(
cut_result_jieba
,
cut_result
))
{
if
(
0
!=
MergeforModify
(
&
cut_result_jieba
,
cut_result
))
{
LOG
(
ERROR
)
<<
"Failed to modify for word segmentation result."
;
LOG
(
ERROR
)
<<
"Failed to modify for word segmentation result."
;
return
-
1
;
return
-
1
;
}
}
...
@@ -274,50 +329,57 @@ int FrontEngineInterface::Cut(const std::string &sentence, std::vector<std::pair
...
@@ -274,50 +329,57 @@ int FrontEngineInterface::Cut(const std::string &sentence, std::vector<std::pair
return
0
;
return
0
;
}
}
int
FrontEngineInterface
::
GetPhone
(
const
std
::
string
&
word
,
std
::
string
&
phone
)
{
int
FrontEngineInterface
::
GetPhone
(
const
std
::
string
&
word
,
std
::
string
*
phone
)
{
// 判断 word 在不在 词典里,如果不在,进行CutAll分词
// 判断 word 在不在 词典里,如果不在,进行CutAll分词
if
(
word_phone_map
.
find
(
word
)
==
word_phone_map
.
end
())
{
if
(
word_phone_map
.
find
(
word
)
==
word_phone_map
.
end
())
{
std
::
vector
<
std
::
string
>
wordcut
;
std
::
vector
<
std
::
string
>
wordcut
;
_jieba
->
CutAll
(
word
,
wordcut
);
_jieba
->
CutAll
(
word
,
wordcut
);
phone
=
word_phone_map
[
wordcut
[
0
]]
;
phone
->
assign
(
word_phone_map
[
wordcut
[
0
]])
;
for
(
int
i
=
1
;
i
<
wordcut
.
size
();
i
++
)
{
for
(
int
i
=
1
;
i
<
wordcut
.
size
();
i
++
)
{
phone
+=
(
" "
+
word_phone_map
[
wordcut
[
i
]]
);
phone
->
assign
((
*
phone
)
+
(
" "
+
word_phone_map
[
wordcut
[
i
]])
);
}
}
}
else
{
}
else
{
phone
=
word_phone_map
[
word
]
;
phone
->
assign
(
word_phone_map
[
word
])
;
}
}
return
0
;
return
0
;
}
}
int
FrontEngineInterface
::
Phone2Phoneid
(
const
std
::
string
&
phone
,
std
::
vector
<
int
>
&
phoneid
,
std
::
vector
<
int
>
&
toneid
)
{
int
FrontEngineInterface
::
Phone2Phoneid
(
const
std
::
string
&
phone
,
std
::
vector
<
int
>
*
phoneid
,
std
::
vector
<
int
>
*
toneid
)
{
std
::
vector
<
std
::
string
>
phone_vec
;
std
::
vector
<
std
::
string
>
phone_vec
;
phone_vec
=
absl
::
StrSplit
(
phone
,
" "
);
phone_vec
=
absl
::
StrSplit
(
phone
,
" "
);
std
::
string
temp_phone
;
std
::
string
temp_phone
;
for
(
int
i
=
0
;
i
<
phone_vec
.
size
();
i
++
)
{
for
(
int
i
=
0
;
i
<
phone_vec
.
size
();
i
++
)
{
temp_phone
=
phone_vec
[
i
];
temp_phone
=
phone_vec
[
i
];
if
(
_seperate_tone
==
"true"
)
{
if
(
_seperate_tone
==
"true"
)
{
phoneid
.
push_back
(
atoi
((
phone_id_map
[
temp_phone
.
substr
(
0
,
temp_phone
.
length
()
-
1
)]).
c_str
()));
phoneid
->
push_back
(
atoi
(
toneid
.
push_back
(
atoi
((
tone_id_map
[
temp_phone
.
substr
(
temp_phone
.
length
()
-
1
,
temp_phone
.
length
())]).
c_str
()));
(
phone_id_map
[
temp_phone
.
substr
(
0
,
temp_phone
.
length
()
-
1
)])
}
else
{
.
c_str
()));
phoneid
.
push_back
(
atoi
((
phone_id_map
[
temp_phone
]).
c_str
()));
toneid
->
push_back
(
atoi
((
tone_id_map
[
temp_phone
.
substr
(
temp_phone
.
length
()
-
1
,
temp_phone
.
length
())])
.
c_str
()));
}
else
{
phoneid
->
push_back
(
atoi
((
phone_id_map
[
temp_phone
]).
c_str
()));
}
}
}
}
return
0
;
return
0
;
}
}
// 根据韵母判断该词中每个字的读音都为第三声。true表示词中每个字都是第三声
// 根据韵母判断该词中每个字的读音都为第三声。true表示词中每个字都是第三声
bool
FrontEngineInterface
::
AllToneThree
(
const
std
::
vector
<
std
::
string
>
&
finals
)
{
bool
FrontEngineInterface
::
AllToneThree
(
const
std
::
vector
<
std
::
string
>
&
finals
)
{
bool
flags
=
true
;
bool
flags
=
true
;
for
(
int
i
=
0
;
i
<
finals
.
size
();
i
++
)
{
for
(
int
i
=
0
;
i
<
finals
.
size
();
i
++
)
{
if
((
int
)
finals
[
i
].
back
(
)
!=
51
)
{
//如果读音不为第三声
if
(
static_cast
<
int
>
(
finals
[
i
].
back
()
)
!=
51
)
{
//如果读音不为第三声
flags
=
false
;
flags
=
false
;
}
}
}
}
return
flags
;
return
flags
;
}
}
// 判断词是否是叠词
// 判断词是否是叠词
...
@@ -325,45 +387,49 @@ bool FrontEngineInterface::IsReduplication(const std::string &word) {
...
@@ -325,45 +387,49 @@ bool FrontEngineInterface::IsReduplication(const std::string &word) {
bool
flags
=
false
;
bool
flags
=
false
;
std
::
wstring
word_wstr
=
ppspeech
::
utf8string2wstring
(
word
);
std
::
wstring
word_wstr
=
ppspeech
::
utf8string2wstring
(
word
);
int
len
=
word_wstr
.
length
();
int
len
=
word_wstr
.
length
();
if
(
len
==
2
&&
word_wstr
[
0
]
==
word_wstr
[
1
])
{
if
(
len
==
2
&&
word_wstr
[
0
]
==
word_wstr
[
1
])
{
flags
=
true
;
flags
=
true
;
}
}
return
flags
;
return
flags
;
}
}
// 获取每个字词的声母和韵母列表, word_initials 为声母列表,word_finals 为韵母列表
// 获取每个字词的声母和韵母列表, word_initials 为声母列表,word_finals
int
FrontEngineInterface
::
GetInitialsFinals
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
string
>
&
word_initials
,
std
::
vector
<
std
::
string
>
&
word_finals
)
{
// 为韵母列表
std
::
string
phone
;
int
FrontEngineInterface
::
GetInitialsFinals
(
GetPhone
(
word
,
phone
);
//获取字词对应的音素
const
std
::
string
&
word
,
std
::
vector
<
std
::
string
>
*
word_initials
,
std
::
vector
<
std
::
string
>
*
word_finals
)
{
std
::
string
phone
;
GetPhone
(
word
,
&
phone
);
//获取字词对应的音素
std
::
vector
<
std
::
string
>
phone_vec
=
absl
::
StrSplit
(
phone
,
" "
);
std
::
vector
<
std
::
string
>
phone_vec
=
absl
::
StrSplit
(
phone
,
" "
);
//获取韵母,每个字的音素有1或者2个,start为单个字音素的起始位置。
//获取韵母,每个字的音素有1或者2个,start为单个字音素的起始位置。
int
start
=
0
;
int
start
=
0
;
while
(
start
<
phone_vec
.
size
())
{
while
(
start
<
phone_vec
.
size
())
{
if
(
phone_vec
[
start
]
==
"sp"
||
phone_vec
[
start
]
==
"sp0"
)
{
if
(
phone_vec
[
start
]
==
"sp"
||
phone_vec
[
start
]
==
"sp0"
)
{
start
+=
1
;
start
+=
1
;
}
}
else
if
(
isdigit
(
phone_vec
[
start
].
back
())
==
0
||
// 最后一位不是数字或者最后一位的数字是0,均表示声母,第二个是韵母
static_cast
<
int
>
(
phone_vec
[
start
].
back
())
==
48
)
{
else
if
(
isdigit
(
phone_vec
[
start
].
back
())
==
0
||
(
int
)
phone_vec
[
start
].
back
()
==
48
)
{
word_initials
->
push_back
(
phone_vec
[
start
]);
word_initials
.
push_back
(
phone_vec
[
start
]);
word_finals
->
push_back
(
phone_vec
[
start
+
1
]);
word_finals
.
push_back
(
phone_vec
[
start
+
1
]);
start
+=
2
;
start
+=
2
;
}
else
{
}
else
{
word_initials
.
push_back
(
""
);
word_initials
->
push_back
(
""
);
word_finals
.
push_back
(
phone_vec
[
start
]);
word_finals
->
push_back
(
phone_vec
[
start
]);
start
+=
1
;
start
+=
1
;
}
}
}
}
assert
(
word_finals
.
size
()
==
ppspeech
::
utf8string2wstring
(
word
).
length
()
&&
word_finals
.
size
()
==
word_initials
.
size
());
assert
(
word_finals
->
size
()
==
ppspeech
::
utf8string2wstring
(
word
).
length
()
&&
word_finals
->
size
()
==
word_initials
->
size
());
return
0
;
return
0
;
}
}
// 获取每个字词的韵母列表
// 获取每个字词的韵母列表
int
FrontEngineInterface
::
GetFinals
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
string
>
&
word_finals
)
{
int
FrontEngineInterface
::
GetFinals
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
string
>
*
word_finals
)
{
std
::
vector
<
std
::
string
>
word_initials
;
std
::
vector
<
std
::
string
>
word_initials
;
if
(
0
!=
GetInitialsFinals
(
word
,
word_initials
,
word_finals
))
{
if
(
0
!=
GetInitialsFinals
(
word
,
&
word_initials
,
word_finals
))
{
LOG
(
ERROR
)
<<
"Failed to get word finals"
;
LOG
(
ERROR
)
<<
"Failed to get word finals"
;
return
-
1
;
return
-
1
;
}
}
...
@@ -371,162 +437,189 @@ int FrontEngineInterface::GetFinals(const std::string &word, std::vector<std::st
...
@@ -371,162 +437,189 @@ int FrontEngineInterface::GetFinals(const std::string &word, std::vector<std::st
return
0
;
return
0
;
}
}
int
FrontEngineInterface
::
Word2WordVec
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
wstring
>
&
wordvec
)
{
int
FrontEngineInterface
::
Word2WordVec
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
wstring
>
*
wordvec
)
{
std
::
wstring
word_wstr
=
ppspeech
::
utf8string2wstring
(
word
);
std
::
wstring
word_wstr
=
ppspeech
::
utf8string2wstring
(
word
);
for
(
int
i
=
0
;
i
<
word_wstr
.
length
();
i
++
)
{
for
(
int
i
=
0
;
i
<
word_wstr
.
length
();
i
++
)
{
std
::
wstring
word_sigle
(
1
,
word_wstr
[
i
]);
std
::
wstring
word_sigle
(
1
,
word_wstr
[
i
]);
wordvec
.
push_back
(
word_sigle
);
wordvec
->
push_back
(
word_sigle
);
}
}
return
0
;
return
0
;
}
}
// yuantian01解释:把一个词再进行分词找到。例子:小雨伞 --> 小 雨伞 或者 小雨 伞
// yuantian01解释:把一个词再进行分词找到。例子:小雨伞 --> 小 雨伞 或者 小雨 伞
int
FrontEngineInterface
::
SplitWord
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
string
>
&
new_word_vec
)
{
int
FrontEngineInterface
::
SplitWord
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
string
>
*
new_word_vec
)
{
std
::
vector
<
std
::
string
>
word_vec
;
std
::
vector
<
std
::
string
>
word_vec
;
std
::
string
second_subword
;
std
::
string
second_subword
;
_jieba
->
CutForSearch
(
word
,
word_vec
);
_jieba
->
CutForSearch
(
word
,
word_vec
);
// 升序
// 升序
std
::
sort
(
word_vec
.
begin
(),
word_vec
.
end
(),
[](
std
::
string
a
,
std
::
string
b
)
{
return
a
.
size
()
>
b
.
size
();});
std
::
sort
(
word_vec
.
begin
(),
word_vec
.
end
(),
[](
std
::
string
a
,
std
::
string
b
)
{
return
a
.
size
()
>
b
.
size
();
});
std
::
string
first_subword
=
word_vec
[
0
];
// 提取长度最短的字符串
std
::
string
first_subword
=
word_vec
[
0
];
// 提取长度最短的字符串
int
first_begin_idx
=
word
.
find_first_of
(
first_subword
);
int
first_begin_idx
=
word
.
find_first_of
(
first_subword
);
if
(
first_begin_idx
==
0
)
{
if
(
first_begin_idx
==
0
)
{
second_subword
=
word
.
substr
(
first_subword
.
length
());
second_subword
=
word
.
substr
(
first_subword
.
length
());
new_word_vec
.
push_back
(
first_subword
);
new_word_vec
->
push_back
(
first_subword
);
new_word_vec
.
push_back
(
second_subword
);
new_word_vec
->
push_back
(
second_subword
);
}
else
{
}
else
{
second_subword
=
word
.
substr
(
0
,
word
.
length
()
-
first_subword
.
length
());
second_subword
=
word
.
substr
(
0
,
word
.
length
()
-
first_subword
.
length
());
new_word_vec
.
push_back
(
second_subword
);
new_word_vec
->
push_back
(
second_subword
);
new_word_vec
.
push_back
(
first_subword
);
new_word_vec
->
push_back
(
first_subword
);
}
}
return
0
;
return
0
;
}
}
//example: 不 一起 --> 不一起
// example: 不 一起 --> 不一起
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
FrontEngineInterface
::
MergeBu
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
&
seg_result
)
{
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
FrontEngineInterface
::
MergeBu
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
*
seg_result
)
{
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
result
;
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
result
;
std
::
string
word
;
std
::
string
word
;
std
::
string
pos
;
std
::
string
pos
;
std
::
string
last_word
=
""
;
std
::
string
last_word
=
""
;
for
(
int
i
=
0
;
i
<
seg_result
.
size
();
i
++
)
{
for
(
int
i
=
0
;
i
<
seg_result
->
size
();
i
++
)
{
word
=
s
eg_result
[
i
].
first
;
word
=
s
td
::
get
<
0
>
((
*
seg_result
)[
i
])
;
pos
=
s
eg_result
[
i
].
second
;
pos
=
s
td
::
get
<
1
>
((
*
seg_result
)[
i
])
;
if
(
last_word
==
"不"
)
{
if
(
last_word
==
"不"
)
{
word
=
last_word
+
word
;
word
=
last_word
+
word
;
}
}
if
(
word
!=
"不"
)
{
if
(
word
!=
"不"
)
{
result
.
push_back
(
make_pair
(
word
,
pos
));
result
.
push_back
(
make_pair
(
word
,
pos
));
}
}
last_word
=
word
;
last_word
=
word
;
}
}
if
(
last_word
==
"不"
)
{
if
(
last_word
==
"不"
)
{
result
.
push_back
(
make_pair
(
last_word
,
"d"
));
result
.
push_back
(
make_pair
(
last_word
,
"d"
));
last_word
=
""
;
last_word
=
""
;
}
}
return
result
;
return
result
;
}
}
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
FrontEngineInterface
::
Mergeyi
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
&
seg_result
)
{
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
FrontEngineInterface
::
Mergeyi
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
result_temp
;
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
*
seg_result
)
{
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
*
result_temp
=
new
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
();
std
::
string
word
;
std
::
string
word
;
std
::
string
pos
;
std
::
string
pos
;
// function 1 example: 听 一 听 --> 听一听
// function 1 example: 听 一 听 --> 听一听
for
(
int
i
=
0
;
i
<
seg_result
.
size
();
i
++
)
{
for
(
int
i
=
0
;
i
<
seg_result
->
size
();
i
++
)
{
word
=
seg_result
[
i
].
first
;
word
=
std
::
get
<
0
>
((
*
seg_result
)[
i
]);
pos
=
seg_result
[
i
].
second
;
pos
=
std
::
get
<
1
>
((
*
seg_result
)[
i
]);
if
((
i
-
1
>=
0
)
&&
(
word
==
"一"
)
&&
(
i
+
1
<
seg_result
.
size
())
&&
(
seg_result
[
i
-
1
].
first
==
seg_result
[
i
+
1
].
first
)
&&
seg_result
[
i
-
1
].
second
==
"v"
)
{
if
((
i
-
1
>=
0
)
&&
(
word
==
"一"
)
&&
(
i
+
1
<
seg_result
->
size
())
&&
result_temp
[
i
-
1
].
first
=
result_temp
[
i
-
1
].
first
+
"一"
+
result_temp
[
i
-
1
].
first
;
(
std
::
get
<
0
>
((
*
seg_result
)[
i
-
1
])
==
std
::
get
<
0
>
((
*
seg_result
)[
i
+
1
]))
&&
std
::
get
<
1
>
((
*
seg_result
)[
i
-
1
])
==
"v"
)
{
std
::
get
<
0
>
((
*
result_temp
)[
i
-
1
])
=
std
::
get
<
0
>
((
*
result_temp
)[
i
-
1
])
+
"一"
+
std
::
get
<
0
>
((
*
result_temp
)[
i
-
1
]);
}
else
{
if
((
i
-
2
>=
0
)
&&
(
std
::
get
<
0
>
((
*
seg_result
)[
i
-
1
])
==
"一"
)
&&
(
std
::
get
<
0
>
((
*
seg_result
)[
i
-
2
])
==
word
)
&&
(
pos
==
"v"
))
{
continue
;
}
else
{
}
else
{
if
((
i
-
2
>=
0
)
&&
(
seg_result
[
i
-
1
].
first
==
"一"
)
&&
(
seg_result
[
i
-
2
].
first
==
word
)
&&
(
pos
==
"v"
))
{
result_temp
->
push_back
(
make_pair
(
word
,
pos
));
continue
;
}
}
else
{
}
result_temp
.
push_back
(
make_pair
(
word
,
pos
));
}
}
}
}
// function 2 example: 一 你 --> 一你
// function 2 example: 一 你 --> 一你
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
result
=
{};
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
result
=
{};
for
(
int
j
=
0
;
j
<
result_temp
.
size
();
j
++
)
{
for
(
int
j
=
0
;
j
<
result_temp
->
size
();
j
++
)
{
word
=
result_temp
[
j
].
first
;
word
=
std
::
get
<
0
>
((
*
result_temp
)[
j
])
;
pos
=
result_temp
[
j
].
second
;
pos
=
std
::
get
<
1
>
((
*
result_temp
)[
j
])
;
if
((
result
.
size
()
!=
0
)
&&
(
result
.
back
().
first
==
"一"
))
{
if
((
result
.
size
()
!=
0
)
&&
(
result
.
back
().
first
==
"一"
))
{
result
.
back
().
first
=
result
.
back
().
first
+
word
;
result
.
back
().
first
=
result
.
back
().
first
+
word
;
}
else
{
}
else
{
result
.
push_back
(
make_pair
(
word
,
pos
));
result
.
push_back
(
make_pair
(
word
,
pos
));
}
}
}
}
return
result
;
return
result
;
}
}
// example: 你 你 --> 你你
// example: 你 你 --> 你你
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
FrontEngineInterface
::
MergeReduplication
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
&
seg_result
)
{
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
FrontEngineInterface
::
MergeReduplication
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
*
seg_result
)
{
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
result
;
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
result
;
std
::
string
word
;
std
::
string
word
;
std
::
string
pos
;
std
::
string
pos
;
for
(
int
i
=
0
;
i
<
seg_result
.
size
();
i
++
)
{
for
(
int
i
=
0
;
i
<
seg_result
->
size
();
i
++
)
{
word
=
seg_result
[
i
].
first
;
word
=
std
::
get
<
0
>
((
*
seg_result
)[
i
]);
pos
=
seg_result
[
i
].
second
;
pos
=
std
::
get
<
1
>
((
*
seg_result
)[
i
]);
if
((
result
.
size
()
!=
0
)
&&
(
word
==
result
.
back
().
first
))
{
if
((
result
.
size
()
!=
0
)
&&
(
word
==
result
.
back
().
first
))
{
result
.
back
().
first
=
result
.
back
().
first
+
seg_result
[
i
].
first
;
result
.
back
().
first
=
result
.
back
().
first
+
std
::
get
<
0
>
((
*
seg_result
)[
i
]);
}
else
{
}
else
{
result
.
push_back
(
make_pair
(
word
,
pos
));
result
.
push_back
(
make_pair
(
word
,
pos
));
}
}
}
}
return
result
;
return
result
;
}
}
// the first and the second words are all_tone_three
// the first and the second words are all_tone_three
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
FrontEngineInterface
::
MergeThreeTones
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
&
seg_result
)
{
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
FrontEngineInterface
::
MergeThreeTones
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
*
seg_result
)
{
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
result
;
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
result
;
std
::
string
word
;
std
::
string
word
;
std
::
string
pos
;
std
::
string
pos
;
std
::
vector
<
std
::
vector
<
std
::
string
>>
finals
;
//韵母数组
std
::
vector
<
std
::
vector
<
std
::
string
>>
finals
;
//韵母数组
std
::
vector
<
std
::
string
>
word_final
;
std
::
vector
<
std
::
string
>
word_final
;
std
::
vector
<
bool
>
merge_last
(
seg_result
.
size
(),
false
);
std
::
vector
<
bool
>
merge_last
(
seg_result
->
size
(),
false
);
// 判断最后一个分词结果是不是标点,不看标点的声母韵母
// 判断最后一个分词结果是不是标点,不看标点的声母韵母
int
word_num
=
seg_result
.
size
()
-
1
;
int
word_num
=
seg_result
->
size
()
-
1
;
if
(
std
::
find
(
_punc
.
begin
(),
_punc
.
end
(),
seg_result
[
word_num
].
first
)
==
_punc
.
end
()){
// 最后一个分词结果不是标点
// seg_result[word_num].first
if
(
std
::
find
(
_punc
.
begin
(),
_punc
.
end
(),
std
::
get
<
0
>
((
*
seg_result
)[
word_num
]))
==
_punc
.
end
())
{
// 最后一个分词结果不是标点
word_num
+=
1
;
word_num
+=
1
;
}
}
// 获取韵母数组
// 获取韵母数组
for
(
int
i
=
0
;
i
<
word_num
;
i
++
)
{
for
(
int
i
=
0
;
i
<
word_num
;
i
++
)
{
word_final
=
{};
word_final
=
{};
word
=
seg_result
[
i
].
first
;
word
=
std
::
get
<
0
>
((
*
seg_result
)[
i
]);
pos
=
seg_result
[
i
].
second
;
pos
=
std
::
get
<
1
>
((
*
seg_result
)[
i
]);
if
(
std
::
find
(
_punc_omit
.
begin
(),
_punc_omit
.
end
(),
word
)
==
_punc_omit
.
end
())
{
// 非可忽略的标点,即文字
if
(
std
::
find
(
_punc_omit
.
begin
(),
_punc_omit
.
end
(),
word
)
==
if
(
0
!=
GetFinals
(
word
,
word_final
))
{
_punc_omit
.
end
())
{
// 非可忽略的标点,即文字
if
(
0
!=
GetFinals
(
word
,
&
word_final
))
{
LOG
(
ERROR
)
<<
"Failed to get the final of word."
;
LOG
(
ERROR
)
<<
"Failed to get the final of word."
;
}
}
}
}
finals
.
push_back
(
word_final
);
finals
.
push_back
(
word_final
);
}
}
assert
(
word_num
==
finals
.
size
());
assert
(
word_num
==
finals
.
size
());
// 对第三声读音的字词分词结果进行处理
// 对第三声读音的字词分词结果进行处理
for
(
int
i
=
0
;
i
<
word_num
;
i
++
)
{
for
(
int
i
=
0
;
i
<
word_num
;
i
++
)
{
word
=
seg_result
[
i
].
first
;
word
=
std
::
get
<
0
>
((
*
seg_result
)[
i
]);
pos
=
seg_result
[
i
].
second
;
pos
=
std
::
get
<
1
>
((
*
seg_result
)[
i
]);
if
(
i
-
1
>=
0
&&
AllToneThree
(
finals
[
i
-
1
])
&&
AllToneThree
(
finals
[
i
])
&&
!
merge_last
[
i
-
1
])
{
if
(
i
-
1
>=
0
&&
AllToneThree
(
finals
[
i
-
1
])
&&
// if the last word is reduplication, not merge, because reduplication need to be _neural_sandhi
AllToneThree
(
finals
[
i
])
&&
!
merge_last
[
i
-
1
])
{
if
(
!
IsReduplication
(
seg_result
[
i
-
1
].
first
)
&&
// if the last word is reduplication, not merge, because
(
ppspeech
::
utf8string2wstring
(
seg_result
[
i
-
1
].
first
)).
length
()
+
(
ppspeech
::
utf8string2wstring
(
word
)).
length
()
<=
3
)
{
// reduplication need to be _neural_sandhi
result
.
back
().
first
=
result
.
back
().
first
+
seg_result
[
i
].
first
;
// seg_result[i - 1].first
if
(
!
IsReduplication
(
std
::
get
<
0
>
((
*
seg_result
)[
i
-
1
]))
&&
(
ppspeech
::
utf8string2wstring
(
std
::
get
<
0
>
((
*
seg_result
)[
i
-
1
])))
.
length
()
+
(
ppspeech
::
utf8string2wstring
(
word
)).
length
()
<=
3
)
{
result
.
back
().
first
=
result
.
back
().
first
+
std
::
get
<
0
>
((
*
seg_result
)[
i
]);
merge_last
[
i
]
=
true
;
merge_last
[
i
]
=
true
;
}
else
{
}
else
{
result
.
push_back
(
make_pair
(
word
,
pos
));
result
.
push_back
(
make_pair
(
word
,
pos
));
...
@@ -537,54 +630,73 @@ std::vector<std::pair<std::string, std::string>> FrontEngineInterface::MergeThre
...
@@ -537,54 +630,73 @@ std::vector<std::pair<std::string, std::string>> FrontEngineInterface::MergeThre
}
}
//把标点的分词结果补上
//把标点的分词结果补上
if
(
word_num
<
seg_result
.
size
())
{
if
(
word_num
<
seg_result
->
size
())
{
result
.
push_back
(
make_pair
(
seg_result
[
word_num
].
first
,
seg_result
[
word_num
].
second
));
result
.
push_back
(
// seg_result[word_num].first seg_result[word_num].second
// std::get<0>((*seg_result)[word_num])
make_pair
(
std
::
get
<
0
>
((
*
seg_result
)[
word_num
]),
std
::
get
<
1
>
((
*
seg_result
)[
word_num
])));
}
}
return
result
;
return
result
;
}
}
// the last char of first word and the first char of second word is tone_three
// the last char of first word and the first char of second word is tone_three
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
FrontEngineInterface
::
MergeThreeTones2
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
&
seg_result
)
{
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
FrontEngineInterface
::
MergeThreeTones2
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
*
seg_result
)
{
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
result
;
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
result
;
std
::
string
word
;
std
::
string
word
;
std
::
string
pos
;
std
::
string
pos
;
std
::
vector
<
std
::
vector
<
std
::
string
>>
finals
;
//韵母数组
std
::
vector
<
std
::
vector
<
std
::
string
>>
finals
;
//韵母数组
std
::
vector
<
std
::
string
>
word_final
;
std
::
vector
<
std
::
string
>
word_final
;
std
::
vector
<
bool
>
merge_last
(
seg_result
.
size
(),
false
);
std
::
vector
<
bool
>
merge_last
(
seg_result
->
size
(),
false
);
// 判断最后一个分词结果是不是标点
// 判断最后一个分词结果是不是标点
int
word_num
=
seg_result
.
size
()
-
1
;
int
word_num
=
seg_result
->
size
()
-
1
;
if
(
std
::
find
(
_punc
.
begin
(),
_punc
.
end
(),
seg_result
[
word_num
].
first
)
==
_punc
.
end
()){
// 最后一个分词结果不是标点
if
(
std
::
find
(
_punc
.
begin
(),
_punc
.
end
(),
std
::
get
<
0
>
((
*
seg_result
)[
word_num
]))
==
_punc
.
end
())
{
// 最后一个分词结果不是标点
word_num
+=
1
;
word_num
+=
1
;
}
}
// 获取韵母数组
// 获取韵母数组
for
(
int
i
=
0
;
i
<
word_num
;
i
++
)
{
for
(
int
i
=
0
;
i
<
word_num
;
i
++
)
{
word_final
=
{};
word_final
=
{};
word
=
s
eg_result
[
i
].
first
;
word
=
s
td
::
get
<
0
>
((
*
seg_result
)[
i
])
;
pos
=
s
eg_result
[
i
].
second
;
pos
=
s
td
::
get
<
1
>
((
*
seg_result
)[
i
])
;
// 如果是文字,则获取韵母,如果是可忽略的标点,例如引号,则跳过
// 如果是文字,则获取韵母,如果是可忽略的标点,例如引号,则跳过
if
(
std
::
find
(
_punc_omit
.
begin
(),
_punc_omit
.
end
(),
word
)
==
_punc_omit
.
end
())
{
if
(
std
::
find
(
_punc_omit
.
begin
(),
_punc_omit
.
end
(),
word
)
==
if
(
0
!=
GetFinals
(
word
,
word_final
))
{
_punc_omit
.
end
())
{
if
(
0
!=
GetFinals
(
word
,
&
word_final
))
{
LOG
(
ERROR
)
<<
"Failed to get the final of word."
;
LOG
(
ERROR
)
<<
"Failed to get the final of word."
;
}
}
}
}
finals
.
push_back
(
word_final
);
finals
.
push_back
(
word_final
);
}
}
assert
(
word_num
==
finals
.
size
());
assert
(
word_num
==
finals
.
size
());
// 对第三声读音的字词分词结果进行处理
// 对第三声读音的字词分词结果进行处理
for
(
int
i
=
0
;
i
<
word_num
;
i
++
)
{
for
(
int
i
=
0
;
i
<
word_num
;
i
++
)
{
word
=
seg_result
[
i
].
first
;
word
=
std
::
get
<
0
>
((
*
seg_result
)[
i
]);
pos
=
seg_result
[
i
].
second
;
pos
=
std
::
get
<
1
>
((
*
seg_result
)[
i
]);
if
(
i
-
1
>=
0
&&
!
finals
[
i
-
1
].
empty
()
&&
absl
::
EndsWith
(
finals
[
i
-
1
].
back
(),
"3"
)
==
true
&&
if
(
i
-
1
>=
0
&&
!
finals
[
i
-
1
].
empty
()
&&
!
finals
[
i
].
empty
()
&&
absl
::
EndsWith
(
finals
[
i
].
front
(),
"3"
)
==
true
&&
!
merge_last
[
i
-
1
])
{
absl
::
EndsWith
(
finals
[
i
-
1
].
back
(),
"3"
)
==
true
&&
// if the last word is reduplication, not merge, because reduplication need to be _neural_sandhi
!
finals
[
i
].
empty
()
&&
if
(
!
IsReduplication
(
seg_result
[
i
-
1
].
first
)
&&
absl
::
EndsWith
(
finals
[
i
].
front
(),
"3"
)
==
true
&&
(
ppspeech
::
utf8string2wstring
(
seg_result
[
i
-
1
].
first
)).
length
()
+
ppspeech
::
utf8string2wstring
(
word
).
length
()
<=
3
)
{
!
merge_last
[
i
-
1
])
{
result
.
back
().
first
=
result
.
back
().
first
+
seg_result
[
i
].
first
;
// if the last word is reduplication, not merge, because
// reduplication need to be _neural_sandhi
// seg_result[i - 1].first
if
(
!
IsReduplication
(
std
::
get
<
0
>
((
*
seg_result
)[
i
-
1
]))
&&
(
ppspeech
::
utf8string2wstring
(
std
::
get
<
0
>
((
*
seg_result
)[
i
-
1
])))
.
length
()
+
ppspeech
::
utf8string2wstring
(
word
).
length
()
<=
3
)
{
result
.
back
().
first
=
result
.
back
().
first
+
std
::
get
<
0
>
((
*
seg_result
)[
i
]);
merge_last
[
i
]
=
true
;
merge_last
[
i
]
=
true
;
}
else
{
}
else
{
result
.
push_back
(
make_pair
(
word
,
pos
));
result
.
push_back
(
make_pair
(
word
,
pos
));
...
@@ -595,73 +707,86 @@ std::vector<std::pair<std::string, std::string>> FrontEngineInterface::MergeThre
...
@@ -595,73 +707,86 @@ std::vector<std::pair<std::string, std::string>> FrontEngineInterface::MergeThre
}
}
//把标点的分词结果补上
//把标点的分词结果补上
if
(
word_num
<
seg_result
.
size
())
{
if
(
word_num
<
seg_result
->
size
())
{
result
.
push_back
(
make_pair
(
seg_result
[
word_num
].
first
,
seg_result
[
word_num
].
second
));
result
.
push_back
(
make_pair
(
std
::
get
<
0
>
((
*
seg_result
)[
word_num
]),
std
::
get
<
1
>
((
*
seg_result
)[
word_num
])));
}
}
return
result
;
return
result
;
}
}
// example: 吃饭 儿 --> 吃饭儿
// example: 吃饭 儿 --> 吃饭儿
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
FrontEngineInterface
::
MergeEr
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
&
seg_result
)
{
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
FrontEngineInterface
::
MergeEr
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
*
seg_result
)
{
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
result
;
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
result
;
std
::
string
word
;
std
::
string
word
;
std
::
string
pos
;
std
::
string
pos
;
for
(
int
i
=
0
;
i
<
seg_result
.
size
();
i
++
)
{
for
(
int
i
=
0
;
i
<
seg_result
->
size
();
i
++
)
{
word
=
seg_result
[
i
].
first
;
word
=
std
::
get
<
0
>
((
*
seg_result
)[
i
]);
pos
=
seg_result
[
i
].
second
;
pos
=
std
::
get
<
1
>
((
*
seg_result
)[
i
]);
if
((
i
-
1
>=
0
)
&&
(
word
==
"儿"
)){
if
((
i
-
1
>=
0
)
&&
(
word
==
"儿"
))
{
result
.
back
().
first
=
result
.
back
().
first
+
seg_result
[
i
].
first
;
result
.
back
().
first
=
result
.
back
().
first
+
std
::
get
<
0
>
((
*
seg_result
)[
i
]);
}
else
{
}
else
{
result
.
push_back
(
make_pair
(
word
,
pos
));
result
.
push_back
(
make_pair
(
word
,
pos
));
}
}
}
}
return
result
;
return
result
;
}
}
int
FrontEngineInterface
::
MergeforModify
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
&
seg_word_type
,
int
FrontEngineInterface
::
MergeforModify
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
&
modify_seg_word_type
)
{
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
*
seg_word_type
,
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
*
modify_seg_word_type
)
{
std
::
vector
<
std
::
string
>
seg_result
;
std
::
vector
<
std
::
string
>
seg_result
;
GetSegResult
(
seg_word_type
,
seg_result
);
GetSegResult
(
seg_word_type
,
&
seg_result
);
LOG
(
INFO
)
<<
"Before merge, seg result is: "
<<
limonp
::
Join
(
seg_result
.
begin
(),
seg_result
.
end
(),
"/"
);
LOG
(
INFO
)
<<
"Before merge, seg result is: "
<<
limonp
::
Join
(
seg_result
.
begin
(),
seg_result
.
end
(),
"/"
);
modify_seg_word_type
=
MergeBu
(
seg_word_type
);
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
tmp
;
modify_seg_word_type
=
Mergeyi
(
modify_seg_word_type
);
tmp
=
MergeBu
(
seg_word_type
);
modify_seg_word_type
=
MergeReduplication
(
modify_seg_word_type
);
*
modify_seg_word_type
=
tmp
;
modify_seg_word_type
=
MergeThreeTones
(
modify_seg_word_type
);
tmp
=
Mergeyi
(
modify_seg_word_type
);
modify_seg_word_type
=
MergeThreeTones2
(
modify_seg_word_type
);
*
modify_seg_word_type
=
tmp
;
modify_seg_word_type
=
MergeEr
(
modify_seg_word_type
);
tmp
=
MergeReduplication
(
modify_seg_word_type
);
*
modify_seg_word_type
=
tmp
;
tmp
=
MergeThreeTones
(
modify_seg_word_type
);
*
modify_seg_word_type
=
tmp
;
tmp
=
MergeThreeTones2
(
modify_seg_word_type
);
*
modify_seg_word_type
=
tmp
;
tmp
=
MergeEr
(
modify_seg_word_type
);
*
modify_seg_word_type
=
tmp
;
seg_result
=
{};
seg_result
=
{};
GetSegResult
(
modify_seg_word_type
,
seg_result
);
LOG
(
INFO
)
<<
"After merge, seg result is: "
<<
limonp
::
Join
(
seg_result
.
begin
(),
seg_result
.
end
(),
"/"
);
GetSegResult
(
modify_seg_word_type
,
&
seg_result
);
LOG
(
INFO
)
<<
"After merge, seg result is: "
<<
limonp
::
Join
(
seg_result
.
begin
(),
seg_result
.
end
(),
"/"
);
return
0
;
return
0
;
}
}
int
FrontEngineInterface
::
BuSandi
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
string
>
&
finals
)
{
int
FrontEngineInterface
::
BuSandi
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
string
>
*
finals
)
{
std
::
wstring
bu
=
L"不"
;
std
::
wstring
bu
=
L"不"
;
std
::
vector
<
std
::
wstring
>
wordvec
;
std
::
vector
<
std
::
wstring
>
wordvec
;
// 一个词转成向量形式
// 一个词转成向量形式
if
(
0
!=
Word2WordVec
(
word
,
wordvec
))
{
if
(
0
!=
Word2WordVec
(
word
,
&
wordvec
))
{
LOG
(
ERROR
)
<<
"Failed to get word vector"
;
LOG
(
ERROR
)
<<
"Failed to get word vector"
;
return
-
1
;
return
-
1
;
}
}
// e.g. 看不懂 b u4 --> b u5, 将韵母的最后一位替换成 5
// e.g. 看不懂 b u4 --> b u5, 将韵母的最后一位替换成 5
if
(
wordvec
.
size
()
==
3
&&
wordvec
[
1
]
==
bu
)
{
if
(
wordvec
.
size
()
==
3
&&
wordvec
[
1
]
==
bu
)
{
finals
[
1
]
=
finals
[
1
].
replace
(
finals
[
1
].
length
()
-
1
,
1
,
"5"
);
(
*
finals
)[
1
]
=
(
*
finals
)[
1
].
replace
((
*
finals
)
[
1
].
length
()
-
1
,
1
,
"5"
);
}
else
{
}
else
{
// e.g. 不怕 b u4 --> b u2, 将韵母的最后一位替换成 2
// e.g. 不怕 b u4 --> b u2, 将韵母的最后一位替换成 2
for
(
int
i
=
0
;
i
<
wordvec
.
size
();
i
++
)
{
for
(
int
i
=
0
;
i
<
wordvec
.
size
();
i
++
)
{
if
(
wordvec
[
i
]
==
bu
&&
i
+
1
<
wordvec
.
size
()
&&
if
(
wordvec
[
i
]
==
bu
&&
i
+
1
<
wordvec
.
size
()
&&
absl
::
EndsWith
(
finals
[
i
+
1
],
"4"
)
==
true
)
{
absl
::
EndsWith
((
*
finals
)[
i
+
1
],
"4"
)
==
true
)
{
finals
[
i
]
=
finals
[
i
].
replace
(
finals
[
i
].
length
()
-
1
,
1
,
"2"
);
(
*
finals
)[
i
]
=
}
(
*
finals
)[
i
].
replace
((
*
finals
)[
i
].
length
()
-
1
,
1
,
"2"
);
}
}
}
}
}
...
@@ -669,11 +794,12 @@ int FrontEngineInterface::BuSandi(const std::string &word, std::vector<std::stri
...
@@ -669,11 +794,12 @@ int FrontEngineInterface::BuSandi(const std::string &word, std::vector<std::stri
}
}
int
FrontEngineInterface
::
YiSandhi
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
string
>
&
finals
)
{
int
FrontEngineInterface
::
YiSandhi
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
string
>
*
finals
)
{
std
::
wstring
yi
=
L"一"
;
std
::
wstring
yi
=
L"一"
;
std
::
vector
<
std
::
wstring
>
wordvec
;
std
::
vector
<
std
::
wstring
>
wordvec
;
// 一个词转成向量形式
// 一个词转成向量形式
if
(
0
!=
Word2WordVec
(
word
,
wordvec
))
{
if
(
0
!=
Word2WordVec
(
word
,
&
wordvec
))
{
LOG
(
ERROR
)
<<
"Failed to get word vector"
;
LOG
(
ERROR
)
<<
"Failed to get word vector"
;
return
-
1
;
return
-
1
;
}
}
...
@@ -681,44 +807,49 @@ int FrontEngineInterface::YiSandhi(const std::string &word, std::vector<std::str
...
@@ -681,44 +807,49 @@ int FrontEngineInterface::YiSandhi(const std::string &word, std::vector<std::str
//情况1:"一" in number sequences, e.g. 一零零, 二一零
//情况1:"一" in number sequences, e.g. 一零零, 二一零
std
::
wstring
num_wstr
=
L"零一二三四六七八九"
;
std
::
wstring
num_wstr
=
L"零一二三四六七八九"
;
std
::
wstring
word_wstr
=
ppspeech
::
utf8string2wstring
(
word
);
std
::
wstring
word_wstr
=
ppspeech
::
utf8string2wstring
(
word
);
if
(
word_wstr
.
find
(
yi
)
!=
word_wstr
.
npos
&&
wordvec
.
back
()
!=
yi
)
{
if
(
word_wstr
.
find
(
yi
)
!=
word_wstr
.
npos
&&
wordvec
.
back
()
!=
yi
)
{
int
flags
=
0
;
int
flags
=
0
;
for
(
int
j
=
0
;
j
<
wordvec
.
size
();
j
++
)
{
for
(
int
j
=
0
;
j
<
wordvec
.
size
();
j
++
)
{
if
(
num_wstr
.
find
(
wordvec
[
j
])
==
num_wstr
.
npos
)
{
if
(
num_wstr
.
find
(
wordvec
[
j
])
==
num_wstr
.
npos
)
{
flags
=
-
1
;
flags
=
-
1
;
break
;
break
;
}
}
}
}
if
(
flags
==
0
)
{
if
(
flags
==
0
)
{
return
0
;
return
0
;
}
}
}
else
if
(
wordvec
.
size
()
==
3
&&
wordvec
[
1
]
==
yi
&&
wordvec
[
0
]
==
wordvec
[
2
])
{
}
else
if
(
wordvec
.
size
()
==
3
&&
wordvec
[
1
]
==
yi
&&
wordvec
[
0
]
==
wordvec
[
2
])
{
// "一" between reduplication words shold be yi5, e.g. 看一看
// "一" between reduplication words shold be yi5, e.g. 看一看
finals
[
1
]
=
finals
[
1
].
replace
(
finals
[
1
].
length
()
-
1
,
1
,
"5"
);
(
*
finals
)[
1
]
=
(
*
finals
)[
1
].
replace
((
*
finals
)
[
1
].
length
()
-
1
,
1
,
"5"
);
}
else
if
(
wordvec
[
0
]
==
L"第"
&&
wordvec
[
1
]
==
yi
)
{
//以第一位开始
}
else
if
(
wordvec
[
0
]
==
L"第"
&&
wordvec
[
1
]
==
yi
)
{
//以第一位开始
finals
[
1
]
=
finals
[
1
].
replace
(
finals
[
1
].
length
()
-
1
,
1
,
"1"
);
(
*
finals
)[
1
]
=
(
*
finals
)[
1
].
replace
((
*
finals
)
[
1
].
length
()
-
1
,
1
,
"1"
);
}
else
{
}
else
{
for
(
int
i
=
0
;
i
<
wordvec
.
size
();
i
++
)
{
for
(
int
i
=
0
;
i
<
wordvec
.
size
();
i
++
)
{
if
(
wordvec
[
i
]
==
yi
&&
i
+
1
<
wordvec
.
size
())
{
if
(
wordvec
[
i
]
==
yi
&&
i
+
1
<
wordvec
.
size
())
{
if
(
absl
::
EndsWith
(
finals
[
i
+
1
],
"4"
)
==
true
)
{
if
(
absl
::
EndsWith
((
*
finals
)
[
i
+
1
],
"4"
)
==
true
)
{
// "一" before tone4 should be yi2, e.g. 一段
// "一" before tone4 should be yi2, e.g. 一段
finals
[
i
]
=
finals
[
i
].
replace
(
finals
[
i
].
length
()
-
1
,
1
,
"2"
);
(
*
finals
)[
i
]
=
(
*
finals
)[
i
].
replace
((
*
finals
)[
i
].
length
()
-
1
,
1
,
"2"
);
}
else
{
}
else
{
// "一" before non-tone4 should be yi4, e.g. 一天
// "一" before non-tone4 should be yi4, e.g. 一天
finals
[
i
]
=
finals
[
i
].
replace
(
finals
[
i
].
length
()
-
1
,
1
,
"4"
);
(
*
finals
)[
i
]
=
(
*
finals
)[
i
].
replace
((
*
finals
)[
i
].
length
()
-
1
,
1
,
"4"
);
}
}
}
}
}
}
}
}
return
0
;
return
0
;
}
}
int
FrontEngineInterface
::
NeuralSandhi
(
const
std
::
string
&
word
,
const
std
::
string
&
pos
,
std
::
vector
<
std
::
string
>
&
finals
)
{
int
FrontEngineInterface
::
NeuralSandhi
(
const
std
::
string
&
word
,
const
std
::
string
&
pos
,
std
::
vector
<
std
::
string
>
*
finals
)
{
std
::
wstring
word_wstr
=
ppspeech
::
utf8string2wstring
(
word
);
std
::
wstring
word_wstr
=
ppspeech
::
utf8string2wstring
(
word
);
std
::
vector
<
std
::
wstring
>
wordvec
;
std
::
vector
<
std
::
wstring
>
wordvec
;
// 一个词转成向量形式
// 一个词转成向量形式
if
(
0
!=
Word2WordVec
(
word
,
wordvec
))
{
if
(
0
!=
Word2WordVec
(
word
,
&
wordvec
))
{
LOG
(
ERROR
)
<<
"Failed to get word vector"
;
LOG
(
ERROR
)
<<
"Failed to get word vector"
;
return
-
1
;
return
-
1
;
}
}
...
@@ -726,10 +857,12 @@ int FrontEngineInterface::NeuralSandhi(const std::string &word, const std::strin
...
@@ -726,10 +857,12 @@ int FrontEngineInterface::NeuralSandhi(const std::string &word, const std::strin
assert
(
word_num
==
word_wstr
.
length
());
assert
(
word_num
==
word_wstr
.
length
());
// 情况1:reduplication words for n. and v. e.g. 奶奶, 试试, 旺旺
// 情况1:reduplication words for n. and v. e.g. 奶奶, 试试, 旺旺
for
(
int
j
=
0
;
j
<
wordvec
.
size
();
j
++
)
{
for
(
int
j
=
0
;
j
<
wordvec
.
size
();
j
++
)
{
std
::
string
inits
=
"nva"
;
std
::
string
inits
=
"nva"
;
if
(
j
-
1
>=
0
&&
wordvec
[
j
]
==
wordvec
[
j
-
1
]
&&
inits
.
find
(
pos
[
0
])
!=
inits
.
npos
)
{
if
(
j
-
1
>=
0
&&
wordvec
[
j
]
==
wordvec
[
j
-
1
]
&&
finals
[
j
]
=
finals
[
j
].
replace
(
finals
[
j
].
length
()
-
1
,
1
,
"5"
);
inits
.
find
(
pos
[
0
])
!=
inits
.
npos
)
{
(
*
finals
)[
j
]
=
(
*
finals
)[
j
].
replace
((
*
finals
)[
j
].
length
()
-
1
,
1
,
"5"
);
}
}
}
}
...
@@ -747,147 +880,204 @@ int FrontEngineInterface::NeuralSandhi(const std::string &word, const std::strin
...
@@ -747,147 +880,204 @@ int FrontEngineInterface::NeuralSandhi(const std::string &word, const std::strin
std
::
wstring
ge
=
L"个"
;
std
::
wstring
ge
=
L"个"
;
std
::
wstring
xiushi
=
L"几有两半多各整每做是零一二三四六七八九"
;
std
::
wstring
xiushi
=
L"几有两半多各整每做是零一二三四六七八九"
;
auto
ge_idx
=
word_wstr
.
find_first_of
(
ge
);
// 出现“个”的第一个位置
auto
ge_idx
=
word_wstr
.
find_first_of
(
ge
);
// 出现“个”的第一个位置
if
(
word_num
>=
1
&&
yuqici
.
find
(
wordvec
.
back
())
!=
yuqici
.
npos
)
{
if
(
word_num
>=
1
&&
yuqici
.
find
(
wordvec
.
back
())
!=
yuqici
.
npos
)
{
finals
.
back
()
=
finals
.
back
().
replace
(
finals
.
back
().
length
()
-
1
,
1
,
"5"
);
(
*
finals
).
back
()
=
}
else
if
(
word_num
>=
1
&&
de
.
find
(
wordvec
.
back
())
!=
de
.
npos
)
{
(
*
finals
).
back
().
replace
((
*
finals
).
back
().
length
()
-
1
,
1
,
"5"
);
finals
.
back
()
=
finals
.
back
().
replace
(
finals
.
back
().
length
()
-
1
,
1
,
"5"
);
}
else
if
(
word_num
>=
1
&&
de
.
find
(
wordvec
.
back
())
!=
de
.
npos
)
{
}
else
if
(
word_num
==
1
&&
le
.
find
(
wordvec
[
0
])
!=
le
.
npos
&&
find
(
le_pos
.
begin
(),
le_pos
.
end
(),
pos
)
!=
le_pos
.
end
())
{
(
*
finals
).
back
()
=
finals
.
back
()
=
finals
.
back
().
replace
(
finals
.
back
().
length
()
-
1
,
1
,
"5"
);
(
*
finals
).
back
().
replace
((
*
finals
).
back
().
length
()
-
1
,
1
,
"5"
);
}
else
if
(
word_num
>
1
&&
men
.
find
(
wordvec
.
back
())
!=
men
.
npos
&&
find
(
men_pos
.
begin
(),
men_pos
.
end
(),
pos
)
!=
men_pos
.
end
()
}
else
if
(
word_num
==
1
&&
le
.
find
(
wordvec
[
0
])
!=
le
.
npos
&&
&&
find
(
must_not_neural_tone_words
.
begin
(),
must_not_neural_tone_words
.
end
(),
word
)
!=
must_not_neural_tone_words
.
end
())
{
find
(
le_pos
.
begin
(),
le_pos
.
end
(),
pos
)
!=
le_pos
.
end
())
{
finals
.
back
()
=
finals
.
back
().
replace
(
finals
.
back
().
length
()
-
1
,
1
,
"5"
);
(
*
finals
).
back
()
=
}
else
if
(
word_num
>
1
&&
weizhi
.
find
(
wordvec
.
back
())
!=
weizhi
.
npos
&&
find
(
weizhi_pos
.
begin
(),
weizhi_pos
.
end
(),
pos
)
!=
weizhi_pos
.
end
())
{
(
*
finals
).
back
().
replace
((
*
finals
).
back
().
length
()
-
1
,
1
,
"5"
);
finals
.
back
()
=
finals
.
back
().
replace
(
finals
.
back
().
length
()
-
1
,
1
,
"5"
);
}
else
if
(
word_num
>
1
&&
men
.
find
(
wordvec
.
back
())
!=
men
.
npos
&&
}
else
if
(
word_num
>
1
&&
dong
.
find
(
wordvec
.
back
())
!=
dong
.
npos
&&
fangxiang
.
find
(
wordvec
[
word_num
-
2
])
!=
fangxiang
.
npos
)
{
find
(
men_pos
.
begin
(),
men_pos
.
end
(),
pos
)
!=
men_pos
.
end
()
&&
finals
.
back
()
=
finals
.
back
().
replace
(
finals
.
back
().
length
()
-
1
,
1
,
"5"
);
find
(
must_not_neural_tone_words
.
begin
(),
}
must_not_neural_tone_words
.
end
(),
// 情况3:对“个”字前面带有修饰词的字词读音处理
word
)
!=
must_not_neural_tone_words
.
end
())
{
else
if
((
ge_idx
!=
word_wstr
.
npos
&&
ge_idx
>=
1
&&
xiushi
.
find
(
wordvec
[
ge_idx
-
1
])
!=
xiushi
.
npos
)
(
*
finals
).
back
()
=
||
word_wstr
==
ge
)
{
(
*
finals
).
back
().
replace
((
*
finals
).
back
().
length
()
-
1
,
1
,
"5"
);
finals
.
back
()
=
finals
.
back
().
replace
(
finals
.
back
().
length
()
-
1
,
1
,
"5"
);
}
else
if
(
word_num
>
1
&&
weizhi
.
find
(
wordvec
.
back
())
!=
weizhi
.
npos
&&
find
(
weizhi_pos
.
begin
(),
weizhi_pos
.
end
(),
pos
)
!=
weizhi_pos
.
end
())
{
(
*
finals
).
back
()
=
(
*
finals
).
back
().
replace
((
*
finals
).
back
().
length
()
-
1
,
1
,
"5"
);
}
else
if
(
word_num
>
1
&&
dong
.
find
(
wordvec
.
back
())
!=
dong
.
npos
&&
fangxiang
.
find
(
wordvec
[
word_num
-
2
])
!=
fangxiang
.
npos
)
{
(
*
finals
).
back
()
=
(
*
finals
).
back
().
replace
((
*
finals
).
back
().
length
()
-
1
,
1
,
"5"
);
}
else
if
((
ge_idx
!=
word_wstr
.
npos
&&
ge_idx
>=
1
&&
xiushi
.
find
(
wordvec
[
ge_idx
-
1
])
!=
xiushi
.
npos
)
||
word_wstr
==
ge
)
{
(
*
finals
).
back
()
=
(
*
finals
).
back
().
replace
((
*
finals
).
back
().
length
()
-
1
,
1
,
"5"
);
}
else
{
}
else
{
if
(
find
(
must_neural_tone_words
.
begin
(),
must_neural_tone_words
.
end
(),
word
)
!=
must_neural_tone_words
.
end
()
if
(
find
(
must_neural_tone_words
.
begin
(),
||
(
word_num
>=
2
&&
find
(
must_neural_tone_words
.
begin
(),
must_neural_tone_words
.
end
(),
ppspeech
::
wstring2utf8string
(
word_wstr
.
substr
(
word_num
-
2
)))
!=
must_neural_tone_words
.
end
()))
{
must_neural_tone_words
.
end
(),
finals
.
back
()
=
finals
.
back
().
replace
(
finals
.
back
().
length
()
-
1
,
1
,
"5"
);
word
)
!=
must_neural_tone_words
.
end
()
||
}
(
word_num
>=
2
&&
find
(
must_neural_tone_words
.
begin
(),
must_neural_tone_words
.
end
(),
ppspeech
::
wstring2utf8string
(
word_wstr
.
substr
(
word_num
-
2
)))
!=
must_neural_tone_words
.
end
()))
{
(
*
finals
).
back
()
=
(
*
finals
).
back
().
replace
((
*
finals
).
back
().
length
()
-
1
,
1
,
"5"
);
}
}
}
// 进行进一步分词,把长词切分更短些
// 进行进一步分词,把长词切分更短些
std
::
vector
<
std
::
string
>
word_list
;
std
::
vector
<
std
::
string
>
word_list
;
if
(
0
!=
SplitWord
(
word
,
word_list
))
{
if
(
0
!=
SplitWord
(
word
,
&
word_list
))
{
LOG
(
ERROR
)
<<
"Failed to split word."
;
LOG
(
ERROR
)
<<
"Failed to split word."
;
return
-
1
;
return
-
1
;
}
}
// 创建对应的 韵母列表
// 创建对应的 韵母列表
std
::
vector
<
std
::
vector
<
std
::
string
>>
finals_list
;
std
::
vector
<
std
::
vector
<
std
::
string
>>
finals_list
;
std
::
vector
<
std
::
string
>
finals_temp
;
std
::
vector
<
std
::
string
>
finals_temp
;
finals_temp
.
assign
(
finals
.
begin
(),
finals
.
begin
()
+
ppspeech
::
utf8string2wstring
(
word_list
[
0
]).
length
());
finals_temp
.
assign
((
*
finals
).
begin
(),
(
*
finals
).
begin
()
+
ppspeech
::
utf8string2wstring
(
word_list
[
0
]).
length
());
finals_list
.
push_back
(
finals_temp
);
finals_list
.
push_back
(
finals_temp
);
finals_temp
.
assign
(
finals
.
begin
()
+
ppspeech
::
utf8string2wstring
(
word_list
[
0
]).
length
(),
finals
.
end
());
finals_temp
.
assign
(
(
*
finals
).
begin
()
+
ppspeech
::
utf8string2wstring
(
word_list
[
0
]).
length
(),
(
*
finals
).
end
());
finals_list
.
push_back
(
finals_temp
);
finals_list
.
push_back
(
finals_temp
);
finals
=
{}
;
finals
=
new
std
::
vector
<
std
::
string
>
()
;
for
(
int
i
=
0
;
i
<
word_list
.
size
();
i
++
)
{
for
(
int
i
=
0
;
i
<
word_list
.
size
();
i
++
)
{
std
::
wstring
temp_wstr
=
ppspeech
::
utf8string2wstring
(
word_list
[
i
]);
std
::
wstring
temp_wstr
=
ppspeech
::
utf8string2wstring
(
word_list
[
i
]);
if
((
find
(
must_neural_tone_words
.
begin
(),
must_neural_tone_words
.
end
(),
word_list
[
i
])
!=
must_neural_tone_words
.
end
())
if
((
find
(
must_neural_tone_words
.
begin
(),
||
(
temp_wstr
.
length
()
>=
2
&&
find
(
must_neural_tone_words
.
begin
(),
must_neural_tone_words
.
end
(),
ppspeech
::
wstring2utf8string
(
temp_wstr
.
substr
(
temp_wstr
.
length
()
-
2
)))
!=
must_neural_tone_words
.
end
()))
{
must_neural_tone_words
.
end
(),
finals_list
[
i
].
back
()
=
finals_list
[
i
].
back
().
replace
(
finals_list
[
i
].
back
().
length
()
-
1
,
1
,
"5"
);
word_list
[
i
])
!=
must_neural_tone_words
.
end
())
||
}
(
temp_wstr
.
length
()
>=
2
&&
finals
.
insert
(
finals
.
end
(),
finals_list
[
i
].
begin
(),
finals_list
[
i
].
end
());
find
(
must_neural_tone_words
.
begin
(),
must_neural_tone_words
.
end
(),
ppspeech
::
wstring2utf8string
(
temp_wstr
.
substr
(
temp_wstr
.
length
()
-
2
)))
!=
must_neural_tone_words
.
end
()))
{
finals_list
[
i
].
back
()
=
finals_list
[
i
].
back
().
replace
(
finals_list
[
i
].
back
().
length
()
-
1
,
1
,
"5"
);
}
(
*
finals
).
insert
(
(
*
finals
).
end
(),
finals_list
[
i
].
begin
(),
finals_list
[
i
].
end
());
}
}
return
0
;
return
0
;
}
}
int
FrontEngineInterface
::
ThreeSandhi
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
string
>
&
finals
)
{
int
FrontEngineInterface
::
ThreeSandhi
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
string
>
*
finals
)
{
std
::
wstring
word_wstr
=
ppspeech
::
utf8string2wstring
(
word
);
std
::
wstring
word_wstr
=
ppspeech
::
utf8string2wstring
(
word
);
std
::
vector
<
std
::
vector
<
std
::
string
>>
finals_list
;
std
::
vector
<
std
::
vector
<
std
::
string
>>
finals_list
;
std
::
vector
<
std
::
string
>
finals_temp
;
std
::
vector
<
std
::
string
>
finals_temp
;
std
::
vector
<
std
::
wstring
>
wordvec
;
std
::
vector
<
std
::
wstring
>
wordvec
;
// 一个词转成向量形式
// 一个词转成向量形式
if
(
0
!=
Word2WordVec
(
word
,
wordvec
))
{
if
(
0
!=
Word2WordVec
(
word
,
&
wordvec
))
{
LOG
(
ERROR
)
<<
"Failed to get word vector"
;
LOG
(
ERROR
)
<<
"Failed to get word vector"
;
return
-
1
;
return
-
1
;
}
}
int
word_num
=
wordvec
.
size
();
int
word_num
=
wordvec
.
size
();
assert
(
word_num
==
word_wstr
.
length
());
assert
(
word_num
==
word_wstr
.
length
());
if
(
word_num
==
2
&&
AllToneThree
(
finals
))
{
if
(
word_num
==
2
&&
AllToneThree
((
*
finals
)
))
{
finals
[
0
]
=
finals
[
0
].
replace
(
finals
[
0
].
length
()
-
1
,
1
,
"2"
);
(
*
finals
)[
0
]
=
(
*
finals
)[
0
].
replace
((
*
finals
)
[
0
].
length
()
-
1
,
1
,
"2"
);
}
else
if
(
word_num
==
3
)
{
}
else
if
(
word_num
==
3
)
{
// 进行进一步分词,把长词切分更短些
// 进行进一步分词,把长词切分更短些
std
::
vector
<
std
::
string
>
word_list
;
std
::
vector
<
std
::
string
>
word_list
;
if
(
0
!=
SplitWord
(
word
,
word_list
))
{
if
(
0
!=
SplitWord
(
word
,
&
word_list
))
{
LOG
(
ERROR
)
<<
"Failed to split word."
;
LOG
(
ERROR
)
<<
"Failed to split word."
;
return
-
1
;
return
-
1
;
}
}
if
(
AllToneThree
(
finals
))
{
if
(
AllToneThree
((
*
finals
)
))
{
std
::
wstring
temp_wstr
=
ppspeech
::
utf8string2wstring
(
word_list
[
0
]);
std
::
wstring
temp_wstr
=
ppspeech
::
utf8string2wstring
(
word_list
[
0
]);
//disyllabic + monosyllabic, e.g. 蒙古/包
// disyllabic + monosyllabic, e.g. 蒙古/包
if
(
temp_wstr
.
length
()
==
2
)
{
if
(
temp_wstr
.
length
()
==
2
)
{
finals
[
0
]
=
finals
[
0
].
replace
(
finals
[
0
].
length
()
-
1
,
1
,
"2"
);
(
*
finals
)[
0
]
=
finals
[
1
]
=
finals
[
1
].
replace
(
finals
[
1
].
length
()
-
1
,
1
,
"2"
);
(
*
finals
)[
0
].
replace
((
*
finals
)[
0
].
length
()
-
1
,
1
,
"2"
);
}
else
if
(
temp_wstr
.
length
()
==
1
)
{
//monosyllabic + disyllabic, e.g. 纸/老虎
(
*
finals
)[
1
]
=
finals
[
1
]
=
finals
[
1
].
replace
(
finals
[
1
].
length
()
-
1
,
1
,
"2"
);
(
*
finals
)[
1
].
replace
((
*
finals
)[
1
].
length
()
-
1
,
1
,
"2"
);
}
else
if
(
temp_wstr
.
length
()
==
1
)
{
// monosyllabic + disyllabic, e.g. 纸/老虎
(
*
finals
)[
1
]
=
(
*
finals
)[
1
].
replace
((
*
finals
)[
1
].
length
()
-
1
,
1
,
"2"
);
}
}
}
else
{
}
else
{
// 创建对应的 韵母列表
// 创建对应的 韵母列表
finals_temp
=
{};
finals_temp
=
{};
finals_list
=
{};
finals_list
=
{};
finals_temp
.
assign
(
finals
.
begin
(),
finals
.
begin
()
+
ppspeech
::
utf8string2wstring
(
word_list
[
0
]).
length
());
finals_temp
.
assign
(
(
*
finals
).
begin
(),
(
*
finals
).
begin
()
+
ppspeech
::
utf8string2wstring
(
word_list
[
0
]).
length
());
finals_list
.
push_back
(
finals_temp
);
finals_list
.
push_back
(
finals_temp
);
finals_temp
.
assign
(
finals
.
begin
()
+
ppspeech
::
utf8string2wstring
(
word_list
[
0
]).
length
(),
finals
.
end
());
finals_temp
.
assign
(
(
*
finals
).
begin
()
+
ppspeech
::
utf8string2wstring
(
word_list
[
0
]).
length
(),
(
*
finals
).
end
());
finals_list
.
push_back
(
finals_temp
);
finals_list
.
push_back
(
finals_temp
);
finals
=
{}
;
finals
=
new
std
::
vector
<
std
::
string
>
()
;
for
(
int
i
=
0
;
i
<
finals_list
.
size
();
i
++
)
{
for
(
int
i
=
0
;
i
<
finals_list
.
size
();
i
++
)
{
// e.g. 所有/人
// e.g. 所有/人
if
(
AllToneThree
(
finals_list
[
i
])
&&
finals_list
[
i
].
size
()
==
2
)
{
if
(
AllToneThree
(
finals_list
[
i
])
&&
finals_list
[
i
][
0
]
=
finals_list
[
i
][
0
].
replace
(
finals_list
[
i
][
0
].
length
()
-
1
,
1
,
"2"
);
finals_list
[
i
].
size
()
==
2
)
{
}
else
if
(
i
==
1
&&
!
(
AllToneThree
(
finals_list
[
i
]))
&&
absl
::
EndsWith
(
finals_list
[
i
][
0
],
"3"
)
==
true
finals_list
[
i
][
0
]
=
finals_list
[
i
][
0
].
replace
(
&&
absl
::
EndsWith
(
finals_list
[
0
].
back
(),
"3"
)
==
true
)
{
finals_list
[
i
][
0
].
length
()
-
1
,
1
,
"2"
);
finals_list
[
0
].
back
()
=
finals_list
[
0
].
back
().
replace
(
finals_list
[
0
].
back
().
length
()
-
1
,
1
,
"2"
);
}
else
if
(
i
==
1
&&
!
(
AllToneThree
(
finals_list
[
i
]))
&&
}
absl
::
EndsWith
(
finals_list
[
i
][
0
],
"3"
)
==
true
&&
absl
::
EndsWith
(
finals_list
[
0
].
back
(),
"3"
)
==
true
)
{
finals_list
[
0
].
back
()
=
finals_list
[
0
].
back
().
replace
(
finals_list
[
0
].
back
().
length
()
-
1
,
1
,
"2"
);
}
}
}
finals
.
insert
(
finals
.
end
(),
finals_list
[
0
].
begin
(),
finals_list
[
0
].
end
());
(
*
finals
).
insert
(
finals
.
insert
(
finals
.
end
(),
finals_list
[
1
].
begin
(),
finals_list
[
1
].
end
());
(
*
finals
).
end
(),
finals_list
[
0
].
begin
(),
finals_list
[
0
].
end
());
(
*
finals
).
insert
(
(
*
finals
).
end
(),
finals_list
[
1
].
begin
(),
finals_list
[
1
].
end
());
}
}
}
else
if
(
word_num
==
4
)
{
//将成语拆分为两个长度为 2 的单词
}
else
if
(
word_num
==
4
)
{
//将成语拆分为两个长度为 2 的单词
// 创建对应的 韵母列表
// 创建对应的 韵母列表
finals_temp
=
{};
finals_temp
=
{};
finals_list
=
{};
finals_list
=
{};
finals_temp
.
assign
(
finals
.
begin
(),
finals
.
begin
()
+
2
);
finals_temp
.
assign
(
(
*
finals
).
begin
(),
(
*
finals
)
.
begin
()
+
2
);
finals_list
.
push_back
(
finals_temp
);
finals_list
.
push_back
(
finals_temp
);
finals_temp
.
assign
(
finals
.
begin
()
+
2
,
finals
.
end
());
finals_temp
.
assign
(
(
*
finals
).
begin
()
+
2
,
(
*
finals
)
.
end
());
finals_list
.
push_back
(
finals_temp
);
finals_list
.
push_back
(
finals_temp
);
finals
=
{};
finals
=
new
std
::
vector
<
std
::
string
>
();
for
(
int
j
=
0
;
j
<
finals_list
.
size
();
j
++
){
for
(
int
j
=
0
;
j
<
finals_list
.
size
();
j
++
)
{
if
(
AllToneThree
(
finals_list
[
j
]))
{
if
(
AllToneThree
(
finals_list
[
j
]))
{
finals_list
[
j
][
0
]
=
finals_list
[
j
][
0
].
replace
(
finals_list
[
j
][
0
].
length
()
-
1
,
1
,
"2"
);
finals_list
[
j
][
0
]
=
finals_list
[
j
][
0
].
replace
(
finals_list
[
j
][
0
].
length
()
-
1
,
1
,
"2"
);
}
}
finals
.
insert
(
finals
.
end
(),
finals_list
[
j
].
begin
(),
finals_list
[
j
].
end
());
(
*
finals
).
insert
(
(
*
finals
).
end
(),
finals_list
[
j
].
begin
(),
finals_list
[
j
].
end
());
}
}
}
}
return
0
;
return
0
;
}
}
int
FrontEngineInterface
::
ModifyTone
(
const
std
::
string
&
word
,
const
std
::
string
&
pos
,
std
::
vector
<
std
::
string
>
&
finals
)
{
int
FrontEngineInterface
::
ModifyTone
(
const
std
::
string
&
word
,
if
((
0
!=
BuSandi
(
word
,
finals
))
||
(
0
!=
YiSandhi
(
word
,
finals
))
||
const
std
::
string
&
pos
,
(
0
!=
NeuralSandhi
(
word
,
pos
,
finals
))
||
(
0
!=
ThreeSandhi
(
word
,
finals
)))
{
std
::
vector
<
std
::
string
>
*
finals
)
{
LOG
(
ERROR
)
<<
"Failed to modify tone of the word: "
<<
word
;
if
((
0
!=
BuSandi
(
word
,
finals
))
||
(
0
!=
YiSandhi
(
word
,
finals
))
||
return
-
1
;
(
0
!=
NeuralSandhi
(
word
,
pos
,
finals
))
||
}
(
0
!=
ThreeSandhi
(
word
,
finals
)))
{
LOG
(
ERROR
)
<<
"Failed to modify tone of the word: "
<<
word
;
return
-
1
;
}
return
0
;
return
0
;
}
}
std
::
vector
<
std
::
vector
<
std
::
string
>>
FrontEngineInterface
::
MergeErhua
(
const
std
::
vector
<
std
::
string
>
&
initials
,
const
std
::
vector
<
std
::
string
>
&
finals
,
const
std
::
string
&
word
,
const
std
::
string
&
pos
)
{
std
::
vector
<
std
::
vector
<
std
::
string
>>
FrontEngineInterface
::
MergeErhua
(
const
std
::
vector
<
std
::
string
>
&
initials
,
const
std
::
vector
<
std
::
string
>
&
finals
,
const
std
::
string
&
word
,
const
std
::
string
&
pos
)
{
std
::
vector
<
std
::
string
>
new_initials
=
{};
std
::
vector
<
std
::
string
>
new_initials
=
{};
std
::
vector
<
std
::
string
>
new_finals
=
{};
std
::
vector
<
std
::
string
>
new_finals
=
{};
std
::
vector
<
std
::
vector
<
std
::
string
>>
new_initials_finals
;
std
::
vector
<
std
::
vector
<
std
::
string
>>
new_initials_finals
;
...
@@ -895,28 +1085,38 @@ std::vector<std::vector<std::string>> FrontEngineInterface::MergeErhua(const std
...
@@ -895,28 +1085,38 @@ std::vector<std::vector<std::string>> FrontEngineInterface::MergeErhua(const std
std
::
wstring
word_wstr
=
ppspeech
::
utf8string2wstring
(
word
);
std
::
wstring
word_wstr
=
ppspeech
::
utf8string2wstring
(
word
);
std
::
vector
<
std
::
wstring
>
wordvec
;
std
::
vector
<
std
::
wstring
>
wordvec
;
// 一个词转成向量形式
// 一个词转成向量形式
if
(
0
!=
Word2WordVec
(
word
,
wordvec
))
{
if
(
0
!=
Word2WordVec
(
word
,
&
wordvec
))
{
LOG
(
ERROR
)
<<
"Failed to get word vector"
;
LOG
(
ERROR
)
<<
"Failed to get word vector"
;
}
}
int
word_num
=
wordvec
.
size
();
int
word_num
=
wordvec
.
size
();
if
((
find
(
must_erhua
.
begin
(),
must_erhua
.
end
(),
word
)
==
must_erhua
.
end
())
&&
if
((
find
(
must_erhua
.
begin
(),
must_erhua
.
end
(),
word
)
==
((
find
(
not_erhua
.
begin
(),
not_erhua
.
end
(),
word
)
!=
not_erhua
.
end
())
||
(
find
(
specified_pos
.
begin
(),
specified_pos
.
end
(),
pos
)
!=
specified_pos
.
end
())))
{
must_erhua
.
end
())
&&
((
find
(
not_erhua
.
begin
(),
not_erhua
.
end
(),
word
)
!=
not_erhua
.
end
())
||
(
find
(
specified_pos
.
begin
(),
specified_pos
.
end
(),
pos
)
!=
specified_pos
.
end
())))
{
new_initials_finals
.
push_back
(
initials
);
new_initials_finals
.
push_back
(
initials
);
new_initials_finals
.
push_back
(
finals
);
new_initials_finals
.
push_back
(
finals
);
return
new_initials_finals
;
return
new_initials_finals
;
}
}
if
(
finals
.
size
()
!=
word_num
)
{
if
(
finals
.
size
()
!=
word_num
)
{
new_initials_finals
.
push_back
(
initials
);
new_initials_finals
.
push_back
(
initials
);
new_initials_finals
.
push_back
(
finals
);
new_initials_finals
.
push_back
(
finals
);
return
new_initials_finals
;
return
new_initials_finals
;
}
}
assert
(
finals
.
size
()
==
word_num
);
assert
(
finals
.
size
()
==
word_num
);
for
(
int
i
=
0
;
i
<
finals
.
size
();
i
++
)
{
for
(
int
i
=
0
;
i
<
finals
.
size
();
i
++
)
{
if
(
i
==
finals
.
size
()
-
1
&&
wordvec
[
i
]
==
L"儿"
&&
(
finals
[
i
]
==
"er2"
||
finals
[
i
]
==
"er5"
)
&&
word_num
>=
2
&&
if
(
i
==
finals
.
size
()
-
1
&&
wordvec
[
i
]
==
L"儿"
&&
find
(
not_erhua
.
begin
(),
not_erhua
.
end
(),
ppspeech
::
wstring2utf8string
(
word_wstr
.
substr
(
word_wstr
.
length
()
-
2
)))
==
not_erhua
.
end
()
&&
!
new_finals
.
empty
())
{
(
finals
[
i
]
==
"er2"
||
finals
[
i
]
==
"er5"
)
&&
word_num
>=
2
&&
new_finals
.
back
()
=
new_finals
.
back
().
substr
(
0
,
new_finals
.
back
().
length
()
-
1
)
+
"r"
+
new_finals
.
back
().
substr
(
new_finals
.
back
().
length
()
-
1
);
find
(
not_erhua
.
begin
(),
not_erhua
.
end
(),
ppspeech
::
wstring2utf8string
(
word_wstr
.
substr
(
word_wstr
.
length
()
-
2
)))
==
not_erhua
.
end
()
&&
!
new_finals
.
empty
())
{
new_finals
.
back
()
=
new_finals
.
back
().
substr
(
0
,
new_finals
.
back
().
length
()
-
1
)
+
"r"
+
new_finals
.
back
().
substr
(
new_finals
.
back
().
length
()
-
1
);
}
else
{
}
else
{
new_initials
.
push_back
(
initials
[
i
]);
new_initials
.
push_back
(
initials
[
i
]);
new_finals
.
push_back
(
finals
[
i
]);
new_finals
.
push_back
(
finals
[
i
]);
...
@@ -926,8 +1126,5 @@ std::vector<std::vector<std::string>> FrontEngineInterface::MergeErhua(const std
...
@@ -926,8 +1126,5 @@ std::vector<std::vector<std::string>> FrontEngineInterface::MergeErhua(const std
new_initials_finals
.
push_back
(
new_finals
);
new_initials_finals
.
push_back
(
new_finals
);
return
new_initials_finals
;
return
new_initials_finals
;
}
}
}
}
// namespace ppspeech
demos/TTSCppFrontend/src/front/front_interface.h
浏览文件 @
1aa7495d
// Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
//
// 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.
#ifndef PADDLE_TTS_SERVING_FRONT_FRONT_INTERFACE_H
#ifndef PADDLE_TTS_SERVING_FRONT_FRONT_INTERFACE_H
#define PADDLE_TTS_SERVING_FRONT_FRONT_INTERFACE_H
#define PADDLE_TTS_SERVING_FRONT_FRONT_INTERFACE_H
#include <glog/logging.h>
#include <fstream>
#include <map>
#include <map>
#include <string>
#include <memory>
#include <memory>
#include <fstream>
#include <string>
#include <glog/logging.h>
//#include "utils/dir_utils.h"
//#include "utils/dir_utils.h"
#include <cppjieba/Jieba.hpp>
#include <cppjieba/Jieba.hpp>
#include "front/text_normalize.h"
#include "absl/strings/str_split.h"
#include "absl/strings/str_split.h"
#include "front/text_normalize.h"
namespace
ppspeech
{
namespace
ppspeech
{
class
FrontEngineInterface
:
public
TextNormalizer
{
public:
FrontEngineInterface
(
std
::
string
conf
)
:
_conf_file
(
conf
)
{
TextNormalizer
();
_jieba
=
nullptr
;
_initialed
=
false
;
init
();
}
int
init
();
~
FrontEngineInterface
()
{
}
// 读取配置文件
int
ReadConfFile
();
// 简体转繁体
int
Trand2Simp
(
const
std
::
wstring
&
sentence
,
std
::
wstring
&
sentence_simp
);
// 生成字典
int
GenDict
(
const
std
::
string
&
file
,
std
::
map
<
std
::
string
,
std
::
string
>
&
map
);
// 由 词+词性的分词结果转为仅包含词的结果
int
GetSegResult
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
&
seg
,
std
::
vector
<
std
::
string
>
&
seg_words
);
// 生成句子的音素,音调id。如果音素和音调未分开,则 toneids 为空(fastspeech2),反之则不为空(speedyspeech)
int
GetSentenceIds
(
const
std
::
string
&
sentence
,
std
::
vector
<
int
>
&
phoneids
,
std
::
vector
<
int
>
&
toneids
);
// 根据分词结果获取词的音素,音调id,并对读音进行适当修改 (ModifyTone)。如果音素和音调未分开,则 toneids 为空(fastspeech2),反之则不为空(speedyspeech)
int
GetWordsIds
(
const
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
&
cut_result
,
std
::
vector
<
int
>
&
phoneids
,
std
::
vector
<
int
>
&
toneids
);
// 结巴分词生成包含词和词性的分词结果,再对分词结果进行适当修改 (MergeforModify)
int
Cut
(
const
std
::
string
&
sentence
,
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
&
cut_result
);
// 字词到音素的映射,查找字典
int
GetPhone
(
const
std
::
string
&
word
,
std
::
string
&
phone
);
// 音素到音素id
int
Phone2Phoneid
(
const
std
::
string
&
phone
,
std
::
vector
<
int
>
&
phoneid
,
std
::
vector
<
int
>
&
toneids
);
// 根据韵母判断该词中每个字的读音都为第三声。true表示词中每个字都是第三声
bool
AllToneThree
(
const
std
::
vector
<
std
::
string
>
&
finals
);
// 判断词是否是叠词
bool
IsReduplication
(
const
std
::
string
&
word
);
// 获取每个字词的声母韵母列表
int
GetInitialsFinals
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
string
>
&
word_initials
,
std
::
vector
<
std
::
string
>
&
word_finals
);
// 获取每个字词的韵母列表
int
GetFinals
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
string
>
&
word_finals
);
// 整个词转成向量形式,向量的每个元素对应词的一个字
class
FrontEngineInterface
:
public
TextNormalizer
{
int
Word2WordVec
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
wstring
>
&
wordvec
);
public:
explicit
FrontEngineInterface
(
std
::
string
conf
)
:
_conf_file
(
conf
)
{
TextNormalizer
();
_jieba
=
nullptr
;
_initialed
=
false
;
init
();
}
// 将整个词重新进行 full cut,分词后,各个词会在词典中
int
init
();
int
SplitWord
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
string
>
&
fullcut_word
);
~
FrontEngineInterface
()
{}
// 对分词结果进行处理:对包含“不”字的分词结果进行整理
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
MergeBu
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
&
seg_result
);
// 对分词结果进行处理:对包含“一”字的分词结果进行整理
// 读取配置文件
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
Mergeyi
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
&
seg_result
);
int
ReadConfFile
(
);
// 对分词结果进行处理:对前后相同的两个字进行合并
// 简体转繁体
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
MergeReduplication
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
&
seg_result
);
int
Trand2Simp
(
const
std
::
wstring
&
sentence
,
std
::
wstring
*
sentence_simp
);
// 对一个词和后一个词他们的读音均为第三声的两个词进行合并
// 生成字典
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
MergeThreeTones
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
&
seg_result
);
int
GenDict
(
const
std
::
string
&
file
,
std
::
map
<
std
::
string
,
std
::
string
>
*
map
);
// 对一个词的最后一个读音和后一个词的第一个读音为第三声的两个词进行合并
// 由 词+词性的分词结果转为仅包含词的结果
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
MergeThreeTones2
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
&
seg_result
);
int
GetSegResult
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
*
seg
,
std
::
vector
<
std
::
string
>
*
seg_words
);
// 对分词结果进行处理:对包含“儿”字的分词结果进行整理
// 生成句子的音素,音调id。如果音素和音调未分开,则 toneids
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
MergeEr
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
&
seg_result
);
// 为空(fastspeech2),反之则不为空(speedyspeech)
int
GetSentenceIds
(
const
std
::
string
&
sentence
,
std
::
vector
<
int
>
*
phoneids
,
std
::
vector
<
int
>
*
toneids
);
// 对分词结果进行处理、修改
// 根据分词结果获取词的音素,音调id,并对读音进行适当修改
int
MergeforModify
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
&
seg_result
,
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
&
merge_seg_result
);
// (ModifyTone)。如果音素和音调未分开,则 toneids
// 为空(fastspeech2),反之则不为空(speedyspeech)
int
GetWordsIds
(
const
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
&
cut_result
,
std
::
vector
<
int
>
*
phoneids
,
std
::
vector
<
int
>
*
toneids
);
// 结巴分词生成包含词和词性的分词结果,再对分词结果进行适当修改
// (MergeforModify)
int
Cut
(
const
std
::
string
&
sentence
,
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
*
cut_result
);
// 对包含“不”字的相关词音调进行修改
// 字词到音素的映射,查找字典
int
BuSandi
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
string
>
&
finals
);
int
GetPhone
(
const
std
::
string
&
word
,
std
::
string
*
phone
);
// 对包含“一”字的相关词音调进行修改
// 音素到音素id
int
YiSandhi
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
string
>
&
finals
);
int
Phone2Phoneid
(
const
std
::
string
&
phone
,
std
::
vector
<
int
>
*
phoneid
,
std
::
vector
<
int
>
*
toneids
);
// 对一些特殊词(包括量词,语助词等)的相关词音调进行修改
int
NeuralSandhi
(
const
std
::
string
&
word
,
const
std
::
string
&
pos
,
std
::
vector
<
std
::
string
>
&
finals
);
// 对包含第三声的相关词音调进行修改
// 根据韵母判断该词中每个字的读音都为第三声。true表示词中每个字都是第三声
int
ThreeSandhi
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
string
>
&
finals
);
bool
AllToneThree
(
const
std
::
vector
<
std
::
string
>
&
finals
);
// 对字词音调进行处理、修改
// 判断词是否是叠词
int
ModifyTone
(
const
std
::
string
&
word
,
const
std
::
string
&
pos
,
std
::
vector
<
std
::
string
>
&
finals
);
bool
IsReduplication
(
const
std
::
string
&
word
);
// 获取每个字词的声母韵母列表
int
GetInitialsFinals
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
string
>
*
word_initials
,
std
::
vector
<
std
::
string
>
*
word_finals
);
// 获取每个字词的韵母列表
int
GetFinals
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
string
>
*
word_finals
);
// 整个词转成向量形式,向量的每个元素对应词的一个字
int
Word2WordVec
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
wstring
>
*
wordvec
);
// 将整个词重新进行 full cut,分词后,各个词会在词典中
int
SplitWord
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
string
>
*
fullcut_word
);
// 对分词结果进行处理:对包含“不”字的分词结果进行整理
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
MergeBu
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
*
seg_result
);
// 对分词结果进行处理:对包含“一”字的分词结果进行整理
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
Mergeyi
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
*
seg_result
);
// 对分词结果进行处理:对前后相同的两个字进行合并
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
MergeReduplication
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
*
seg_result
);
// 对一个词和后一个词他们的读音均为第三声的两个词进行合并
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
MergeThreeTones
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
*
seg_result
);
// 对一个词的最后一个读音和后一个词的第一个读音为第三声的两个词进行合并
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
MergeThreeTones2
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
*
seg_result
);
// 对分词结果进行处理:对包含“儿”字的分词结果进行整理
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
MergeEr
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
*
seg_result
);
// 对分词结果进行处理、修改
int
MergeforModify
(
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
*
seg_result
,
std
::
vector
<
std
::
pair
<
std
::
string
,
std
::
string
>>
*
merge_seg_result
);
// 对儿化音进行处理
std
::
vector
<
std
::
vector
<
std
::
string
>>
MergeErhua
(
const
std
::
vector
<
std
::
string
>
&
initials
,
const
std
::
vector
<
std
::
string
>
&
finals
,
const
std
::
string
&
word
,
const
std
::
string
&
pos
);
// 对包含“不”字的相关词音调进行修改
int
BuSandi
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
string
>
*
finals
);
private:
// 对包含“一”字的相关词音调进行修改
bool
_initialed
;
int
YiSandhi
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
string
>
*
finals
);
cppjieba
::
Jieba
*
_jieba
;
std
::
vector
<
std
::
string
>
_punc
;
// 对一些特殊词(包括量词,语助词等)的相关词音调进行修改
std
::
vector
<
std
::
string
>
_punc_omit
;
int
NeuralSandhi
(
const
std
::
string
&
word
,
const
std
::
string
&
pos
,
std
::
vector
<
std
::
string
>
*
finals
);
std
::
string
_conf_file
;
// 对包含第三声的相关词音调进行修改
std
::
map
<
std
::
string
,
std
::
string
>
conf_map
;
int
ThreeSandhi
(
const
std
::
string
&
word
,
std
::
vector
<
std
::
string
>
*
finals
);
std
::
map
<
std
::
string
,
std
::
string
>
word_phone_map
;
std
::
map
<
std
::
string
,
std
::
string
>
phone_id_map
;
// 对字词音调进行处理、修改
std
::
map
<
std
::
string
,
std
::
string
>
tone_id_map
;
int
ModifyTone
(
const
std
::
string
&
word
,
std
::
map
<
std
::
string
,
std
::
string
>
trand_simp_map
;
const
std
::
string
&
pos
,
std
::
vector
<
std
::
string
>
*
finals
);
std
::
string
_jieba_dict_path
;
// 对儿化音进行处理
std
::
string
_jieba_hmm_path
;
std
::
vector
<
std
::
vector
<
std
::
string
>>
MergeErhua
(
std
::
string
_jieba_user_dict_path
;
const
std
::
vector
<
std
::
string
>
&
initials
,
std
::
string
_jieba_idf_path
;
const
std
::
vector
<
std
::
string
>
&
finals
,
std
::
string
_jieba_stop_word_path
;
const
std
::
string
&
word
,
const
std
::
string
&
pos
);
std
::
string
_seperate_tone
;
private:
std
::
string
_word2phone_path
;
bool
_initialed
;
std
::
string
_phone2id_path
;
cppjieba
::
Jieba
*
_jieba
;
std
::
string
_tone2id_path
;
std
::
vector
<
std
::
string
>
_punc
;
std
::
string
_trand2simp_path
;
std
::
vector
<
std
::
string
>
_punc_omit
;
std
::
vector
<
std
::
string
>
must_erhua
;
std
::
string
_conf_file
;
std
::
vector
<
std
::
string
>
not_erhua
;
std
::
map
<
std
::
string
,
std
::
string
>
conf_map
;
std
::
map
<
std
::
string
,
std
::
string
>
word_phone_map
;
std
::
map
<
std
::
string
,
std
::
string
>
phone_id_map
;
std
::
map
<
std
::
string
,
std
::
string
>
tone_id_map
;
std
::
map
<
std
::
string
,
std
::
string
>
trand_simp_map
;
std
::
vector
<
std
::
string
>
must_not_neural_tone_words
;
std
::
vector
<
std
::
string
>
must_neural_tone_words
;
std
::
string
_jieba_dict_path
;
std
::
string
_jieba_hmm_path
;
std
::
string
_jieba_user_dict_path
;
std
::
string
_jieba_idf_path
;
std
::
string
_jieba_stop_word_path
;
std
::
string
_seperate_tone
;
std
::
string
_word2phone_path
;
std
::
string
_phone2id_path
;
std
::
string
_tone2id_path
;
std
::
string
_trand2simp_path
;
std
::
vector
<
std
::
string
>
must_erhua
;
std
::
vector
<
std
::
string
>
not_erhua
;
};
std
::
vector
<
std
::
string
>
must_not_neural_tone_words
;
}
std
::
vector
<
std
::
string
>
must_neural_tone_words
;
};
}
// namespace ppspeech
#endif
#endif
\ No newline at end of file
demos/TTSCppFrontend/src/front/text_normalize.cpp
浏览文件 @
1aa7495d
// Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
//
// 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.
#include "front/text_normalize.h"
#include "front/text_normalize.h"
namespace
ppspeech
{
namespace
ppspeech
{
// 初始化 digits_map and unit_map
// 初始化 digits_map and unit_map
int
TextNormalizer
::
InitMap
()
{
int
TextNormalizer
::
InitMap
()
{
digits_map
[
"0"
]
=
"零"
;
digits_map
[
"0"
]
=
"零"
;
digits_map
[
"1"
]
=
"一"
;
digits_map
[
"1"
]
=
"一"
;
digits_map
[
"2"
]
=
"二"
;
digits_map
[
"2"
]
=
"二"
;
...
@@ -21,77 +33,84 @@ int TextNormalizer::InitMap() {
...
@@ -21,77 +33,84 @@ int TextNormalizer::InitMap() {
units_map
[
3
]
=
"千"
;
units_map
[
3
]
=
"千"
;
units_map
[
4
]
=
"万"
;
units_map
[
4
]
=
"万"
;
units_map
[
8
]
=
"亿"
;
units_map
[
8
]
=
"亿"
;
return
0
;
return
0
;
}
}
// 替换
// 替换
int
TextNormalizer
::
Replace
(
std
::
wstring
&
sentence
,
const
int
&
pos
,
const
int
&
len
,
const
std
::
wstring
&
repstr
)
{
int
TextNormalizer
::
Replace
(
std
::
wstring
*
sentence
,
const
int
&
pos
,
const
int
&
len
,
const
std
::
wstring
&
repstr
)
{
// 删除原来的
// 删除原来的
sentence
.
erase
(
pos
,
len
);
sentence
->
erase
(
pos
,
len
);
// 插入新的
// 插入新的
sentence
.
insert
(
pos
,
repstr
);
sentence
->
insert
(
pos
,
repstr
);
return
0
;
return
0
;
}
}
// 根据标点符号切分句子
// 根据标点符号切分句子
int
TextNormalizer
::
SplitByPunc
(
const
std
::
wstring
&
sentence
,
std
::
vector
<
std
::
wstring
>
&
sentence_part
)
{
int
TextNormalizer
::
SplitByPunc
(
const
std
::
wstring
&
sentence
,
std
::
vector
<
std
::
wstring
>
*
sentence_part
)
{
std
::
wstring
temp
=
sentence
;
std
::
wstring
temp
=
sentence
;
std
::
wregex
reg
(
L"[:,;。?!,;?!]"
);
std
::
wregex
reg
(
L"[:,;。?!,;?!]"
);
std
::
wsmatch
match
;
std
::
wsmatch
match
;
while
(
std
::
regex_search
(
temp
,
match
,
reg
))
{
while
(
std
::
regex_search
(
temp
,
match
,
reg
))
{
sentence_part
.
push_back
(
temp
.
substr
(
0
,
match
.
position
(
0
)
+
match
.
length
(
0
)));
sentence_part
->
push_back
(
Replace
(
temp
,
0
,
match
.
position
(
0
)
+
match
.
length
(
0
),
L""
);
temp
.
substr
(
0
,
match
.
position
(
0
)
+
match
.
length
(
0
)));
Replace
(
&
temp
,
0
,
match
.
position
(
0
)
+
match
.
length
(
0
),
L""
);
}
}
// 如果最后没有标点符号
// 如果最后没有标点符号
if
(
temp
!=
L""
)
{
if
(
temp
!=
L""
)
{
sentence_part
.
push_back
(
temp
);
sentence_part
->
push_back
(
temp
);
}
}
return
0
;
return
0
;
}
}
//数字转文本,10200 - > 一万零二百
// 数字转文本,10200 - > 一万零二百
std
::
string
TextNormalizer
::
CreateTextValue
(
const
std
::
string
&
num_str
,
bool
use_zero
)
{
std
::
string
TextNormalizer
::
CreateTextValue
(
const
std
::
string
&
num_str
,
bool
use_zero
)
{
std
::
string
num_lstrip
=
std
::
string
(
absl
::
StripPrefix
(
num_str
,
"0"
)).
data
();
std
::
string
num_lstrip
=
std
::
string
(
absl
::
StripPrefix
(
num_str
,
"0"
)).
data
();
int
len
=
num_lstrip
.
length
();
int
len
=
num_lstrip
.
length
();
if
(
len
==
0
)
{
if
(
len
==
0
)
{
return
""
;
return
""
;
}
else
if
(
len
==
1
)
{
}
else
if
(
len
==
1
)
{
if
(
use_zero
&&
(
len
<
num_str
.
length
()))
{
if
(
use_zero
&&
(
len
<
num_str
.
length
()))
{
return
digits_map
[
"0"
]
+
digits_map
[
num_lstrip
];
return
digits_map
[
"0"
]
+
digits_map
[
num_lstrip
];
}
else
{
}
else
{
return
digits_map
[
num_lstrip
];
return
digits_map
[
num_lstrip
];
}
}
}
else
{
}
else
{
int
largest_unit
=
0
;
// 最大单位
int
largest_unit
=
0
;
// 最大单位
std
::
string
first_part
;
std
::
string
first_part
;
std
::
string
second_part
;
std
::
string
second_part
;
if
(
len
>
1
and
len
<=
2
)
{
if
(
len
>
1
&&
len
<=
2
)
{
largest_unit
=
1
;
largest_unit
=
1
;
}
else
if
(
len
>
2
and
len
<=
3
)
{
}
else
if
(
len
>
2
&&
len
<=
3
)
{
largest_unit
=
2
;
largest_unit
=
2
;
}
else
if
(
len
>
3
and
len
<=
4
)
{
}
else
if
(
len
>
3
&&
len
<=
4
)
{
largest_unit
=
3
;
largest_unit
=
3
;
}
else
if
(
len
>
4
and
len
<=
8
)
{
}
else
if
(
len
>
4
&&
len
<=
8
)
{
largest_unit
=
4
;
largest_unit
=
4
;
}
else
if
(
len
>
8
)
{
}
else
if
(
len
>
8
)
{
largest_unit
=
8
;
largest_unit
=
8
;
}
}
first_part
=
num_str
.
substr
(
0
,
num_str
.
length
()
-
largest_unit
);
first_part
=
num_str
.
substr
(
0
,
num_str
.
length
()
-
largest_unit
);
second_part
=
num_str
.
substr
(
num_str
.
length
()
-
largest_unit
);
second_part
=
num_str
.
substr
(
num_str
.
length
()
-
largest_unit
);
return
CreateTextValue
(
first_part
,
use_zero
)
+
units_map
[
largest_unit
]
+
CreateTextValue
(
second_part
,
use_zero
);
return
CreateTextValue
(
first_part
,
use_zero
)
+
units_map
[
largest_unit
]
+
CreateTextValue
(
second_part
,
use_zero
);
}
}
}
}
// 数字一个一个对应,可直接用于年份,电话,手机,
// 数字一个一个对应,可直接用于年份,电话,手机,
std
::
string
TextNormalizer
::
SingleDigit2Text
(
const
std
::
string
&
num_str
,
bool
alt_one
)
{
std
::
string
TextNormalizer
::
SingleDigit2Text
(
const
std
::
string
&
num_str
,
bool
alt_one
)
{
std
::
string
text
=
""
;
std
::
string
text
=
""
;
if
(
alt_one
)
{
if
(
alt_one
)
{
digits_map
[
"1"
]
=
"幺"
;
digits_map
[
"1"
]
=
"幺"
;
...
@@ -110,13 +129,16 @@ std::string TextNormalizer::SingleDigit2Text(const std::string &num_str, bool al
...
@@ -110,13 +129,16 @@ std::string TextNormalizer::SingleDigit2Text(const std::string &num_str, bool al
return
text
;
return
text
;
}
}
std
::
string
TextNormalizer
::
SingleDigit2Text
(
const
std
::
wstring
&
num
,
bool
alt_one
)
{
std
::
string
TextNormalizer
::
SingleDigit2Text
(
const
std
::
wstring
&
num
,
bool
alt_one
)
{
std
::
string
num_str
=
wstring2utf8string
(
num
);
std
::
string
num_str
=
wstring2utf8string
(
num
);
return
SingleDigit2Text
(
num_str
,
alt_one
);
return
SingleDigit2Text
(
num_str
,
alt_one
);
}
}
// 数字整体对应,可直接用于月份,日期,数值整数部分
// 数字整体对应,可直接用于月份,日期,数值整数部分
std
::
string
TextNormalizer
::
MultiDigit2Text
(
const
std
::
string
&
num_str
,
bool
alt_one
,
bool
use_zero
)
{
std
::
string
TextNormalizer
::
MultiDigit2Text
(
const
std
::
string
&
num_str
,
bool
alt_one
,
bool
use_zero
)
{
LOG
(
INFO
)
<<
"aaaaaaaaaaaaaaaa: "
<<
alt_one
<<
use_zero
;
LOG
(
INFO
)
<<
"aaaaaaaaaaaaaaaa: "
<<
alt_one
<<
use_zero
;
if
(
alt_one
)
{
if
(
alt_one
)
{
digits_map
[
"1"
]
=
"幺"
;
digits_map
[
"1"
]
=
"幺"
;
...
@@ -124,18 +146,22 @@ std::string TextNormalizer::MultiDigit2Text(const std::string &num_str, bool alt
...
@@ -124,18 +146,22 @@ std::string TextNormalizer::MultiDigit2Text(const std::string &num_str, bool alt
digits_map
[
"1"
]
=
"一"
;
digits_map
[
"1"
]
=
"一"
;
}
}
std
::
wstring
result
=
utf8string2wstring
(
CreateTextValue
(
num_str
,
use_zero
));
std
::
wstring
result
=
utf8string2wstring
(
CreateTextValue
(
num_str
,
use_zero
));
std
::
wstring
result_0
(
1
,
result
[
0
]);
std
::
wstring
result_0
(
1
,
result
[
0
]);
std
::
wstring
result_1
(
1
,
result
[
1
]);
std
::
wstring
result_1
(
1
,
result
[
1
]);
// 一十八 --> 十八
// 一十八 --> 十八
if
((
result_0
==
utf8string2wstring
(
digits_map
[
"1"
]))
&&
(
result_1
==
utf8string2wstring
(
units_map
[
1
])))
{
if
((
result_0
==
utf8string2wstring
(
digits_map
[
"1"
]))
&&
return
wstring2utf8string
(
result
.
substr
(
1
,
result
.
length
()));
(
result_1
==
utf8string2wstring
(
units_map
[
1
])))
{
return
wstring2utf8string
(
result
.
substr
(
1
,
result
.
length
()));
}
else
{
}
else
{
return
wstring2utf8string
(
result
);
return
wstring2utf8string
(
result
);
}
}
}
}
std
::
string
TextNormalizer
::
MultiDigit2Text
(
const
std
::
wstring
&
num
,
bool
alt_one
,
bool
use_zero
)
{
std
::
string
TextNormalizer
::
MultiDigit2Text
(
const
std
::
wstring
&
num
,
bool
alt_one
,
bool
use_zero
)
{
std
::
string
num_str
=
wstring2utf8string
(
num
);
std
::
string
num_str
=
wstring2utf8string
(
num
);
return
MultiDigit2Text
(
num_str
,
alt_one
,
use_zero
);
return
MultiDigit2Text
(
num_str
,
alt_one
,
use_zero
);
}
}
...
@@ -145,15 +171,20 @@ std::string TextNormalizer::Digits2Text(const std::string &num_str) {
...
@@ -145,15 +171,20 @@ std::string TextNormalizer::Digits2Text(const std::string &num_str) {
std
::
string
text
;
std
::
string
text
;
std
::
vector
<
std
::
string
>
integer_decimal
;
std
::
vector
<
std
::
string
>
integer_decimal
;
integer_decimal
=
absl
::
StrSplit
(
num_str
,
"."
);
integer_decimal
=
absl
::
StrSplit
(
num_str
,
"."
);
if
(
integer_decimal
.
size
()
==
1
)
{
// 整数
if
(
integer_decimal
.
size
()
==
1
)
{
// 整数
text
=
MultiDigit2Text
(
integer_decimal
[
0
]);
text
=
MultiDigit2Text
(
integer_decimal
[
0
]);
}
else
if
(
integer_decimal
.
size
()
==
2
)
{
// 小数
}
else
if
(
integer_decimal
.
size
()
==
2
)
{
// 小数
if
(
integer_decimal
[
0
]
==
""
)
{
// 无整数的小数类型,例如:.22
if
(
integer_decimal
[
0
]
==
""
)
{
// 无整数的小数类型,例如:.22
text
=
"点"
+
SingleDigit2Text
(
std
::
string
(
absl
::
StripSuffix
(
integer_decimal
[
1
],
"0"
)).
data
());
text
=
"点"
+
SingleDigit2Text
(
std
::
string
(
absl
::
StripSuffix
(
integer_decimal
[
1
],
"0"
))
.
data
());
}
else
{
// 常规小数类型,例如:12.34
}
else
{
// 常规小数类型,例如:12.34
text
=
MultiDigit2Text
(
integer_decimal
[
0
])
+
"点"
+
\
text
=
MultiDigit2Text
(
integer_decimal
[
0
])
+
"点"
+
SingleDigit2Text
(
std
::
string
(
absl
::
StripSuffix
(
integer_decimal
[
1
],
"0"
)).
data
());
SingleDigit2Text
(
std
::
string
(
absl
::
StripSuffix
(
integer_decimal
[
1
],
"0"
))
.
data
());
}
}
}
else
{
}
else
{
return
"The value does not conform to the numeric format"
;
return
"The value does not conform to the numeric format"
;
...
@@ -168,23 +199,28 @@ std::string TextNormalizer::Digits2Text(const std::wstring &num) {
...
@@ -168,23 +199,28 @@ std::string TextNormalizer::Digits2Text(const std::wstring &num) {
}
}
// 日期,2021年8月18日 --> 二零二一年八月十八日
// 日期,2021年8月18日 --> 二零二一年八月十八日
int
TextNormalizer
::
ReData
(
std
::
wstring
&
sentence
)
{
int
TextNormalizer
::
ReData
(
std
::
wstring
*
sentence
)
{
std
::
wregex
reg
(
L"(
\\
d{4}|
\\
d{2})年((0?[1-9]|1[0-2])月)?(((0?[1-9])|((1|2)[0-9])|30|31)([日号]))?"
);
std
::
wregex
reg
(
L"(
\\
d{4}|
\\
d{2})年((0?[1-9]|1[0-2])月)?(((0?[1-9])|((1|2)[0-9])|30|31)"
L"([日号]))?"
);
std
::
wsmatch
match
;
std
::
wsmatch
match
;
std
::
string
rep
;
std
::
string
rep
;
while
(
std
::
regex_search
(
sentence
,
match
,
reg
))
{
while
(
std
::
regex_search
(
*
sentence
,
match
,
reg
))
{
rep
=
""
;
rep
=
""
;
rep
+=
SingleDigit2Text
(
match
[
1
])
+
"年"
;
rep
+=
SingleDigit2Text
(
match
[
1
])
+
"年"
;
if
(
match
[
3
]
!=
L""
)
{
if
(
match
[
3
]
!=
L""
)
{
rep
+=
MultiDigit2Text
(
match
[
3
],
false
,
false
)
+
"月"
;
rep
+=
MultiDigit2Text
(
match
[
3
],
false
,
false
)
+
"月"
;
}
}
if
(
match
[
5
]
!=
L""
)
{
if
(
match
[
5
]
!=
L""
)
{
rep
+=
MultiDigit2Text
(
match
[
5
],
false
,
false
)
+
wstring2utf8string
(
match
[
9
]);
rep
+=
MultiDigit2Text
(
match
[
5
],
false
,
false
)
+
wstring2utf8string
(
match
[
9
]);
}
}
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
rep
));
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
rep
));
}
}
return
0
;
return
0
;
...
@@ -192,255 +228,301 @@ int TextNormalizer::ReData(std::wstring &sentence) {
...
@@ -192,255 +228,301 @@ int TextNormalizer::ReData(std::wstring &sentence) {
// XX-XX-XX or XX/XX/XX 例如:2021/08/18 --> 二零二一年八月十八日
// XX-XX-XX or XX/XX/XX 例如:2021/08/18 --> 二零二一年八月十八日
int
TextNormalizer
::
ReData2
(
std
::
wstring
&
sentence
)
{
int
TextNormalizer
::
ReData2
(
std
::
wstring
*
sentence
)
{
std
::
wregex
reg
(
L"(
\\
d{4})([- /.])(0[1-9]|1[012])
\\
2(0[1-9]|[12][0-9]|3[01])"
);
std
::
wregex
reg
(
L"(
\\
d{4})([- /.])(0[1-9]|1[012])
\\
2(0[1-9]|[12][0-9]|3[01])"
);
std
::
wsmatch
match
;
std
::
wsmatch
match
;
std
::
string
rep
;
std
::
string
rep
;
while
(
std
::
regex_search
(
sentence
,
match
,
reg
))
{
while
(
std
::
regex_search
(
*
sentence
,
match
,
reg
))
{
rep
=
""
;
rep
=
""
;
rep
+=
(
SingleDigit2Text
(
match
[
1
])
+
"年"
);
rep
+=
(
SingleDigit2Text
(
match
[
1
])
+
"年"
);
rep
+=
(
MultiDigit2Text
(
match
[
3
],
false
,
false
)
+
"月"
);
rep
+=
(
MultiDigit2Text
(
match
[
3
],
false
,
false
)
+
"月"
);
rep
+=
(
MultiDigit2Text
(
match
[
4
],
false
,
false
)
+
"日"
);
rep
+=
(
MultiDigit2Text
(
match
[
4
],
false
,
false
)
+
"日"
);
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
rep
));
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
rep
));
}
}
return
0
;
return
0
;
}
}
// XX:XX:XX 09:09:02 --> 九点零九分零二秒
// XX:XX:XX 09:09:02 --> 九点零九分零二秒
int
TextNormalizer
::
ReTime
(
std
::
wstring
&
sentence
)
{
int
TextNormalizer
::
ReTime
(
std
::
wstring
*
sentence
)
{
std
::
wregex
reg
(
L"([0-1]?[0-9]|2[0-3]):([0-5][0-9])(:([0-5][0-9]))?"
);
std
::
wregex
reg
(
L"([0-1]?[0-9]|2[0-3]):([0-5][0-9])(:([0-5][0-9]))?"
);
std
::
wsmatch
match
;
std
::
wsmatch
match
;
std
::
string
rep
;
std
::
string
rep
;
while
(
std
::
regex_search
(
sentence
,
match
,
reg
))
{
while
(
std
::
regex_search
(
*
sentence
,
match
,
reg
))
{
rep
=
""
;
rep
=
""
;
rep
+=
(
MultiDigit2Text
(
match
[
1
],
false
,
false
)
+
"点"
);
rep
+=
(
MultiDigit2Text
(
match
[
1
],
false
,
false
)
+
"点"
);
if
(
absl
::
StartsWith
(
wstring2utf8string
(
match
[
2
]),
"0"
))
{
if
(
absl
::
StartsWith
(
wstring2utf8string
(
match
[
2
]),
"0"
))
{
rep
+=
"零"
;
rep
+=
"零"
;
}
}
rep
+=
(
MultiDigit2Text
(
match
[
2
])
+
"分"
);
rep
+=
(
MultiDigit2Text
(
match
[
2
])
+
"分"
);
if
(
absl
::
StartsWith
(
wstring2utf8string
(
match
[
4
]),
"0"
))
{
if
(
absl
::
StartsWith
(
wstring2utf8string
(
match
[
4
]),
"0"
))
{
rep
+=
"零"
;
rep
+=
"零"
;
}
}
rep
+=
(
MultiDigit2Text
(
match
[
4
])
+
"秒"
);
rep
+=
(
MultiDigit2Text
(
match
[
4
])
+
"秒"
);
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
rep
));
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
rep
));
}
}
return
0
;
return
0
;
}
}
// 温度,例如:-24.3℃ --> 零下二十四点三度
// 温度,例如:-24.3℃ --> 零下二十四点三度
int
TextNormalizer
::
ReTemperature
(
std
::
wstring
&
sentence
)
{
int
TextNormalizer
::
ReTemperature
(
std
::
wstring
*
sentence
)
{
std
::
wregex
reg
(
L"(-?)(
\\
d+(
\\
.
\\
d+)?)(°C|℃|度|摄氏度)"
);
std
::
wregex
reg
(
L"(-?)(
\\
d+(
\\
.
\\
d+)?)(°C|℃|度|摄氏度)"
);
std
::
wsmatch
match
;
std
::
wsmatch
match
;
std
::
string
rep
;
std
::
string
rep
;
std
::
string
sign
;
std
::
string
sign
;
std
::
vector
<
std
::
string
>
integer_decimal
;
std
::
vector
<
std
::
string
>
integer_decimal
;
std
::
string
unit
;
std
::
string
unit
;
while
(
std
::
regex_search
(
sentence
,
match
,
reg
))
{
while
(
std
::
regex_search
(
*
sentence
,
match
,
reg
))
{
match
[
1
]
==
L"-"
?
sign
=
"负"
:
sign
=
""
;
match
[
1
]
==
L"-"
?
sign
=
"负"
:
sign
=
""
;
match
[
4
]
==
L"摄氏度"
?
unit
=
"摄氏度"
:
unit
=
"度"
;
match
[
4
]
==
L"摄氏度"
?
unit
=
"摄氏度"
:
unit
=
"度"
;
rep
=
sign
+
Digits2Text
(
match
[
2
])
+
unit
;
rep
=
sign
+
Digits2Text
(
match
[
2
])
+
unit
;
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
rep
));
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
rep
));
}
}
return
0
;
return
0
;
}
}
// 分数,例如: 1/3 --> 三分之一
// 分数,例如: 1/3 --> 三分之一
int
TextNormalizer
::
ReFrac
(
std
::
wstring
&
sentence
)
{
int
TextNormalizer
::
ReFrac
(
std
::
wstring
*
sentence
)
{
std
::
wregex
reg
(
L"(-?)(
\\
d+)/(
\\
d+)"
);
std
::
wregex
reg
(
L"(-?)(
\\
d+)/(
\\
d+)"
);
std
::
wsmatch
match
;
std
::
wsmatch
match
;
std
::
string
sign
;
std
::
string
sign
;
std
::
string
rep
;
std
::
string
rep
;
while
(
std
::
regex_search
(
sentence
,
match
,
reg
))
{
while
(
std
::
regex_search
(
*
sentence
,
match
,
reg
))
{
match
[
1
]
==
L"-"
?
sign
=
"负"
:
sign
=
""
;
match
[
1
]
==
L"-"
?
sign
=
"负"
:
sign
=
""
;
rep
=
sign
+
MultiDigit2Text
(
match
[
3
])
+
"分之"
+
MultiDigit2Text
(
match
[
2
]);
rep
=
sign
+
MultiDigit2Text
(
match
[
3
])
+
"分之"
+
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
rep
));
MultiDigit2Text
(
match
[
2
]);
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
rep
));
}
}
return
0
;
return
0
;
}
}
// 百分数,例如:45.5% --> 百分之四十五点五
// 百分数,例如:45.5% --> 百分之四十五点五
int
TextNormalizer
::
RePercentage
(
std
::
wstring
&
sentence
)
{
int
TextNormalizer
::
RePercentage
(
std
::
wstring
*
sentence
)
{
std
::
wregex
reg
(
L"(-?)(
\\
d+(
\\
.
\\
d+)?)%"
);
std
::
wregex
reg
(
L"(-?)(
\\
d+(
\\
.
\\
d+)?)%"
);
std
::
wsmatch
match
;
std
::
wsmatch
match
;
std
::
string
sign
;
std
::
string
sign
;
std
::
string
rep
;
std
::
string
rep
;
std
::
vector
<
std
::
string
>
integer_decimal
;
std
::
vector
<
std
::
string
>
integer_decimal
;
while
(
std
::
regex_search
(
sentence
,
match
,
reg
))
{
while
(
std
::
regex_search
(
*
sentence
,
match
,
reg
))
{
match
[
1
]
==
L"-"
?
sign
=
"负"
:
sign
=
""
;
match
[
1
]
==
L"-"
?
sign
=
"负"
:
sign
=
""
;
rep
=
sign
+
"百分之"
+
Digits2Text
(
match
[
2
]);
rep
=
sign
+
"百分之"
+
Digits2Text
(
match
[
2
]);
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
rep
));
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
rep
));
}
}
return
0
;
return
0
;
}
}
// 手机号码,例如:+86 18883862235 --> 八六幺八八八三八六二二三五
// 手机号码,例如:+86 18883862235 --> 八六幺八八八三八六二二三五
int
TextNormalizer
::
ReMobilePhone
(
std
::
wstring
&
sentence
)
{
int
TextNormalizer
::
ReMobilePhone
(
std
::
wstring
*
sentence
)
{
std
::
wregex
reg
(
L"(
\\
d)?((
\\
+?86 ?)?1([38]
\\
d|5[0-35-9]|7[678]|9[89])
\\
d{8})(
\\
d)?"
);
std
::
wregex
reg
(
L"(
\\
d)?((
\\
+?86 ?)?1([38]
\\
d|5[0-35-9]|7[678]|9[89])
\\
d{8})(
\\
d)?"
);
std
::
wsmatch
match
;
std
::
wsmatch
match
;
std
::
string
rep
;
std
::
string
rep
;
std
::
vector
<
std
::
string
>
country_phonenum
;
std
::
vector
<
std
::
string
>
country_phonenum
;
while
(
std
::
regex_search
(
sentence
,
match
,
reg
))
{
while
(
std
::
regex_search
(
*
sentence
,
match
,
reg
))
{
country_phonenum
=
absl
::
StrSplit
(
wstring2utf8string
(
match
[
0
]),
"+"
);
country_phonenum
=
absl
::
StrSplit
(
wstring2utf8string
(
match
[
0
]),
"+"
);
rep
=
""
;
rep
=
""
;
for
(
int
i
=
0
;
i
<
country_phonenum
.
size
();
i
++
)
{
for
(
int
i
=
0
;
i
<
country_phonenum
.
size
();
i
++
)
{
LOG
(
INFO
)
<<
country_phonenum
[
i
];
LOG
(
INFO
)
<<
country_phonenum
[
i
];
rep
+=
SingleDigit2Text
(
country_phonenum
[
i
],
true
);
rep
+=
SingleDigit2Text
(
country_phonenum
[
i
],
true
);
}
}
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
rep
));
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
rep
));
}
}
return
0
;
return
0
;
}
}
// 座机号码,例如:010-51093154 --> 零幺零五幺零九三幺五四
// 座机号码,例如:010-51093154 --> 零幺零五幺零九三幺五四
int
TextNormalizer
::
RePhone
(
std
::
wstring
&
sentence
)
{
int
TextNormalizer
::
RePhone
(
std
::
wstring
*
sentence
)
{
std
::
wregex
reg
(
L"(
\\
d)?((0(10|2[1-3]|[3-9]
\\
d{2})-?)?[1-9]
\\
d{6,7})(
\\
d)?"
);
std
::
wregex
reg
(
L"(
\\
d)?((0(10|2[1-3]|[3-9]
\\
d{2})-?)?[1-9]
\\
d{6,7})(
\\
d)?"
);
std
::
wsmatch
match
;
std
::
wsmatch
match
;
std
::
vector
<
std
::
string
>
zone_phonenum
;
std
::
vector
<
std
::
string
>
zone_phonenum
;
std
::
string
rep
;
std
::
string
rep
;
while
(
std
::
regex_search
(
sentence
,
match
,
reg
))
{
while
(
std
::
regex_search
(
*
sentence
,
match
,
reg
))
{
rep
=
""
;
rep
=
""
;
zone_phonenum
=
absl
::
StrSplit
(
wstring2utf8string
(
match
[
0
]),
"-"
);
zone_phonenum
=
absl
::
StrSplit
(
wstring2utf8string
(
match
[
0
]),
"-"
);
for
(
int
i
=
0
;
i
<
zone_phonenum
.
size
();
i
++
)
{
for
(
int
i
=
0
;
i
<
zone_phonenum
.
size
();
i
++
)
{
rep
+=
SingleDigit2Text
(
zone_phonenum
[
i
],
true
);
rep
+=
SingleDigit2Text
(
zone_phonenum
[
i
],
true
);
}
}
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
rep
));
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
rep
));
}
}
return
0
;
return
0
;
}
}
// 范围,例如:60~90 --> 六十到九十
// 范围,例如:60~90 --> 六十到九十
int
TextNormalizer
::
ReRange
(
std
::
wstring
&
sentence
)
{
int
TextNormalizer
::
ReRange
(
std
::
wstring
*
sentence
)
{
std
::
wregex
reg
(
L"((-?)((
\\
d+)(
\\
.
\\
d+)?)|(
\\
.(
\\
d+)))[-~]((-?)((
\\
d+)(
\\
.
\\
d+)?)|(
\\
.(
\\
d+)))"
);
std
::
wregex
reg
(
L"((-?)((
\\
d+)(
\\
.
\\
d+)?)|(
\\
.(
\\
d+)))[-~]((-?)((
\\
d+)(
\\
.
\\
d+)?)|(
\\
.("
L"
\\
d+)))"
);
std
::
wsmatch
match
;
std
::
wsmatch
match
;
std
::
string
rep
;
std
::
string
rep
;
std
::
string
sign1
;
std
::
string
sign1
;
std
::
string
sign2
;
std
::
string
sign2
;
while
(
std
::
regex_search
(
sentence
,
match
,
reg
))
{
while
(
std
::
regex_search
(
*
sentence
,
match
,
reg
))
{
rep
=
""
;
rep
=
""
;
match
[
2
]
==
L"-"
?
sign1
=
"负"
:
sign1
=
""
;
match
[
2
]
==
L"-"
?
sign1
=
"负"
:
sign1
=
""
;
if
(
match
[
6
]
!=
L""
)
{
if
(
match
[
6
]
!=
L""
)
{
rep
+=
sign1
+
Digits2Text
(
match
[
6
])
+
"到"
;
rep
+=
sign1
+
Digits2Text
(
match
[
6
])
+
"到"
;
}
else
{
}
else
{
rep
+=
sign1
+
Digits2Text
(
match
[
3
])
+
"到"
;
rep
+=
sign1
+
Digits2Text
(
match
[
3
])
+
"到"
;
}
}
match
[
9
]
==
L"-"
?
sign2
=
"负"
:
sign2
=
""
;
match
[
9
]
==
L"-"
?
sign2
=
"负"
:
sign2
=
""
;
if
(
match
[
13
]
!=
L""
)
{
if
(
match
[
13
]
!=
L""
)
{
rep
+=
sign2
+
Digits2Text
(
match
[
13
]);
rep
+=
sign2
+
Digits2Text
(
match
[
13
]);
}
else
{
}
else
{
rep
+=
sign2
+
Digits2Text
(
match
[
10
]);
rep
+=
sign2
+
Digits2Text
(
match
[
10
]);
}
}
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
rep
));
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
rep
));
}
}
return
0
;
return
0
;
}
}
// 带负号的整数,例如:-10 --> 负十
// 带负号的整数,例如:-10 --> 负十
int
TextNormalizer
::
ReInterger
(
std
::
wstring
&
sentence
)
{
int
TextNormalizer
::
ReInterger
(
std
::
wstring
*
sentence
)
{
std
::
wregex
reg
(
L"(-)(
\\
d+)"
);
std
::
wregex
reg
(
L"(-)(
\\
d+)"
);
std
::
wsmatch
match
;
std
::
wsmatch
match
;
std
::
string
rep
;
std
::
string
rep
;
while
(
std
::
regex_search
(
sentence
,
match
,
reg
))
{
while
(
std
::
regex_search
(
*
sentence
,
match
,
reg
))
{
rep
=
"负"
+
MultiDigit2Text
(
match
[
2
]);
rep
=
"负"
+
MultiDigit2Text
(
match
[
2
]);
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
rep
));
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
rep
));
}
}
return
0
;
return
0
;
}
}
// 纯小数
// 纯小数
int
TextNormalizer
::
ReDecimalNum
(
std
::
wstring
&
sentence
)
{
int
TextNormalizer
::
ReDecimalNum
(
std
::
wstring
*
sentence
)
{
std
::
wregex
reg
(
L"(-?)((
\\
d+)(
\\
.
\\
d+))|(
\\
.(
\\
d+))"
);
std
::
wregex
reg
(
L"(-?)((
\\
d+)(
\\
.
\\
d+))|(
\\
.(
\\
d+))"
);
std
::
wsmatch
match
;
std
::
wsmatch
match
;
std
::
string
sign
;
std
::
string
sign
;
std
::
string
rep
;
std
::
string
rep
;
//std::vector<std::string> integer_decimal;
//
std::vector<std::string> integer_decimal;
while
(
std
::
regex_search
(
sentence
,
match
,
reg
))
{
while
(
std
::
regex_search
(
*
sentence
,
match
,
reg
))
{
match
[
1
]
==
L"-"
?
sign
=
"负"
:
sign
=
""
;
match
[
1
]
==
L"-"
?
sign
=
"负"
:
sign
=
""
;
if
(
match
[
5
]
!=
L""
)
{
if
(
match
[
5
]
!=
L""
)
{
rep
=
sign
+
Digits2Text
(
match
[
5
]);
rep
=
sign
+
Digits2Text
(
match
[
5
]);
}
else
{
}
else
{
rep
=
sign
+
Digits2Text
(
match
[
2
]);
rep
=
sign
+
Digits2Text
(
match
[
2
]);
}
}
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
rep
));
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
rep
));
}
}
return
0
;
return
0
;
}
}
// 正整数 + 量词
// 正整数 + 量词
int
TextNormalizer
::
RePositiveQuantifiers
(
std
::
wstring
&
sentence
)
{
int
TextNormalizer
::
RePositiveQuantifiers
(
std
::
wstring
*
sentence
)
{
std
::
wstring
common_quantifiers
=
L"(朵|匹|张|座|回|场|尾|条|个|首|阙|阵|网|炮|顶|丘|棵|只|支|袭|辆|挑|担|颗|壳|窠|曲| \
std
::
wstring
common_quantifiers
=
墙|群|腔|砣|座|客|贯|扎|捆|刀|令|打|手|罗|坡|山|岭|江|溪|钟|队|单|双|对|出|口|头|脚|板|跳|枝|件|贴|针|线|管|名|位|身|堂| \
L"(朵|匹|张|座|回|场|尾|条|个|首|阙|阵|网|炮|顶|丘|棵|只|支|袭|辆|挑|"
课|本|页|家|户|层|丝|毫|厘|分|钱|两|斤|担|铢|石|钧|锱|忽|(千|毫|微)克|毫|厘|(公)分|分|寸|尺|丈|里|寻|常|铺|程|(千|分|厘| \
L"担|颗|壳|窠|曲|墙|群|腔|砣|座|客|贯|扎|捆|刀|令|打|手|罗|坡|山|岭|江|"
毫|微)米|米|撮|勺|合|升|斗|石|盘|碗|碟|叠|桶|笼|盆|盒|杯|钟|斛|锅|簋|篮|盘|桶|罐|瓶|壶|卮|盏|箩|箱|煲|啖|袋|钵|年|月|日| \
L"溪|钟|队|单|双|对|出|口|头|脚|板|跳|枝|件|贴|针|线|管|名|位|身|堂|课|"
季|刻|时|周|天|秒|分|旬|纪|岁|世|更|夜|春|夏|秋|冬|代|伏|辈|丸|泡|粒|颗|幢|堆|条|根|支|道|面|片|张|颗|块|元|(亿|千万|百万| \
L"本|页|家|户|层|丝|毫|厘|分|钱|两|斤|担|铢|石|钧|锱|忽|(千|毫|微)克|"
万|千|百)|(亿|千万|百万|万|千|百|美|)元|(亿|千万|百万|万|千|百|)块|角|毛|分)"
;
L"毫|厘|(公)分|分|寸|尺|丈|里|寻|常|铺|程|(千|分|厘|毫|微)米|米|撮|勺|"
std
::
wregex
reg
(
L"(
\\
d+)([多余几])?"
+
common_quantifiers
);
L"合|升|斗|石|盘|碗|碟|叠|桶|笼|盆|盒|杯|钟|斛|锅|簋|篮|盘|桶|罐|瓶|壶|"
L"卮|盏|箩|箱|煲|啖|袋|钵|年|月|日|季|刻|时|周|天|秒|分|旬|纪|岁|世|更|"
L"夜|春|夏|秋|冬|代|伏|辈|丸|泡|粒|颗|幢|堆|条|根|支|道|面|片|张|颗|块|"
L"元|(亿|千万|百万|万|千|百)|(亿|千万|百万|万|千|百|美|)元|(亿|千万|"
L"百万|万|千|百|)块|角|毛|分)"
;
std
::
wregex
reg
(
L"(
\\
d+)([多余几])?"
+
common_quantifiers
);
std
::
wsmatch
match
;
std
::
wsmatch
match
;
std
::
string
rep
;
std
::
string
rep
;
while
(
std
::
regex_search
(
sentence
,
match
,
reg
))
{
while
(
std
::
regex_search
(
*
sentence
,
match
,
reg
))
{
rep
=
MultiDigit2Text
(
match
[
1
]);
rep
=
MultiDigit2Text
(
match
[
1
]);
Replace
(
sentence
,
match
.
position
(
1
),
match
.
length
(
1
),
utf8string2wstring
(
rep
));
Replace
(
sentence
,
match
.
position
(
1
),
match
.
length
(
1
),
utf8string2wstring
(
rep
));
}
}
return
0
;
return
0
;
}
}
// 编号类数字,例如: 89757 --> 八九七五七
// 编号类数字,例如: 89757 --> 八九七五七
int
TextNormalizer
::
ReDefalutNum
(
std
::
wstring
&
sentence
)
{
int
TextNormalizer
::
ReDefalutNum
(
std
::
wstring
*
sentence
)
{
std
::
wregex
reg
(
L"
\\
d{3}
\\
d*"
);
std
::
wregex
reg
(
L"
\\
d{3}
\\
d*"
);
std
::
wsmatch
match
;
std
::
wsmatch
match
;
while
(
std
::
regex_search
(
sentence
,
match
,
reg
))
{
while
(
std
::
regex_search
(
*
sentence
,
match
,
reg
))
{
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
SingleDigit2Text
(
match
[
0
])));
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
SingleDigit2Text
(
match
[
0
])));
}
}
return
0
;
return
0
;
}
}
int
TextNormalizer
::
ReNumber
(
std
::
wstring
&
sentence
)
{
int
TextNormalizer
::
ReNumber
(
std
::
wstring
*
sentence
)
{
std
::
wregex
reg
(
L"(-?)((
\\
d+)(
\\
.
\\
d+)?)|(
\\
.(
\\
d+))"
);
std
::
wregex
reg
(
L"(-?)((
\\
d+)(
\\
.
\\
d+)?)|(
\\
.(
\\
d+))"
);
std
::
wsmatch
match
;
std
::
wsmatch
match
;
std
::
string
sign
;
std
::
string
sign
;
std
::
string
rep
;
std
::
string
rep
;
while
(
std
::
regex_search
(
sentence
,
match
,
reg
))
{
while
(
std
::
regex_search
(
*
sentence
,
match
,
reg
))
{
match
[
1
]
==
L"-"
?
sign
=
"负"
:
sign
=
""
;
match
[
1
]
==
L"-"
?
sign
=
"负"
:
sign
=
""
;
if
(
match
[
5
]
!=
L""
)
{
if
(
match
[
5
]
!=
L""
)
{
rep
=
sign
+
Digits2Text
(
match
[
5
]);
rep
=
sign
+
Digits2Text
(
match
[
5
]);
}
else
{
}
else
{
rep
=
sign
+
Digits2Text
(
match
[
2
]);
rep
=
sign
+
Digits2Text
(
match
[
2
]);
}
}
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
rep
));
Replace
(
sentence
,
match
.
position
(
0
),
match
.
length
(
0
),
utf8string2wstring
(
rep
));
}
}
return
0
;
return
0
;
}
}
// 整体正则,按顺序
// 整体正则,按顺序
int
TextNormalizer
::
SentenceNormalize
(
std
::
wstring
&
sentence
)
{
int
TextNormalizer
::
SentenceNormalize
(
std
::
wstring
*
sentence
)
{
ReData
(
sentence
);
ReData
(
sentence
);
ReData2
(
sentence
);
ReData2
(
sentence
);
ReTime
(
sentence
);
ReTime
(
sentence
);
...
@@ -452,11 +534,9 @@ int TextNormalizer::SentenceNormalize(std::wstring &sentence) {
...
@@ -452,11 +534,9 @@ int TextNormalizer::SentenceNormalize(std::wstring &sentence) {
ReRange
(
sentence
);
ReRange
(
sentence
);
ReInterger
(
sentence
);
ReInterger
(
sentence
);
ReDecimalNum
(
sentence
);
ReDecimalNum
(
sentence
);
RePositiveQuantifiers
(
sentence
);
RePositiveQuantifiers
(
sentence
);
ReDefalutNum
(
sentence
);
ReDefalutNum
(
sentence
);
ReNumber
(
sentence
);
ReNumber
(
sentence
);
return
0
;
return
0
;
}
}
}
// namespace ppspeech
\ No newline at end of file
}
\ No newline at end of file
demos/TTSCppFrontend/src/front/text_normalize.h
浏览文件 @
1aa7495d
// Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
//
// 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.
#ifndef PADDLE_TTS_SERVING_FRONT_TEXT_NORMALIZE_H
#ifndef PADDLE_TTS_SERVING_FRONT_TEXT_NORMALIZE_H
#define PADDLE_TTS_SERVING_FRONT_TEXT_NORMALIZE_H
#define PADDLE_TTS_SERVING_FRONT_TEXT_NORMALIZE_H
#include <glog/logging.h>
#include <codecvt>
#include <map>
#include <map>
#include <regex>
#include <regex>
#include <string>
#include <string>
#include <codecvt>
#include <glog/logging.h>
#include "absl/strings/str_split.h"
#include "absl/strings/str_split.h"
#include "absl/strings/strip.h"
#include "absl/strings/strip.h"
#include "base/type_conv.h"
#include "base/type_conv.h"
...
@@ -13,50 +26,52 @@
...
@@ -13,50 +26,52 @@
namespace
ppspeech
{
namespace
ppspeech
{
class
TextNormalizer
{
class
TextNormalizer
{
public:
public:
TextNormalizer
()
{
TextNormalizer
()
{
InitMap
();
}
InitMap
();
~
TextNormalizer
()
{}
}
~
TextNormalizer
()
{
}
int
InitMap
();
int
InitMap
();
int
Replace
(
std
::
wstring
&
sentence
,
const
int
&
pos
,
const
int
&
len
,
const
std
::
wstring
&
repstr
);
int
Replace
(
std
::
wstring
*
sentence
,
int
SplitByPunc
(
const
std
::
wstring
&
sentence
,
std
::
vector
<
std
::
wstring
>
&
sentence_part
);
const
int
&
pos
,
const
int
&
len
,
const
std
::
wstring
&
repstr
);
int
SplitByPunc
(
const
std
::
wstring
&
sentence
,
std
::
vector
<
std
::
wstring
>
*
sentence_part
);
std
::
string
CreateTextValue
(
const
std
::
string
&
num
,
bool
use_zero
=
true
);
std
::
string
CreateTextValue
(
const
std
::
string
&
num
,
bool
use_zero
=
true
);
std
::
string
SingleDigit2Text
(
const
std
::
string
&
num_str
,
bool
alt_one
=
false
);
std
::
string
SingleDigit2Text
(
const
std
::
string
&
num_str
,
bool
alt_one
=
false
);
std
::
string
SingleDigit2Text
(
const
std
::
wstring
&
num
,
bool
alt_one
=
false
);
std
::
string
SingleDigit2Text
(
const
std
::
wstring
&
num
,
bool
alt_one
=
false
);
std
::
string
MultiDigit2Text
(
const
std
::
string
&
num_str
,
bool
alt_one
=
false
,
bool
use_zero
=
true
);
std
::
string
MultiDigit2Text
(
const
std
::
string
&
num_str
,
std
::
string
MultiDigit2Text
(
const
std
::
wstring
&
num
,
bool
alt_one
=
false
,
bool
use_zero
=
true
);
bool
alt_one
=
false
,
bool
use_zero
=
true
);
std
::
string
MultiDigit2Text
(
const
std
::
wstring
&
num
,
bool
alt_one
=
false
,
bool
use_zero
=
true
);
std
::
string
Digits2Text
(
const
std
::
string
&
num_str
);
std
::
string
Digits2Text
(
const
std
::
string
&
num_str
);
std
::
string
Digits2Text
(
const
std
::
wstring
&
num
);
std
::
string
Digits2Text
(
const
std
::
wstring
&
num
);
int
ReData
(
std
::
wstring
&
sentence
);
int
ReData
(
std
::
wstring
*
sentence
);
int
ReData2
(
std
::
wstring
&
sentence
);
int
ReData2
(
std
::
wstring
*
sentence
);
int
ReTime
(
std
::
wstring
&
sentence
);
int
ReTime
(
std
::
wstring
*
sentence
);
int
ReTemperature
(
std
::
wstring
&
sentence
);
int
ReTemperature
(
std
::
wstring
*
sentence
);
int
ReFrac
(
std
::
wstring
&
sentence
);
int
ReFrac
(
std
::
wstring
*
sentence
);
int
RePercentage
(
std
::
wstring
&
sentence
);
int
RePercentage
(
std
::
wstring
*
sentence
);
int
ReMobilePhone
(
std
::
wstring
&
sentence
);
int
ReMobilePhone
(
std
::
wstring
*
sentence
);
int
RePhone
(
std
::
wstring
&
sentence
);
int
RePhone
(
std
::
wstring
*
sentence
);
int
ReRange
(
std
::
wstring
&
sentence
);
int
ReRange
(
std
::
wstring
*
sentence
);
int
ReInterger
(
std
::
wstring
&
sentence
);
int
ReInterger
(
std
::
wstring
*
sentence
);
int
ReDecimalNum
(
std
::
wstring
&
sentence
);
int
ReDecimalNum
(
std
::
wstring
*
sentence
);
int
RePositiveQuantifiers
(
std
::
wstring
&
sentence
);
int
RePositiveQuantifiers
(
std
::
wstring
*
sentence
);
int
ReDefalutNum
(
std
::
wstring
&
sentence
);
int
ReDefalutNum
(
std
::
wstring
*
sentence
);
int
ReNumber
(
std
::
wstring
&
sentence
);
int
ReNumber
(
std
::
wstring
*
sentence
);
int
SentenceNormalize
(
std
::
wstring
&
sentence
);
int
SentenceNormalize
(
std
::
wstring
*
sentence
);
private:
std
::
map
<
std
::
string
,
std
::
string
>
digits_map
;
std
::
map
<
int
,
std
::
string
>
units_map
;
private:
std
::
map
<
std
::
string
,
std
::
string
>
digits_map
;
std
::
map
<
int
,
std
::
string
>
units_map
;
};
};
}
// namespace ppspeech
}
#endif
#endif
\ No newline at end of file
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录