Skip to content

Commit

Permalink
Extend hype to support graphical user interface (#10)
Browse files Browse the repository at this point in the history
* uv add --dev gradio

* Add gui module

* Add gui example

* Access field constraints through metadata

* Fix issues with undefined defaults

* Use text analysis example for GUI

* Update example

* Add kwargs to create_gradio_component

* Fix handling of list of Path values

* Fix remaining issues around default handling

* Configure asyncio_default_fixture_loop_scope

* Add test coverage for Gradio functionality

* Update README
  • Loading branch information
mattt authored Nov 8, 2024
1 parent dbda679 commit 55d74f0
Show file tree
Hide file tree
Showing 8 changed files with 1,512 additions and 1 deletion.
51 changes: 51 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,57 @@ Content-Type: application/json
33
```

Or if ClickOps are more your thing,
hype can automatically generate a Gradio app 🖱️

```python
from pydantic import BaseModel, Field, field_validator
from textstat import flesch_reading_ease, lexicon_count

import hype


class TextAnalysis(BaseModel):
word_count: int = Field(description="Total number of words in text")
reading_ease: float = Field(
description="Flesch reading ease score (0-100, higher is easier)"
)

@field_validator('reading_ease')
def clamp_reading_ease(cls, v: float) -> float:
return max(0, min(100, v))


@hype.up
def analyze(
text: str = Field(
description="Text to analyze",
max_length=10000,
),
) -> TextAnalysis:
"""Performs sentiment and readability analysis on text."""

word_count = lexicon_count(text)
reading_ease = flesch_reading_ease(text) if word_count > 0 else 0

return TextAnalysis(
word_count=word_count,
reading_ease=reading_ease,
)


if __name__ == "__main__":
hype.create_gradio_interface(analyze).launch()

```

```console
$ uv run examples/text_analysis.py
$ open http://127.0.0.1:7860
```

<img width="1243" alt="Screenshot of example Gradio app created by Hype" src="https://github.com/user-attachments/assets/d97e92ff-7469-4c80-a9e0-22b7657129e2"/>

Hyped up functions have tool definitions that you can pass to LLMs like
[Claude](https://docs.anthropic.com/en/docs/build-with-claude/tool-use) and
[ChatGPT](https://platform.openai.com/docs/guides/function-calling).
Expand Down
55 changes: 55 additions & 0 deletions examples/text_analysis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""
This example shows how to construct a simple text analysis tool using Hype.
Download `uv` to run this example: https://github.com/astral-sh/uv
```
uv run examples/text_analysis.py
```
"""

# /// script
# dependencies = [
# "hype @ git+https://github.com/mattt/hype.git",
# "textstat",
# ]
# ///

from pydantic import BaseModel, Field, field_validator
from textstat import flesch_reading_ease, lexicon_count

import hype


class TextAnalysis(BaseModel):
word_count: int = Field(description="Total number of words in text")
reading_ease: float = Field(
description="Flesch reading ease score (0-100, higher is easier)"
)

@field_validator('reading_ease')
def clamp_reading_ease(cls, v: float) -> float:
"""Clamp reading ease score between 0 and 100"""
return max(0, min(100, v))


@hype.up
def analyze(
text: str = Field(
description="Text to analyze",
max_length=10000,
),
) -> TextAnalysis:
"""Performs sentiment and readability analysis on text."""

word_count = lexicon_count(text)
reading_ease = flesch_reading_ease(text) if word_count > 0 else 0

return TextAnalysis(
word_count=word_count,
reading_ease=reading_ease,
)


if __name__ == "__main__":
hype.create_gradio_interface(analyze).launch()
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ build-backend = "hatchling.build"

[tool.uv]
dev-dependencies = [
"gradio>=5.5.0",
"pytest-mock>=3.14.0",
"pytest>=8.3.3",
"ruff>=0.7.0",
Expand Down Expand Up @@ -68,3 +69,6 @@ lint.ignore = [

[tool.ruff.lint.per-file-ignores]
"tests/*" = ["ANN"]

[tool.pytest.ini_options]
asyncio_default_fixture_loop_scope = "session"
2 changes: 2 additions & 0 deletions src/hype/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from hype.function import Function
from hype.function import wrap as up
from hype.gui import create_gradio_interface
from hype.http import create_fastapi_app
from hype.tools.anthropic import create_anthropic_tools
from hype.tools.ollama import create_ollama_tools
Expand All @@ -12,4 +13,5 @@
"create_anthropic_tools",
"create_openai_tools",
"create_ollama_tools",
"create_gradio_interface",
]
3 changes: 3 additions & 0 deletions src/hype/gui/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from hype.gui.gradio import create_gradio_component, create_gradio_interface

__all__ = ["create_gradio_component", "create_gradio_interface"]
Loading

0 comments on commit 55d74f0

Please sign in to comment.