Skip to main content

Build AI Assistants using language models

Project description

phidata

Build AI Assistants using function calling

version pythonversion downloads build-status

โœจ What is phidata?

Phidata is a framework for building AI Assistants by letting LLMs call functions and take actions.

This is a powerful paradigm that allows LLMs to solve complex problems by intelligently choosing their course of action -- similar to how a human would solve a problem.

For example, to answer questions from a database, an Assistant will first call a function to show tables, then describe those tables and finally, run a query to get the answer.

assistants-explanation

Assistants come with built-in memory, knowledge, storage and tools, making it easy to build RAG, Autonomous or Multimodal applications like:

  • Knowledge Assistants: Answer questions from documents (PDFs, text)
  • Data Assistants: Analyze data by running SQL queries.
  • Python Assistants: Perform tasks by running python code.
  • Customer Assistants: Answer customer queries using product descriptions and purchase history.
  • Research Assistants: Perform research and summarize findings.
  • Marketing Assistants: Provide marketing insights, copywriting and content ideas.
  • Customer Assistants: Answer customer queries using product descriptions and purchase history.
  • Travel Assistants: Help plan travel by researching destinations, flight and hotel prices.
  • Meal Prep Assistants: Help plan meals by researching recipes and adding ingredients to shopping lists.

Templates

After building an Assistant, we serve it using Streamlit, FastApi or Django to build an AI application. Instead of wiring tools manually, phidata provides pre-built templates for AI Apps that you can customise and make your own. Here's how they work:

  • Create your codebase using a template: phi ws create
  • Run your app locally: phi ws up
  • Run your app on AWS: phi ws up prd:aws

Live Demos

Phidata Tutorial

๐Ÿ‘ฉโ€๐Ÿ’ป Getting Started

Installation

  • Open the Terminal and create an ai directory with a python virtual environment.
mkdir ai && cd ai

python3 -m venv aienv
source aienv/bin/activate
  • Install phidata
pip install -U phidata

Create a Simple Assistant

  • Create a file assistant.py and install openai using pip install openai
from phi.assistant import Assistant

assistant = Assistant(description="You help people with their health and fitness goals.")
assistant.print_response("Share a quick healthy breakfast recipe.")
  • Run the assistant.py file
python assistant.py

Output

โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ Message  โ”‚ Share a quick healthy breakfast recipe.                           โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Response โ”‚ Sure! Here's a quick and healthy breakfast recipe for you:        โ”‚
โ”‚ (3.3s)   โ”‚                                                                   โ”‚
โ”‚          โ”‚ Greek Yogurt Parfait:                                             โ”‚
โ”‚          โ”‚                                                                   โ”‚
โ”‚          โ”‚ Ingredients:                                                      โ”‚
โ”‚          โ”‚                                                                   โ”‚
โ”‚          โ”‚  โ€ข 1 cup Greek yogurt                                             โ”‚
โ”‚          โ”‚  โ€ข 1/2 cup fresh mixed berries (strawberries, blueberries,        โ”‚
โ”‚          โ”‚    raspberries)                                                   โ”‚
โ”‚          โ”‚  โ€ข 1/4 cup granola                                                โ”‚
โ”‚          โ”‚  โ€ข 1 tablespoon honey                                             โ”‚
โ”‚          โ”‚  โ€ข Optional: chia seeds or sliced almonds for extra nutrients     โ”‚
โ”‚          โ”‚                                                                   โ”‚
โ”‚          โ”‚ Instructions:                                                     โ”‚
โ”‚          โ”‚                                                                   โ”‚
โ”‚          โ”‚  1 In a glass or bowl, layer Greek yogurt, mixed berries, and     โ”‚
โ”‚          โ”‚    granola.                                                       โ”‚
โ”‚          โ”‚  2 Drizzle honey on top for some natural sweetness.               โ”‚
โ”‚          โ”‚  3 Optional: Sprinkle with chia seeds or sliced almonds for added โ”‚
โ”‚          โ”‚    texture and nutrients.                                         โ”‚
โ”‚          โ”‚                                                                   โ”‚
โ”‚          โ”‚ Enjoy your nutritious and delicious Greek yogurt parfait!         โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

