diff --git a/06_gpu_and_ml/langchains/potus_speech_qanda.py b/06_gpu_and_ml/langchains/potus_speech_qanda.py index 38d6eed95..4c67221b9 100644 --- a/06_gpu_and_ml/langchains/potus_speech_qanda.py +++ b/06_gpu_and_ml/langchains/potus_speech_qanda.py @@ -1,6 +1,5 @@ # --- # args: ["--query", "How many oil barrels were released from reserves?"] -# deploy: true # env: {"MODAL_ENVIRONMENT": "main"} # --- @@ -232,7 +231,7 @@ def cli(query: str, show_sources: bool = False): # ```bash # curl --get \ # --data-urlencode "query=What did the president say about Justice Breyer" \ -# https://modal-labs--example-langchain-qanda-web.modal.run +# https://modal-labs--example-langchain-qanda-web.modal.run # your URL here # ``` # ```json diff --git a/06_gpu_and_ml/llm-serving/download_llama.py b/06_gpu_and_ml/llm-serving/download_llama.py index c7da2cc4d..0ed01d9c5 100644 --- a/06_gpu_and_ml/llm-serving/download_llama.py +++ b/06_gpu_and_ml/llm-serving/download_llama.py @@ -1,6 +1,5 @@ # --- # args: ["--force-download"] -# env: {"MODAL_ENVIRONMENT": "main"} # --- import modal @@ -30,9 +29,9 @@ app = modal.App( image=image, - secrets=[ - modal.Secret.from_name("huggingface-secret", required_keys=["HF_TOKEN"]) - ], + # secrets=[ # add a Hugging Face Secret if you need to download a gated model + # modal.Secret.from_name("huggingface-secret", required_keys=["HF_TOKEN"]) + # ], ) diff --git a/06_gpu_and_ml/llm-serving/trtllm_llama.py b/06_gpu_and_ml/llm-serving/trtllm_llama.py index 154275598..9bd622cc3 100644 --- a/06_gpu_and_ml/llm-serving/trtllm_llama.py +++ b/06_gpu_and_ml/llm-serving/trtllm_llama.py @@ -1,6 +1,5 @@ # --- # deploy: true -# env: {"MODAL_ENVIRONMENT": "main"} # --- # # Serverless TensorRT-LLM (LLaMA 3 8B) diff --git a/06_gpu_and_ml/llm-serving/vllm_inference.py b/06_gpu_and_ml/llm-serving/vllm_inference.py index 54ed82b8f..b4672c269 100644 --- a/06_gpu_and_ml/llm-serving/vllm_inference.py +++ b/06_gpu_and_ml/llm-serving/vllm_inference.py @@ -1,7 +1,6 @@ # --- # cmd: ["modal", "serve", "06_gpu_and_ml/llm-serving/vllm_inference.py"] # pytest: false -# env: {"MODAL_ENVIRONMENT": "main"} # --- # # Run OpenAI-compatible LLM inference with LLaMA 3.1-8B and vLLM diff --git a/06_gpu_and_ml/obj_detection_webcam/webcam.py b/06_gpu_and_ml/obj_detection_webcam/webcam.py index 85c24c9f2..d6aa69cf7 100644 --- a/06_gpu_and_ml/obj_detection_webcam/webcam.py +++ b/06_gpu_and_ml/obj_detection_webcam/webcam.py @@ -1,7 +1,6 @@ # --- # cmd: ["modal", "serve", "06_gpu_and_ml/obj_detection_webcam/webcam.py"] # deploy: true -# env: {"MODAL_ENVIRONMENT": "main"} # --- # # Real-time object detection via webcam @@ -12,12 +11,12 @@ # The Modal web endpoint in turn calls a Modal function that runs the actual model. # If you run this, it will look something like this: -# + # ![webcam](./webcam.png) # ## Live demo -# [Take a look at the deployed app](https://modal-labs--example-webcam-object-detection-fastapi-app.modal.run/). +# [Take a look at the deployed app](https://modal-labs-examples--example-webcam-object-detection.modal.run/). # A couple of caveats: # * This is not optimized for latency: every prediction takes about 1s, and @@ -42,15 +41,14 @@ # and a system font for drawing. # This example uses the `facebook/detr-resnet-50` pre-trained model, which is downloaded -# once at image build time using the `@build` hook and saved into the image. 'Baking' -# models into the `modal.Image` at build time provided the fastest cold start. +# once at image build time using the `@build` hook and saved into the image. model_repo_id = "facebook/detr-resnet-50" app = modal.App("example-webcam-object-detection") image = ( - modal.Image.debian_slim() + modal.Image.debian_slim(python_version="3.12") .pip_install( "huggingface-hub==0.16.4", "Pillow", @@ -173,7 +171,7 @@ def detect(self, img_data_in): image=modal.Image.debian_slim().pip_install("fastapi[standard]"), mounts=[modal.Mount.from_local_dir(static_path, remote_path="/assets")], ) -@modal.asgi_app() +@modal.asgi_app(label="example-webcam-object-detection") def fastapi_app(): from fastapi import FastAPI, Request, Response from fastapi.staticfiles import StaticFiles diff --git a/07_web_endpoints/fasthtml-checkboxes/cbx_load_test.py b/07_web_endpoints/fasthtml-checkboxes/cbx_load_test.py index 6a944444f..47ed5028a 100644 --- a/07_web_endpoints/fasthtml-checkboxes/cbx_load_test.py +++ b/07_web_endpoints/fasthtml-checkboxes/cbx_load_test.py @@ -1,7 +1,3 @@ -# --- -# env: {"MODAL_ENVIRONMENT": "main"} -# --- - import os from datetime import datetime from pathlib import Path @@ -10,14 +6,16 @@ if modal.is_local(): workspace = modal.config._profile + environment = modal.config.config["environment"] else: workspace = os.environ["MODAL_WORKSPACE"] + environment = os.environ["MODAL_ENVIRONMENT"] image = ( modal.Image.debian_slim(python_version="3.12") .pip_install("locust~=2.29.1", "beautifulsoup4~=4.12.3", "lxml~=5.3.0") - .env({"MODAL_WORKSPACE": workspace}) + .env({"MODAL_WORKSPACE": workspace, "MODAL_ENVIRONMENT": environment}) .copy_local_file( Path(__file__).parent / "cbx_locustfile.py", remote_path="/root/locustfile.py", @@ -38,7 +36,7 @@ app = modal.App("loadtest-checkbox", image=image, volumes={remote_path: volume}) workers = 8 -host = f"https://{workspace}--example-checkboxes-web.modal.run" +host = f"https://{workspace}{'-' + environment if environment else ''}--example-checkboxes-web.modal.run" csv_file = OUT_DIRECTORY / "stats.csv" default_args = [ "-H", diff --git a/07_web_endpoints/fasthtml-checkboxes/fasthtml_checkboxes.py b/07_web_endpoints/fasthtml-checkboxes/fasthtml_checkboxes.py index def199f38..2bf2e70b9 100644 --- a/07_web_endpoints/fasthtml-checkboxes/fasthtml_checkboxes.py +++ b/07_web_endpoints/fasthtml-checkboxes/fasthtml_checkboxes.py @@ -1,13 +1,12 @@ # --- # cmd: ["modal", "serve", "07_web_endpoints.fasthtml-checkboxes.fasthtml_checkboxes"] # deploy: true -# env: {"MODAL_ENVIRONMENT": "main"} # mypy: ignore-errors # --- # # Deploy 100,000 multiplayer checkboxes on Modal with FastHTML -# ![Screenshot of FastHTML Checkboxes UI](./ui.png) +# [![Screenshot of FastHTML Checkboxes UI](./ui.png)](https://modal-labs-examples--example-checkboxes-web.modal.run) # This example shows how you can deploy a multiplayer checkbox game with FastHTML on Modal. diff --git a/07_web_endpoints/streaming.py b/07_web_endpoints/streaming.py index 0448a5aba..16117a940 100644 --- a/07_web_endpoints/streaming.py +++ b/07_web_endpoints/streaming.py @@ -1,10 +1,9 @@ # --- # cmd: ["modal", "serve", "07_web_endpoints/streaming.py"] -# deploy: true -# env: {"MODAL_ENVIRONMENT": "main"} # --- -# # Deploy FastAPI app with streaming results with Modal +# # Deploy a FastAPI app with streaming responses + # This example shows how you can deploy a [FastAPI](https://fastapi.tiangolo.com/) app with Modal that streams results back to the client. import asyncio @@ -32,7 +31,7 @@ async def fake_video_streamer(): # ASGI app with streaming handler. -# + # This `fastapi_app` also uses the fake video streamer async generator, # passing it directly into `StreamingResponse`. @@ -87,19 +86,14 @@ def mapped(): ) -# A collection of basic examples of a webhook streaming response. -# -# -# ``` +# To try for yourself, run + +# ```shell # modal serve streaming.py # ``` -# -# To try out the webhook, ensure that your client is not buffering the server response + +# and then send requests to the URLs that appear in the terminal output. + +# Make sure that your client is not buffering the server response # until it gets newline (\n) characters. By default browsers and `curl` are buffering, # though modern browsers should respect the "text/event-stream" content type header being set. -# -# ```shell -# curl --no-buffer https://modal-labs--example-fastapi-streaming-fastapi-app.modal.run -# curl --no-buffer https://modal-labs--example-fastapi-streaming-hook.modal.run -# curl --no-buffer https://modal-labs--example-fastapi-streaming-mapped.modal.run -# ```` diff --git a/09_job_queues/doc_ocr_jobs.py b/09_job_queues/doc_ocr_jobs.py index 8926e8944..5bc20052b 100644 --- a/09_job_queues/doc_ocr_jobs.py +++ b/09_job_queues/doc_ocr_jobs.py @@ -1,6 +1,5 @@ # --- # deploy: true -# env: {"MODAL_ENVIRONMENT": "main"} # --- # # Document OCR job queue @@ -15,7 +14,7 @@ # Our job queue will handle a single task: running OCR transcription for images. # We'll make use of a pre-trained Document Understanding model using the # [`donut`](https://github.com/clovaai/donut) package. Try -# it out for yourself [here](https://modal-labs--example-doc-ocr-webapp-wrapper.modal.run/). +# it out for yourself [here](https://modal-labs-examples--example-doc-ocr-webapp-wrapper.modal.run/). # ![receipt parser frontend](./receipt_parser_frontend_2.jpg) diff --git a/09_job_queues/doc_ocr_webapp.py b/09_job_queues/doc_ocr_webapp.py index 289413108..9621266a4 100644 --- a/09_job_queues/doc_ocr_webapp.py +++ b/09_job_queues/doc_ocr_webapp.py @@ -1,23 +1,22 @@ # --- # deploy: true # cmd: ["modal", "serve", "09_job_queues/doc_ocr_webapp.py"] -# env: {"MODAL_ENVIRONMENT": "main"} # --- -# + # # Document OCR web app -# + # This tutorial shows you how to use Modal to deploy a fully serverless # [React](https://reactjs.org/) + [FastAPI](https://fastapi.tiangolo.com/) application. # We're going to build a simple "Receipt Parser" web app that submits OCR transcription # tasks to a separate Modal app defined in the [Job Queue tutorial](https://modal.com/docs/examples/doc_ocr_jobs), # polls until the task is completed, and displays # the results. Try it out for yourself -# [here](https://modal-labs--example-doc-ocr-webapp-wrapper.modal.run/). -# +# [here](https://modal-labs-examples--example-doc-ocr-webapp-wrapper.modal.run/). + # ![receipt parser frontend](./receipt_parser_frontend.jpg) # ## Basic setup -# + # Let's get the imports out of the way and define a [`App`](https://modal.com/docs/reference/modal.App). from pathlib import Path @@ -34,14 +33,14 @@ web_app = fastapi.FastAPI() # ## Define endpoints -# + # We need two endpoints: one to accept an image and submit it to the Modal job queue, # and another to poll for the results of the job. -# + # In `parse`, we're going to submit tasks to the function defined in the [Job # Queue tutorial](https://modal.com/docs/examples/doc_ocr_jobs), so we import it first using # [`Function.lookup`](https://modal.com/docs/reference/modal.Function#lookup). -# + # We call [`.spawn()`](https://modal.com/docs/reference/modal.Function#spawn) on the function handle # we imported above to kick off our function without blocking on the results. `spawn` returns # a unique ID for the function call, which we then use @@ -87,7 +86,9 @@ async def poll_results(call_id: str): @app.function( - image=modal.Image.debian_slim().pip_install("fastapi[standard]==0.115.4"), + image=modal.Image.debian_slim(python_version="3.12").pip_install( + "fastapi[standard]==0.115.4" + ), mounts=[modal.Mount.from_local_dir(assets_path, remote_path="/assets")], ) @modal.asgi_app() @@ -100,28 +101,28 @@ def wrapper(): # ## Running -# + # While developing, you can run this as an ephemeral app by executing the command -# + # ```shell # modal serve doc_ocr_webapp.py # ``` -# + # Modal watches all the mounted files and updates the app if anything changes. -# See [these docs](https://www.notion.so/modal-com/Simple-RAG-chat-with-PDF-app-a20fc171f0fc415cb320606f737e6db4?pvs=4) +# See [these docs](https://modal.com/docs/guide/webhooks#developing-with-modal-serve) # for more details. -# + # ## Deploy -# + # To deploy your application, run -# + # ```shell # modal deploy doc_ocr_webapp.py # ``` -# + # That's all! -# + # If successful, this will print a URL for your app that you can navigate to in # your browser 🎉 . -# + # ![receipt parser processed](./receipt_parser_frontend_2.jpg) diff --git a/10_integrations/covid_datasette.py b/10_integrations/covid_datasette.py index b1ab97d9a..e29030c8f 100644 --- a/10_integrations/covid_datasette.py +++ b/10_integrations/covid_datasette.py @@ -1,6 +1,5 @@ # --- # deploy: true -# env: {"MODAL_ENVIRONMENT": "main"} # --- # # Publish interactive datasets with Datasette @@ -9,7 +8,7 @@ # This example shows how to serve a Datasette application on Modal. The published dataset # is COVID-19 case data from Johns Hopkins University which is refreshed daily. -# Try it out for yourself [here](https://modal-labs--example-covid-datasette-ui.modal.run). +# Try it out for yourself [here](https://modal-labs-examples--example-covid-datasette-ui.modal.run). # Some Modal features it uses: diff --git a/10_integrations/dbt/dbt_duckdb.py b/10_integrations/dbt/dbt_duckdb.py index ea9537e8e..f4605dcc2 100644 --- a/10_integrations/dbt/dbt_duckdb.py +++ b/10_integrations/dbt/dbt_duckdb.py @@ -258,9 +258,9 @@ def serve_dbt_docs(): # ``` # If you navigate to the output URL, you should see something like -# [![example dbt docs](./dbt_docs.png)](https://modal-labs--example-dbt-duckdb-s3-serve-dbt-docs.modal.run) +# [![example dbt docs](./dbt_docs.png)](https://modal-labs-examples--example-dbt-duckdb-s3-serve-dbt-docs.modal.run) -# You can also check out our instance of the docs [here](https://modal-labs--example-dbt-duckdb-s3-serve-dbt-docs.modal.run). +# You can also check out our instance of the docs [here](https://modal-labs-examples--example-dbt-duckdb-s3-serve-dbt-docs.modal.run). # The app will be served "serverlessly" -- it will automatically scale up or down # during periods of increased or decreased usage, and you won't be charged at all # when it has scaled to zero. diff --git a/10_integrations/dbt_modal_inference/dbt_modal_inference.py b/10_integrations/dbt_modal_inference/dbt_modal_inference.py index 6124fda41..f7589caf4 100644 --- a/10_integrations/dbt_modal_inference/dbt_modal_inference.py +++ b/10_integrations/dbt_modal_inference/dbt_modal_inference.py @@ -1,24 +1,20 @@ -# --- -# env: {"MODAL_ENVIRONMENT": "main"} -# --- - # # LLM inference within your data warehouse using dbt python models -# + # In this example we demonstrate how you could combine [dbt's python models](https://docs.getdbt.com/docs/build/python-models) # with LLM inference models powered by Modal, allowing you to run serverless gpu workloads within dbt. -# + # This example runs [dbt](https://docs.getdbt.com/docs/introduction) with a [DuckDB](https://duckdb.org) # backend directly on top of Modal, but could be translated to run on any dbt-compatible # database that supports python models. Similarly you could make these requests from UDFs # directly in SQL instead if you don't want to use dbt's python models. -# + # In this example we use an LLM deployed in a previous example: [Serverless TensorRT-LLM (LLaMA 3 8B)](https://modal.com/docs/examples/trtllm_llama) # but you could easily swap this for whichever Modal Function you wish. We use this to classify the sentiment # for free-text product reviews and aggregate them in subsequent dbt sql models. These product names, descriptions and reviews # were also generated by an LLM running on Modal! -# + # ## Configure Modal and dbt -# + # We set up the environment variables necessary for dbt and # create a slim debian and install the packages necessary to run. @@ -73,17 +69,22 @@ dbt_vol = modal.Volume.from_name("dbt-inference-vol", create_if_missing=True) # ## Run dbt in a serverless Modal Function -# + # With Modal it's easy to run python code serverless # and with dbt's [programmatic invocations](https://docs.getdbt.com/reference/programmatic-invocations) # you can easily run dbt from python instead of using the command line -# + # Using the above configuration we can invoke dbt from Modal -# and use this to run transformations in our warehouse +# and use this to run transformations in our warehouse. + # The `dbt_run` function does a few things, it: + # 1. creates the directories for storing the DuckDB database and dbt target files + # 2. gets a reference to a deployed Modal Function that serves an LLM inference endpoint + # 3. runs dbt with a variable for the inference url + # 4. prints the output of the final dbt table in the DuckDB parquet output @@ -117,10 +118,14 @@ def dbt_run() -> None: ).show() -# Running the Modal Function: -# `modal run dbt_modal_inference.py` +# Running the Modal Function with + +# ```sh +# modal run dbt_modal_inference.py +# ``` + # will result in something like: -# + # ``` # 21:25:21 Running with dbt=1.8.4 # 21:25:21 Registered adapter: duckdb=1.8.1 @@ -163,27 +168,27 @@ def dbt_run() -> None: # │ 11 rows 4 columns │ # └──────────────────────────────────────────────────────────────────────┘ # ``` -# + # Here we can see that the LLM classified the results into three different categories # that we could then aggregate in a subsequent sql model! -# + # ## Python dbt model -# + # The python dbt model in [`dbt_modal_inference_proj/models/product_reviews_sentiment.py`](https://github.com/modal-labs/modal-examples/blob/main/10_integrations/dbt_modal_inference/dbt_modal_inference_proj/models/product_reviews_sentiment.py) is quite simple. -# + # It defines a python dbt model that reads a record batch of product reviews, # generates a prompt for each review and makes an inference call to a Modal Function # that serves an LLM inference endpoint. It then stores the output in a new column # and writes the data to a parquet file. -# + # And it's that simple to call a Modal web endpoint from dbt! -# + # ## View the stored output -# + # Since we're using a [Volume](https://modal.com/docs/guide/volumes) for storing our dbt target results # and our DuckDB parquet files # you can view the results and use them outside the Modal Function too. -# + # View the target directory by: # ```sh # modal volume ls dbt-inference-vol target/ @@ -201,7 +206,7 @@ def dbt_run() -> None: # │ target/graph.gpickle │ file │ 2024-07-19 23:25 CEST │ 15.7 KiB │ # └───────────────────────────────┴──────┴───────────────────────┴───────────┘ # ``` -# + # And the db directory: # ```sh # modal volume ls dbt-inference-vol db/ diff --git a/10_integrations/pushgateway.py b/10_integrations/pushgateway.py index 895e113e9..1e6b89e74 100644 --- a/10_integrations/pushgateway.py +++ b/10_integrations/pushgateway.py @@ -1,20 +1,20 @@ # --- # deploy: true # cmd: ["modal", "serve", "10_integrations/pushgateway.py"] -# env: {"MODAL_ENVIRONMENT": "main"} # --- + # # Publish custom metrics with Prometheus Pushgateway -# + # This example shows how to publish custom metrics to a Prometheus instance with Modal. # Due to a Modal container's ephemeral nature, it's not a good fit for a traditional # scraping-based Prometheus setup. Instead, we'll use a [Prometheus Pushgateway](https://github.com/prometheus/pushgateway) # to collect and store metrics from our Modal container. We can run the Pushgateway in Modal # as a separate process and have our application push metrics to it. -# + # ![Prometheus Pushgateway diagram](./pushgateway_diagram.png) -# + # ## Install Prometheus Pushgateway -# + # Since the official Prometheus pushgateway image does not have Python installed, we'll # use a custom image that includes Python to push metrics to the Pushgateway. Pushgateway # ships a single binary, so it's easy to get it into a Modal container. @@ -39,39 +39,41 @@ ) # ## Start the Pushgateway -# + # We'll start the Pushgateway as a separate Modal app. This way, we can run the Pushgateway # in the background and have our main app push metrics to it. We'll use the `web_server` # decorator to expose the Pushgateway's web interface. Note that we must set `concurrency_limit=1` # as the Pushgateway is a single-process application. If we spin up multiple instances, they'll # conflict with each other. -# + # This is an example configuration, but a production-ready configuration will differ in two respects: + # 1. You should set up authentication for the Pushgateway. Pushgateway has support for [basic authentication](https://github.com/prometheus/pushgateway/blob/42c4075fc5e2564031f2852885cdb2f5d570f672/README.md#tls-and-basic-authentication) # out of the box. If you need more advanced authentication, consider using a [web endpoint with authentication](https://modal.com/docs/guide/webhooks#authentication) # which proxies requests to the Pushgateway. + # 2. The Pushgateway should listen on a [custom domain](https://modal.com/docs/guide/webhook-urls#custom-domains). # This will allow you to configure Prometheus to scrape metrics from a predictable URL rather than # the autogenerated URL Modal assigns to your app. gw_app = modal.App( - "pushgateway-example", + "example-pushgateway-server", image=gw_image, ) @gw_app.function(keep_warm=1, concurrency_limit=1) @modal.web_server(9091) -def run_pushgateway(): +def serve(): subprocess.Popen("/usr/local/bin/pushgateway") # ## Push metrics to the Pushgateway -# + # Now that we have the Pushgateway running, we can push metrics to it. We'll use the `prometheus_client` # library to create a simple counter and push it to the Pushgateway. This example is a simple counter, # but you can push any metric type to the Pushgateway. -# + # Note that we use the `grouping_key` argument to distinguish between different instances of the same # metric. This is useful when you have multiple instances of the same app pushing metrics to the Pushgateway. # Without this, the Pushgateway will overwrite the metric with the latest value. @@ -80,7 +82,7 @@ def run_pushgateway(): "prometheus-client==0.20.0", "fastapi[standard]==0.115.4" ) app = modal.App( - "client-example", + "example-pushgateway", image=client_image, ) @@ -98,7 +100,7 @@ class ExampleClientApplication: @modal.enter() def init(self): self.registry = CollectorRegistry() - self.web_url = run_pushgateway.web_url + self.web_url = serve.web_url self.instance_id = os.environ["MODAL_TASK_ID"] self.counter = Counter( "hello_counter", @@ -116,7 +118,7 @@ def cleanup(self): grouping_key={"instance": self.instance_id}, ) - @modal.web_endpoint() + @modal.web_endpoint(label="hello-pushgateway") def hello(self): self.counter.inc() push_to_gateway( @@ -130,43 +132,40 @@ def hello(self): app.include(gw_app) -# Now, we can deploy the `client-example` app and see the metrics in the Pushgateway's web interface. +# Now, we can deploy the app and see the metrics in the Pushgateway's web interface. # ```shell # $ modal deploy pushgateway.py # ✓ Created objects. -# ├── 🔨 Created mount -# │ /home/runner/work/modal-examples/modal-examples/10_integrations/pushgateway.py +# ├── 🔨 Created mount /home/ec2-user/modal/examples/10_integrations/pushgateway.py # ├── 🔨 Created function ExampleClientApplication.*. -# ├── 🔨 Created web function run_pushgateway => -# │ https://modal-labs--client-example-run-pushgateway.modal.run -# └── 🔨 Created web function ExampleClientApplication.hello => -# https://modal-labs--client-example-exampleclientapplication-hello.modal.run +# ├── 🔨 Created web function serve => https://modal-labs-examples--example-pushgateway-serve.modal.run +# └── 🔨 Created web endpoint for ExampleClientApplication.hello => https://modal-labs-examples--hello-pushgateway.modal.run # ✓ App deployed! 🎉 # ``` -# -# You can now go to both the [client application](https://modal-labs--client-example-exampleclientapplication-hello.modal.run) -# and [Pushgateway](https://modal-labs--client-example-run-pushgateway.modal.run) URLs to see the metrics being pushed. -# + +# You can now go to both the [client application](https://modal-labs-examples--hello-pushgateway.modal.run) +# and [Pushgateway](https://modal-labs-examples--example-pushgateway-serve.modal.run) URLs to see the metrics being pushed. + # ## Hooking up Prometheus -# + # Now that we have metrics in the Pushgateway, we can configure Prometheus to scrape them. This # is as simple as adding a new job to your Prometheus configuration. Here's an example configuration # snippet: -# + # ```yaml # scrape_configs: # - job_name: 'pushgateway' # honor_labels: true # required so that the instance label is preserved # static_configs: -# - targets: ['modal-labs--client-example-run-pushgateway.modal.run'] +# - targets: ['modal-labs-examples--example-pushgateway-serve.modal.run'] # ``` -# + # Note that the target will be different if you have a custom domain set up for the Pushgateway, # and you may need to configure authentication. -# + # Once you've added the job to your Prometheus configuration, Prometheus will start scraping metrics # from the Pushgateway. You can then use Grafana or another visualization tool to create dashboards # and alerts based on these metrics! -# + # ![Grafana example](./pushgateway_grafana.png) diff --git a/10_integrations/streamlit/serve_streamlit.py b/10_integrations/streamlit/serve_streamlit.py index 6bb9d4e8b..deeb340aa 100644 --- a/10_integrations/streamlit/serve_streamlit.py +++ b/10_integrations/streamlit/serve_streamlit.py @@ -1,18 +1,18 @@ # --- # deploy: true # cmd: ["modal", "serve", "10_integrations/streamlit/serve_streamlit.py"] -# env: {"MODAL_ENVIRONMENT": "main"} # --- -# + # # Run and share Streamlit apps -# + # This example shows you how to run a Streamlit app with `modal serve`, and then deploy it as a serverless web app. -# + # ![example streamlit app](./streamlit.png) -# + # This example is structured as two files: -# + # 1. This module, which defines the Modal objects (name the script `serve_streamlit.py` locally). + # 2. `app.py`, which is any Streamlit script to be mounted into the Modal # function ([download script](https://github.com/modal-labs/modal-examples/blob/main/10_integrations/streamlit/app.py)). @@ -23,7 +23,7 @@ import modal # ## Define container dependencies -# + # The `app.py` script imports three third-party packages, so we include these in the example's # image definition. @@ -34,7 +34,7 @@ app = modal.App(name="example-modal-streamlit", image=image) # ## Mounting the `app.py` script -# + # We can just mount the `app.py` script inside the container at a pre-defined path using a Modal # [`Mount`](https://modal.com/docs/guide/local-data#mounting-directories). @@ -52,7 +52,7 @@ ) # ## Spawning the Streamlit server -# + # Inside the container, we will run the Streamlit server in a background subprocess using # `subprocess.Popen`. We also expose port 8000 using the `@web_server` decorator. @@ -69,19 +69,19 @@ def run(): # ## Iterate and Deploy -# + # While you're iterating on your screamlit app, you can run it "ephemerally" with `modal serve`. This will # run a local process that watches your files and updates the app if anything changes. -# + # ```shell # modal serve serve_streamlit.py # ``` -# + # Once you're happy with your changes, you can deploy your application with -# + # ```shell # modal deploy serve_streamlit.py # ``` -# + # If successful, this will print a URL for your app that you can navigate to from # your browser 🎉 .