The Bash example opens this page.
recognize: find every name in the evidence and say what kind it is.
{
"version": 1,
"recognize": {
"kinds": {
"person": null,
"organization": null,
"place": null
},
"relations": [
{
"name": "works_for",
"source": "person",
"target": "organization"
},
{
"name": "based_in",
"source": "organization",
"target": "place"
}
]
}
}person="PER=Part of a person's name."
org="ORG=Part of the name of an organization:"
org+=" a company, band, team, agency, government"
org+=" body, or media outlet."
place="LOC=Part of the name of a place: a country,"
place+=" region, city, or geographic feature."
other="MISC=Part of another named entity: a"
other+=" nationality, an event, a product, or the"
other+=" name of a creative work."
text="Maria Chen joined Northwind Freight in Chicago"
text+=" last spring."
printf '%s' "$text" |
thinkthen recognize \
--kind "$person" \
--kind "$org" \
--kind "$place" \
--kind "$other" |
jq -c '.entities[] | [.text, .kind, .strength]'["Maria Chen","PER",0.9987] ["Northwind Freight","ORG",0.997] ["Chicago","LOC",1.0]
You give it the evidence and the kinds of name you allow. You get back each name, its kind, where it sits, and a strength.
Read the answer
With kinds, the model picks each name's kind from them. A name that is not in the evidence cannot come back. The number on a name is its strength. ThinkThen computes it, and it is not a probability. Your threshold decides which names you keep.
| Exit code | What it means |
|---|---|
| 0 | the run finished |
| 2 | usage or input error |
| 4 | the backend failed or refused, as it does for evidence over the size limit |
| 5 | a local failure |
| 70 | a defect in the tool |
Call it from your language
import thinkthen as tt
text = (
"Maria Chen joined Northwind Freight "
"in Chicago last spring."
)
kinds = {
"PER": "Part of a person's name.",
"ORG": (
"Part of the name of an organization: a company, "
"band, team, agency, government body, "
"or media outlet."
),
"LOC": "Part of the name of a place: a country, "
"region, city, or geographic feature.",
"MISC": (
"Part of another named entity: a nationality, "
"an event, a product, or the name of a "
"creative work."
),
}
facts = tt.recognize(
text,
kinds=kinds,
).value
names = [(one.text, one.kind) for one in facts.entities]
assert names == [
("Maria Chen", "PER"),
("Northwind Freight", "ORG"),
("Chicago", "LOC"),
]No Polars sample for recognize.
No pandas sample for recognize.
import assert from "node:assert/strict";
import * as tt from "thinkthen";
const text =
"Maria Chen joined Northwind Freight, " +
"a company in Chicago.";
const kinds = ["person", "organization", "place"];
const relations = {
works_for: ["person", "organization"] as const,
based_in: ["organization", "place"] as const,
};
const facts = (await tt.recognize(text, {
kinds,
relations,
})).value;
const names = facts.entities.map((one) => [
one.text,
one.kind,
]);
assert.deepEqual(names, [
["Maria Chen", "person"],
["Northwind Freight", "organization"],
["Chicago", "place"],
]);
const links = (facts.relations ?? []).map((one) => [
one.relation,
one.source.text,
one.target.text,
]);
assert.deepEqual(links, [
["works_for", "Maria Chen", "Northwind Freight"],
["based_in", "Northwind Freight", "Chicago"],
]);require "thinkthen"
text = "Maria Chen joined Northwind Freight, " \
"a company in Chicago."
kinds = ["person", "organization", "place"]
relations = {
works_for: ["person", "organization"],
based_in: ["organization", "place"]
}
facts = ThinkThen.recognize(text, kinds:, relations:).value
names = facts.entities.map { |one| [one.text, one.kind] }
raise unless names == [
["Maria Chen", "person"],
["Northwind Freight", "organization"],
["Chicago", "place"]
]
links = facts.relations.map do |one|
[one.relation, one.source.text, one.target.text]
end
raise unless links == [
["works_for", "Maria Chen", "Northwind Freight"],
["based_in", "Northwind Freight", "Chicago"]
]library(thinkthen)
text <- paste0(
"Maria Chen joined Northwind Freight, ",
"a company in Chicago."
)
kinds <- c("person", "organization", "place")
rules <- c(
"works_for=person:organization",
"based_in=organization:place"
)
facts <- tt_recognize(
text, kinds, relations = rules
)$value[[1]]
stopifnot(identical(
facts$text,
c("Maria Chen", "Northwind Freight", "Chicago")
))
stopifnot(identical(facts$kind, kinds))
links <- attr(facts, "relations")
stopifnot(identical(
links$relation,
c("works_for", "based_in")
))
stopifnot(identical(
links$source,
c("Maria Chen", "Northwind Freight")
))
stopifnot(identical(
links$target,
c("Northwind Freight", "Chicago")
))use thinkthen::{Engine, Kind, Recognize, RelationRule};
let tt = Engine::from_env()?;
let text = concat!(
"Maria Chen joined Northwind Freight, ",
"a company in Chicago.",
);
let works_for = RelationRule::one_way(
"works_for",
"person",
"organization",
)?;
let based_in = RelationRule::one_way(
"based_in",
"organization",
"place",
)?;
let ask = Recognize::builder()
.kind(Kind::new("person", None)?)?
.kind(Kind::new("organization", None)?)?
.kind(Kind::new("place", None)?)?
.relation(works_for)?
.relation(based_in)?
.build()?;
let facts = tt.recognize(&ask, text)?.into_value();
let names: Vec<_> = facts
.entities()
.iter()
.map(|one| (one.text(), one.kind()))
.collect();
let expected = [
("Maria Chen", "person"),
("Northwind Freight", "organization"),
("Chicago", "place"),
];
assert_eq!(names, expected);
let links: Vec<_> = facts
.relations()
.unwrap_or_default()
.iter()
.map(|one| {
let source = one.source().text();
let target = one.target().text();
(one.relation(), source, target)
})
.collect();
let expected = [
("works_for", "Maria Chen", "Northwind Freight"),
("based_in", "Northwind Freight", "Chicago"),
];
assert_eq!(links, expected);Put this code inside fn main() -> Result<(), Box<dyn std::error::Error>> and end it with Ok(()). main returns a Result, so ? compiles.
#include <assert.h>
#include <string.h>
#include <thinkthen.h>
thinkthen_engine *tt = thinkthen_engine_new();
assert(tt);
const char *text =
"Maria Chen joined Northwind Freight, "
"a company in Chicago.";
const char *spec =
"{\"version\": 1, \"recognize\": {"
"\"kinds\": {\"person\": null, "
"\"organization\": null, \"place\": null}, "
"\"relations\": ["
"{\"name\": \"works_for\", \"source\": \"person\", "
"\"target\": \"organization\"}, "
"{\"name\": \"based_in\", "
"\"source\": \"organization\", "
"\"target\": \"place\"}]}}";
char *facts;
size_t facts_len;
int rc = thinkthen_recognize(
tt,
spec,
text,
strlen(text),
&facts,
&facts_len
);
assert(rc == THINKTHEN_OK);
assert(strstr(facts, "\"Maria Chen\""));
assert(strstr(facts, "\"Northwind Freight\""));
assert(strstr(facts, "\"Chicago\""));
assert(strstr(facts, "\"works_for\""));
assert(strstr(facts, "\"based_in\""));
thinkthen_free_string(facts);
thinkthen_engine_free(tt);Keep the #include lines on top. Put the rest inside int main(void) and end it with return 0;.
No C++ sample for recognize.
No Objective-C sample for recognize.
No COBOL sample for recognize.
No Ada sample for recognize.
No Java sample for recognize.
No Kotlin sample for recognize.
No Scala sample for recognize.
No C# sample for recognize.
No Go sample for recognize.
No Swift sample for recognize.
No Zig sample for recognize.
No PHP sample for recognize.
No Dart sample for recognize.
LOAD './thinkthen.duckdb_extension';
CREATE TABLE tickets AS FROM (VALUES
(1, 'Maria Chen joined Northwind Freight, ' ||
'a company in Chicago.')
) t(id, body);
SELECT id, entity.text, entity.kind
FROM (
SELECT
id,
unnest(thinkthen_recognize(
body,
['person', 'organization', 'place']
)) AS entity
FROM tickets
);
SELECT id, link.relation, link.source, link.target
FROM (
SELECT id, unnest(thinkthen_relations(
body, '@names.json'
)) AS link
FROM tickets
);id|text|kind 1|Maria Chen|person 1|Northwind Freight|organization 1|Chicago|place id|relation|source|target 1|works_for|Maria Chen|Northwind Freight 1|based_in|Northwind Freight|Chicago
.load ./thinkthen
CREATE TABLE tickets(id INTEGER, body TEXT);
INSERT INTO tickets VALUES (
1,
'Maria Chen joined Northwind Freight, ' ||
'a company in Chicago.'
);
SELECT t.id, entity.text, entity.kind
FROM
tickets t,
thinkthen_recognize(
t.body,
'person,organization,place'
) entity;
WITH found AS (
SELECT
id,
thinkthen_relations(body, '@names.json')
AS links_found
FROM tickets)
SELECT found.id, link.value ->> 'relation' AS relation,
link.value ->> '$.source.text' AS source,
link.value ->> '$.target.text' AS target
FROM
found,
json_each(found.links_found, '$.relations') AS link;1|Maria Chen|person 1|Northwind Freight|organization 1|Chicago|place 1|works_for|Maria Chen|Northwind Freight 1|based_in|Northwind Freight|Chicago
CREATE TABLE tickets (id int, body text);
INSERT INTO tickets VALUES (
1,
'Maria Chen joined Northwind Freight, ' ||
'a company in Chicago.'
);
SELECT t.id, entity.text, entity.kind
FROM tickets t, LATERAL thinkthen_recognize(
t.body,
ARRAY['person', 'organization', 'place']
) entity;
SELECT t.id, link.relation, link.source_text,
link.target_text
FROM tickets t, LATERAL thinkthen_relations(
t.body,
'@names.json'
) link;id | text | kind ----+-------------------+-------------- 1 | Maria Chen | person 1 | Northwind Freight | organization 1 | Chicago | place (3 rows) id | relation | source_text | target_text ----+-----------+-------------------+------------------- 1 | works_for | Maria Chen | Northwind Freight 1 | based_in | Northwind Freight | Chicago (2 rows)
Arguments, options, and more examples
Watch recognize answer questions about Beatles songs: recognize labels things it finds.
On GitHub: github.com/botassembly/thinkthen