Create a Data Assistant

The DuckDbAssistant can perform data analysis using SQL queries.

  • Create a file data_assistant.py and install duckdb using pip install duckdb
import json
from phi.assistant.duckdb import DuckDbAssistant

duckdb_assistant = DuckDbAssistant(
    semantic_model=json.dumps({
        "tables": [
            {
                "name": "movies",
                "description": "Contains information about movies from IMDB.",
                "path": "https://phidata-public.s3.amazonaws.com/demo_data/IMDB-Movie-Data.csv",
            }
        ]
    }),
)

duckdb_assistant.print_response("What is the average rating of movies? Show me the SQL.")
  • Run the data_assistant.py file
python data_assistant.py
  • See it work through the problem

Output

INFO     Running: SHOW TABLES
INFO     Running: CREATE TABLE IF NOT EXISTS 'movies'
         AS SELECT * FROM
         'https://phidata-public.s3.amazonaws.com/demo_
         data/IMDB-Movie-Data.csv'
INFO     Running: DESCRIBE movies
INFO     Running: SELECT AVG(Rating) AS average_rating
         FROM movies
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ Message  โ”‚ What is the average rating of movies? Show me the SQL. โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Response โ”‚ The average rating of movies in the dataset is 6.72.   โ”‚
โ”‚ (7.6s)   โ”‚                                                        โ”‚
โ”‚          โ”‚ Here is the SQL query used to calculate the average    โ”‚
โ”‚          โ”‚ rating:                                                โ”‚
โ”‚          โ”‚                                                        โ”‚
โ”‚          โ”‚                                                        โ”‚
โ”‚          โ”‚  SELECT AVG(Rating) AS average_rating                  โ”‚
โ”‚          โ”‚  FROM movies;                                          โ”‚
โ”‚          โ”‚                                                        โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

Create a Python Assistant

The PythonAssistant can perform virtually any task using python code.

  • Create a file python_assistant.py and install pandas using pip install pandas
from phi.assistant.python import PythonAssistant
from phi.file.local.csv import CsvFile

python_assistant = PythonAssistant(
    files=[
        CsvFile(
            path="https://phidata-public.s3.amazonaws.com/demo_data/IMDB-Movie-Data.csv",
            description="Contains information about movies from IMDB.",
        )
    ],
    pip_install=True,
    show_tool_calls=True,
)

python_assistant.print_response("What is the average rating of movies?")
  • Run the python_assistant.py file
python python_assistant.py
  • See it work through the problem

Output

WARNING  PythonTools can run arbitrary code, please provide human supervision.
INFO     Saved: /Users/zu/ai/average_rating
INFO     Running /Users/zu/ai/average_rating
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ Message  โ”‚ What is the average rating of movies?                             โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Response โ”‚                                                                   โ”‚
โ”‚ (4.1s)   โ”‚  โ€ข Running: save_to_file_and_run(file_name=average_rating,        โ”‚
โ”‚          โ”‚    code=..., variable_to_return=average_rating)                   โ”‚
โ”‚          โ”‚                                                                   โ”‚
โ”‚          โ”‚ The average rating of movies is approximately 6.72.               โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

๐Ÿš€ More Examples

Structured output from a Movie Assistant

One of our favorite features is generating structured data (i.e. a pydantic model) from sparse information. Meaning we can use Assistants to return pydantic models and generate content which previously could not be possible. In this example, our movie assistant generates an object of the MovieScript class.

  • Create a file movie_assistant.py
from typing import List
from pydantic import BaseModel, Field
from rich.pretty import pprint
from phi.assistant import Assistant


class MovieScript(BaseModel):
    setting: str = Field(..., description="Provide a nice setting for a blockbuster movie.")
    ending: str = Field(..., description="Ending of the movie. If not available, provide a happy ending.")
    genre: str = Field(..., description="Genre of the movie. If not available, select action, thriller or romantic comedy.")
    name: str = Field(..., description="Give a name to this movie")
    characters: List[str] = Field(..., description="Name of characters for this movie.")
    storyline: str = Field(..., description="3 sentence storyline for the movie. Make it exciting!")


