Skip to content

Commit 9940abf

Browse files
authored
Merge pull request #858 from realpython/add-hello-jev-materials
Add hello-jev materials for the Jev video
2 parents 1f752c6 + 9c614d8 commit 9940abf

5 files changed

Lines changed: 345 additions & 0 deletions

File tree

‎hello-jev/README.md‎

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Hello Jev: Getting Started With Jev in Python
2+
3+
This folder provides the code examples for *Get Started With Jev in Python*,
4+
a video on the [Real Python YouTube channel](https://www.youtube.com/@realpython).
5+
6+
Both scripts run the same train-station info desk. The desk asks a visitor
7+
whether they lost something and then points them at the lost-and-found counter
8+
or asks what else it can help with. The difference is how the answer is read:
9+
10+
- **`plain_python.py`** handles the input by hand. It only accepts an uppercase
11+
`Y` or `N`, so anything else sends the visitor back around the loop.
12+
- **`jev_noul.py`** replaces that branching with a single `Noul` question. Jev
13+
scores how affirmative the answer is on a scale from `0` to `1`, so the script
14+
compares thresholds instead of strings and understands replies like
15+
`yeah, I've lost something`.
16+
17+
## Setup
18+
19+
Install [uv](https://docs.astral.sh/uv/), then create the virtual environment.
20+
Because `pyproject.toml` pins `requires-python = ">=3.14"`, uv downloads
21+
CPython 3.14 for you if you don't have it yet:
22+
23+
```sh
24+
$ uv sync
25+
```
26+
27+
`jev_noul.py` reaches Jev through [OpenRouter](https://openrouter.ai/), which
28+
lets you try the model without opening an account with TypeSafe AI. Grab an
29+
OpenRouter API key, then create a `.env` file next to the scripts and add it:
30+
31+
```dotenv
32+
OPENROUTER_API_KEY=<YOUR-OPENROUTER-KEY>
33+
```
34+
35+
Keep `.env` out of version control. An API key belongs in your environment, not
36+
in your repository.
37+
38+
## Running the Examples
39+
40+
Start with the plain script to see where hand-written input handling gives up:
41+
42+
```sh
43+
$ uv run plain_python.py
44+
Did you lose something? (Y/N)
45+
```
46+
47+
Only an uppercase `Y` or `N` gets you past the prompt. Try `yes` or `y` and the
48+
script asks again.
49+
50+
Now run the Jev version. The `--env-file` flag tells uv to load your API key
51+
from `.env` before it starts the script:
52+
53+
```sh
54+
$ uv run --env-file .env jev_noul.py
55+
Did you lose something?
56+
```
57+
58+
Answer in your own words. `jev_noul.py` treats a Noul above `0.8` as a yes and
59+
below `0.2` as a no, and asks again for anything in between.
60+
61+
## Where to Go Next
62+
63+
`Noul` is one of three Jev primitives. `Score` rates something on a scale, and
64+
`Choice` picks from a list of options. The
65+
[TypeSafe SDK on PyPI](https://pypi.org/project/typesafe-sdk/) documents all
66+
three, and the TypeSafe AI blog explains the idea behind them in
67+
[Introducing System One Models and Jev](https://typesafe.ai/blog/introducing-system-one-models-and-jev).

‎hello-jev/jev_noul.py‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import os
2+
3+
from typesafe_sdk import Noul, TypeSafeClient
4+
5+
client = TypeSafeClient(
6+
api_key=os.environ["OPENROUTER_API_KEY"],
7+
base_url="https://openrouter.ai/api",
8+
)
9+
10+
11+
def respond(lost_something):
12+
if lost_something:
13+
print("You can find the lost and found counter on the right.")
14+
else:
15+
print("What can I help you with?")
16+
17+
18+
def ask():
19+
while True:
20+
answer = input("Did you lose something? ")
21+
r = client.system_one(
22+
state=f"{answer}",
23+
questions={
24+
"lost_something": Noul(
25+
instructions="Is the answer from the user affirmative?"
26+
),
27+
},
28+
)
29+
lost_something = r.answers["lost_something"].noul
30+
if lost_something > 0.8:
31+
return True
32+
if lost_something < 0.2:
33+
return False
34+
print("Sorry, I didn't get that.")
35+
36+
37+
def main():
38+
lost_something = ask()
39+
respond(lost_something)
40+
41+
42+
if __name__ == "__main__":
43+
main()

‎hello-jev/plain_python.py‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
def respond(lost_something):
2+
if lost_something:
3+
print("You can find the lost and found counter on the right.")
4+
else:
5+
print("What can I help you with?")
6+
7+
8+
def ask():
9+
while True:
10+
answer = input("Did you lose something? (Y/N) ")
11+
if answer == "Y":
12+
return True
13+
if answer == "N":
14+
return False
15+
print("Please answer with Y or N.")
16+
17+
18+
def main():
19+
lost_something = ask()
20+
respond(lost_something)
21+
22+
23+
if __name__ == "__main__":
24+
main()

‎hello-jev/pyproject.toml‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[project]
2+
name = "hello-jev"
3+
version = "0.1.0"
4+
description = "Hello Jev: a train station info desk that routes visitors with a Choice, a Score, and a Noul."
5+
requires-python = ">=3.14"
6+
dependencies = [
7+
"typesafe-sdk>=0.7.0",
8+
]

0 commit comments

Comments
 (0)