Skip to content

Commit

Permalink
Merge pull request #9 from Haidra-Org/mid-alpha-renames-and-docs
Browse files Browse the repository at this point in the history
docs: better `getting started`, refactor: class renames for clarity
  • Loading branch information
tazlin authored Jul 13, 2023
2 parents 12dd7b6 + 81cd5f5 commit f7d289c
Show file tree
Hide file tree
Showing 30 changed files with 627 additions and 121 deletions.
11 changes: 11 additions & 0 deletions .env.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Template
# Copy this file to .env and fill in the values
AI_HORDE_URL="https://aihorde.net/api/"
AI_HORDE_DEV_URL="http://localhost:7001/api/"

AI_HORDE_DEV_APIKEY="devkey"

RATINGS_URL="https://ratings.aihorde.net/api/"
RATINGS_DEV_URL="http://localhost:7002/api/"

RATINGS_DEV_APIKEY=${AI_HORDE_DEV_APIKEY}
6 changes: 5 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Contributing to horde_sdk

Here are a list of code quality tools this project uses:
## Code Quality Tools

* [tox](https://tox.wiki/)
- Creates virtual environments for CI or local pytest runs.
Expand All @@ -19,3 +19,7 @@ Here are a list of code quality tools this project uses:
- Static type safety
- I recommending using the [mypy daemon](https://mypy.readthedocs.io/en/stable/mypy_daemon.html).
- If you are using VSCode, I recommend the `matangover.mypy` extension, which implements this nicely.

## Things to know

* The `AI_HORDE_DEV_URL` environment variable overrides `AI_HORDE_URL`. This is useful for testing changes.
3 changes: 2 additions & 1 deletion docs/.pages
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ nav:
- index.md
- getting_started.md
- faq.md
- examples.md
- horde_sdk
- GitHub Repo: https://https://github.com/Haidra-Org/horde-sdk

order: asc
order: desc
5 changes: 4 additions & 1 deletion docs/build_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ def main() -> None:
relative_folder.mkdir(parents=True, exist_ok=True)

with open(relative_folder / ".pages", "w") as f:
f.write(f"title: {relative_folder.name}\n")
if relative_folder.name == "horde_sdk":
f.write("title: Horde SDK Code Reference")
else:
f.write(f"title: {relative_folder.name}")

# Get all the files in the folder
files_in_folder = list(folder.glob("*.py"))
Expand Down
83 changes: 83 additions & 0 deletions docs/examples.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Example Clients

See `examples/` for a complete list. These examples are all made in mind with your current working directory as `horde_sdk` (e.g., `cd horde_sdk`).

## Simple Client (sync) Example
From `examples/ai_horde_client/aihorde_simple_client_example.py`:

``` python
from horde_sdk.ai_horde_api.ai_horde_clients import AIHordeAPISimpleClient
from horde_sdk.ai_horde_api.apimodels import ImageGenerateAsyncRequest, ImageGeneration


def simple_generate_example() -> None:
simple_client = AIHordeAPISimpleClient()

generations: list[ImageGeneration] = simple_client.image_generate_request(
ImageGenerateAsyncRequest(
apikey="0000000000",
prompt="A cat in a hat",
models=["Deliberate"],
),
)

image = simple_client.generation_to_image(generations[0])

image.save("cat_in_hat.png")

if __name__ == "__main__":
simple_generate_example()
```

## Simple Client (using asyncio) Example
From `examples/ai_horde_client/async_aihorde_simple_client_example.py`:

``` python

import asyncio

from horde_sdk.ai_horde_api.ai_horde_clients import AIHordeAPISimpleClient
from horde_sdk.ai_horde_api.apimodels import ImageGenerateAsyncRequest, ImageGeneration


async def async_simple_generate_example() -> None:
simple_client = AIHordeAPISimpleClient()

generations: list[ImageGeneration] = await simple_client.async_image_generate_request(
ImageGenerateAsyncRequest(
apikey="0000000000",
prompt="A cat in a hat",
models=["Deliberate"],
),
)

image = simple_client.generation_to_image(generations[0])
image.save("cat_in_hat.png")

# Do 2 requests at once.
multi_generations: tuple[list[ImageGeneration], list[ImageGeneration]] = await asyncio.gather(
simple_client.async_image_generate_request(
ImageGenerateAsyncRequest(
apikey="0000000000",
prompt="A cat in a hat",
models=["Deliberate"],
),
),
simple_client.async_image_generate_request(
ImageGenerateAsyncRequest(
apikey="0000000000",
prompt="A cat in a hat",
models=["Deliberate"],
),
),
)

multi_image_1 = simple_client.generation_to_image(multi_generations[0][0])
multi_image_1.save("cat_in_hat_multi_1.png")

multi_image_2 = simple_client.generation_to_image(multi_generations[1][0])

multi_image_2.save("cat_in_hat_multi_2.png")
if __name__ == "__main__":
asyncio.run(async_simple_generate_example())
```
15 changes: 6 additions & 9 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,21 @@ title: Frequently Asked Questions

> The objects returned by horde_sdk are immutable. If you need to change
> something, you'll need to create a new object with the changes you
> want. See [pydantic's
> docs](https://docs.pydantic.dev/2.0/usage/validation_errors/#frozen_instance)
> for more information.
> want. See the [section in getting started](../getting_started/#faux-immutability-or-why-cant-i-change-this-attribute) for more info.
# I don't like types. Why is this library so focused on them?

> Types are a great way to ensure that your code is correct. They also
> make it easier for other developers to understand what your code is
> doing with [type
> hints](https://docs.python.org/3/library/typing.html). These *hint*
> what data format class attributes or functions are expecting or will
> what data format variables or functions are expecting or will
> return. This is how IDEs such as PyCharm or VSCode can provide
> autocomplete and other helpful features.
>
> If you don't like working with the objects within your own code, you
> can always translate between the types and dicts using pydantic's
> `.model_dump()` `.model_validate()`. There is also a convenience
> function
> `horde_sdk.generic_api.apimodels.HordeAPIModel.to_json_horde_sdk_safe`
> If you don't like working with the objects from this library within
> your own code, you can always translate between the types and dicts using
> pydantic's `.model_dump()` `.model_validate()`. There is also a convenience
> function [to_json_horde_sdk_safe()](../horde_sdk/generic_api/apimodels/#horde_sdk.generic_api.apimodels.HordeAPIModel.to_json_horde_sdk_safe)
> which may be useful. All API models in this library have this method,
> but certain other classes may not.
116 changes: 92 additions & 24 deletions docs/getting_started.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,100 @@
# Getting Started

See `installation` for installation instructions.
To get started, you need to install the package into your project:

``` console
pip install horde_sdk
```

<div class="note" markdown="1">
<div class="title" markdown="1">
Note
</div>
This library requires python >3.10
</div>

## First steps

1. Choose a client for the API you wish to consume:
- For AI Horde, this is either:
- [AIHordeAPISimpleClient](../horde_sdk/ai_horde_api/ai_horde_clients/#horde_sdk.ai_horde_api.ai_horde_clients.AIHordeAPISimpleClient) (easier, more safeties)

- [AIHordeAPIManualClient](../horde_sdk/ai_horde_api/ai_horde_clients/#horde_sdk.ai_horde_api.ai_horde_clients.AIHordeAPIManualClient) (more control, manual cleanup required)

2. Find the `*Request` object type appropriate to what you want to do. (see also: [naming](../getting_started/#naming))
- These objects types are always found in the `apimodels` namespace of the `*_api` sub package.
- e.g., [ImageGenerateAsyncRequest](../horde_sdk/ai_horde_api/apimodels/generate/_async/#horde_sdk.ai_horde_api.apimodels.generate._async.ImageGenerateAsyncRequest)
- **Note** that there is always one or more response types mapped to a request. You can get the default success response `type` like so:


```python
>>> ImageGenerateAsyncRequest.get_success_response_type()
<class 'horde_sdk.ai_horde_api.apimodels.generate._async.ImageGenerateAsyncResponse'>

# Alternatively:
>>> image_gen_request = ImageGenerateAsyncRequest( ... ) # Removed for brevity
>>> image_gen_request.get_success_response_type()
<class 'horde_sdk.ai_horde_api.apimodels.generate._async.ImageGenerateAsyncResponse'>
```
Accordingly, the [ImageGenerateAsyncResponse](../horde_sdk/ai_horde_api/apimodels/generate/_async/#horde_sdk.ai_horde_api.apimodels.generate._async.ImageGenerateAsyncResponse) type is expected to be the return type from the API.

<div class="warning" markdown="1">
<div class="title" markdown="1">
Warning
</div>
<a href="../horde_sdk/generic_api/apimodels/#horde_sdk.generic_api.apimodels.RequestErrorResponse"> RequestErrorResponse </a> may be also returned depending on the client you are using. Check the <a href="../horde_sdk/generic_api/apimodels/#horde_sdk.generic_api.apimodels.RequestErrorResponse.message"> RequestErrorResponse.message </a> attribute for info on the error encountered.
</div>

3. Construct the request as appropriate:
``` python
image_generate_async_request = ImageGenerateAsyncRequest(
apikey="0000000000",
prompt="A cat in a hat",
models=["Deliberate"],
params=ImageGenerationInputPayload(
width=512,
height=768,
sampler_name=KNOWN_SAMPLERS.k_euler_a,
clip_skip=1,
n=2,
),
)
```

4. Submit the request:

Simple Client:
``` python
simple_client = AIHordeAPISimpleClient()
generations: list[ImageGeneration] = simple_client.image_generate_request(
image_generate_async_request,
)
```

Manual Client:
``` python
manual_client = AIHordeAPIManualClient()

response = manual_client.submit_request(
image_generate_async_request,
image_generate_async_request.get_success_response_type(),
)
```
<div class="warning" markdown="1">
<div class="title" markdown="1">
Warning
</div>
Manual clients may leave server resources tied up if you do not implement handling. See the <a href="#important-note-about-manual-clients"> important note about manual clients </a> for more info.
</div>



## General Notes and Guidance

### API Expectations
#### Important note about manual clients
A few endpoints, such as `/v2/generate/async` ([ImageGenerateAsyncRequest](../horde_sdk/ai_horde_api/apimodels/generate/_async/#horde_sdk.ai_horde_api.apimodels.generate._async.ImageGenerateAsyncRequest)), will have their operations live on the API server until they are retrieved or cancelled (in this case, with either a [ImageGenerateStatusRequest](../horde_sdk/ai_horde_api/apimodels/generate/_status/#horde_sdk.ai_horde_api.apimodels.generate._status.ImageGenerateStatusRequest) or [DeleteImageGenerateRequest](../horde_sdk/ai_horde_api/apimodels/generate/_status/#horde_sdk.ai_horde_api.apimodels.generate._status.DeleteImageGenerateRequest)). If you use a manual client, you are assuming responsibility for making a best-effort for cleaning up errant requests, especially if your implementation crashes. If you use a simple client, you do not have to worry about this, as [context handlers](../horde_sdk/generic_api/generic_clients/#horde_sdk.generic_api.generic_clients.GenericHordeAPISession) take care of this.

### Typing

- Under the hood, **this project is strongly typed**. Practically,
Expand Down Expand Up @@ -31,15 +122,6 @@ See `installation` for installation instructions.
or
[model_validate_json](https://docs.pydantic.dev/2.0/api/main/#pydantic.main.BaseModel.model_validate_json)

### Inheritance

- At first glance, the hierarchy of classes may seem a bit confusing.
Rest assured, however, that these very docs are very helpful here.
All relevant inherited attributes and functions are included in the
child class documentation. Accordingly if you are looking at the
code, and don't want to go up the hierarchy and figure out the
inheritance, use these docs to see the resolved attributes and
functions.

### Naming

Expand Down Expand Up @@ -67,17 +149,3 @@ See `installation` for installation instructions.
docs](https://docs.pydantic.dev/2.0/usage/validation_errors/#frozen_instance)
for more information. See a
- See also `faq` for more information.

# Examples

<div class="note" markdown="1">

<div class="title" markdown="1">

Note

</div>

TODO: Add examples

</div>
2 changes: 1 addition & 1 deletion docs/horde_sdk/.pages
Original file line number Diff line number Diff line change
@@ -1 +1 @@
title: horde_sdk
title: Horde SDK Code Reference
2 changes: 0 additions & 2 deletions docs/horde_sdk/ai_horde_api/ai_horde_client.md

This file was deleted.

2 changes: 2 additions & 0 deletions docs/horde_sdk/ai_horde_api/ai_horde_clients.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# ai_horde_clients
::: horde_sdk.ai_horde_api.ai_horde_clients
2 changes: 0 additions & 2 deletions docs/horde_sdk/generic_api/generic_client.md

This file was deleted.

2 changes: 2 additions & 0 deletions docs/horde_sdk/generic_api/generic_clients.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# generic_clients
::: horde_sdk.generic_api.generic_clients
9 changes: 0 additions & 9 deletions docs/installation.md

This file was deleted.

10 changes: 9 additions & 1 deletion docs/stylesheets/extra.css
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,15 @@ code {


.md-nav__item--nested label {
font-style: italic;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-size: 14px;
line-height: 1.5;
color: #333;
background-color: #f8f8f8;
border: 1px solid #ccc;
border-radius: 4px;
padding: 5px;
overflow-x: auto;
}


Expand Down
34 changes: 0 additions & 34 deletions examples/ai_horde_api_client.example.py

This file was deleted.

Loading

0 comments on commit f7d289c

Please sign in to comment.