diff --git a/.Rbuildignore b/.Rbuildignore index c9a5c92..00d0777 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -19,3 +19,5 @@ ^CRAN-RELEASE$ ^appveyor\.yml$ ^tools$ +^LICENSE\.md$ +^lib$ \ No newline at end of file diff --git a/DESCRIPTION b/DESCRIPTION index 63f012b..32f07fc 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: swiftspeech Type: Package -Title: swiftspeech title goes here otherwise CRAN checks fail +Title: Classify Parts of Speech Using Apple's CoreML and NaturalLanguage Libraries Version: 0.1.0 Date: 2021-01-23 Authors@R: c( @@ -8,17 +8,16 @@ Authors@R: c( comment = c(ORCID = "0000-0001-5670-2640")) ) Maintainer: Bob Rudis -Description: A good description goes here otherwise CRAN checks fail. +Description: Classify Parts of Speech Using Apple's CoreML and NaturalLanguage Libraries. URL: https://git.rud.is/hrbrmstr/swiftspeech BugReports: https://git.rud.is/hrbrmstr/swiftspeech/issues Encoding: UTF-8 -License: AGPL +License: MIT + file LICENSE Suggests: covr, tinytest Depends: - R (>= 3.5.0) -Imports: - httr, - jsonlite + R (>= 3.6.0) Roxygen: list(markdown = TRUE) RoxygenNote: 7.1.1 +RequiresCompilation: yes +SystemRequirments: macOS; Swift diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f51d1b2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,2 @@ +YEAR: 2021 +COPYRIGHT HOLDER: Bob Rudis diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..c2304a0 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +# MIT License + +Copyright (c) 2021 Bob Rudis + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/NAMESPACE b/NAMESPACE index 5b4b9ae..2b521ae 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,4 +1,4 @@ # Generated by roxygen2: do not edit by hand -import(httr) -importFrom(jsonlite,fromJSON) +export(parts_of_speech) +useDynLib(swiftspeech, .registration = TRUE) diff --git a/R/parts-of-speech.R b/R/parts-of-speech.R new file mode 100644 index 0000000..792ac9d --- /dev/null +++ b/R/parts-of-speech.R @@ -0,0 +1,13 @@ +#' Parts of speech +#' +#' @usage +#' parts_of_speech("The ripe taste of cheese improves with age.") +#' @param x words +#' @return (list) one vector with words, one with parts of speech +#' @export +#' @examples +#' parts_of_speech("The ripe taste of cheese improves with age.") +parts_of_speech <- function(x) { + res <- .Call("part_of_speech", x) + as.data.frame(stats::setNames(res, c("name", "tag"))) +} \ No newline at end of file diff --git a/R/swiftspeech-package.R b/R/swiftspeech-package.R index 096f745..e1f6ddf 100644 --- a/R/swiftspeech-package.R +++ b/R/swiftspeech-package.R @@ -1,9 +1,8 @@ -#' ... -#' +#' Classify Parts of Speech Using Apple's CoreML and NaturalLanguage Libraries +#' #' @md #' @name swiftspeech #' @keywords internal #' @author Bob Rudis (bob@@rud.is) -#' @import httr -#' @importFrom jsonlite fromJSON +#' @useDynLib swiftspeech, .registration = TRUE "_PACKAGE" diff --git a/inst/lib/libswiftspeech.dylib b/inst/lib/libswiftspeech.dylib new file mode 100755 index 0000000..c722a57 Binary files /dev/null and b/inst/lib/libswiftspeech.dylib differ diff --git a/lib/libswiftspeech.dylib b/lib/libswiftspeech.dylib new file mode 100755 index 0000000..c722a57 Binary files /dev/null and b/lib/libswiftspeech.dylib differ diff --git a/man/parts_of_speech.Rd b/man/parts_of_speech.Rd new file mode 100644 index 0000000..b0b0504 --- /dev/null +++ b/man/parts_of_speech.Rd @@ -0,0 +1,20 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/parts-of-speech.R +\name{parts_of_speech} +\alias{parts_of_speech} +\title{Parts of speech} +\usage{ +parts_of_speech("The ripe taste of cheese improves with age.") +} +\arguments{ +\item{x}{words} +} +\value{ +(list) one vector with words, one with parts of speech +} +\description{ +Parts of speech +} +\examples{ +parts_of_speech("The ripe taste of cheese improves with age.") +} diff --git a/man/swiftspeech.Rd b/man/swiftspeech.Rd index 9d8a0c3..19946bf 100644 --- a/man/swiftspeech.Rd +++ b/man/swiftspeech.Rd @@ -4,9 +4,9 @@ \name{swiftspeech} \alias{swiftspeech} \alias{swiftspeech-package} -\title{...} +\title{Classify Parts of Speech Using Apple's CoreML and NaturalLanguage Libraries} \description{ -A good description goes here otherwise CRAN checks fail. +Classify Parts of Speech Using Apple's CoreML and NaturalLanguage Libraries. } \seealso{ Useful links: diff --git a/src/Makevars b/src/Makevars new file mode 100644 index 0000000..7d4a67c --- /dev/null +++ b/src/Makevars @@ -0,0 +1,22 @@ +SWIFTC = /usr/bin/swiftc +INSTALL_NAME_TOOL = /usr/bin/install_name_tool +SWIFTLIB = libswiftspeech.dylib +LIBDIR = ../inst/lib +DEVLIB = ../lib +PKG_LIBS = -lswiftspeech -L../inst/lib + +all: $(SHLIB) swiftLibrary + +swiftLibrary: $(SWIFTLIB) + -@if test ! -e $(LIBDIR); then mkdir -p $(LIBDIR); fi + -@if test ! -e $(DEVLIB); then mkdir -p $(DEVLIB); fi + cp $(SWIFTLIB) $(LIBDIR) + cp $(SWIFTLIB) $(DEVLIB) + +$(SWIFTLIB): $(OBJECTS) + $(SHLIB_CXXLD) -o $(SWIFTLIB) $^ $(SHLIB_CXXLDFLAGS) $(LDFLAGS) $(ALL_LIBS) + $(SWIFTC) -I /Library/Frameworks/R.framework/Headers -F/Library/Frameworks -framework R -framework CoreML -framework NaturalLanguage -import-objc-header swiftspeech.h -emit-library swiftspeech.swift + $(INSTALL_NAME_TOOL) -change $(SWIFTLIB) @loader_path/../lib/$(SWIFTLIB) swiftspeech.so + +clean: + rm -Rf $(SHLIB) $(SWIFTLIB) $(OBJECTS) $(DEVLIB)/$(SWIFTLIB) diff --git a/src/init.c b/src/init.c new file mode 100644 index 0000000..b206819 --- /dev/null +++ b/src/init.c @@ -0,0 +1,21 @@ +#include +#include +#include // for NULL +#include + +/* .Call calls */ +extern SEXP hey(); +extern SEXP plus_one(SEXP); +extern SEXP part_of_speech(SEXP); + +static const R_CallMethodDef CallEntries[] = { + {"hey", (DL_FUNC) &hey, 0}, + {"plus_one", (DL_FUNC) &plus_one, 1}, + {"part_of_speech", (DL_FUNC) &part_of_speech, 1}, + {NULL, NULL, 0} +}; + +void R_init_daybreak(DllInfo *dll) { + R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); + R_useDynamicSymbols(dll, FALSE); +} diff --git a/src/libswiftspeech.dylib b/src/libswiftspeech.dylib new file mode 100755 index 0000000..c722a57 Binary files /dev/null and b/src/libswiftspeech.dylib differ diff --git a/src/swiftspeech.h b/src/swiftspeech.h new file mode 100644 index 0000000..192e916 --- /dev/null +++ b/src/swiftspeech.h @@ -0,0 +1,6 @@ +#define USE_RINTERNALS + +#include +#include + +const char* R_CHAR(SEXP x); \ No newline at end of file diff --git a/src/swiftspeech.swift b/src/swiftspeech.swift new file mode 100644 index 0000000..2f95774 --- /dev/null +++ b/src/swiftspeech.swift @@ -0,0 +1,40 @@ +import NaturalLanguage +import CoreML + +extension Array where Element == String { + var SEXP: SEXP? { + let charVec = Rf_protect(Rf_allocVector(SEXPTYPE(STRSXP), count)) + defer { Rf_unprotect(1) } + for (idx, elem) in enumerated() { SET_STRING_ELT(charVec, idx, Rf_mkChar(elem)) } + return(charVec) + } +} + +@_cdecl("part_of_speech") +public func part_of_speech(_ x: SEXP) -> SEXP { + + let text = String(cString: R_CHAR(STRING_ELT(x, 0))) + let tagger = NLTagger(tagSchemes: [.lexicalClass]) + + tagger.string = text + + let options: NLTagger.Options = [.omitPunctuation, .omitWhitespace] + + var txts = [String]() + var tags = [String]() + + tagger.enumerateTags(in: text.startIndex..