ruby-spacy 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b759c507a1cad8e726bd36ad39e4539894395407e2ac5d64a31b7b907a4e34d8
4
- data.tar.gz: 0f02f9b8f6bcf39a49b50b1934905e72c0c13bb9652eee8fbaad3a3b7b58b7e7
3
+ metadata.gz: eff16e19adc4863d93ac22803e63e5ac2ab8bba077eca7cbc8c2403174704aac
4
+ data.tar.gz: 1766dc8fbb6c2c4b10314c925ddae484907f6677f9fb314ede756c9b3752923e
5
5
  SHA512:
6
- metadata.gz: 5b7d8078148e05c860f3ef698b5103cfca533fabfac5001c5afd12419efaae21d6492aa22fcebfba9d9d22bf8701fe2c6a21eb1ee879344cdbd5d897af9b8853
7
- data.tar.gz: 4ffab4be8e0338e86c34aad0285cd9471a3d5c570fbf48b4214cdbe5ca5cc01c7d251d4f6d5edc778de2185d89fc3858e094c363499c81f89d5c3a61ab8859c2
6
+ metadata.gz: b1ef879141c89307e0fa05d5130fa997c0e1746ab0fc4a466dca032a6c4f1007341e8e6a5d1369d1f5a260070e161df8df60f87042343870c862d931faaa7789
7
+ data.tar.gz: 54baa96c6f475f147b374d8b27a80c6aa792937d759793178fd4f78592588f93d121f4e1edbfb89fdb7e8da5cd6b74abf8b1ccc404ef8bd6f836cc88b55fa407
@@ -0,0 +1,97 @@
1
+ name: CI
2
+
3
+ on:
4
+ # Every branch, so that work in progress is tested before a pull request exists
5
+ push:
6
+ branches: ["**"]
7
+ pull_request:
8
+ # Weekly run to detect breakage from new spaCy / PyCall / Ruby releases
9
+ # even when the repository itself is untouched
10
+ schedule:
11
+ - cron: "23 3 * * 2"
12
+
13
+ jobs:
14
+ test:
15
+ name: ruby ${{ matrix.ruby }} / python ${{ matrix.python }}
16
+ runs-on: ubuntu-latest
17
+ # Pull requests from this repository are already covered by the push event;
18
+ # only run the pull_request event for forks, to avoid duplicate matrices
19
+ if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository
20
+ # This project has known hang paths (pipeline calls from non-main threads,
21
+ # spacy.load hangs that Ruby's Timeout cannot interrupt); never let a job
22
+ # run until GitHub's 6-hour limit
23
+ timeout-minutes: 30
24
+ continue-on-error: ${{ matrix.experimental == true }}
25
+ strategy:
26
+ fail-fast: false
27
+ matrix:
28
+ ruby: ["3.2", "3.3", "3.4", "4.0"]
29
+ python: ["3.11", "3.12", "3.13", "3.14"]
30
+ include:
31
+ # Ruby 4.1 is not released yet; track the development branch instead
32
+ - { ruby: head, python: "3.13", experimental: true }
33
+ env:
34
+ # PyCall locates the Python interpreter via this variable
35
+ PYTHON: python
36
+ # rsyntaxtree (used by the syntax_tree tests) is in the :rendering
37
+ # bundler group and needs pango/rsvg system libraries; install it only
38
+ # on representative jobs
39
+ BUNDLE_WITHOUT: ${{ matrix.python != '3.13' && 'rendering' || '' }}
40
+ steps:
41
+ - uses: actions/checkout@v7
42
+
43
+ # Must precede ruby/setup-ruby: installing the pycall gem compiles its
44
+ # native extension against this Python
45
+ - uses: actions/setup-python@v7
46
+ with:
47
+ python-version: ${{ matrix.python }}
48
+
49
+ # Must precede ruby/setup-ruby: bundler-cache installs the pango/rsvg2
50
+ # gems, which compile against these system libraries
51
+ - name: Install rsyntaxtree system dependencies (representative jobs)
52
+ if: matrix.python == '3.13'
53
+ run: sudo apt-get update && sudo apt-get install -y libpango1.0-dev librsvg2-dev libgirepository1.0-dev
54
+
55
+ - uses: ruby/setup-ruby@v1
56
+ with:
57
+ ruby-version: ${{ matrix.ruby }}
58
+ bundler-cache: true
59
+
60
+ - id: site-packages
61
+ run: echo "path=$(python -c 'import site; print(site.getsitepackages()[0])')" >> "$GITHUB_OUTPUT"
62
+
63
+ # Cache the language models only (en_core_web_lg alone is several hundred
64
+ # MB). spaCy itself is intentionally installed fresh on every run so that
65
+ # new releases are exercised immediately. Bump the key suffix when
66
+ # upgrading the models. The ja/ru/de/zh models are installed only on the
67
+ # python 3.13 jobs (where the syntax_tree tests run); listing them here
68
+ # for other jobs is harmless
69
+ - uses: actions/cache@v6
70
+ with:
71
+ path: |
72
+ ${{ steps.site-packages.outputs.path }}/en_core_web_sm*
73
+ ${{ steps.site-packages.outputs.path }}/en_core_web_lg*
74
+ ${{ steps.site-packages.outputs.path }}/ja_core_news_sm*
75
+ ${{ steps.site-packages.outputs.path }}/ru_core_news_sm*
76
+ ${{ steps.site-packages.outputs.path }}/de_core_news_sm*
77
+ ${{ steps.site-packages.outputs.path }}/zh_core_web_sm*
78
+ key: spacy-models-${{ matrix.python }}-v2
79
+
80
+ # en_core_web_lg and the ja/ru/de/zh models are large; install them only
81
+ # on representative jobs (where the syntax_tree tests run). Tests that
82
+ # need them are skipped automatically where they are absent.
83
+ - name: Install spaCy and language models
84
+ run: |
85
+ python -m pip install --upgrade pip
86
+ python -m pip install --upgrade spacy
87
+ python -m spacy download en_core_web_sm
88
+ if [ "${{ matrix.python }}" = "3.13" ]; then
89
+ python -m spacy download en_core_web_lg
90
+ python -m spacy download ja_core_news_sm
91
+ python -m spacy download ru_core_news_sm
92
+ python -m spacy download de_core_news_sm
93
+ python -m spacy download zh_core_web_sm
94
+ fi
95
+
96
+ - name: Run tests
97
+ run: bundle exec rake test
data/CHANGELOG.md CHANGED
@@ -1,5 +1,63 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.7.0 - 2026-09-03
4
+ ### Added
5
+ - `Doc#syntax_tree` and `Span#syntax_tree` — turn a parse into rsyntaxtree
6
+ bracket notation, or draw it as SVG, PNG, PDF, TikZ, or JSON. Two styles:
7
+ `:projection` builds a phrase-structure-like tree from the head words,
8
+ `:chunks` lays the noun chunks out flat. Noun chunks are shaded, named
9
+ entities that coincide with one are labeled, and `morphology: true` attaches
10
+ a table of features to every leaf. rsyntaxtree (>= 2.4.0) is an optional
11
+ dependency, required on first use rather than at load time
12
+ - `Language.new(py_nlp:)` — wrap a Python pipeline built elsewhere, for the
13
+ languages spaCy ships no trained model for. Every right-to-left language is
14
+ one of them, and their trees are drawn mirrored so the leaves run in reading
15
+ order. A package such as spacy-stanza builds the pipeline; ruby-spacy gains
16
+ no dependency
17
+ - `docs/syntax_trees.md` — a gallery of trees in six languages, generated by
18
+ the scripts in `examples/rsyntaxtree/`
19
+
20
+ ### Changed
21
+ - CI runs the syntax tree tests against English, Japanese, Russian, German, and
22
+ Chinese models, which between them cover the paths that differ: with and
23
+ without noun chunks, two-line entity labels, and a mirrored right-to-left tree
24
+
25
+ ## 0.6.0 - 2026-08-31
26
+ ### Added
27
+ - GitHub Actions CI — Ruby 3.2 to 4.0 (plus ruby-head) and Python 3.11 to 3.14,
28
+ with a weekly run to catch breakage from new spaCy or PyCall releases
29
+ - `:label` in `Matcher#match` results — the label string of the matched pattern
30
+
31
+ ### Changed
32
+ - PyCall 1.5.3 or later is now required; earlier versions freeze the whole
33
+ process when Ruby's GC releases a Python object on a non-main thread, which
34
+ affects any threaded application (Rails, Puma, Sidekiq)
35
+ - Minimum Ruby version raised to 3.2
36
+ - Removed the `numpy` gem dependency; NumPy is used directly through PyCall
37
+ - Relaxed the `terminal-table` requirement to `>= 3.0, < 5`
38
+ - Language models are no longer stored in Python's `__main__`, so creating a
39
+ `Language` no longer keeps a pipeline alive until the process exits
40
+ - `Language.new(timeout:)` now actually fires. The wait happens on a Python
41
+ thread rather than through Ruby's `Timeout`, whose watcher thread cannot run
42
+ while PyCall holds the GVL. `timeout: nil` waits indefinitely, and a timeout
43
+ is never retried
44
+ - README documents the thread-safety constraint: all spaCy calls must be made
45
+ from the thread that initialized PyCall
46
+
47
+ ### Deprecated
48
+ - `Language#spacy_nlp_id` — use `#py_nlp` instead; referencing it still works
49
+ but creates a Python global variable that is never released
50
+
51
+ ### Fixed
52
+ - `Matcher#match` returned a corrupted `:match_id` (often `0`) for labels whose
53
+ hash was `2**62` or larger, since unsigned 64-bit values do not survive the
54
+ PyCall boundary. Ids now round-trip through `Language#vocab_string_lookup`,
55
+ which accepts large ids again
56
+ - Integer attributes reached through `method_missing`, such as `Token#orth`,
57
+ were silently corrupted for the same reason: 7 of 12 common words returned a
58
+ negative `orth`. They are now fetched safely, which also restores
59
+ `Token#rank` for out-of-vocabulary tokens
60
+
3
61
  ## 0.5.0 - 2026-07-21
