# Cookie-cutter template app

Quickest way to get started with Luxonis ecosystem is to use the template app. This app is a starting point for your own
applications and includes all the necessary components to get you up and running. Apps range from very simple pipelines (e.g.
camera stream) to complex and wide-encompassing (e.g using custom AI models and nodes).

Get up and running in under 5 minutes:

```bash
# Install core packages
pip install depthai --force-reinstall
# Clone the template app
git clone https://github.com/luxonis/oak-template.git
# Change directory to the template app
cd oak-template
# Install requirements
pip install -r requirements.txt
```

This will download the template / cookie-cutter app to your current directory.

```text
template-app/
├── main.py
├── oakapp.toml
├── requirements.txt
├── media/ # Optional media files
└── utils/ # Optional helper functions
```

This is where your main logic resides. The downloaded script will use "Camera + NN + Hub" as a default pipeline. Feel free to swap
it with any of the other examples below if you don't need the NN or Hub functionality.

#### Camera + NN + HUB (default)

```python
import depthai as dai
import os

from depthai_nodes.node import SnapsUploader
from depthai_nodes.node.parsing_neural_network import ParsingNeuralNetwork
from utils.snaps_producer import SnapsProducer
from dotenv import load_dotenv

# Assumes `DEPTHAI_HUB_API_KEY` is defined in the workspace root `.env` file.
# Load environment variables before initializing the pipeline.
load_dotenv(override=True)

model = "luxonis/yolov6-nano:r2-coco-512x288"
time_interval = 10.0  # min nr of seconds between snaps uploading

visualizer = dai.RemoteConnection(httpPort=8082)
device = dai.Device()

with dai.Pipeline(device) as pipeline:
    print("Creating pipeline...")

    model_description = dai.NNModelDescription(model)
    platform = device.getPlatformAsString()
    model_description.platform = platform
    nn_archive = dai.NNArchive(
        dai.getModelFromZoo(
            model_description,
        )
    )

    input_node = pipeline.create(dai.node.Camera).build()

    nn_with_parser = pipeline.create(ParsingNeuralNetwork).build(
        input_node, nn_archive
    )

    visualizer.addTopic("Video", nn_with_parser.passthrough, "images")
    visualizer.addTopic("Visualizations", nn_with_parser.out, "images")

    snaps_producer = pipeline.create(SnapsProducer).build(
        frame=nn_with_parser.passthrough,
        detections=nn_with_parser.out,
        time_interval=time_interval
    )

    snaps_uploader = pipeline.create(SnapsUploader).build(snaps_producer.out)

    print("Pipeline created.")

    pipeline.start()
    visualizer.registerPipeline(pipeline)

    while pipeline.isRunning():
        key = visualizer.waitKey(1)
        if key == ord("q"):
            print("Got q key from the remote connection!")
            break
```

#### Camera stream

```python
import depthai as dai

remoteConnector = dai.RemoteConnection(httpPort=8082)

with dai.Pipeline() as pipeline:
    # Define source and output
    cam = pipeline.create(dai.node.Camera).build()

    remoteConnector.addTopic("video", cam.requestOutput((640,400)), "video")
    
    pipeline.start()
    remoteConnector.registerPipeline(pipeline)

    while pipeline.isRunning():
        key = remoteConnector.waitKey(1)
        if key == ord("q"):
            print("Got q key from the remote connection!")
            break
```

#### Depth

