pangram 0.1.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 +7 -0
- data/.github/workflows/ci.yml +31 -0
- data/.github/workflows/release.yml +80 -0
- data/.gitignore +11 -0
- data/.mise.toml +3 -0
- data/.rspec +2 -0
- data/.rubocop.yml +31 -0
- data/CHANGELOG.md +10 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +110 -0
- data/LICENSE +21 -0
- data/Makefile +66 -0
- data/README.md +228 -0
- data/Rakefile +8 -0
- data/docs/API_REFERENCE.md +254 -0
- data/docs/DEVELOPMENT.md +113 -0
- data/docs/README.md +25 -0
- data/docs/RELEASING.md +72 -0
- data/lib/pangram/client.rb +587 -0
- data/lib/pangram/errors.rb +37 -0
- data/lib/pangram/version.rb +7 -0
- data/lib/pangram.rb +15 -0
- data/pangram.gemspec +51 -0
- metadata +270 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 0366ca93432eaa95c91f307b3b1ebc3bfb7d3e0e23c13e57ae6ce32b03e15b94
|
|
4
|
+
data.tar.gz: e1b5a5f13e60dad75b78781446759b66219f060088aae07f3c135403a0dade37
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 0a5b2d970317274451d40d5ee847fce196bd776612dc2bddef6f680150bcdb2ccb9c6b4deafc10728998ec238e0c5195e6cc4a5adc1b3aa411202b019a7f17d6
|
|
7
|
+
data.tar.gz: 0abcdcf76d3199b9dff883e364a5894292901b3bb03127ff5f03d550bc811d078bfb0f622de4e4e80be1948e6d27aa250d037e0820ab10f0a192bbafe5bda2aa
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
strategy:
|
|
11
|
+
fail-fast: false
|
|
12
|
+
matrix:
|
|
13
|
+
ruby-version: ['3.1', '3.2', '3.3', '3.4', '4.0']
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
- uses: ruby/setup-ruby@v1
|
|
17
|
+
with:
|
|
18
|
+
ruby-version: ${{ matrix.ruby-version }}
|
|
19
|
+
bundler-cache: true
|
|
20
|
+
- run: bundle exec rake spec
|
|
21
|
+
|
|
22
|
+
lint-and-build:
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v4
|
|
26
|
+
- uses: ruby/setup-ruby@v1
|
|
27
|
+
with:
|
|
28
|
+
ruby-version: '4.0'
|
|
29
|
+
bundler-cache: true
|
|
30
|
+
- run: bundle exec rubocop
|
|
31
|
+
- run: bundle exec rake build
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
name: Release Gem
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: release-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: false
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
release:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
permissions:
|
|
16
|
+
contents: write
|
|
17
|
+
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- name: Set up Ruby
|
|
22
|
+
uses: ruby/setup-ruby@v1
|
|
23
|
+
with:
|
|
24
|
+
ruby-version: '4.0'
|
|
25
|
+
bundler-cache: true
|
|
26
|
+
|
|
27
|
+
- name: Verify tag matches gem version
|
|
28
|
+
id: version
|
|
29
|
+
run: |
|
|
30
|
+
tag="${GITHUB_REF_NAME#v}"
|
|
31
|
+
version="$(ruby -Ilib -e 'require "pangram/version"; print Pangram::VERSION')"
|
|
32
|
+
if [ "$tag" != "$version" ]; then
|
|
33
|
+
echo "Tag v$tag does not match Pangram::VERSION $version"
|
|
34
|
+
exit 1
|
|
35
|
+
fi
|
|
36
|
+
echo "version=$version" >> "$GITHUB_OUTPUT"
|
|
37
|
+
|
|
38
|
+
- name: Extract release notes from CHANGELOG.md
|
|
39
|
+
env:
|
|
40
|
+
VERSION: ${{ steps.version.outputs.version }}
|
|
41
|
+
run: |
|
|
42
|
+
awk -v ver="$VERSION" '
|
|
43
|
+
index($0, "## [" ver "]") == 1 { found=1; next }
|
|
44
|
+
found && /^## / { exit }
|
|
45
|
+
found { print }
|
|
46
|
+
' CHANGELOG.md > release_notes.md
|
|
47
|
+
if ! grep -q '[^[:space:]]' release_notes.md; then
|
|
48
|
+
echo "No CHANGELOG.md entry found for version $VERSION"
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
- name: Run tests
|
|
53
|
+
run: bundle exec rake spec
|
|
54
|
+
|
|
55
|
+
- name: Run RuboCop
|
|
56
|
+
run: bundle exec rubocop
|
|
57
|
+
|
|
58
|
+
- name: Build gem
|
|
59
|
+
run: bundle exec rake build
|
|
60
|
+
|
|
61
|
+
- name: Create GitHub Release
|
|
62
|
+
uses: softprops/action-gh-release@v2
|
|
63
|
+
with:
|
|
64
|
+
files: pkg/pangram-${{ steps.version.outputs.version }}.gem
|
|
65
|
+
body_path: release_notes.md
|
|
66
|
+
draft: false
|
|
67
|
+
prerelease: false
|
|
68
|
+
env:
|
|
69
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
70
|
+
|
|
71
|
+
- name: Publish to RubyGems
|
|
72
|
+
run: |
|
|
73
|
+
if [ -z "$GEM_HOST_API_KEY" ]; then
|
|
74
|
+
echo "Secret RUBYGEMS_API_KEY is not set"
|
|
75
|
+
exit 1
|
|
76
|
+
fi
|
|
77
|
+
gem push "pkg/pangram-${VERSION}.gem"
|
|
78
|
+
env:
|
|
79
|
+
VERSION: ${{ steps.version.outputs.version }}
|
|
80
|
+
GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }}
|
data/.gitignore
ADDED
data/.mise.toml
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
AllCops:
|
|
2
|
+
TargetRubyVersion: 3.1
|
|
3
|
+
NewCops: enable
|
|
4
|
+
SuggestExtensions: false
|
|
5
|
+
Exclude:
|
|
6
|
+
- 'Gemfile'
|
|
7
|
+
- 'Rakefile'
|
|
8
|
+
- 'pangram.gemspec'
|
|
9
|
+
- 'vendor/**/*'
|
|
10
|
+
|
|
11
|
+
Layout/LineLength:
|
|
12
|
+
Max: 120
|
|
13
|
+
|
|
14
|
+
Style/Documentation:
|
|
15
|
+
Enabled: false
|
|
16
|
+
|
|
17
|
+
Metrics/BlockLength:
|
|
18
|
+
Exclude:
|
|
19
|
+
- 'spec/**/*'
|
|
20
|
+
|
|
21
|
+
Metrics/ClassLength:
|
|
22
|
+
Max: 500
|
|
23
|
+
|
|
24
|
+
Metrics/MethodLength:
|
|
25
|
+
Max: 45
|
|
26
|
+
|
|
27
|
+
Metrics/AbcSize:
|
|
28
|
+
Max: 35
|
|
29
|
+
|
|
30
|
+
Metrics/ParameterLists:
|
|
31
|
+
Enabled: false
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [Unreleased]
|
|
4
|
+
|
|
5
|
+
## [0.1.0] - 2026-08-14
|
|
6
|
+
|
|
7
|
+
- Add model discovery and asynchronous text prediction.
|
|
8
|
+
- Add bulk submission, status polling, pagination, and result aggregation.
|
|
9
|
+
- Add single and multi-file prediction.
|
|
10
|
+
- Add plagiarism detection.
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
pangram (0.1.0)
|
|
5
|
+
faraday (>= 1.8, < 3.0)
|
|
6
|
+
faraday-multipart (~> 1.0)
|
|
7
|
+
faraday-net_http (>= 1.0, < 4.0)
|
|
8
|
+
json (~> 2.0)
|
|
9
|
+
|
|
10
|
+
GEM
|
|
11
|
+
remote: https://rubygems.org/
|
|
12
|
+
specs:
|
|
13
|
+
addressable (2.9.0)
|
|
14
|
+
public_suffix (>= 2.0.2, < 8.0)
|
|
15
|
+
ast (2.4.3)
|
|
16
|
+
bigdecimal (4.1.2)
|
|
17
|
+
crack (1.0.1)
|
|
18
|
+
bigdecimal
|
|
19
|
+
rexml
|
|
20
|
+
diff-lcs (1.6.2)
|
|
21
|
+
docile (1.4.1)
|
|
22
|
+
faraday (2.14.3)
|
|
23
|
+
faraday-net_http (>= 2.0, < 3.5)
|
|
24
|
+
json
|
|
25
|
+
logger
|
|
26
|
+
faraday-multipart (1.2.0)
|
|
27
|
+
multipart-post (~> 2.0)
|
|
28
|
+
faraday-net_http (3.4.4)
|
|
29
|
+
net-http (~> 0.5)
|
|
30
|
+
hashdiff (1.2.1)
|
|
31
|
+
json (2.21.2)
|
|
32
|
+
language_server-protocol (3.17.0.6)
|
|
33
|
+
lint_roller (1.1.0)
|
|
34
|
+
logger (1.7.0)
|
|
35
|
+
multipart-post (2.4.1)
|
|
36
|
+
net-http (0.9.1)
|
|
37
|
+
uri (>= 0.11.1)
|
|
38
|
+
parallel (1.28.0)
|
|
39
|
+
parser (3.3.12.0)
|
|
40
|
+
ast (~> 2.4.1)
|
|
41
|
+
racc
|
|
42
|
+
prism (1.9.0)
|
|
43
|
+
public_suffix (6.0.2)
|
|
44
|
+
racc (1.8.1)
|
|
45
|
+
rainbow (3.1.1)
|
|
46
|
+
rake (13.4.2)
|
|
47
|
+
regexp_parser (2.12.0)
|
|
48
|
+
rexml (3.4.4)
|
|
49
|
+
rspec (3.13.2)
|
|
50
|
+
rspec-core (~> 3.13.0)
|
|
51
|
+
rspec-expectations (~> 3.13.0)
|
|
52
|
+
rspec-mocks (~> 3.13.0)
|
|
53
|
+
rspec-core (3.13.6)
|
|
54
|
+
rspec-support (~> 3.13.0)
|
|
55
|
+
rspec-expectations (3.13.5)
|
|
56
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
57
|
+
rspec-support (~> 3.13.0)
|
|
58
|
+
rspec-mocks (3.13.8)
|
|
59
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
|
60
|
+
rspec-support (~> 3.13.0)
|
|
61
|
+
rspec-support (3.13.7)
|
|
62
|
+
rubocop (1.89.0)
|
|
63
|
+
json (~> 2.3)
|
|
64
|
+
language_server-protocol (~> 3.17.0.2)
|
|
65
|
+
lint_roller (~> 1.1.0)
|
|
66
|
+
parallel (>= 1.10)
|
|
67
|
+
parser (>= 3.3.0.2)
|
|
68
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
69
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
|
70
|
+
rubocop-ast (>= 1.49.0, < 2.0)
|
|
71
|
+
ruby-progressbar (~> 1.7)
|
|
72
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
|
73
|
+
rubocop-ast (1.50.0)
|
|
74
|
+
parser (>= 3.3.7.2)
|
|
75
|
+
prism (~> 1.7)
|
|
76
|
+
ruby-progressbar (1.13.0)
|
|
77
|
+
simplecov (0.22.0)
|
|
78
|
+
docile (~> 1.1)
|
|
79
|
+
simplecov-html (~> 0.11)
|
|
80
|
+
simplecov_json_formatter (~> 0.1)
|
|
81
|
+
simplecov-html (0.13.2)
|
|
82
|
+
simplecov_json_formatter (0.1.4)
|
|
83
|
+
unicode-display_width (3.2.0)
|
|
84
|
+
unicode-emoji (~> 4.1)
|
|
85
|
+
unicode-emoji (4.2.0)
|
|
86
|
+
uri (1.1.1)
|
|
87
|
+
webmock (3.26.2)
|
|
88
|
+
addressable (>= 2.8.0)
|
|
89
|
+
crack (>= 0.3.2)
|
|
90
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
|
91
|
+
yard (0.9.45)
|
|
92
|
+
|
|
93
|
+
PLATFORMS
|
|
94
|
+
arm64-darwin-25
|
|
95
|
+
ruby
|
|
96
|
+
|
|
97
|
+
DEPENDENCIES
|
|
98
|
+
bundler (>= 2.0, < 3.0)
|
|
99
|
+
pangram!
|
|
100
|
+
parallel (~> 1.0)
|
|
101
|
+
public_suffix (< 7.0)
|
|
102
|
+
rake (~> 13.0)
|
|
103
|
+
rspec (~> 3.0)
|
|
104
|
+
rubocop (~> 1.0)
|
|
105
|
+
simplecov (~> 0.22)
|
|
106
|
+
webmock (~> 3.0)
|
|
107
|
+
yard (~> 0.9)
|
|
108
|
+
|
|
109
|
+
BUNDLED WITH
|
|
110
|
+
2.6.9
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pangram Ruby SDK Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/Makefile
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
.PHONY: help install test spec coverage lint lint-fix docs build verify clean console tag
|
|
2
|
+
|
|
3
|
+
help: ## Show available commands
|
|
4
|
+
@awk 'BEGIN {FS = ":.*## "; printf "Usage: make <target>\n\nTargets:\n"} /^[a-zA-Z_-]+:.*## / {printf " \033[36m%-12s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
|
5
|
+
|
|
6
|
+
install: ## Install gem dependencies
|
|
7
|
+
bundle install
|
|
8
|
+
|
|
9
|
+
spec: ## Run the RSpec test suite
|
|
10
|
+
bundle exec rake spec
|
|
11
|
+
|
|
12
|
+
test: spec ## Alias for spec
|
|
13
|
+
|
|
14
|
+
coverage: spec ## Generate the test coverage report
|
|
15
|
+
@echo "Coverage report: coverage/index.html"
|
|
16
|
+
|
|
17
|
+
lint: ## Run RuboCop
|
|
18
|
+
bundle exec rubocop
|
|
19
|
+
|
|
20
|
+
lint-fix: ## Run RuboCop with safe and unsafe auto-corrections
|
|
21
|
+
bundle exec rubocop -A
|
|
22
|
+
|
|
23
|
+
docs: ## Generate YARD API documentation in doc/
|
|
24
|
+
bundle exec yard doc --output-dir doc
|
|
25
|
+
|
|
26
|
+
build: ## Build the gem in pkg/
|
|
27
|
+
bundle exec rake build
|
|
28
|
+
|
|
29
|
+
verify: spec lint docs build ## Run all release checks
|
|
30
|
+
|
|
31
|
+
clean: ## Remove generated artifacts
|
|
32
|
+
rm -rf .yardoc coverage doc pkg .rspec_status
|
|
33
|
+
|
|
34
|
+
console: ## Start IRB with Pangram loaded
|
|
35
|
+
bundle exec irb -Ilib -rpangram
|
|
36
|
+
|
|
37
|
+
tag: ## Tag a release and push it. Usage: make tag [VERSION=x.y.z] [FORCE=1]
|
|
38
|
+
@set -e; \
|
|
39
|
+
git diff --cached --quiet || { echo "Error: 索引中已有暂存改动,请先提交或 git reset"; exit 1; }; \
|
|
40
|
+
git fetch --tags --quiet; \
|
|
41
|
+
CURRENT=$$(ruby -Ilib -rpangram/version -e 'print Pangram::VERSION'); \
|
|
42
|
+
if [ -n "$(VERSION)" ]; then \
|
|
43
|
+
NEW_VERSION=$$(echo "$(VERSION)" | sed 's/^v//'); \
|
|
44
|
+
elif git rev-parse -q --verify "refs/tags/v$$CURRENT" >/dev/null; then \
|
|
45
|
+
NEW_VERSION=$$(ruby -e 'a = ARGV[0].split("."); a[2] = a[2].to_i + 1; print a.join(".")' "$$CURRENT"); \
|
|
46
|
+
else \
|
|
47
|
+
NEW_VERSION=$$CURRENT; \
|
|
48
|
+
fi; \
|
|
49
|
+
echo "$$NEW_VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$$' || { echo "Error: 非法版本号 $$NEW_VERSION"; exit 1; }; \
|
|
50
|
+
NEW_TAG="v$$NEW_VERSION"; \
|
|
51
|
+
if git rev-parse -q --verify "refs/tags/$$NEW_TAG" >/dev/null; then \
|
|
52
|
+
[ -n "$(FORCE)" ] || { echo "Error: $$NEW_TAG 已存在。RubyGems 同版本不可重复发布,确认要重来请加 FORCE=1"; exit 1; }; \
|
|
53
|
+
echo "FORCE: 删除已存在的 $$NEW_TAG ..."; \
|
|
54
|
+
git tag -d "$$NEW_TAG"; \
|
|
55
|
+
git push origin --delete "$$NEW_TAG" || true; \
|
|
56
|
+
fi; \
|
|
57
|
+
grep -q "^## \[$$NEW_VERSION\]" CHANGELOG.md || { echo "Error: CHANGELOG.md 缺少 ## [$$NEW_VERSION] 条目"; exit 1; }; \
|
|
58
|
+
echo "Updating version to $$NEW_VERSION ..."; \
|
|
59
|
+
ruby -pi -e "sub(/VERSION = .*/, \"VERSION = '$$NEW_VERSION'\")" lib/pangram/version.rb; \
|
|
60
|
+
bundle install --quiet; \
|
|
61
|
+
git add lib/pangram/version.rb Gemfile.lock; \
|
|
62
|
+
git diff --cached --quiet || git commit -m "Release $$NEW_TAG"; \
|
|
63
|
+
git tag "$$NEW_TAG"; \
|
|
64
|
+
echo "Pushing $$NEW_TAG ..."; \
|
|
65
|
+
git push origin HEAD && git push origin "$$NEW_TAG"; \
|
|
66
|
+
echo "Done! Tagged and pushed $$NEW_TAG"
|
data/README.md
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# Pangram Ruby SDK
|
|
2
|
+
|
|
3
|
+
Ruby client for the [Pangram Labs API](https://docs.pangram.com), with support
|
|
4
|
+
for AI detection, asynchronous bulk jobs, file uploads, and plagiarism checks.
|
|
5
|
+
|
|
6
|
+
## Requirements
|
|
7
|
+
|
|
8
|
+
- Ruby 3.1 or newer
|
|
9
|
+
- A Pangram API key
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
Add the gem to your application:
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
gem 'pangram'
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Then run `bundle install`, or install it directly:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
gem install pangram
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Client setup
|
|
26
|
+
|
|
27
|
+
Set your API key in the environment:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
export PANGRAM_API_KEY='your-api-key'
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
require 'pangram'
|
|
35
|
+
|
|
36
|
+
client = Pangram.new
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
You can also pass the key directly. A constructor argument takes precedence
|
|
40
|
+
over `PANGRAM_API_KEY`.
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
client = Pangram.new(api_key: 'your-api-key')
|
|
44
|
+
# Equivalent: Pangram::Client.new(api_key: 'your-api-key')
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
All API responses are ordinary Ruby `Hash` and `Array` values. Response keys
|
|
48
|
+
remain strings and match Pangram's JSON schema.
|
|
49
|
+
|
|
50
|
+
## Discover models
|
|
51
|
+
|
|
52
|
+
Model access depends on the API key and current service availability. Discover
|
|
53
|
+
selectors instead of hard-coding a model catalog:
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
models = client.list_models
|
|
57
|
+
# => ["default", "pangram-4"]
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Pass `model: "default"` to track Pangram's default, or pass another selector
|
|
61
|
+
returned by `list_models`. Omitting `model` is temporarily supported but emits
|
|
62
|
+
a deprecation warning; Pangram plans to require it after September 30, 2026.
|
|
63
|
+
|
|
64
|
+
## AI detection
|
|
65
|
+
|
|
66
|
+
`predict` submits an asynchronous task, polls until it succeeds, and returns
|
|
67
|
+
the completed result:
|
|
68
|
+
|
|
69
|
+
```ruby
|
|
70
|
+
result = client.predict(
|
|
71
|
+
'Text to analyze',
|
|
72
|
+
model: 'pangram-4',
|
|
73
|
+
timeout: 300,
|
|
74
|
+
poll_interval: 0.5
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
puts result['prediction_short']
|
|
78
|
+
puts result['fraction_ai']
|
|
79
|
+
|
|
80
|
+
result['windows'].each do |window|
|
|
81
|
+
puts "#{window['label']}: #{window['ai_assistance_score']}"
|
|
82
|
+
end
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Request a public dashboard link either directly or with the convenience
|
|
86
|
+
method:
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
result = client.predict(
|
|
90
|
+
'Text to analyze',
|
|
91
|
+
model: 'pangram-4',
|
|
92
|
+
public_dashboard_link: true
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
result = client.predict_with_dashboard_link(
|
|
96
|
+
'Text to analyze',
|
|
97
|
+
model: 'pangram-4'
|
|
98
|
+
)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Polling intervals below 0.1 seconds are clamped to 0.1. `timeout` is a total
|
|
102
|
+
deadline covering task submission and polling.
|
|
103
|
+
|
|
104
|
+
## Bulk jobs
|
|
105
|
+
|
|
106
|
+
Submit either a plain `text` list or an `items` list with optional customer
|
|
107
|
+
IDs. Do not pass both.
|
|
108
|
+
|
|
109
|
+
```ruby
|
|
110
|
+
bulk = client.submit_bulk(
|
|
111
|
+
items: [
|
|
112
|
+
{ id: 'row-001', text: 'First text' },
|
|
113
|
+
{ id: 'row-002', text: 'Second text' }
|
|
114
|
+
],
|
|
115
|
+
model: 'pangram-4'
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
bulk_id = bulk['bulk_id']
|
|
119
|
+
status = client.wait_for_bulk(bulk_id, timeout: 3600, poll_interval: 1)
|
|
120
|
+
results = client.get_bulk_results(bulk_id)
|
|
121
|
+
|
|
122
|
+
results['items'].each do |item|
|
|
123
|
+
prediction = item['result']
|
|
124
|
+
puts "#{item['id']}: #{prediction['prediction_short']}" if prediction
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
results['failed_items'].each do |item|
|
|
128
|
+
warn "#{item['id']}: #{item['error']}"
|
|
129
|
+
end
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Use the lower-level methods to inspect a job without materializing all result
|
|
133
|
+
pages:
|
|
134
|
+
|
|
135
|
+
```ruby
|
|
136
|
+
client.get_bulk_status(bulk_id)
|
|
137
|
+
client.get_bulk_items(bulk_id, offset: 0, limit: 100)
|
|
138
|
+
client.get_bulk_results_page(bulk_id, offset: 0, limit: 100)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
`get_bulk_results` requests all pages and stores them in memory. For very large
|
|
142
|
+
jobs, process `get_bulk_results_page` one page at a time. The API accepts at
|
|
143
|
+
most 1,000 submitted item slots per results page.
|
|
144
|
+
|
|
145
|
+
## File uploads
|
|
146
|
+
|
|
147
|
+
File prediction uses Pangram's default model and does not accept `model`.
|
|
148
|
+
|
|
149
|
+
```ruby
|
|
150
|
+
result = client.predict_file(
|
|
151
|
+
'document.pdf',
|
|
152
|
+
public_dashboard_link: true,
|
|
153
|
+
timeout: 300
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
results = client.predict_files(
|
|
157
|
+
['first.docx', 'second.pdf'],
|
|
158
|
+
public_dashboard_link: true
|
|
159
|
+
)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
The SDK sends one multipart field named `files` for each path and closes every
|
|
163
|
+
opened file after the request, including when the request fails.
|
|
164
|
+
|
|
165
|
+
## Plagiarism detection
|
|
166
|
+
|
|
167
|
+
```ruby
|
|
168
|
+
result = client.check_plagiarism('Text to check')
|
|
169
|
+
|
|
170
|
+
puts result['plagiarism_detected']
|
|
171
|
+
puts result['percent_plagiarized']
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Errors
|
|
175
|
+
|
|
176
|
+
All SDK errors inherit from `Pangram::Error`:
|
|
177
|
+
|
|
178
|
+
| Error | Meaning |
|
|
179
|
+
| --- | --- |
|
|
180
|
+
| `Pangram::AuthenticationError` | No API key was configured |
|
|
181
|
+
| `Pangram::ValidationError` | A local argument is invalid |
|
|
182
|
+
| `Pangram::APIError` | Pangram rejected the request or a task failed |
|
|
183
|
+
| `Pangram::InvalidResponseError` | Pangram returned invalid JSON or an unexpected schema |
|
|
184
|
+
| `Pangram::NetworkError` | The HTTP connection failed or a request timed out |
|
|
185
|
+
| `Pangram::TimeoutError` | An async prediction or bulk job exceeded its total deadline |
|
|
186
|
+
|
|
187
|
+
```ruby
|
|
188
|
+
begin
|
|
189
|
+
client.predict('Text', model: 'default')
|
|
190
|
+
rescue Pangram::TimeoutError => e
|
|
191
|
+
warn e.message
|
|
192
|
+
rescue Pangram::Error => e
|
|
193
|
+
warn "Pangram request failed: #{e.message}"
|
|
194
|
+
end
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Transient network failures and responses with status 408, 429, 500, 502, 503,
|
|
198
|
+
or 504 are retried until the total deadline while polling a prediction or bulk
|
|
199
|
+
job and while paginating bulk results. Other API errors are raised immediately
|
|
200
|
+
with the HTTP `status` and response `body` attached.
|
|
201
|
+
|
|
202
|
+
## Deprecated compatibility methods
|
|
203
|
+
|
|
204
|
+
The current Python SDK still includes these methods, so Ruby provides matching
|
|
205
|
+
compatibility helpers:
|
|
206
|
+
|
|
207
|
+
- `predict_short(text, model:)` forwards to the current prediction flow.
|
|
208
|
+
- `batch_predict(texts, model:)` calls the prediction flow sequentially.
|
|
209
|
+
|
|
210
|
+
Prefer `predict` for one input and `submit_bulk` for many inputs.
|
|
211
|
+
|
|
212
|
+
## Development
|
|
213
|
+
|
|
214
|
+
Extended documentation is available in [`docs/`](docs/README.md), including
|
|
215
|
+
the [API reference](docs/API_REFERENCE.md), [development guide](docs/DEVELOPMENT.md),
|
|
216
|
+
and [release checklist](docs/RELEASING.md).
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
mise install
|
|
220
|
+
bundle install
|
|
221
|
+
make verify
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
The test suite uses WebMock and never needs a live Pangram API key.
|
|
225
|
+
|
|
226
|
+
## License
|
|
227
|
+
|
|
228
|
+
[MIT](LICENSE)
|