4
62
  ### Added
5
63
  - `Language#with_llm(provider:)` — provider-neutral block-based LLM API
data/Gemfile CHANGED
@@ -5,15 +5,14 @@ source "https://rubygems.org"
5
5
  # Specify your gem's dependencies in ruby-spacy.gemspec
6
6
  gemspec
7
7
 
8
- gem "fiddle" # Required for Ruby 4.0+ (moved from default to bundled gem)
9
- gem "numpy"
10
- gem "pycall", "~> 1.5.1"
11
- gem "terminal-table"
12
-
13
8
  group :development do
14
9
  gem "github-markup"
15
- gem "minitest", "~> 5.0"
16
- gem "rake", "~> 13.0"
17
10
  gem "redcarpet"
18
- gem "yard"
11
+ end
12
+
13
+ # Used only for rendering in Doc#syntax_tree / Span#syntax_tree tests.
14
+ # Kept in its own group so CI jobs without the pango/rsvg system libraries
15
+ # can exclude it with BUNDLE_WITHOUT=rendering.
16
+ group :rendering do
17
+ gem "rsyntaxtree", ">= 2.4.0", require: false
19
18
  end
data/README.md CHANGED
@@ -10,29 +10,31 @@
10
10
  | ✅ | Part-of-speech tagging and dependency parsing |
