mirror of
https://github.com/Picovoice/porcupine.git
synced 2022-01-28 03:27:53 +03:00
Github actions dotnet add platforms and non-English tests (#607)
This commit is contained in:
27
.github/workflows/dotnet.yml
vendored
27
.github/workflows/dotnet.yml
vendored
@@ -45,8 +45,12 @@ defaults:
|
||||
working-directory: binding/dotnet
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
build-github-hosted:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@@ -69,3 +73,22 @@ jobs:
|
||||
|
||||
- name: Test
|
||||
run: dotnet test -- TestRunParameters.Parameter\(name=\"pvTestAccessKey\",\ value=\"${{secrets.PV_VALID_ACCESS_KEY}}\"\)
|
||||
|
||||
build-self-hosted:
|
||||
runs-on: ${{ matrix.machine }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
machine: [rpi2, rpi3, rpi4, jetson, beaglebone]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
|
||||
- name: Build
|
||||
run: dotnet build --no-restore
|
||||
|
||||
- name: Test
|
||||
run: dotnet test -- TestRunParameters.Parameter\(name=\"pvTestAccessKey\",\ value=\"${{secrets.PV_VALID_ACCESS_KEY}}\"\)
|
||||
@@ -11,8 +11,10 @@
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
using Pv;
|
||||
@@ -23,6 +25,35 @@ namespace PorcupineTest
|
||||
public class MainTest
|
||||
{
|
||||
private static string ACCESS_KEY;
|
||||
private static string _relativeDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
private static Architecture _arch => RuntimeInformation.ProcessArchitecture;
|
||||
private static string _env => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "mac" :
|
||||
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "windows" :
|
||||
RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && _arch == Architecture.X64 ? "linux" :
|
||||
RuntimeInformation.IsOSPlatform(OSPlatform.Linux) &&
|
||||
(_arch == Architecture.Arm || _arch == Architecture.Arm64) ? PvLinuxEnv() : "";
|
||||
private Porcupine porcupine;
|
||||
|
||||
private static string PvLinuxEnv()
|
||||
{
|
||||
string cpuInfo = File.ReadAllText("/proc/cpuinfo");
|
||||
string[] cpuPartList = cpuInfo.Split('\n').Where(x => x.Contains("CPU part")).ToArray();
|
||||
if (cpuPartList.Length == 0)
|
||||
throw new PlatformNotSupportedException($"Unsupported CPU.\n{cpuInfo}");
|
||||
|
||||
string cpuPart = cpuPartList[0].Split(' ').Last().ToLower();
|
||||
|
||||
switch (cpuPart)
|
||||
{
|
||||
case "0xc07":
|
||||
case "0xd03":
|
||||
case "0xd08": return "raspberry-pi";
|
||||
case "0xd07": return "jetson";
|
||||
case "0xc08": return "beaglebone";
|
||||
default:
|
||||
throw new PlatformNotSupportedException($"This device (CPU part = {cpuPart}) is not supported by Picovoice.");
|
||||
}
|
||||
}
|
||||
|
||||
[ClassInitialize]
|
||||
public static void ClassInitialize(TestContext testContext)
|
||||
@@ -33,28 +64,48 @@ namespace PorcupineTest
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestFrameLength()
|
||||
private static string AppendLanguage(string s, string language)
|
||||
{
|
||||
using Porcupine p = Porcupine.FromBuiltInKeywords(ACCESS_KEY, new List<BuiltInKeyword> { BuiltInKeyword.PORCUPINE });
|
||||
Assert.IsTrue(p.FrameLength > 0, "Specified frame length was not a valid number.");
|
||||
if(language == "en")
|
||||
return s;
|
||||
return $"{s}_{language}";
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestVersion()
|
||||
private static string GetKeywordPath(string language, string keyword)
|
||||
{
|
||||
using Porcupine p = Porcupine.FromBuiltInKeywords(ACCESS_KEY, new List<BuiltInKeyword> { BuiltInKeyword.PORCUPINE });
|
||||
Assert.IsFalse(string.IsNullOrWhiteSpace(p.Version), "Porcupine did not return a valid version number.");
|
||||
return Path.Combine(
|
||||
_relativeDir,
|
||||
"../../../../../../resources",
|
||||
AppendLanguage("keyword_files", language),
|
||||
$"{_env}/{keyword}_{_env}.ppn"
|
||||
);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestProcess()
|
||||
private static List<string> GetKeywordPaths(string language, List<string> keywords)
|
||||
{
|
||||
using Porcupine p = Porcupine.FromBuiltInKeywords(ACCESS_KEY, new List<BuiltInKeyword> { BuiltInKeyword.PORCUPINE });
|
||||
int frameLen = p.FrameLength;
|
||||
List<string> keywordPaths = new List<string>();
|
||||
foreach (string keyword in keywords)
|
||||
{
|
||||
keywordPaths.Add(GetKeywordPath(language, keyword));
|
||||
}
|
||||
return keywordPaths;
|
||||
}
|
||||
|
||||
string testAudioPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "resources/audio_samples/porcupine.wav");
|
||||
List<short> data = GetPcmFromFile(testAudioPath, p.SampleRate);
|
||||
private static string GetModelPath(string language)
|
||||
{
|
||||
string file_name = AppendLanguage("porcupine_params", language);
|
||||
return Path.Combine(
|
||||
_relativeDir,
|
||||
"../../../../../../lib/common",
|
||||
$"{file_name}.pv"
|
||||
);
|
||||
}
|
||||
|
||||
private void RunTestCase(string audioFileName, List<int> expectedResults)
|
||||
{
|
||||
int frameLen = porcupine.FrameLength;
|
||||
string testAudioPath = Path.Combine(_relativeDir, "resources/audio_samples", audioFileName);
|
||||
List<short> data = GetPcmFromFile(testAudioPath, porcupine.SampleRate);
|
||||
|
||||
int framecount = (int)Math.Floor((float)(data.Count / frameLen));
|
||||
var results = new List<int>();
|
||||
@@ -63,20 +114,50 @@ namespace PorcupineTest
|
||||
int start = i * frameLen;
|
||||
int count = frameLen;
|
||||
List<short> frame = data.GetRange(start, count);
|
||||
int result = p.Process(frame.ToArray());
|
||||
Assert.IsTrue(result == -1 || result == 0, "Porcupine returned an unexpected result (should return 0 or -1)");
|
||||
int result = porcupine.Process(frame.ToArray());
|
||||
Assert.IsTrue(result >= -1, "Porcupine returned an unexpected result (<-1)");
|
||||
if (result >= 0)
|
||||
{
|
||||
results.Add(result);
|
||||
}
|
||||
}
|
||||
|
||||
Assert.IsTrue(results.Count == 1 && results[0] == 0, "Expected to find keyword 'porcupine', but no keyword was detected.");
|
||||
p.Dispose();
|
||||
Assert.AreEqual(expectedResults.Count, results.Count, $"Should have found {expectedResults.Count} keywords, but {results.Count} were found.");
|
||||
for (int i = 0; i < results.Count; i++)
|
||||
{
|
||||
Assert.AreEqual(expectedResults[i], results[i], $"Expected keyword {expectedResults[i]}, but Porcupine detected keyword {results[i]}.");
|
||||
}
|
||||
|
||||
porcupine.Dispose();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestProcessMultiple()
|
||||
public void TestFrameLength()
|
||||
{
|
||||
porcupine = Porcupine.FromBuiltInKeywords(ACCESS_KEY, new List<BuiltInKeyword> { BuiltInKeyword.PORCUPINE });
|
||||
Assert.IsTrue(porcupine.FrameLength > 0, "Specified frame length was not a valid number.");
|
||||
porcupine.Dispose();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestVersion()
|
||||
{
|
||||
porcupine = Porcupine.FromBuiltInKeywords(ACCESS_KEY, new List<BuiltInKeyword> { BuiltInKeyword.PORCUPINE });
|
||||
Assert.IsFalse(string.IsNullOrWhiteSpace(porcupine.Version), "Porcupine did not return a valid version number.");
|
||||
porcupine.Dispose();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestSingleKeyword()
|
||||
{
|
||||
porcupine = Porcupine.FromBuiltInKeywords(ACCESS_KEY, new List<BuiltInKeyword> { BuiltInKeyword.PORCUPINE });
|
||||
RunTestCase(
|
||||
"porcupine.wav",
|
||||
new List<int>() {0});
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestMultipleKeyword()
|
||||
{
|
||||
List<BuiltInKeyword> inputKeywords = new List<BuiltInKeyword>
|
||||
{
|
||||
@@ -90,54 +171,131 @@ namespace PorcupineTest
|
||||
BuiltInKeyword.PORCUPINE,
|
||||
BuiltInKeyword.TERMINATOR
|
||||
};
|
||||
porcupine = Porcupine.FromBuiltInKeywords(ACCESS_KEY, inputKeywords);
|
||||
RunTestCase(
|
||||
"multiple_keywords.wav",
|
||||
new List<int>() {7, 0, 1, 2, 3, 4, 5, 6, 7, 8});
|
||||
}
|
||||
|
||||
List<BuiltInKeyword> expectedResults = new List<BuiltInKeyword>() {
|
||||
BuiltInKeyword.PORCUPINE,
|
||||
BuiltInKeyword.ALEXA,
|
||||
BuiltInKeyword.AMERICANO,
|
||||
BuiltInKeyword.BLUEBERRY,
|
||||
BuiltInKeyword.BUMBLEBEE,
|
||||
BuiltInKeyword.GRAPEFRUIT,
|
||||
BuiltInKeyword.GRASSHOPPER,
|
||||
BuiltInKeyword.PICOVOICE,
|
||||
BuiltInKeyword.PORCUPINE,
|
||||
BuiltInKeyword.TERMINATOR
|
||||
[TestMethod]
|
||||
public void TestSingleKeywordDe()
|
||||
{
|
||||
string language = "de";
|
||||
List<string> keywords = new List<string>() {"heuschrecke"};
|
||||
|
||||
porcupine = Porcupine.FromKeywordPaths(
|
||||
ACCESS_KEY,
|
||||
GetKeywordPaths(language, keywords),
|
||||
GetModelPath(language)
|
||||
);
|
||||
|
||||
RunTestCase(
|
||||
"heuschrecke.wav",
|
||||
new List<int>() {0});
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestMultipleKeywordDe()
|
||||
{
|
||||
string language = "de";
|
||||
List<string> keywords = new List<string>() {
|
||||
"heuschrecke",
|
||||
"ananas",
|
||||
"leguan",
|
||||
"stachelschwein"
|
||||
};
|
||||
|
||||
Porcupine p = Porcupine.FromBuiltInKeywords(ACCESS_KEY, inputKeywords);
|
||||
int frameLen = p.FrameLength;
|
||||
porcupine = Porcupine.FromKeywordPaths(
|
||||
ACCESS_KEY,
|
||||
GetKeywordPaths(language, keywords),
|
||||
GetModelPath(language)
|
||||
);
|
||||
|
||||
string testAudioPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "resources/audio_samples/multiple_keywords.wav");
|
||||
List<short> data = GetPcmFromFile(testAudioPath, p.SampleRate);
|
||||
|
||||
int framecount = (int)Math.Floor((float)(data.Count / frameLen));
|
||||
var results = new List<int>();
|
||||
for (int i = 0; i < framecount; i++)
|
||||
{
|
||||
int start = i * frameLen;
|
||||
int count = frameLen;
|
||||
List<short> frame = data.GetRange(start, count);
|
||||
int result = p.Process(frame.ToArray());
|
||||
Assert.IsTrue(result >= -1, "Porcupine returned an unexpected result (<-1)");
|
||||
|
||||
if (result >= 0)
|
||||
{
|
||||
results.Add(result);
|
||||
}
|
||||
}
|
||||
|
||||
Assert.AreEqual(expectedResults.Count, results.Count, $"Should have found {expectedResults.Count} keywords, but {results.Count} were found.");
|
||||
for (int i = 0; i < results.Count; i++)
|
||||
{
|
||||
Assert.AreEqual(
|
||||
expectedResults[i],
|
||||
inputKeywords[results[i]],
|
||||
$"Expected '{expectedResults[i]}', but '{inputKeywords[results[i]]}' was detected.");
|
||||
}
|
||||
|
||||
p.Dispose();
|
||||
RunTestCase(
|
||||
"multiple_keywords_de.wav",
|
||||
new List<int>() {1, 0, 2, 3});
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestSingleKeywordEs()
|
||||
{
|
||||
string language = "es";
|
||||
List<string> keywords = new List<string>() {
|
||||
"manzana"
|
||||
};
|
||||
|
||||
porcupine = Porcupine.FromKeywordPaths(
|
||||
ACCESS_KEY,
|
||||
GetKeywordPaths(language, keywords),
|
||||
GetModelPath(language)
|
||||
);
|
||||
|
||||
RunTestCase(
|
||||
"manzana.wav",
|
||||
new List<int>() {0});
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestMultipleKeywordEs()
|
||||
{
|
||||
string language = "es";
|
||||
List<string> keywords = new List<string>() {
|
||||
"emparedado",
|
||||
"leopardo",
|
||||
"manzana"
|
||||
};
|
||||
|
||||
porcupine = Porcupine.FromKeywordPaths(
|
||||
ACCESS_KEY,
|
||||
GetKeywordPaths(language, keywords),
|
||||
GetModelPath(language)
|
||||
);
|
||||
|
||||
RunTestCase(
|
||||
"multiple_keywords_es.wav",
|
||||
new List<int>() {0, 1, 2});
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestSingleKeywordFr()
|
||||
{
|
||||
string language = "fr";
|
||||
List<string> keywords = new List<string>() {
|
||||
"mon chouchou"
|
||||
};
|
||||
|
||||
porcupine = Porcupine.FromKeywordPaths(
|
||||
ACCESS_KEY,
|
||||
GetKeywordPaths(language, keywords),
|
||||
GetModelPath(language)
|
||||
);
|
||||
|
||||
RunTestCase(
|
||||
"mon_chouchou.wav",
|
||||
new List<int>() {0});
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TestMultipleKeywordFr()
|
||||
{
|
||||
string language = "fr";
|
||||
List<string> keywords = new List<string>() {
|
||||
"framboise",
|
||||
"mon chouchou",
|
||||
"parapluie"
|
||||
};
|
||||
|
||||
porcupine = Porcupine.FromKeywordPaths(
|
||||
ACCESS_KEY,
|
||||
GetKeywordPaths(language, keywords),
|
||||
GetModelPath(language)
|
||||
);
|
||||
|
||||
RunTestCase(
|
||||
"multiple_keywords_fr.wav",
|
||||
new List<int>() {0, 1, 0, 2});
|
||||
}
|
||||
|
||||
private List<short> GetPcmFromFile(string audioFilePath, int expectedSampleRate)
|
||||
{
|
||||
List<short> data = new List<short>();
|
||||
|
||||
Reference in New Issue
Block a user