From b9db93af48606cb4c341dffec62f5cecfe2525fa Mon Sep 17 00:00:00 2001 From: Aleksandr Movchan Date: Tue, 23 Jul 2024 11:37:07 +0000 Subject: [PATCH] Update documentation and it's style --- aana/__init__.py | 3 + aana/core/models/audio.py | 38 +-- aana/core/models/image.py | 42 ++-- aana/core/models/media.py | 30 +-- aana/core/models/video.py | 12 +- docs/images/favicon.ico | Bin 0 -> 15086 bytes docs/images/white_logo.png | Bin 0 -> 2401 bytes docs/index.md | 319 ++++++++++++++++++++++++- docs/pages/code_standards.md | 13 + docs/pages/integrations.md | 2 +- docs/pages/settings.md | 13 + docs/pages/tutorial.md | 31 ++- docs/reference/{api.md => endpoint.md} | 2 +- docs/reference/index.md | 29 +++ docs/reference/sdk.md | 3 + docs/stylesheets/extra.css | 11 + mkdocs.yml | 29 ++- 17 files changed, 481 insertions(+), 96 deletions(-) create mode 100644 docs/images/favicon.ico create mode 100644 docs/images/white_logo.png rename docs/reference/{api.md => endpoint.md} (66%) create mode 100644 docs/reference/index.md create mode 100644 docs/reference/sdk.md create mode 100644 docs/stylesheets/extra.css diff --git a/aana/__init__.py b/aana/__init__.py index e69de29b..cc518313 100644 --- a/aana/__init__.py +++ b/aana/__init__.py @@ -0,0 +1,3 @@ +from aana.sdk import AanaSDK + +__all__ = ["AanaSDK"] diff --git a/aana/core/models/audio.py b/aana/core/models/audio.py index 6761f1d7..1e98181b 100644 --- a/aana/core/models/audio.py +++ b/aana/core/models/audio.py @@ -15,8 +15,8 @@ class Audio(Media): """A class representing an audio. - At least one of 'path', 'url', or 'content' must be provided. - If 'save_on_disk' is True, the audio will be saved on disk automatically. + At least one of `path`, `url`, or `content` must be provided. + If `save_on_disk` is True, the audio will be saved on disk automatically. Attributes: path (Path): the path to the audio file @@ -34,7 +34,7 @@ class Audio(Media): numpy: np.ndarray | None = None audio_lib: type[AbstractAudioLibrary] = pyAVWrapper - def validate(self): + def _validate(self): """Validate the audio. Raises: @@ -42,7 +42,7 @@ def validate(self): AudioReadingException: if the audio is not valid """ # validate the parent class - super().validate() + super()._validate() # check that at least one of 'path', 'url' or 'content' is provided if not any( @@ -87,11 +87,11 @@ def save(self): audio_dir.mkdir(parents=True, exist_ok=True) file_path = audio_dir / (self.media_id + ".wav") if self.content is not None: - self.save_from_audio_content(file_path) + self._save_from_audio_content(file_path) elif self.numpy is not None: - self.save_from_numpy(file_path) + self._save_from_numpy(file_path) elif self.url: - self.save_from_url(file_path) + self._save_from_url(file_path) else: raise ValueError( # noqa: TRY003 "At least one of 'path', 'url', 'content' or 'numpy' must be provided." @@ -99,7 +99,7 @@ def save(self): self.path = file_path self.is_saved = True - def save_from_audio_content(self, file_path: Path): + def _save_from_audio_content(self, file_path: Path): """Save the audio from the content. Args: @@ -108,7 +108,7 @@ def save_from_audio_content(self, file_path: Path): assert self.content is not None # noqa: S101 self.audio_lib.write_audio_bytes(file_path, self.content) - def save_from_audio_url(self, file_path): + def _save_from_audio_url(self, file_path): """Save the audio from the URL. Args: @@ -121,7 +121,7 @@ def save_from_audio_url(self, file_path): content: bytes = download_file(self.url) self.audio_lib.write_audio_bytes(file_path, content) - def save_from_numpy(self, file_path: Path): + def _save_from_numpy(self, file_path: Path): """Save the audio from numpy on disk. Args: @@ -143,11 +143,11 @@ def get_numpy(self) -> np.ndarray: if self.numpy is not None: return self.numpy elif self.path: - self.load_numpy_from_path() + self._load_numpy_from_path() elif self.url: - self.load_numpy_from_url() + self._load_numpy_from_url() elif self.content: - self.load_numpy_from_content() + self._load_numpy_from_content() else: raise ValueError( # noqa: TRY003 "At least one of 'path', 'url', 'content' or 'numpy' must be provided." @@ -155,7 +155,7 @@ def get_numpy(self) -> np.ndarray: assert self.numpy is not None # noqa: S101 return self.numpy - def load_numpy_from_path(self): + def _load_numpy_from_path(self): """Load the audio as a numpy array from a path. Raises: @@ -167,7 +167,7 @@ def load_numpy_from_path(self): except Exception as e: raise AudioReadingException(self) from e - def load_numpy_from_audio_bytes(self, audio_bytes: bytes): + def _load_numpy_from_audio_bytes(self, audio_bytes: bytes): """Load the image as a numpy array from image bytes (downloaded from URL or read from file). Raises: @@ -178,7 +178,7 @@ def load_numpy_from_audio_bytes(self, audio_bytes: bytes): except Exception as e: raise AudioReadingException(self) from e - def load_numpy_from_url(self): + def _load_numpy_from_url(self): """Load the audio as a numpy array from a URL. Raises: @@ -186,16 +186,16 @@ def load_numpy_from_url(self): """ assert self.url is not None # noqa: S101 content: bytes = download_file(self.url) - self.load_numpy_from_audio_bytes(content) + self._load_numpy_from_audio_bytes(content) - def load_numpy_from_content(self): + def _load_numpy_from_content(self): """Load the image as a numpy array from content. Raises: ImageReadingException: If there is an error reading the image. """ assert self.content is not None # noqa: S101 - self.load_numpy_from_audio_bytes(self.content) + self._load_numpy_from_audio_bytes(self.content) def __repr__(self) -> str: """Get the representation of the audio. diff --git a/aana/core/models/image.py b/aana/core/models/image.py index 4fe20b83..2d2f545f 100644 --- a/aana/core/models/image.py +++ b/aana/core/models/image.py @@ -32,8 +32,8 @@ class Image(Media): """A class representing an image. - At least one of 'path', 'url', 'content' or 'numpy' must be provided. - If 'save_on_disk' is True, the image will be saved on disk automatically. + At least one of `path`, `url`, `content` or `numpy` must be provided. + If `save_on_disk` is True, the image will be saved on disk automatically. Attributes: path (Path): The file path of the image. @@ -49,10 +49,10 @@ class Image(Media): AbstractImageLibrary ] = OpenCVWrapper # The image library to use, TODO: add support for PIL and allow to choose the library - def validate(self): + def _validate(self): """Validate the image.""" # validate the parent class - super().validate() + super()._validate() # check that at least one of 'path', 'url', 'content' or 'numpy' is provided if not any( @@ -89,11 +89,11 @@ def save(self): file_path = image_dir / (self.media_id + ".bmp") if self.content: - self.save_from_content(file_path) + self._save_from_content(file_path) elif self.numpy is not None: - self.save_from_numpy(file_path) + self._save_from_numpy(file_path) elif self.url: - self.save_from_url(file_path) + self._save_from_url(file_path) else: raise ValueError( # noqa: TRY003 "At least one of 'path', 'url', 'content' or 'numpy' must be provided." @@ -101,7 +101,7 @@ def save(self): self.path = file_path self.is_saved = True - def save_from_numpy(self, file_path: Path): + def _save_from_numpy(self, file_path: Path): """Save the image from numpy on disk. Args: @@ -123,11 +123,11 @@ def get_numpy(self) -> np.ndarray: if self.numpy is not None: return self.numpy elif self.path: - self.load_numpy_from_path() + self._load_numpy_from_path() elif self.url: - self.load_numpy_from_url() + self._load_numpy_from_url() elif self.content: - self.load_numpy_from_content() + self._load_numpy_from_content() else: raise ValueError( # noqa: TRY003 "At least one of 'path', 'url', 'content' or 'numpy' must be provided." @@ -143,7 +143,7 @@ def get_pil_image(self) -> PIL.Image: """ return PIL.Image.fromarray(self.get_numpy()) - def load_numpy_from_path(self): + def _load_numpy_from_path(self): """Load the image as a numpy array from a path. Raises: @@ -155,7 +155,7 @@ def load_numpy_from_path(self): except Exception as e: raise ImageReadingException(self) from e - def load_numpy_from_image_bytes(self, img_bytes: bytes): + def _load_numpy_from_image_bytes(self, img_bytes: bytes): """Load the image as a numpy array from image bytes (downloaded from URL or read from file). Raises: @@ -166,7 +166,7 @@ def load_numpy_from_image_bytes(self, img_bytes: bytes): except Exception as e: raise ImageReadingException(self) from e - def load_numpy_from_url(self): + def _load_numpy_from_url(self): """Load the image as a numpy array from a URL. Raises: @@ -174,16 +174,16 @@ def load_numpy_from_url(self): """ assert self.url is not None # noqa: S101 content: bytes = download_file(self.url) - self.load_numpy_from_image_bytes(content) + self._load_numpy_from_image_bytes(content) - def load_numpy_from_content(self): + def _load_numpy_from_content(self): """Load the image as a numpy array from content. Raises: ImageReadingException: If there is an error reading the image. """ assert self.content is not None # noqa: S101 - self.load_numpy_from_image_bytes(self.content) + self._load_numpy_from_image_bytes(self.content) def get_content(self) -> bytes: """Get the content of the image as bytes. @@ -197,11 +197,11 @@ def get_content(self) -> bytes: if self.content: return self.content elif self.path: - self.load_content_from_path() + self._load_content_from_path() elif self.url: - self.load_content_from_url() + self._load_content_from_url() elif self.numpy is not None: - self.load_content_from_numpy() + self._load_content_from_numpy() else: raise ValueError( # noqa: TRY003 "At least one of 'path', 'url', 'content' or 'numpy' must be provided." @@ -209,7 +209,7 @@ def get_content(self) -> bytes: assert self.content is not None # noqa: S101 return self.content - def load_content_from_numpy(self): + def _load_content_from_numpy(self): """Load the content of the image from numpy.""" assert self.numpy is not None # noqa: S101 self.content = self.image_lib.write_to_bytes(self.numpy) diff --git a/aana/core/models/media.py b/aana/core/models/media.py index 190fb728..d6e45f6c 100644 --- a/aana/core/models/media.py +++ b/aana/core/models/media.py @@ -51,8 +51,8 @@ class Media: It is used to represent images, videos, and audio files. - At least one of 'path', 'url', or 'content' must be provided. - If 'save_on_disk' is True, the media will be saved on disk automatically. + At least one of `path`, `url`, or `content` must be provided. + If `save_on_disk` is True, the media will be saved on disk automatically. Attributes: path (Path): the path to the media file @@ -69,7 +69,7 @@ class Media: is_saved: bool = False media_dir: Path | None = None - def validate(self): + def _validate(self): """Validate the media.""" # check that path is a Path object if self.path and not isinstance(self.path, Path): @@ -84,7 +84,7 @@ def __post_init__(self): Perform checks and save the media on disk if needed. """ - self.validate() + self._validate() if self.save_on_disk: self.save() @@ -110,16 +110,16 @@ def save(self): file_path = self.media_dir / (self.media_id + ".mp4") if self.content: - self.save_from_content(file_path) + self._save_from_content(file_path) elif self.url: - self.save_from_url(file_path) + self._save_from_url(file_path) else: raise ValueError( # noqa: TRY003 "At least one of 'path', 'url', or 'content' must be provided." ) self.is_saved = True - def save_from_bytes(self, file_path: Path, content: bytes): + def _save_from_bytes(self, file_path: Path, content: bytes): """Save the media from bytes. Args: @@ -129,16 +129,16 @@ def save_from_bytes(self, file_path: Path, content: bytes): file_path.write_bytes(content) self.path = file_path - def save_from_content(self, file_path: Path): + def _save_from_content(self, file_path: Path): """Save the media from the content. Args: file_path (Path): the path to save the media to """ assert self.content is not None # noqa: S101 - self.save_from_bytes(file_path, self.content) + self._save_from_bytes(file_path, self.content) - def save_from_url(self, file_path): + def _save_from_url(self, file_path): """Save the media from the URL. Args: @@ -149,7 +149,7 @@ def save_from_url(self, file_path): """ assert self.url is not None # noqa: S101 content: bytes = download_file(self.url) - self.save_from_bytes(file_path, content) + self._save_from_bytes(file_path, content) def get_content(self) -> bytes: """Get the content of the media as bytes. @@ -163,9 +163,9 @@ def get_content(self) -> bytes: if self.content: return self.content elif self.path: - self.load_content_from_path() + self._load_content_from_path() elif self.url: - self.load_content_from_url() + self._load_content_from_url() else: raise ValueError( # noqa: TRY003 "At least one of 'path', 'url', or 'content' must be provided." @@ -173,12 +173,12 @@ def get_content(self) -> bytes: assert self.content is not None # noqa: S101 return self.content - def load_content_from_path(self): + def _load_content_from_path(self): """Load the content of the media from the path.""" assert self.path is not None # noqa: S101 self.content = self.path.read_bytes() - def load_content_from_url(self): + def _load_content_from_url(self): """Load the content of the media from the URL. Raises: diff --git a/aana/core/models/video.py b/aana/core/models/video.py index fbba2d94..6995ac67 100644 --- a/aana/core/models/video.py +++ b/aana/core/models/video.py @@ -31,8 +31,8 @@ class Video(Media): """A class representing a video. - At least one of 'path', 'url', or 'content' must be provided. - If 'save_on_disk' is True, the video will be saved on disk automatically. + At least one of `path`, `url`, or `content` must be provided. + If `save_on_disk` is True, the video will be saved on disk automatically. Attributes: path (Path): the path to the video file @@ -48,7 +48,7 @@ class Video(Media): description: str = "" media_dir: Path | None = settings.video_dir - def validate(self): + def _validate(self): """Validate the video. Raises: @@ -56,7 +56,7 @@ def validate(self): VideoReadingException: if the video is not valid """ # validate the parent class - super().validate() + super()._validate() # check that at least one of 'path', 'url' or 'content' is provided if not any( @@ -88,7 +88,7 @@ def is_video(self) -> bool: return False return True - def save_from_url(self, file_path): + def _save_from_url(self, file_path): """Save the media from the URL. Args: @@ -98,7 +98,7 @@ def save_from_url(self, file_path): DownloadError: if the media can't be downloaded VideoReadingException: if the media is not a valid video """ - super().save_from_url(file_path) + super()._save_from_url(file_path) # check that the file is a video if not self.is_video(): raise VideoReadingException(video=self) diff --git a/docs/images/favicon.ico b/docs/images/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..228ae061f9f373bd4ed4c7bedd7e9447d6d302ad GIT binary patch literal 15086 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 ASO5S3 literal 0 HcmV?d00001 diff --git a/docs/images/white_logo.png b/docs/images/white_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..2c6ae02d674bbc0a5fe49cebcdde162c98d8f772 GIT binary patch literal 2401 zcmV-n37+004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00002 zVoOIv0RM-N%)bBt00(qQO+^Rj2Nw$zI<4Aae*gdo21!IgRCwC$nr&>AXBo$T&vQ;+ zp)mSFg$?>b0iATItPmK{WlP+`hO&&g&CMm~*qr-7T$s@rF($@@MNKqLbk?a0o5{qP z^#f7R%mvrNXbBs#Q3iBwPzrsar|<3QIp^<()0gKw&w1}TZBBCj{c?Ie_jTRZ|9-pf z`?_z)B8x1t$Rdj@<_|{fA_|ssQ$Pi)S;}(CCiO<~(8))9%qRHp#ba*LS`LLQr-CBf zbkjvAefSB);Z9-%1SX4F#x2}IJ>?XTOCC9sp9A<9XOvMs;V4IWpB~1I==KU(&KB;b zj)mmo#=y%21ANFKj`Lx3{e%bz+^k{?_i!7<ZHBdsU^Ryq>AbRE2)3 zkK{|x`5*%7&>vMRtZvAqpJ^yA{c-(Op9$4Y#CcStojRrQq@16^gwE+P-7w>X4Be+| zaccW?MC+2EAY`gmFRFi5&QD=Pzf;YW8$!9-t=_nM@vy2BCt&C7m%e z$e3~;gZp`&RS`=D@X*B-&T^3+x)D%H6*a73Ib{?^)NEoGZN^kR)%=osG3e(K?OY~@ zPf^1%7Kd4R-{2{(#T9F1YO791Y>RQ7(tbUvO6ABUQ-*@m-H<7l7N}l()Tr)=efF}J zYNoFBYSBNnOE=0bmt1mdrFQD?8gXd$Xlq~sEA?iW3NPsy z6(=4{gv#`rFpFiMz8Kw_&>FpM(`whM*aV)`sH3_odTeUcCQJY=)qV$sfc~I-Im;TB zI8m*)Y+9GKI=UBbirGxQO*+i;yq4Ua&_K||J}TL2`*0`AX`gW(C}J}=bDbuAj4xt~ z#AvZij&UcwphZb;re<1pn>rlp**9b@QKpyFr!kG`zxuMw2t7~}YY08*Sby47KO6Ta z9n971jzRR2g@CCiEL-)HTALgJlMRjt*vPwaoi(Gt051m_vI#4hIVa?@WBOzVb*xUV zCX+gwq?=ZJvpx|49B0@jDd8r|e+xp$MqqNC^Wu$L!Nr5z9TM=w3-d@I3C0_FBt#P6 zRWnIr^MQO8+9bl8Nd!tmq6olsMl*zf09HCq>{l4f5CT9E4^v^2wb47blh`1SJh>u# z^;3Y$p;1Vo7O|dfJmT1(wQ+rJ36$|eo{qRr6h*AF$rkf_+$`Y+7CK_qHCpk_Er9|y zCaAH14H3V+!wJZoIbcU0uhV5@FoEMVLgx0sF`lE}$XEi+Jj?0e&rI421u@J)e!+WF zhu-uONM-*DFCLC^fF`cbti?SjL<;~NBMwZWDO+gBrwWP zC{Bp*3ijHP41Mh30zGt1og3^?Fd+g0Fv+K!D#}=hi(&fc$K3ozjQSvIi*w*5WpgKvOCHRnu`Lyz(x-7a~+#)UN6N2fMR~cqj5~ge0H#s@9~yG z-knU&9Xl(3Du~7;Ajso8JmE;eN5Tev&EquNq&aNoW=kdxCTO5<*8YP!ZTa96s1 zKmKz;s*-E~|F-GQ<004EY zcgR}!EsYEygn>ydkMn?InBC5bWHZjGBap);M~PORrq#Lt>Lh1q=LeSDKfpTHa87BD z2+=38o6p%wjPaLH_rZX1Ug6&k-CL8rbx9=w`_0u=n!<*ks~mQW_-e}?*gO$f=x9Sv zxE-beaF$M+xO^_od(jD$I$Ri|H^Qj)IC`LzNIAGUBTzW2L*eYSQ$k=aB2iiiWB@Xr zK+@}kz>SF?|JKp2(i=%+2yz#_qRcm@GXm_G_7||0!GR<0I9PS1sNX)vIOQE z8BZYD?2H%h^a|rm*{)Rtz!DUVkX&8_0v_8dsOY5!0r0TPvXBNi1Na$aFm{F07zvY8 z^6+xVQ$T|O$GbZl4Ba1h))P#+IfAesiv=v*Kpi!8Fp zB8x22gZ~5D-kRt4H$F*-6ZIyE>e zFfckWF!fL)0RR91S9(-fbW&k=AaHVTW@&6?Aar?fWguyAbYlPjc%0+%3K74o T@32I8 literal 0 HcmV?d00001 diff --git a/docs/index.md b/docs/index.md index ad99ad19..eb2bdca7 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,14 +1,111 @@ -# Aana SDK Documentation +--- +hide: + - navigation +--- -Welcome to the documentation for Aana SDK. + -## Getting Started -If you're new to the project, we recommend starting with the [Tutorial](pages/tutorial.md) to get a hands-on introduction. From there, you can explore the other documentation files based on your specific needs or interests. +[![Build Status](https://github.com/mobiusml/aana_sdk/actions/workflows/python-package.yml/badge.svg)](https://github.com/mobiusml/aana_sdk/actions/workflows/python-package.yml) +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](/LICENSE) +[![Website](https://img.shields.io/badge/website-online-brightgreen.svg)](http://www.mobiuslabs.com) +[![PyPI version](https://img.shields.io/pypi/v/aana.svg)](https://pypi.org/project/aana/) +[![GitHub release](https://img.shields.io/github/v/release/mobiusml/aana_sdk.svg)](https://github.com/mobiusml/aana_sdk/releases) -For developers looking to contribute, make sure to review the [Code Standards](pages/code_standards.md) and [Development Guide](pages/development.md). +Aana SDK is a powerful framework for building multimodal applications. It facilitates the large-scale deployment of machine learning models, including those for vision, audio, and language, and supports Retrieval-Augmented Generation (RAG) systems. This enables the development of advanced applications such as search engines, recommendation systems, and data insights platforms. -If you have any questions or need further assistance, please don't hesitate to reach out to our support team or community forums. +The SDK is designed according to the following principles: + +- **Reliability**: Aana is designed to be reliable and robust. It is built to be fault-tolerant and to handle failures gracefully. +- **Scalability**: Aana is designed to be scalable. It is built on top of Ray, a distributed computing framework, and can be easily scaled to multiple servers. +- **Efficiency**: Aana is designed to be efficient. It is built to be fast and parallel and to use resources efficiently. +- **Easy to Use**: Aana is designed to be easy to use by developers. It is built to be modular, with a lot of automation and abstraction. + +The SDK is still in development, and not all features are fully implemented. We are constantly working on improving the SDK, and we welcome any feedback or suggestions. + +## Why use Aana SDK? + +Nowadays, it is getting easier to experiment with machine learning models and build prototypes. However, deploying these models at scale and integrating them into real-world applications is still a challenge. + +Aana SDK simplifies this process by providing a framework that allows: +- Deploy and scale machine learning models on a single machine or a cluster. +- Build multimodal applications that combine multiple different machine learning models. + +### Key Features + +**Model Deployment**: + + - Deploy models on a single machine or scale them across a cluster. + +**API Generation**: + + - Automatically generate an API for your application based on the endpoints you define. + - Input and output of the endpoints will be automatically validated. + - Simply annotate the types of input and output of the endpoint functions. + +**Predefined Types**: + + - Comes with a set of predefined types for various data such as images, videos, etc. + +**Documentation Generation**: + + - Automatically generate documentation for your application based on the defined endpoints. + +**Streaming Support**: + + - Stream the output of the endpoint to the client as it is generated. + - Ideal for real-time applications and Large Language Models (LLMs). + +**Task Queue Support**: + + - Run every endpoint you define as a task in the background without any changes to your code. + +**Integrations**: + + - Aana SDK has integrations with various machine learning models and libraries: Whisper, vLLM, Hugging Face Transformers, Deepset Haystack, and more to come (for more information see [Integrations](docs/pages/integrations.md)). + +## Installation + +### Installing via PyPI + +To install Aana SDK via PyPI, you can use the following command: + +```bash +pip install aana +``` + +For optimal performance install [PyTorch](https://pytorch.org/get-started/locally/) version >=2.1 appropriate for your system. You can skip it, but it will install a default version that may not make optimal use of your system's resources, for example, a GPU or even some SIMD operations. Therefore we recommend choosing your PyTorch package carefully and installing it manually. + +Some models use Flash Attention. Install Flash Attention library for better performance. See [flash attention installation instructions](https://github.com/Dao-AILab/flash-attention?tab=readme-ov-file#installation-and-features) for more details and supported GPUs. + +### Installing from GitHub + +1. Clone the repository. + +```bash +git clone https://github.com/mobiusml/aana_sdk.git +``` + +2. Install additional libraries. + +For optimal performance install [PyTorch](https://pytorch.org/get-started/locally/) version >=2.1 appropriate for your system. You can continue directly to the next step, but it will install a default version that may not make optimal use of your system's resources, for example, a GPU or even some SIMD operations. Therefore we recommend choosing your PyTorch package carefully and installing it manually. + +Some models use Flash Attention. Install Flash Attention library for better performance. See [flash attention installation instructions](https://github.com/Dao-AILab/flash-attention?tab=readme-ov-file#installation-and-features) for more details and supported GPUs. + +3. Install the package with poetry. + +The project is managed with [Poetry](https://python-poetry.org/docs/). See the [Poetry installation instructions](https://python-poetry.org/docs/#installation) on how to install it on your system. + +It will install the package and all dependencies in a virtual environment. + +```bash +sh install.sh +``` ## Integrations - [Integrations](pages/integrations.md): Overview of the available predefined deployments like Whisper, vLLM, Hugging Face Transformers, Haystack etc. @@ -30,3 +127,213 @@ If you have any questions or need further assistance, please don't hesitate to r - [Testing](pages/testing.md): This document covers the testing procedures and guidelines for our project. - [Deployment Test Cache](pages/deployment_test_cache.md): Information on how deployment test caching works and its configuration. +## Getting Started + +If you're new to the project, we recommend starting with the [Tutorial](pages/tutorial.md) to get a hands-on introduction. From there, you can explore the other documentation files based on your specific needs or interests. + +For developers looking to contribute, make sure to review the [Code Standards](pages/code_standards.md) and [Development Guide](pages/development.md). + +If you have any questions or need further assistance, please don't hesitate to reach out to our support team or community forums. + +### Creating a New Application + +You can quickly develop multimodal applications using Aana SDK's intuitive APIs and components. + +If you want to start building a new application, you can use the following GitHub template: [Aana App Template](https://github.com/mobiusml/aana_app_template). It will help you get started with the Aana SDK and provide you with a basic structure for your application and its dependencies. + +Let's create a simple application that transcribes a video. The application will download a video from YouTube, extract the audio, and transcribe it using an ASR model. + +Aana SDK already provides a deployment for ASR (Automatic Speech Recognition) based on the Whisper model. We will use this [deployment](#Deployments) in the example. + +```python +from aana.api.api_generation import Endpoint +from aana.core.models.video import VideoInput +from aana.deployments.aana_deployment_handle import AanaDeploymentHandle +from aana.deployments.whisper_deployment import ( + WhisperComputeType, + WhisperConfig, + WhisperDeployment, + WhisperModelSize, + WhisperOutput, +) +from aana.integrations.external.yt_dlp import download_video +from aana.processors.remote import run_remote +from aana.processors.video import extract_audio +from aana.sdk import AanaSDK + + +# Define the model deployments. +asr_deployment = WhisperDeployment.options( + num_replicas=1, + ray_actor_options={"num_gpus": 0.25}, # Remove this line if you want to run Whisper on a CPU. + user_config=WhisperConfig( + model_size=WhisperModelSize.MEDIUM, + compute_type=WhisperComputeType.FLOAT16, + ).model_dump(mode="json"), +) +deployments = [{"name": "asr_deployment", "instance": asr_deployment}] + + +# Define the endpoint to transcribe the video. +class TranscribeVideoEndpoint(Endpoint): + """Transcribe video endpoint.""" + + async def initialize(self): + """Initialize the endpoint.""" + self.asr_handle = await AanaDeploymentHandle.create("asr_deployment") + await super().initialize() + + async def run(self, video: VideoInput) -> WhisperOutput: + """Transcribe video.""" + video_obj = await run_remote(download_video)(video_input=video) + audio = extract_audio(video=video_obj) + transcription = await self.asr_handle.transcribe(audio=audio) + return transcription + +endpoints = [ + { + "name": "transcribe_video", + "path": "/video/transcribe", + "summary": "Transcribe a video", + "endpoint_cls": TranscribeVideoEndpoint, + }, +] + +aana_app = AanaSDK(name="transcribe_video_app") + +for deployment in deployments: + aana_app.register_deployment(**deployment) + +for endpoint in endpoints: + aana_app.register_endpoint(**endpoint) + +if __name__ == "__main__": + aana_app.connect(host="127.0.0.1", port=8000, show_logs=False) # Connects to the Ray cluster or starts a new one. + aana_app.migrate() # Runs the migrations to create the database tables. + aana_app.deploy(blocking=True) # Deploys the application. +``` + +You have a few options to run the application: +- Copy the code above and run it in a Jupyter notebook. +- Save the code to a Python file, for example `app.py`, and run it as a Python script: `python app.py`. +- Save the code to a Python file, for example `app.py`, and run it using the Aana CLI: `aana deploy app:aana_app --host 127.0.0.1 --port 8000 --hide-logs`. + +Once the application is running, you will see the message `Deployed successfully.` in the logs. You can now send a request to the application to transcribe a video. + +To get an overview of the Ray cluster, you can use the Ray Dashboard. The Ray Dashboard is available at `http://127.0.0.1:8265` by default. You can see the status of the Ray cluster, the resources used, running applications and deployments, logs, and more. It is a useful tool for monitoring and debugging your applications. See [Ray Dashboard documentation](https://docs.ray.io/en/latest/ray-observability/getting-started.html) for more information. + +Let's transcribe [Gordon Ramsay's perfect scrambled eggs tutorial](https://www.youtube.com/watch?v=VhJFyyukAzA) using the application. + +```bash +curl -X POST http://127.0.0.1:8000/video/transcribe -Fbody='{"video":{"url":"https://www.youtube.com/watch?v=VhJFyyukAzA"}}' +``` + +This will return the full transcription of the video, transcription for each segment, and transcription info like identified language. You can also use the [Swagger UI](http://127.0.0.1:8000/docs) to send the request. + +### Running Example Applications + +Aana SDK comes with a set of example applications that demonstrate the capabilities of the SDK. You can run the example applications using the Aana CLI. + +The following applications are available: +- `chat_with_video`: A multimodal chat application that allows users to upload a video and ask questions about the video content based on the visual and audio information. See [Chat with Video Demo notebook](/notebooks/chat_with_video_demo.ipynb) for more information. +- `whisper`: An application that demonstrates the Whisper model for automatic speech recognition (ASR). +- `llama2`: An application that deploys LLaMa2 7B Chat model. + +To run an example application, use the following command: + +```bash +aana deploy aana.projects..app:aana_app +``` + +For example, to run the `whisper` application, use the following command: + +```bash +aana deploy aana.projects.whisper.app:aana_app +``` + +> **⚠️ Warning** +> +> The example applications require a GPU to run. +> +> The applications will detect the available GPU automatically but you need to make sure that `CUDA_VISIBLE_DEVICES` is set correctly. +> +> Sometimes `CUDA_VISIBLE_DEVICES` is set to an empty string and the application will not be able to detect the GPU. Use `unset CUDA_VISIBLE_DEVICES` to unset the variable. +> +> You can also set the `CUDA_VISIBLE_DEVICES` environment variable to the GPU index you want to use: `export CUDA_VISIBLE_DEVICES=0`. +> +> Different applications have different requirements for the GPU memory: +> - `chat_with_video` requires at least 48GB. +> - `llama2` requires at least 16GB. +> - `whisper` requires at least 4GB. + +### Main components + +There are three main components in Aana SDK: deployments, endpoints, and AanaSDK. + +#### Deployments + +Deployments are the building blocks of Aana SDK. They represent the machine learning models that you want to deploy. Aana SDK comes with a set of predefined deployments that you can use or you can define your own deployments. See [Integrations](#integrations) section for more information about predefined deployments. + +Each deployment has a main class that defines it and a configuration class that allows you to specify the deployment parameters. + +For example, we have a predefined deployment for the Whisper model that allows you to transcribe audio. You can define the deployment like this: + +```python +from aana.deployments.whisper_deployment import WhisperDeployment, WhisperConfig, WhisperModelSize, WhisperComputeType + +asr_deployment = WhisperDeployment.options( + num_replicas=1, + ray_actor_options={"num_gpus": 0.25}, + user_config=WhisperConfig(model_size=WhisperModelSize.MEDIUM, compute_type=WhisperComputeType.FLOAT16).model_dump(mode="json"), +) +``` + +#### Endpoints + +Endpoints define the functionality of your application. They allow you to connect multiple deployments (models) to each other and define the input and output of your application. + +Each endpoint is defined as a class that inherits from the `Endpoint` class. The class has two main methods: `initialize` and `run`. + +For example, you can define an endpoint that transcribes a video like this: + +```python +class TranscribeVideoEndpoint(Endpoint): + """Transcribe video endpoint.""" + + async def initialize(self): + """Initialize the endpoint.""" + self.asr_handle = await AanaDeploymentHandle.create("asr_deployment") + await super().initialize() + + async def run(self, video: VideoInput) -> WhisperOutput: + """Transcribe video.""" + video_obj = await run_remote(download_video)(video_input=video) + audio = extract_audio(video=video_obj) + transcription = await self.asr_handle.transcribe(audio=audio) + return transcription +``` + +#### AanaSDK + +AanaSDK is the main class that you use to build your application. It allows you to deploy the deployments and endpoints you defined and start the application. + +For example, you can define an application that transcribes a video like this: + +```python +aana_app = AanaSDK(name="transcribe_video_app") + +aana_app.register_deployment(name="asr_deployment", instance=asr_deployment) +aana_app.register_endpoint( + name="transcribe_video", + path="/video/transcribe", + summary="Transcribe a video", + endpoint_cls=TranscribeVideoEndpoint, +) + +aana_app.connect() # Connects to the Ray cluster or starts a new one. +aana_app.migrate() # Runs the migrations to create the database tables. +aana_app.deploy() # Deploys the application. +``` + +All you need to do is define the deployments and endpoints you want to use in your application, and Aana SDK will take care of the rest. + diff --git a/docs/pages/code_standards.md b/docs/pages/code_standards.md index 2e0f359d..d2731b47 100644 --- a/docs/pages/code_standards.md +++ b/docs/pages/code_standards.md @@ -1,3 +1,16 @@ +--- +hide: + - navigation +--- + + + + # Code Standards This project uses Ruff for linting and formatting. If you want to diff --git a/docs/pages/integrations.md b/docs/pages/integrations.md index 1210e849..1036edf5 100644 --- a/docs/pages/integrations.md +++ b/docs/pages/integrations.md @@ -1,4 +1,4 @@ -# Integrations +# Deployments Aana SDK comes with a set of predefined deployments that you can use out of the box to deploy models. diff --git a/docs/pages/settings.md b/docs/pages/settings.md index bbff385d..b664abee 100644 --- a/docs/pages/settings.md +++ b/docs/pages/settings.md @@ -1,3 +1,16 @@ +--- +hide: + - navigation +--- + + + + # Settings Here are the environment variables that can be used to configure the Aaana SDK: diff --git a/docs/pages/tutorial.md b/docs/pages/tutorial.md index 33ae2181..283c102c 100644 --- a/docs/pages/tutorial.md +++ b/docs/pages/tutorial.md @@ -1,3 +1,16 @@ +--- +hide: + - navigation +--- + + + + # How to Create a New Project with Aana SDK Aana SDK is a powerful framework for building multimodal applications. It facilitates the large-scale deployment of machine learning models, including those for vision, audio, and language, and supports Retrieval-Augmented Generation (RAG) systems. This enables the development of advanced applications such as search engines, recommendation systems, and data insights platforms. @@ -6,27 +19,13 @@ Aana SDK comes with a set of example applications that demonstrate the capabilit If you want to start building a new application, you can use the following GitHub template: [Aana App Template](https://github.com/mobiusml/aana_app_template). It will help you get started with the Aana SDK and provide you with a basic structure for your application and its dependencies. -In this tutorial, we will walk you through the process of creating a new project with Aana SDK. By the end of this tutorial, you will have a runnable application that transcribes a video and summarizes the transcript using a Language Model (LLM). We will use the video transcription application from the [README](/README.md) as a starting point and extend it to include the LLM model for summarization and a new endpoints. - - -- [Prerequisites](#prerequisites) -- [Video Transcription Application](#video-transcription-application) -- [Running the Application](#running-the-application) -- [Application Components](#application-components) - - [Deployments](#deployments) - - [Endpoints](#endpoints) - - [Application](#application) - - [Connecting to the Deployments](#connecting-to-the-deployments) -- [Transcript Summarization Application](#transcript-summarization-application) - - [LLM Model](#llm-model) - - [Summarization Endpoint](#summarization-endpoint) - - [Extending the Application](#extending-the-application) +In this tutorial, we will walk you through the process of creating a new project with Aana SDK. By the end of this tutorial, you will have a runnable application that transcribes a video and summarizes the transcript using a Language Model (LLM). We will use [the video transcription application](/#creating-a-new-application) as a starting point and extend it to include the LLM model for summarization and a new endpoints. ## Prerequisites -Before you begin, make sure you have a working installation of Aana SDK. See the [README](/README.md#installation) for installation instructions. +Before you begin, make sure you have a working installation of Aana SDK. See the [installation instructions](/#installation) for more information. ## Video Transcription Application diff --git a/docs/reference/api.md b/docs/reference/endpoint.md similarity index 66% rename from docs/reference/api.md rename to docs/reference/endpoint.md index 8bf725ef..bc941724 100644 --- a/docs/reference/api.md +++ b/docs/reference/endpoint.md @@ -1,3 +1,3 @@ -# API +# Endpoint ::: aana.api.Endpoint \ No newline at end of file diff --git a/docs/reference/index.md b/docs/reference/index.md new file mode 100644 index 00000000..1d1ad976 --- /dev/null +++ b/docs/reference/index.md @@ -0,0 +1,29 @@ +# Reference Documentation (Code API) + +This section contains the reference documentation for the public API of the project. Quick links to the most important classes and functions are provided below. + +## SDK + +[`aana.AanaSDK`](./sdk.md#aana.AanaSDK) - The main class for interacting with the Aana SDK. Use it to register endpoints and deployments and to start the server. + +## Endpoint + +[`aana.api.Endpoint`](./endpoint.md#aana.api.Endpoint) - The base class for defining endpoints in the Aana SDK. + +## Deployments + +[Deployments](./deployments.md) contains information about how to deploy models with a number of predefined deployments for such models as Whisper, LLMs, Hugging Face models, and more. + +## Models + +- [Media Models](./models/media.md) - Models for working with media types like audio, video, and images. +- [Automatic Speech Recognition (ASR) Models](./models/asr.md) - Models for working with automatic speech recognition (ASR) models. +- [Caption Models](./models/captions.md) - Models for working with captions. +- [Chat Models](./models/chat.md) - Models for working with chat models. +- [Custom Config](./models/custom_config.md) - Custom Config model can be used to pass arbitrary configuration to the deployment. +- [Sampling Models](./models/sampling.md) - Contains Sampling Parameters model which can be used to pass sampling parameters to the LLM models. +- [Time Models](./models/time.md) - Contains time models like TimeInterval. +- [Types Models](./models/types.md) - Contains types models like Dtype. +- [Video Models](./models/video.md) - Models for working with video files. +- [Whisper Models](./models/whisper.md) - Models for working with whispers. + diff --git a/docs/reference/sdk.md b/docs/reference/sdk.md new file mode 100644 index 00000000..f1894adf --- /dev/null +++ b/docs/reference/sdk.md @@ -0,0 +1,3 @@ +# SDK + +::: aana.AanaSDK \ No newline at end of file diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css new file mode 100644 index 00000000..a52dd316 --- /dev/null +++ b/docs/stylesheets/extra.css @@ -0,0 +1,11 @@ +:root { + --md-primary-fg-color: #A66CFF; + --md-primary-fg-color--light: #CFF500; + --md-primary-fg-color--dark: #3E3E3E; + --md-primary-bg-color: #F0F0F0; + --md-primary-bg-color--light: #FFFFFF; +} + +/* .md-header__topic { + display: none; +} */ \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index fac6a28c..11c60ab1 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,4 +1,4 @@ -site_name: Aana SDK +site_name: "Aana SDK" # Repository @@ -12,7 +12,6 @@ theme: - navigation.tabs - navigation.indexes - navigation.path - # - toc.integrate - toc.follow - navigation.top - search.suggest @@ -20,20 +19,24 @@ theme: - content.tabs.link - content.code.annotation - content.code.copy + - content.tooltips language: en + logo: images/white_logo.png + favicon: images/favicon.ico palette: - scheme: default toggle: icon: material/toggle-switch-off-outline name: Switch to dark mode - primary: 5c21d1 - accent: purple + primary: custom - scheme: slate toggle: icon: material/toggle-switch name: Switch to light mode - primary: 5c21d1 - accent: lime + primary: custom +extra_css: + - stylesheets/extra.css + # Extensions markdown_extensions: @@ -79,6 +82,8 @@ plugins: show_symbol_type_heading: true show_symbol_type_toc: true show_labels: false + docstring_options: + ignore_init_summary: true # Customization extra: social: @@ -93,7 +98,7 @@ nav: - Getting Started: - Tutorial: pages/tutorial.md - Integrations: - - Overview: pages/integrations.md + - Deployments: pages/integrations.md - OpenAI API: pages/openai_api.md - Deployment: - Docker: pages/docker.md @@ -108,7 +113,9 @@ nav: - Testing: pages/testing.md - Deployment Test Cache: pages/deployment_test_cache.md - Reference (Code API): - - reference/api.md + - reference/index.md + - reference/sdk.md + - reference/endpoint.md - reference/deployments.md - reference/settings.md - Models: @@ -124,7 +131,7 @@ nav: - reference/models/vad.md - reference/models/video.md - reference/models/whisper.md - - reference/exceptions.md - - reference/utils.md - reference/integrations.md - - reference/processors.md \ No newline at end of file + - reference/processors.md + - reference/exceptions.md + - reference/utils.md \ No newline at end of file