11
11
  | ✅ | Named entity recognition |
12
12
  | ✅ | Syntactic dependency visualization |
13
+ | ✅ | Syntax tree visualization (via rsyntaxtree) |
13
14
  | ✅ | Access to pre-trained word vectors |
14
15
  | ✅ | LLM integration: OpenAI, Anthropic (Claude), and local models |
15
16
 
16
- Current Version: `0.5.0`
17
+ Current Version: `0.7.0`
17
18
 
18
- - Ruby 4.0 supported
19
+ - Ruby 3.2 to 4.0 supported (PyCall 1.5.3 or later required)
19
20
  - spaCy 3.8 supported
21
+ - Syntax trees drawn with rsyntaxtree, including right-to-left languages
20
22
  - Multi-provider LLM API: OpenAI, Anthropic (Claude), and local models via Ollama or any OpenAI-compatible server
21
23
  - Structured outputs (JSON Schema) support
22
24
  - Block-based LLM API with linguistic analysis
23
25
 
24
26
  ## Installation of Prerequisites
25
27
 
26
- **IMPORTANT**: Make sure that the `enable-shared` option is enabled in your Python installation. You can use [pyenv](https://github.com/pyenv/pyenv) to install any version of Python you like. Install Python 3.10.6, for instance, using pyenv with `enable-shared` as follows:
28
+ **IMPORTANT**: Make sure that the `enable-shared` option is enabled in your Python installation. You can use [pyenv](https://github.com/pyenv/pyenv) to install any version of Python you like. spaCy 3.8 supports Python 3.10 and later (wheels are provided for Python 3.10–3.14), so we recommend using one of those versions. Install Python 3.13, for instance, using pyenv with `enable-shared` as follows:
27
29
 
28
30
  ```shell
29
- $ env CONFIGURE_OPTS="--enable-shared" pyenv install 3.10.6
31
+ $ env CONFIGURE_OPTS="--enable-shared" pyenv install 3.13
30
32
  ```
31
33
 
32
34
  Remember to make it accessible from your working directory. It is recommended that you set `global` to the version of python you just installed.
33
35
 
34
36
  ```shell
35
- $ pyenv global 3.10.6
37
+ $ pyenv global 3.13
36
38
  ```
37
39
 
38
40
  Then, install [spaCy](https://spacy.io/). If you use `pip`, the following command will do:
@@ -77,6 +79,18 @@ Or install it yourself as:
77
79
 
78
80
  See [Examples](#examples) below.
79
81
 
82
+ ### Using an External Pipeline
83
+
84
+ `Spacy::Language.new` normally loads an installed model by name. To use a language spaCy has no model for, or a pipeline you built yourself, pass an existing Python `Language` object instead:
85
+
86
+ ```ruby
87
+ py_nlp = PyCall.import_module("spacy_stanza").load_pipeline("ar")
88
+ nlp = Spacy::Language.new(py_nlp: py_nlp)
89
+ nlp.read("...").tokens # works like any other nlp
90
+ ```
91
+
92
+ Third-party packages such as [spacy-stanza](https://github.com/explosion/spacy-stanza) or [spacy-udpipe](https://github.com/TakeLab/spacy-udpipe) are not ruby-spacy dependencies; install them yourself. `model` and `py_nlp:` are mutually exclusive.
93
+
80
94
  ## Examples
81
95
 
82
96
  Many of the following examples are Python-to-Ruby translations of code snippets in [spaCy 101](https://spacy.io/usage/spacy-101). For more examples, look inside the `examples` directory.
@@ -286,6 +300,42 @@ Output:
286
300
 
287
301
  ![](https://github.com/yohasebe/ruby-spacy/blob/main/examples/get_started/outputs/test_dep_compact.svg)
288
302
 
303
+ ### Syntax Trees
304
+
305
+ → [rsyntaxtree](https://github.com/yohasebe/rsyntaxtree)
306
+
307
+ `Doc#syntax_tree` (and `Span#syntax_tree`) converts the parse into rsyntaxtree bracket notation and can render it as an image. rsyntaxtree (>= 2.4.0) is an optional dependency: `gem install rsyntaxtree`.
308
+
309
+ ```ruby
310
+ require "ruby-spacy"
311
+
312
+ nlp = Spacy::Language.new("en_core_web_sm")
313
+ doc = nlp.read("The quick brown fox jumped over the lazy dog near the river.")
314
+
315
+ doc.syntax_tree # => "[S [%NP [DET The] [ADJ quick] ...] ...]"
316
+ File.binwrite("tree.png", doc.syntax_tree(format: :png))
317
+ doc.syntax_tree(style: :chunks) # shallow tree with noun chunks
318
+ doc.syntax_tree(morphology: true) # attach morphology tables to the leaves
319
+ ```
320
+
321
+ <img src="https://github.com/yohasebe/ruby-spacy/blob/main/examples/rsyntaxtree/outputs/tree_en_projection.png" alt="English projection tree" width="560">
322
+
323
+ <img src="https://github.com/yohasebe/ruby-spacy/blob/main/examples/rsyntaxtree/outputs/tree_en_morphology.png" alt="English projection tree with morphology tables" width="760">
324
+
325
+ <img src="https://github.com/yohasebe/ruby-spacy/blob/main/examples/rsyntaxtree/outputs/tree_ja_projection.png" alt="Japanese projection tree with named entities" width="500">
326
+
327
+ Two styles are available: `:projection` (default; a phrase-structure-like tree projected from the head words) and `:chunks` (a shallow tree with noun chunks). In both, noun chunks are shaded grey, and a chunk that is also a named entity is shaded orange and labeled with the entity type (`entities: false` to disable). The blue and green are rsyntaxtree's default palette, not marking of any kind; only the shading carries meaning. Punctuation is omitted (`punctuation: true` to keep it). The `format:` option accepts `:bracket` (default), `:svg`, `:png`, `:pdf`, `:tikz`, and `:json`; any other keywords are passed through to rsyntaxtree (e.g. `fontsize: 12`).
328
+
329
+ The notation is rsyntaxtree-flavored: it can contain AVMs (`#(...#)`), region backgrounds (`%`), and in-word space joins (`<>`). A doc must hold a single sentence; for a multi-sentence doc, use `doc.sents.map { |s| s.syntax_tree }`.
330
+
331
+ **Annotation schemes differ between models.** spaCy's English models make the preposition the head of its phrase, so projection trees contain `PP` nodes. UD-style models (Japanese, Russian, Chinese, and most others) attach prepositions and particles to the noun instead, so no `PP` appears. Phrase labels come from the head's POS tag and follow whatever scheme the model uses.
332
+
333
+ **Entity highlighting requires noun chunks.** An entity gets its colored background only where it coincides with a noun chunk. In languages whose models have no noun chunk iterator (Russian, Chinese, Korean, Polish, ...) `entities: true` highlights nothing and `style: :chunks` raises `ArgumentError`.
334
+
335
+ **Right-to-left languages.** spaCy ships no pipelines for Arabic, Hebrew, or other RTL languages, so one has to come from outside (see [Using an External Pipeline](#using-an-external-pipeline)). Their trees are drawn mirrored automatically; pass `mirror: "off"` to disable.
336
+
337
+ See the [syntax tree gallery](docs/syntax_trees.md) for rendered trees in six languages, and `examples/rsyntaxtree/` for the scripts that generate them.
338
+
289
339
  ### Named Entity Recognition
290
340
 
291
341
  → [spaCy: Named entities](https://spacy.io/usage/spacy-101#annotations-ner)
@@ -525,6 +575,30 @@ Output:
525
575
  | 9 | アルザス | 0.5644999742507935 |
526
576
  | 10 | 南仏 | 0.5547999739646912 |
527
577
 
578
+ ### Matcher
579
+
580
+ `Matcher` finds token sequences with rule-based patterns.
581
+
582
+ ```ruby
583
+ require "ruby-spacy"
584
+
585
+ nlp = Spacy::Language.new("en_core_web_sm")
586
+
587
+ matcher = nlp.matcher
588
+ matcher.add("GREETING", [[{ LOWER: "hello" }, { IS_PUNCT: true }, { LOWER: "world" }]])
589
+
590
+ doc = nlp.read("Hello, world!")
591
+ matcher.match(doc).each do |match|
592
+ span = doc.span(match[:start_index]..match[:end_index])
593
+ puts "#{match[:label]}: #{span.text}"
594
+ end
595
+ # => GREETING: Hello, world
596
+ ```
597
+
598
+ `Matcher#match` returns an array of hashes with `:match_id` (the label's numeric id), `:start_index`, `:end_index`, and `:label` (the label string).
599
+
600
+ See `examples/rule_based_matching/` for more examples.
601
+
528
602
  ### PhraseMatcher
529
603
 
530
604
  `PhraseMatcher` is more efficient than `Matcher` for matching large terminology lists. It's ideal for extracting known entities like product names, company names, or domain-specific terms.
@@ -974,6 +1048,14 @@ See `examples/llm/` for complete scripts, including a spaCy-vs-LLM NER compariso
974
1048
 
975
1049
  ## Advanced Usage
976
1050
 
1051
+ ### Thread Safety
1052
+
1053
+ All spaCy calls must be made from the same thread that initialized PyCall (normally the main thread). Calling the spaCy pipeline from another thread — e.g. `nlp.read(text)` inside a `Thread.new` block, a Rails multi-threaded server, or a Sidekiq worker — will hang the entire process.
1054
+
1055
+ Note that attribute access (such as `nlp.pipe_names`) works from other threads, so the failure mode is not obvious: the process only freezes when the pipeline actually runs. The root cause is currently unknown (it is specific to spaCy pipeline execution; other GIL-releasing Python calls work fine from other threads).
1056
+
1057
+ If you need concurrent processing, serialize all Python calls onto a single dedicated thread, for example with a worker thread and a queue.
1058
+
977
1059
  ### Setting a Timeout
978
1060
 
979
1061
  You can set a timeout for the `Spacy::Language.new` method:
@@ -982,6 +1064,8 @@ You can set a timeout for the `Spacy::Language.new` method:
982
1064
  nlp = Spacy::Language.new("en_core_web_sm", timeout: 120) # Set timeout to 120 seconds
983
1065
  ```
984
1066
 
1067
+ If the model does not finish loading within the given seconds, a `RuntimeError` is raised. Pass `timeout: nil` to wait indefinitely.
1068
+
985
1069
  ### Document Serialization
986
1070
 
987
1071
  You can serialize processed documents to binary format for caching or storage. This is useful when you want to avoid re-processing the same text multiple times.
@@ -0,0 +1,55 @@
1
+ # Syntax Tree Gallery
2
+
3
+ Trees drawn by `Doc#syntax_tree` with the [rsyntaxtree](https://github.com/yohasebe/rsyntaxtree) gem. The scripts in `examples/rsyntaxtree/` generate every image here.
4
+
5
+ Noun chunks are shaded grey; a chunk that is also a named entity is shaded orange and labeled with the entity type. The blue and green are rsyntaxtree's default palette, not marking of any kind. Phrase labels come from the head's POS tag, so they follow whatever annotation scheme the model uses. Both are explained in the [README](../README.md#syntax-trees).
6
+
7
+ ## English (`en_core_web_sm`)
8
+
9
+ Projection, the default style:
10
+
11
+ ![English projection](https://github.com/yohasebe/ruby-spacy/blob/main/examples/rsyntaxtree/outputs/tree_en_projection.png)
12
+
13
+ Chunks style:
14
+
15
+ ![English chunks](https://github.com/yohasebe/ruby-spacy/blob/main/examples/rsyntaxtree/outputs/tree_en_chunks.png)
16
+
17
+ With morphology (a shorter sentence — the tables are tall):
18
+
19
+ ![English morphology](https://github.com/yohasebe/ruby-spacy/blob/main/examples/rsyntaxtree/outputs/tree_en_morphology.png)
20
+
21
+ ## Japanese (`ja_core_news_sm`)
22
+
23
+ Projection, with PERSON and GPE highlighted:
24
+
25
+ ![Japanese projection](https://github.com/yohasebe/ruby-spacy/blob/main/examples/rsyntaxtree/outputs/tree_ja_projection.png)
26
+
27
+ Chunks style:
28
+
29
+ ![Japanese chunks](https://github.com/yohasebe/ruby-spacy/blob/main/examples/rsyntaxtree/outputs/tree_ja_chunks.png)
30
+
31
+ ## Russian (`ru_core_news_sm`)
32
+
33
+ No noun chunk iterator, so `style: :chunks` is unavailable.
34
+
35
+ ![Russian projection](https://github.com/yohasebe/ruby-spacy/blob/main/examples/rsyntaxtree/outputs/tree_ru_projection.png)
36
+
37
+ With morphology — Russian marks case, gender, animacy, aspect, and voice:
38
+
39
+ ![Russian morphology](https://github.com/yohasebe/ruby-spacy/blob/main/examples/rsyntaxtree/outputs/tree_ru_morphology.png)
40
+
41
+ ## German (`de_core_news_sm`)
42
+
43
+ ![German projection](https://github.com/yohasebe/ruby-spacy/blob/main/examples/rsyntaxtree/outputs/tree_de_projection.png)
44
+
45
+ ## Chinese (`zh_core_web_sm`)
46
+
47
+ No noun chunk iterator, so `style: :chunks` is unavailable.
48
+
49
+ ![Chinese projection](https://github.com/yohasebe/ruby-spacy/blob/main/examples/rsyntaxtree/outputs/tree_zh_projection.png)
50
+
51
+ ## Arabic (right-to-left)
52
+
53
+ spaCy ships no Arabic pipeline, so this tree was parsed with [Stanza](https://stanfordnlp.github.io/stanza/) via [spacy-stanza](https://github.com/explosion/spacy-stanza) and wrapped with `Spacy::Language.new(py_nlp:)`. Right-to-left languages are drawn mirrored automatically. This pipeline has no noun chunks, so nothing is shaded. See `examples/rsyntaxtree/syntax_tree_ar.rb`.
54
+
55
+ ![Arabic projection](https://github.com/yohasebe/ruby-spacy/blob/main/examples/rsyntaxtree/outputs/tree_ar_projection.png)
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Arabic via an external pipeline. spaCy ships no trained pipeline for
4
+ # Arabic (or any other right-to-left language), so this example builds one
5
+ # with Stanza through spacy-stanza. These are NOT ruby-spacy dependencies;
6
+ # install them yourself first:
7
+ #
8
+ # pip install spacy-stanza
9
+ # pip install --upgrade "stanza>=1.10" # spacy-stanza's stanza pin is old and conflicts with current torch
10
+ # python -c "import stanza; stanza.download('ar')"
11
+ #
12
+ # Note: at exit, spacy-stanza under PyCall prints a harmless
13
+ # multiprocessing.resource_tracker LoadError to stderr (sys.executable
14
+ # points to ruby, not python); the results are unaffected.
15
+
16
+ # add path to ruby-spacy lib to load path
17
+ $LOAD_PATH.unshift(File.expand_path("../../lib", __dir__))
18
+
19
+ require "ruby-spacy"
20
+ require "fileutils"
21
+
22
+ # Requires the rsyntaxtree gem (>= 2.4.0): gem install rsyntaxtree
23
+
24
+ py_nlp = PyCall.import_module("spacy_stanza")
25
+ .load_pipeline("ar", processors: "tokenize,pos,lemma,depparse", verbose: false)
26
+ nlp = Spacy::Language.new(py_nlp: py_nlp)
27
+ doc = nlp.read("قرأ الطالب الجديد كتابا مثيرا في المكتبة أمس.")
28
+
29
+ puts doc.syntax_tree
30
+
31
+ # Right-to-left languages are drawn mirrored automatically (pass
32
+ # mirror: "off" to disable)
33
+ output_dir = File.join(File.dirname(__FILE__), "outputs")
34
+ FileUtils.mkdir_p(output_dir)
35
+ File.binwrite(File.join(output_dir, "tree_ar_projection.png"),
36
+ doc.syntax_tree(format: :png))
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # add path to ruby-spacy lib to load path
4
+ $LOAD_PATH.unshift(File.expand_path("../../lib", __dir__))
5
+
6
+ require "ruby-spacy"
7
+ require "fileutils"
8
+
9
+ # Requires the rsyntaxtree gem (>= 2.4.0): gem install rsyntaxtree
10
+
11
+ nlp = Spacy::Language.new("de_core_news_sm")
12
+ doc = nlp.read("Der alte Professor las gestern ein interessantes Buch.")
13
+
14
+ puts doc.syntax_tree
15
+
16
+ output_dir = File.join(File.dirname(__FILE__), "outputs")
17
+ FileUtils.mkdir_p(output_dir)
18
+ File.binwrite(File.join(output_dir, "tree_de_projection.png"),
19
+ doc.syntax_tree(format: :png))
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ # add path to ruby-spacy lib to load path
4
+ $LOAD_PATH.unshift(File.expand_path("../../lib", __dir__))
5
+
6
+ require "ruby-spacy"
7
+ require "fileutils"
8
+
9
+ # Requires the rsyntaxtree gem (>= 2.4.0): gem install rsyntaxtree
10
+
11
+ nlp = Spacy::Language.new("en_core_web_sm")
12
+ doc = nlp.read("The quick brown fox jumped over the lazy dog near the river.")
13
+
14
+ puts doc.syntax_tree
15
+
16
+ output_dir = File.join(File.dirname(__FILE__), "outputs")
17
+ FileUtils.mkdir_p(output_dir)
18
+ File.binwrite(File.join(output_dir, "tree_en_projection.png"),
19
+ doc.syntax_tree(format: :png))
20
+ File.binwrite(File.join(output_dir, "tree_en_chunks.png"),
21
+ doc.syntax_tree(style: :chunks, format: :png))
22
+ # A shorter sentence for the morphology tables: every leaf becomes a box, so a
23
+ # long sentence draws a figure too wide to read
24
+ compact = nlp.read("He was sitting under the old tree.")
25
+ File.binwrite(File.join(output_dir, "tree_en_morphology.png"),
26
+ compact.syntax_tree(format: :png, morphology: true))
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ # add path to ruby-spacy lib to load path
4
+ $LOAD_PATH.unshift(File.expand_path("../../lib", __dir__))
5
+
6
+ require "ruby-spacy"
7
+ require "fileutils"
8
+
9
+ # Requires the rsyntaxtree gem (>= 2.4.0): gem install rsyntaxtree
10
+
11
+ nlp = Spacy::Language.new("ja_core_news_sm")
12
+ doc = nlp.read("太郎は昨日、東京で花子に古い本を渡した。")
13
+
14
+ puts doc.syntax_tree
15
+
16
+ output_dir = File.join(File.dirname(__FILE__), "outputs")
17
+ FileUtils.mkdir_p(output_dir)
18
+ File.binwrite(File.join(output_dir, "tree_ja_projection.png"),
19
+ doc.syntax_tree(format: :png))
20
+ File.binwrite(File.join(output_dir, "tree_ja_chunks.png"),
21
+ doc.syntax_tree(style: :chunks, format: :png))
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ # add path to ruby-spacy lib to load path
4
+ $LOAD_PATH.unshift(File.expand_path("../../lib", __dir__))
5
+
6
+ require "ruby-spacy"
7
+ require "fileutils"
8
+
9
+ # Requires the rsyntaxtree gem (>= 2.4.0): gem install rsyntaxtree
10
+
11
+ nlp = Spacy::Language.new("ru_core_news_sm")
12
+ doc = nlp.read("Старый профессор читал интересную книгу в библиотеке.")
13
+
14
+ puts doc.syntax_tree
15
+
16
+ # ru_core_news_sm has no noun chunk iterator, so style: :chunks raises
17
+ # ArgumentError for this language; Russian morphology is rich, though
18
+ output_dir = File.join(File.dirname(__FILE__), "outputs")
19
+ FileUtils.mkdir_p(output_dir)
20
+ File.binwrite(File.join(output_dir, "tree_ru_projection.png"),
21
+ doc.syntax_tree(format: :png))
22
+ File.binwrite(File.join(output_dir, "tree_ru_morphology.png"),
23
+ doc.syntax_tree(format: :png, morphology: true))
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ # add path to ruby-spacy lib to load path
4
+ $LOAD_PATH.unshift(File.expand_path("../../lib", __dir__))
5
+
6
+ require "ruby-spacy"
7
+ require "fileutils"
8
+
9
+ # Requires the rsyntaxtree gem (>= 2.4.0): gem install rsyntaxtree
10
+
11
+ nlp = Spacy::Language.new("zh_core_web_sm")
12
+ doc = nlp.read("老教授昨天在图书馆读了一本有趣的书。")
13
+
14
+ puts doc.syntax_tree
15
+
16
+ # zh_core_web_sm has no noun chunk iterator, so style: :chunks raises
17
+ # ArgumentError for this language
18
+ output_dir = File.join(File.dirname(__FILE__), "outputs")
19
+ FileUtils.mkdir_p(output_dir)
20
+ File.binwrite(File.join(output_dir, "tree_zh_projection.png"),
21
+ doc.syntax_tree(format: :png))
@@ -14,7 +14,7 @@ doc = nlp.read("Barack Obama was the 44th president of the United States")
14
14
  matches = matcher.match(doc)
15
15
 
16
16
  matches.each do |match|
17
- span = Spacy::Span.new(doc, start_index: match[:start_index], end_index: match[:end_index], options: { label: match[:match_id] })
17
+ span = Spacy::Span.new(doc, start_index: match[:start_index], end_index: match[:end_index], options: { label: match[:label] })
18
18
  puts "#{span.text} / #{span.label}"
19
19
  end
20
20