```python
import depthai as dai
from depthai_nodes.node import ApplyColormap
import cv2

remoteConnector = dai.RemoteConnection(httpPort=8082)

with dai.Pipeline() as pipeline:

    monoLeft = pipeline.create(dai.node.Camera).build(dai.CameraBoardSocket.CAM_B)
    monoRight = pipeline.create(dai.node.Camera).build(dai.CameraBoardSocket.CAM_C)
    stereo = pipeline.create(dai.node.StereoDepth)

    # Linking
    monoLeftOut = monoLeft.requestFullResolutionOutput(type=dai.ImgFrame.Type.NV12)
    monoRightOut = monoRight.requestFullResolutionOutput(type=dai.ImgFrame.Type.NV12)
    monoLeftOut.link(stereo.left)
    monoRightOut.link(stereo.right)

    remoteConnector.addTopic("left", monoLeftOut, "stream")
    remoteConnector.addTopic("right", monoRightOut, "stream")

    coloredDepth = pipeline.create(ApplyColormap).build(stereo.disparity)
    coloredDepth.setColormap(cv2.COLORMAP_JET)
    remoteConnector.addTopic("disparity", coloredDepth.out, "stream")

    pipeline.start()
    remoteConnector.registerPipeline(pipeline)

    while pipeline.isRunning():
        key = remoteConnector.waitKey(1)
        if key == ord("q"):
            print("Got q key from the remote connection!")
            break
```

### DepthAI Examples

If you wish to use a different pipeline, you can find a list of available nodes and their examples

[DepthAI Examples](https://docs.luxonis.com/software-v3/depthai/examples.md)

This is where you define the build process for your container. For template apps, we recommend using the Luxonis base image and
installing Python dependencies from `requirements.txt`. You can find more information
[here](https://docs.luxonis.com/software-v3/oak-apps/oakctl.md).

```toml
identifier = "custom.oakapp"
app_version = "1.0.0"

prepare_container = [
    { type = "RUN", command = "apt-get update" },
    { type = "RUN", command = "apt-get install -y python3 python3-pip wget git" },
]

prepare_build_container = []

build_steps = ["pip3 install -r /app/requirements.txt --break-system-packages"]

entrypoint = ["bash", "-c", "python3 /app/main.py"]

[base_image]
api_url = "https://registry-1.docker.io"
service = "registry.docker.io"
oauth_url = "https://auth.docker.io/token"
auth_type = "repository"
auth_name = "luxonis/oakapp-base"
image_name = "luxonis/oakapp-base"
image_tag = "1.2.6"
```

If you are working with Luxonis Hub as is the case in the "Camera + NN + HUB (default)" example you will need to authenticate with
Hub API Key. The simplest way to do that safely is to create an `.env` file in the root folder of the app and insert:

```bash
# content of .env file
DEPTHAI_HUB_API_KEY=<INSERT_YOUR_HUB_APIKEY_HERE>
```

To get the API Key you will first need to create a Luxonis Hub account and then [navigate to team
settings](https://hub.luxonis.com/team-settings?view=page) and click `Create API Key` button.

This is safe because `.env` files are automatically ignored by git so there is no danger of uploading your private API Key to a
public repo where everybody can see it. Variables in `.env` files are set up by the `dotenv` library, and authentication is then
automatically done with the key stored in the `DEPTHAI_HUB_API_KEY` environment variable. Please check our [API Key Security -
Good Practices](https://docs.luxonis.com/software-v3/oak-apps/apikey-good-practices.md) page to get to know other examples for
safely passing API Keys to apps.

Now that you have your `main.py` and `oakapp.toml`, you can deploy your application in one of these ways:

### Standalone

This is the simplest option. Just run the following command in the same directory as your main.py and oakapp.toml files:

```bash
oakctl app run .
```

This command builds your app into a container and runs it directly on the OAK device, with no host-side app process required.
Results can be viewed with the visualizer webapp at `http://<device-ip>:8082`.

### Peripheral

This option is for when you want to run your application from your host machine. No containerization is needed in this mode, but
you need a steady connection to the device. To run your application in peripheral mode, run the following command:

```bash
python3 main.py
```

Results can be viewed with the visualizer webapp at `http://<host-ip>:8082`.

### Continue developing

Follow the tutorials and guides in OAK Apps section to continue developing your app.

[Open OAK Apps overview](https://docs.luxonis.com/software-v3/oak-apps.md)

### Publish the app to Luxonis Hub

Build and publish the app so your team can install it from Hub.

[Go to app publishing](https://docs.luxonis.com/cloud/features/application-management/uploading-applications.md)
