nbd-jev3 0.1.0__tar.gz
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.
- nbd_jev3-0.1.0/PKG-INFO +7 -0
- nbd_jev3-0.1.0/README.md +16 -0
- nbd_jev3-0.1.0/nbd_jev/__init__.py +8 -0
- nbd_jev3-0.1.0/nbd_jev/check.py +21 -0
- nbd_jev3-0.1.0/nbd_jev/classify.py +101 -0
- nbd_jev3-0.1.0/nbd_jev3.egg-info/PKG-INFO +7 -0
- nbd_jev3-0.1.0/nbd_jev3.egg-info/SOURCES.txt +10 -0
- nbd_jev3-0.1.0/nbd_jev3.egg-info/dependency_links.txt +1 -0
- nbd_jev3-0.1.0/nbd_jev3.egg-info/requires.txt +1 -0
- nbd_jev3-0.1.0/nbd_jev3.egg-info/top_level.txt +1 -0
- nbd_jev3-0.1.0/pyproject.toml +14 -0
- nbd_jev3-0.1.0/setup.cfg +4 -0
nbd_jev3-0.1.0/PKG-INFO
ADDED
nbd_jev3-0.1.0/README.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# nbd-jev3
|
|
2
|
+
|
|
3
|
+
Standalone Jev client. Requires Python 3.12 and `JEV_API_KEY`. The model is `typesafe/jev-1.13`.
|
|
4
|
+
|
|
5
|
+
```python
|
|
6
|
+
from nbd_jev import classify_text_classifier, classify_parseer
|
|
7
|
+
|
|
8
|
+
classify_text_classifier(text) # text_classifier labels, or "not sure"
|
|
9
|
+
classify_parseer(text) # Parseer page labels, or "not sure"
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
A choice below 0.5 confidence is `not sure`. A failed request is also `not sure`.
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
python -m nbd_jev.check
|
|
16
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Offline checks. Run: python -m nbd_jev.check"""
|
|
2
|
+
|
|
3
|
+
from nbd_jev.classify import (
|
|
4
|
+
NOT_SURE,
|
|
5
|
+
PARSEER_CRITERIA,
|
|
6
|
+
TEXT_CLASSIFIER_CRITERIA,
|
|
7
|
+
_resolve,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
assert "wiki page" not in TEXT_CLASSIFIER_CRITERIA
|
|
11
|
+
assert "news article" in TEXT_CLASSIFIER_CRITERIA
|
|
12
|
+
assert set(PARSEER_CRITERIA) == {
|
|
13
|
+
"news article", "not sure", "other", "product page",
|
|
14
|
+
"advertisement", "job listing", "forum post", "wiki page",
|
|
15
|
+
}
|
|
16
|
+
assert _resolve("news article", 0.5, TEXT_CLASSIFIER_CRITERIA) == "news article"
|
|
17
|
+
assert _resolve("news article", 0.49, TEXT_CLASSIFIER_CRITERIA) == NOT_SURE
|
|
18
|
+
assert _resolve("made up", 0.9, TEXT_CLASSIFIER_CRITERIA) == NOT_SURE
|
|
19
|
+
assert _resolve(None, None, TEXT_CLASSIFIER_CRITERIA) == NOT_SURE
|
|
20
|
+
|
|
21
|
+
print("ok")
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""Jev decision calls: text_classifier labels and Parseer labels."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
import requests
|
|
8
|
+
|
|
9
|
+
MODEL = "typesafe/jev-1.13"
|
|
10
|
+
DECISIONS_URL = "https://openrouter.ai/api/alpha/decisions"
|
|
11
|
+
TIMEOUT = 30
|
|
12
|
+
CONFIDENCE_THRESHOLD = 0.5
|
|
13
|
+
NOT_SURE = "not sure"
|
|
14
|
+
|
|
15
|
+
TEXT_CLASSIFIER_CRITERIA = {
|
|
16
|
+
"job listing": "A vacancy with role, requirements, and how to apply.",
|
|
17
|
+
"ecommerce": "A store homepage or shop section, not one product and not a search-results page.",
|
|
18
|
+
"product page": "One product for sale, with price and a buy action.",
|
|
19
|
+
"forum post": "A single user message on a forum.",
|
|
20
|
+
"porn": "Sexually explicit adult content or an age-gated adult video page.",
|
|
21
|
+
"forum discussion": "A thread made of an opening post and replies.",
|
|
22
|
+
"podcast or audio program": "An audio episode or podcast with listen duration and subscribe links.",
|
|
23
|
+
"horoscope": "Daily or weekly zodiac predictions and lucky numbers.",
|
|
24
|
+
"recipe": "Cooking instructions with ingredients and steps.",
|
|
25
|
+
"advertisement": "Sponsored or promotional marketing copy for a product or service.",
|
|
26
|
+
"real estate listing": "A property for sale or rent with price, beds, and tour details.",
|
|
27
|
+
"ecommerce listing": "A search or category page listing many products for sale.",
|
|
28
|
+
"pet adoption listing": "An adoptable pet profile with adoption fee and application.",
|
|
29
|
+
"crossword puzzle": "A crossword or word puzzle with clues and a grid.",
|
|
30
|
+
"gambling": "Sports betting odds, wagers, or a sportsbook page.",
|
|
31
|
+
"casino content": "Online casino games such as slots, roulette, or blackjack.",
|
|
32
|
+
"sports statistics": "League tables, match stats, or player scoring records.",
|
|
33
|
+
"glossary": "A dictionary or glossary entry defining a term.",
|
|
34
|
+
"weather": "A forecast with temperature, conditions, and multi-day outlook.",
|
|
35
|
+
"news article": "A reported story about an event, with who, what, and when.",
|
|
36
|
+
NOT_SURE: "Too little text, or none of the other categories fit.",
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
PARSEER_CRITERIA = {
|
|
40
|
+
"news article": "A reported story about an event, with who, what, and when.",
|
|
41
|
+
NOT_SURE: "Too little text, or none of the other categories fit.",
|
|
42
|
+
"other": "None of the other categories fit, and there is enough text to tell.",
|
|
43
|
+
"product page": "One product for sale, with price and a buy action.",
|
|
44
|
+
"advertisement": "Sponsored or promotional marketing copy for a product or service.",
|
|
45
|
+
"job listing": "A vacancy with role, requirements, and how to apply.",
|
|
46
|
+
"forum post": "A single user message on a forum.",
|
|
47
|
+
"wiki page": "An encyclopedia-style article with sections, see-also links, and references.",
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
PARSEER_INSTRUCTIONS = (
|
|
51
|
+
"Which category best describes this web page text? "
|
|
52
|
+
"For newsroom or press-release content, be slightly more forgiving: "
|
|
53
|
+
"if there is a reasonable chance it is editorial news, prefer 'news article' over 'advertisement'."
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
def classify_text_classifier(text: str) -> str:
|
|
57
|
+
"""text_classifier labels. Returns a category, or 'not sure' when the call fails."""
|
|
58
|
+
return _classify(text, "Which category best describes this web page text?", TEXT_CLASSIFIER_CRITERIA)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def classify_parseer(text: str) -> str:
|
|
62
|
+
"""Parseer page labels. Returns a category, or 'not sure' when the call fails."""
|
|
63
|
+
return _classify(text, PARSEER_INSTRUCTIONS, PARSEER_CRITERIA)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _classify(text: str, instructions: str, criteria: dict[str, str]) -> str:
|
|
67
|
+
cleaned = (text or "").strip()
|
|
68
|
+
if not cleaned:
|
|
69
|
+
return NOT_SURE
|
|
70
|
+
try:
|
|
71
|
+
body = _post({
|
|
72
|
+
"model": MODEL,
|
|
73
|
+
"state": {"text": cleaned},
|
|
74
|
+
"questions": {
|
|
75
|
+
"category": {"type": "choice", "instructions": instructions, "criteria": criteria},
|
|
76
|
+
},
|
|
77
|
+
})
|
|
78
|
+
answer = body["answers"]["category"]
|
|
79
|
+
return _resolve(answer.get("choice"), answer.get("confidence"), criteria)
|
|
80
|
+
except (requests.RequestException, KeyError, ValueError):
|
|
81
|
+
return NOT_SURE
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _resolve(choice: str | None, confidence: float | None, criteria: dict[str, str]) -> str:
|
|
85
|
+
if choice not in criteria or confidence is None or confidence < CONFIDENCE_THRESHOLD:
|
|
86
|
+
return NOT_SURE
|
|
87
|
+
return choice
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _post(payload: dict) -> dict:
|
|
91
|
+
key = os.environ.get("JEV_API_KEY")
|
|
92
|
+
if not key:
|
|
93
|
+
raise ValueError("JEV_API_KEY is not set")
|
|
94
|
+
response = requests.post(
|
|
95
|
+
DECISIONS_URL,
|
|
96
|
+
headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json"},
|
|
97
|
+
json=payload,
|
|
98
|
+
timeout=TIMEOUT,
|
|
99
|
+
)
|
|
100
|
+
response.raise_for_status()
|
|
101
|
+
return response.json()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
requests
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
nbd_jev
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "nbd-jev3"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Jev classifiers for text_classifier and Parseer pages"
|
|
9
|
+
requires-python = ">=3.12"
|
|
10
|
+
authors = [{ name = "Shaked Degani", email = "shaked@webz.io" }]
|
|
11
|
+
dependencies = ["requests"]
|
|
12
|
+
|
|
13
|
+
[tool.setuptools.packages.find]
|
|
14
|
+
include = ["nbd_jev*"]
|
nbd_jev3-0.1.0/setup.cfg
ADDED