movie_assistant = Assistant(
    description="You help people write movie ideas.",
    output_model=MovieScript,
)

pprint(movie_assistant.run("New York"))
  • Run the movie_assistant.py file
python movie_assistant.py
  • See how the assistant generates a structured output
MovieScript(
โ”‚   setting='A bustling and vibrant New York City',
โ”‚   ending='The protagonist saves the city and reconciles with their estranged family.',
โ”‚   genre='action',
โ”‚   name='City Pulse',
โ”‚   characters=['Alex Mercer', 'Nina Castillo', 'Detective Mike Johnson'],
โ”‚   storyline='In the heart of New York City, a former cop turned vigilante, Alex Mercer, teams up with a street-smart activist, Nina Castillo, to take down a corrupt political figure who threatens to destroy the city. As they navigate through the intricate web of power and deception, they uncover shocking truths that push them to the brink of their abilities. With time running out, they must race against the clock to save New York and confront their own demons.'
)

Create a PDF Assistant with Knowledge & Storage

  • Knowledge Base: information that an Assistant can search to improve its responses. Uses a vector db.
  • Storage: provides long term memory for Assistants. Uses a database.

Let's run PgVector as it can provide both, knowledge and storage for our Assistants.

  • Install docker desktop for running PgVector in a container.
  • Create a file resources.py with the following contents
from phi.docker.app.postgres import PgVectorDb
from phi.docker.resources import DockerResources

# -*- PgVector running on port 5432:5432
vector_db = PgVectorDb(
    pg_user="ai",
    pg_password="ai",
    pg_database="ai",
    debug_mode=True,
)

# -*- DockerResources
dev_docker_resources = DockerResources(apps=[vector_db])
  • Start PgVector using
phi start resources.py
  • Create a file pdf_assistant.py and install libraries using pip install pgvector pypdf psycopg sqlalchemy
import typer
from rich.prompt import Prompt
from typing import Optional, List
from phi.assistant import Assistant
from phi.storage.assistant.postgres import PgAssistantStorage
from phi.knowledge.pdf import PDFUrlKnowledgeBase
from phi.vectordb.pgvector import PgVector

from resources import vector_db

knowledge_base = PDFUrlKnowledgeBase(
    urls=["https://www.family-action.org.uk/content/uploads/2019/07/meals-more-recipes.pdf"],
    vector_db=PgVector(
        collection="recipes",
        db_url=vector_db.get_db_connection_local(),
    ),
)

storage = PgAssistantStorage(
    table_name="recipe_assistant",
    db_url=vector_db.get_db_connection_local(),
)


def recipe_assistant(new: bool = False, user: str = "user"):
    run_id: Optional[str] = None

    if not new:
        existing_run_ids: List[str] = storage.get_all_run_ids(user)
        if len(existing_run_ids) > 0:
            run_id = existing_run_ids[0]

    assistant = Assistant(
        run_id=run_id,
        user_id=user,
        knowledge_base=knowledge_base,
        storage=storage,
        # use_tools=True adds functions to
        # search the knowledge base and chat history
        use_tools=True,
        show_tool_calls=True,
        # Uncomment the following line to use traditional RAG
        # add_references_to_prompt=True,
    )
    if run_id is None:
        run_id = assistant.run_id
        print(f"Started Run: {run_id}\n")
    else:
        print(f"Continuing Run: {run_id}\n")

    assistant.knowledge_base.load(recreate=False)
    while True:
        message = Prompt.ask(f"[bold] :sunglasses: {user} [/bold]")
        if message in ("exit", "bye"):
            break
        assistant.print_response(message)

if __name__ == "__main__":
    typer.run(recipe_assistant)
  • Run the pdf_assistant.py file
python pdf_assistant.py
  • Ask a question:
How do I make chicken tikka salad?
  • See how the Assistant searches the knowledge base and returns a response.
Result
Started Run: d28478ea-75ed-4710-8191-22564ebfb140

INFO     Loading knowledge base
INFO     Reading:
         https://www.family-action.org.uk/content/uploads/2019/07/meals-more-recipes.pdf
