Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions hello-jev/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Hello Jev: Getting Started With Jev in Python

This folder provides the code examples for *Get Started With Jev in Python*,
a video on the [Real Python YouTube channel](https://www.youtube.com/@realpython).

Both scripts run the same train-station info desk. The desk asks a visitor
whether they lost something and then points them at the lost-and-found counter
or asks what else it can help with. The difference is how the answer is read:

- **`plain_python.py`** handles the input by hand. It only accepts an uppercase
`Y` or `N`, so anything else sends the visitor back around the loop.
- **`jev_noul.py`** replaces that branching with a single `Noul` question. Jev
scores how affirmative the answer is on a scale from `0` to `1`, so the script
compares thresholds instead of strings and understands replies like
`yeah, I've lost something`.

## Setup

Install [uv](https://docs.astral.sh/uv/), then create the virtual environment.
Because `pyproject.toml` pins `requires-python = ">=3.14"`, uv downloads
CPython 3.14 for you if you don't have it yet:

```sh
$ uv sync
```

`jev_noul.py` reaches Jev through [OpenRouter](https://openrouter.ai/), which
lets you try the model without opening an account with TypeSafe AI. Grab an
OpenRouter API key, then create a `.env` file next to the scripts and add it:

```dotenv
OPENROUTER_API_KEY=<YOUR-OPENROUTER-KEY>
```

Keep `.env` out of version control. An API key belongs in your environment, not
in your repository.

## Running the Examples

Start with the plain script to see where hand-written input handling gives up:

```sh
$ uv run plain_python.py
Did you lose something? (Y/N)
```

Only an uppercase `Y` or `N` gets you past the prompt. Try `yes` or `y` and the
script asks again.

Now run the Jev version. The `--env-file` flag tells uv to load your API key
from `.env` before it starts the script:

```sh
$ uv run --env-file .env jev_noul.py
Did you lose something?
```

Answer in your own words. `jev_noul.py` treats a Noul above `0.8` as a yes and
below `0.2` as a no, and asks again for anything in between.

## Where to Go Next

`Noul` is one of three Jev primitives. `Score` rates something on a scale, and
`Choice` picks from a list of options. The
[TypeSafe SDK on PyPI](https://pypi.org/project/typesafe-sdk/) documents all
three, and the TypeSafe AI blog explains the idea behind them in
[Introducing System One Models and Jev](https://typesafe.ai/blog/introducing-system-one-models-and-jev).
43 changes: 43 additions & 0 deletions hello-jev/jev_noul.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import os

from typesafe_sdk import Noul, TypeSafeClient

client = TypeSafeClient(
api_key=os.environ["OPENROUTER_API_KEY"],
base_url="https://openrouter.ai/api",
)


def respond(lost_something):
if lost_something:
print("You can find the lost and found counter on the right.")
else:
print("What can I help you with?")


def ask():
while True:
answer = input("Did you lose something? ")
r = client.system_one(
state=f"{answer}",
questions={
"lost_something": Noul(
instructions="Is the answer from the user affirmative?"
),
},
)
lost_something = r.answers["lost_something"].noul
if lost_something > 0.8:
return True
if lost_something < 0.2:
return False
print("Sorry, I didn't get that.")


def main():
lost_something = ask()
respond(lost_something)


if __name__ == "__main__":
main()
24 changes: 24 additions & 0 deletions hello-jev/plain_python.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
def respond(lost_something):
if lost_something:
print("You can find the lost and found counter on the right.")
else:
print("What can I help you with?")


def ask():
while True:
answer = input("Did you lose something? (Y/N) ")
if answer == "Y":
return True
if answer == "N":
return False
print("Please answer with Y or N.")


def main():
lost_something = ask()
respond(lost_something)


if __name__ == "__main__":
main()
8 changes: 8 additions & 0 deletions hello-jev/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[project]
name = "hello-jev"
version = "0.1.0"
description = "Hello Jev: a train station info desk that routes visitors with a Choice, a Score, and a Noul."
requires-python = ">=3.14"
dependencies = [
"typesafe-sdk>=0.7.0",
]
Loading
Loading