Skip to content

Commit

Permalink
v2.0 python (#256)
Browse files Browse the repository at this point in the history
  • Loading branch information
ksyeo1010 authored Nov 23, 2023
1 parent ceb492d commit 71d3b62
Show file tree
Hide file tree
Showing 10 changed files with 338 additions and 81 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/python-codestyle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ name: Python Codestyle
on:
workflow_dispatch:
push:
branches: [master]
branches: [ master ]
paths:
- 'binding/python/*.py'
- 'demo/python/*.py'
pull_request:
branches: [master]
branches: [ master, 'v[0-9]+.[0-9]+' ]
paths:
- 'binding/python/*.py'
- 'demo/python/*.py'
Expand Down
16 changes: 14 additions & 2 deletions .github/workflows/python-demos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ name: Python Demos
on:
workflow_dispatch:
push:
branches: [master]
branches: [ master ]
paths:
- '.github/workflows/python-demos.yml'
- 'demo/python/**'
- '!demo/python/README.md'
pull_request:
branches: [master]
branches: [ master, 'v[0-9]+.[0-9]+' ]
paths:
- '.github/workflows/python-demos.yml'
- 'demo/python/**'
Expand Down Expand Up @@ -39,6 +39,12 @@ jobs:
- name: Pre-build dependencies
run: python -m pip install --upgrade pip

# ************** REMOVE AFTER RELEASE ********************
- name: Build binding
run: |
pip install wheel && cd ../../binding/python && python setup.py sdist bdist_wheel && pip install dist/pvcheetah-2.0.0-py3-none-any.whl
# ********************************************************

- name: Install dependencies
run: pip install -r requirements.txt

Expand All @@ -55,6 +61,12 @@ jobs:
steps:
- uses: actions/checkout@v3

# ************** REMOVE AFTER RELEASE ********************
- name: Build binding
run: |
pip3 install wheel && cd ../../binding/python && python3 setup.py sdist bdist_wheel && pip3 install dist/pvcheetah-2.0.0-py3-none-any.whl
# ********************************************************

- name: Install dependencies
run: pip3 install -r requirements.txt

Expand Down
36 changes: 18 additions & 18 deletions .github/workflows/python-perf.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Python performance
on:
workflow_dispatch:
push:
branches: [master]
branches: [ master ]
paths:
- '.github/workflows/python-perf.yml'
- 'binding/python/test_cheetah_perf.py'
Expand All @@ -14,7 +14,7 @@ on:
- 'lib/raspberry-pi/**'
- 'lib/windows/**'
pull_request:
branches: [master]
branches: [ master, 'v[0-9]+.[0-9]+' ]
paths:
- '.github/workflows/python-perf.yml'
- 'binding/python/test_cheetah_perf.py'
Expand All @@ -39,14 +39,14 @@ jobs:
os: [ubuntu-latest, windows-latest, macos-latest]
include:
- os: ubuntu-latest
init_performance_threshold_sec: 2.1
proc_performance_threshold_sec: 0.5
init_performance_threshold_sec: 4.0
proc_performance_threshold_sec: 0.8
- os: windows-latest
init_performance_threshold_sec: 2.4
proc_performance_threshold_sec: 0.6
init_performance_threshold_sec: 4.0
proc_performance_threshold_sec: 0.7
- os: macos-latest
init_performance_threshold_sec: 3.0
proc_performance_threshold_sec: 0.8
init_performance_threshold_sec: 4.5
proc_performance_threshold_sec: 2.5

steps:
- uses: actions/checkout@v3
Expand Down Expand Up @@ -74,20 +74,20 @@ jobs:
machine: [rpi3-32, rpi3-64, rpi4-32, rpi4-64, jetson]
include:
- machine: rpi3-32
init_performance_threshold_sec: 7.5
proc_performance_threshold_sec: 3.6
init_performance_threshold_sec: 9.0
proc_performance_threshold_sec: 9.0
- machine: rpi3-64
init_performance_threshold_sec: 8.3
proc_performance_threshold_sec: 3.5
init_performance_threshold_sec: 9.0
proc_performance_threshold_sec: 7.5
- machine: rpi4-32
init_performance_threshold_sec: 5.7
proc_performance_threshold_sec: 2.0
init_performance_threshold_sec: 7.5
proc_performance_threshold_sec: 4.0
- machine: rpi4-64
init_performance_threshold_sec: 5.1
proc_performance_threshold_sec: 1.9
init_performance_threshold_sec: 7.5
proc_performance_threshold_sec: 4.0
- machine: jetson
init_performance_threshold_sec: 5.2
proc_performance_threshold_sec: 1.9
init_performance_threshold_sec: 7.5
proc_performance_threshold_sec: 4.0

steps:
- uses: actions/checkout@v3
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Python
on:
workflow_dispatch:
push:
branches: [master]
branches: [ master ]
paths:
- '.github/workflows/python.yml'
- 'binding/python/**'
Expand All @@ -15,7 +15,7 @@ on:
- 'lib/raspberry-pi/**'
- 'lib/windows/**'
pull_request:
branches: [master]
branches: [ master, 'v[0-9]+.[0-9]+' ]
paths:
- '.github/workflows/python.yml'
- 'binding/python/**'
Expand Down
81 changes: 73 additions & 8 deletions binding/python/_cheetah.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,27 @@


class CheetahError(Exception):
pass
def __init__(self, message: str = '', message_stack: Sequence[str] = None):
super().__init__(message)

self._message = message
self._message_stack = list() if message_stack is None else message_stack

def __str__(self):
message = self._message
if len(self._message_stack) > 0:
message += ':'
for i in range(len(self._message_stack)):
message += '\n [%d] %s' % (i, self._message_stack[i])
return message

@property
def message(self) -> str:
return self._message

@property
def message_stack(self) -> Sequence[str]:
return self._message_stack


class CheetahMemoryError(CheetahError):
Expand Down Expand Up @@ -122,14 +142,28 @@ def __init__(
if not os.path.exists(library_path):
raise CheetahIOError("Could not find Cheetah's dynamic library at `%s`." % library_path)

library = cdll.LoadLibrary(library_path)

if not os.path.exists(model_path):
raise CheetahIOError("Could not find model file at `%s`." % model_path)

if endpoint_duration_sec is not None and not endpoint_duration_sec > 0.:
raise CheetahInvalidArgumentError("`endpoint_duration_sec` must be either `None` or a positive number")

library = cdll.LoadLibrary(library_path)

set_sdk_func = library.pv_set_sdk
set_sdk_func.argtypes = [c_char_p]
set_sdk_func.restype = None

set_sdk_func('python'.encode('utf-8'))

self._get_error_stack_func = library.pv_get_error_stack
self._get_error_stack_func.argtypes = [POINTER(POINTER(c_char_p)), POINTER(c_int)]
self._get_error_stack_func.restype = self.PicovoiceStatuses

self._free_error_stack_func = library.pv_free_error_stack
self._free_error_stack_func.argtypes = [POINTER(c_char_p)]
self._free_error_stack_func.restype = None

init_func = library.pv_cheetah_init
init_func.argtypes = [c_char_p, c_char_p, c_float, c_bool, POINTER(POINTER(self.CCheetah))]
init_func.restype = self.PicovoiceStatuses
Expand All @@ -143,7 +177,9 @@ def __init__(
enable_automatic_punctuation,
byref(self._handle))
if status is not self.PicovoiceStatuses.SUCCESS:
raise self._PICOVOICE_STATUS_TO_EXCEPTION[status]()
raise self._PICOVOICE_STATUS_TO_EXCEPTION[status](
message='Initialization failed',
message_stack=self._get_error_stack())

self._delete_func = library.pv_cheetah_delete
self._delete_func.argtypes = [POINTER(self.CCheetah)]
Expand All @@ -158,6 +194,10 @@ def __init__(
self._flush_func.argtypes = [POINTER(self.CCheetah), POINTER(c_char_p)]
self._flush_func.restype = self.PicovoiceStatuses

self._transcript_delete_func = library.pv_cheetah_transcript_delete
self._transcript_delete_func.argtypes = [c_char_p]
self._transcript_delete_func.restype = None

version_func = library.pv_cheetah_version
version_func.argtypes = []
version_func.restype = c_char_p
Expand Down Expand Up @@ -192,9 +232,14 @@ def process(self, pcm: Sequence[int]) -> Tuple[str, bool]:
byref(c_partial_transcript),
byref(is_endpoint))
if status is not self.PicovoiceStatuses.SUCCESS:
raise self._PICOVOICE_STATUS_TO_EXCEPTION[status]()
raise self._PICOVOICE_STATUS_TO_EXCEPTION[status](
message='Process failed',
message_stack=self._get_error_stack())

partial_transcript = c_partial_transcript.value.decode('utf-8')
self._transcript_delete_func(c_partial_transcript)

return c_partial_transcript.value.decode('utf-8'), is_endpoint.value
return partial_transcript, is_endpoint.value

def flush(self) -> str:
"""
Expand All @@ -207,9 +252,14 @@ def flush(self) -> str:
c_final_transcript = c_char_p()
status = self._flush_func(self._handle, byref(c_final_transcript))
if status is not self.PicovoiceStatuses.SUCCESS:
raise self._PICOVOICE_STATUS_TO_EXCEPTION[status]()
raise self._PICOVOICE_STATUS_TO_EXCEPTION[status](
message='Flush failed',
message_stack=self._get_error_stack())

final_transcript = c_final_transcript.value.decode('utf-8')
self._transcript_delete_func(c_final_transcript)

return c_final_transcript.value.decode('utf-8')
return final_transcript

def delete(self) -> None:
"""Releases resources acquired by Cheetah."""
Expand All @@ -234,6 +284,21 @@ def frame_length(self) -> int:

return self._frame_length

def _get_error_stack(self) -> Sequence[str]:
message_stack_ref = POINTER(c_char_p)()
message_stack_depth = c_int()
status = self._get_error_stack_func(byref(message_stack_ref), byref(message_stack_depth))
if status is not self.PicovoiceStatuses.SUCCESS:
raise self._PICOVOICE_STATUS_TO_EXCEPTION[status](message='Unable to get Porcupine error state')

message_stack = list()
for i in range(message_stack_depth.value):
message_stack.append(message_stack_ref[i].decode('utf-8'))

self._free_error_stack_func(message_stack_ref)

return message_stack


__all__ = [
'Cheetah',
Expand Down
39 changes: 18 additions & 21 deletions binding/python/setup.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright 2022 Picovoice Inc.
# Copyright 2022-2023 Picovoice Inc.
#
# You may not use this file except in compliance with the license. A copy of the license is located in the "LICENSE"
# file accompanying this source.
Expand All @@ -14,44 +14,41 @@

import setuptools

INCLUDE_FILES = ('../../LICENSE', '__init__.py', '_factory.py', '_cheetah.py', '_util.py')
INCLUDE_LIBS = ('linux', 'mac', 'windows', 'jetson', 'raspberry-pi')

os.system('git clean -dfx')

package_folder = os.path.join(os.path.dirname(__file__), 'pvcheetah')
os.mkdir(package_folder)
manifest_in = ""

shutil.copy(os.path.join(os.path.dirname(__file__), '../../LICENSE'), package_folder)

shutil.copy(os.path.join(os.path.dirname(__file__), '__init__.py'), os.path.join(package_folder, '__init__.py'))
shutil.copy(os.path.join(os.path.dirname(__file__), '_cheetah.py'), os.path.join(package_folder, '_cheetah.py'))
shutil.copy(os.path.join(os.path.dirname(__file__), '_factory.py'), os.path.join(package_folder, '_factory.py'))
shutil.copy(os.path.join(os.path.dirname(__file__), '_util.py'), os.path.join(package_folder, '_util.py'))
for rel_path in INCLUDE_FILES:
shutil.copy(os.path.join(os.path.dirname(__file__), rel_path), package_folder)
manifest_in += "include pvcheetah/%s\n" % os.path.basename(rel_path)

platforms = ('jetson', 'linux', 'mac', 'raspberry-pi', 'windows')
model_file = 'lib/common/cheetah_params.pv'
os.makedirs(os.path.join(package_folder, os.path.split(model_file)[0]))
shutil.copy(
os.path.join(os.path.dirname(__file__), '../..', model_file),
os.path.join(package_folder, model_file))
manifest_in += "include pvcheetah/%s\n" % model_file

os.mkdir(os.path.join(package_folder, 'lib'))
for platform in ('common',) + platforms:
for platform in INCLUDE_LIBS:
shutil.copytree(
os.path.join(os.path.dirname(__file__), '../../lib', platform),
os.path.join(package_folder, 'lib', platform))

MANIFEST_IN = """
include pvcheetah/LICENSE
include pvcheetah/__init__.py
include pvcheetah/_cheetah.py
include pvcheetah/_factory.py
include pvcheetah/_util.py
recursive-include pvcheetah/lib/ *
"""
manifest_in += "recursive-include pvcheetah/lib/%s *\n" % platform

with open(os.path.join(os.path.dirname(__file__), 'MANIFEST.in'), 'w') as f:
f.write(MANIFEST_IN.strip('\n '))
f.write(manifest_in)

with open(os.path.join(os.path.dirname(__file__), 'README.md'), 'r') as f:
long_description = f.read()

setuptools.setup(
name="pvcheetah",
version="1.1.3",
version="2.0.0",
author="Picovoice",
author_email="[email protected]",
description="Cheetah Speech-to-Text Engine.",
Expand Down
Loading

0 comments on commit 71d3b62

Please sign in to comment.