INFO     Loaded 82 documents to knowledge base
 ๐Ÿ˜Ž user : How do I make chicken tikka salad?
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ Message  โ”‚ How do I make chicken tikka salad?                                              โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ Response โ”‚                                                                                 โ”‚
โ”‚ (7.2s)   โ”‚  โ€ข Running: search_knowledge_base(query=chicken tikka salad)                    โ”‚
โ”‚          โ”‚                                                                                 โ”‚
โ”‚          โ”‚ I found a recipe for Chicken Tikka Salad that serves 2. Here are the            โ”‚
โ”‚          โ”‚ ingredients and steps:                                                          โ”‚
โ”‚          โ”‚                                                                                 โ”‚
โ”‚          โ”‚ Ingredients:                                                                    โ”‚

...
  • Message bye to exit, start the app again and ask:
What was my last message?

See how the assistant now maintains storage across sessions.

  • Run the pdf_assistant.py file with the --new flag to start a new run.
python pdf_assistant.py --new
  • Stop PgVector

Play around and then stop PgVector using phi stop resources.py

phi stop resources.py

Build an AI App using Streamlit, FastApi and PgVector

Phidata provides pre-built templates for AI Apps that you can use as a starting point. The general workflow is:

  • Create your codebase using a template: phi ws create
  • Run your app locally: phi ws up dev:docker
  • Run your app on AWS: phi ws up prd:aws

Let's build an AI App using GPT-4 as the LLM, Streamlit as the chat interface, FastApi as the backend and PgVector for knowledge and storage. Read the full tutorial here.

Step 1: Create your codebase

Create your codebase using the ai-app template

phi ws create -t ai-app -n ai-app

This will create a folder ai-app with a pre-built AI App that you can customize and make your own.

Step 2: Serve your App using Streamlit

Streamlit allows us to build micro front-ends and is extremely useful for building basic applications in pure python. Start the app group using:

phi ws up --group app

Press Enter to confirm and give a few minutes for the image to download.

PDF Assistant

  • Open localhost:8501 to view streamlit apps that you can customize and make your own.
  • Click on PDF Assistant in the sidebar
  • Enter a username and wait for the knowledge base to load.
  • Choose either the RAG or Autonomous Assistant type.
  • Ask "How do I make chicken curry?"
  • Upload PDFs and ask questions
chat-with-pdf

Step 3: Serve your App using FastApi

Streamlit is great for building micro front-ends but any production application will be built using a front-end framework like next.js backed by a RestApi built using a framework like FastApi.

Your AI App comes ready-to-use with FastApi endpoints, start the api group using:

phi ws up --group api

Press Enter to confirm and give a few minutes for the image to download.

  • View API Endpoints

  • Open localhost:8000/docs to view the API Endpoints.

  • Load the knowledge base using /v1/assitants/load-knowledge-base

  • Test the v1/assitants/chat endpoint with {"message": "How do I make chicken curry?"}

  • The Api comes pre-built with endpoints that you can integrate with your front-end.

Optional: Run Jupyterlab

A jupyter notebook is a must-have for AI development and your ai-app comes with a notebook pre-installed with the required dependencies. Enable it by updating the workspace/settings.py file:

...
ws_settings = WorkspaceSettings(
    ...
    # Uncomment the following line
    dev_jupyter_enabled=True,
...

Start jupyter using:

phi ws up --group jupyter

Press Enter to confirm and give a few minutes for the image to download (only the first time). Verify container status and view logs on the docker dashboard.

View Jupyterlab UI

  • Open localhost:8888 to view the Jupyterlab UI. Password: admin

  • Play around with cookbooks in the notebooks folder.

  • Delete local resources

Step 4: Stop the workspace

Play around and stop the workspace using:

phi ws down

Step 5: Run your AI App on AWS

Read how to run your AI App on AWS.

๐Ÿ“š Documentation

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

phidata-2.3.4.tar.gz (334.9 kB view hashes)

Uploaded Source

Built Distribution

phidata-2.3.4-py3-none-any.whl (486.5 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page