> For the complete documentation index, see [llms.txt](https://docs.tonic.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.tonic.ai/textual/textual-integrations/snowflake-native-app-and-spcs/textual-spcs.md).

# Using Textual with Snowpark Container Services directly

Snowpark Container Services (SPCS) allow developers to run containerized workloads directly within Snowflake. Because Tonic Textual is distributed using a private Docker repository, you can use these images in SPCS to run Textual workloads.

It is quicker to use the [Snowflake Native App](/textual/textual-integrations/snowflake-native-app-and-spcs/about-the-snowflake-native-app.md), but SPCS allows for more customization.

## Add images to the repository <a href="#spcs-add-images" id="spcs-add-images"></a>

To use the Textual images, you must add them to Snowflake. The Snowflake [documentation](https://docs.snowflake.com/en/developer-guide/snowpark-container-services/working-with-registry-repository) and [tutorial](https://docs.snowflake.com/en/developer-guide/snowpark-container-services/tutorials/tutorial-1) walks through the process in great detail, but the basic steps are as follows:

1. [Set up an image repository in Snowflake](https://docs.snowflake.com/en/developer-guide/snowpark-container-services/tutorials/common-setup#create-snowflake-objects).
2. To pull down the required images, you must have access to our private Docker image repository on [Quay.io](http://quay.io/).  You should have been provided credentials during onboarding.\
   \
   If you require new credentials, or you experience issues accessing the repository, contact <support@tonic.ai>.\
   \
   Once you have access, pull down the following images:
   * `textual-snowflake`
   * `textual-roberta-gpu`
3. [Use the Docker CLI to upload the images to the image repository.](https://docs.snowflake.com/en/developer-guide/snowpark-container-services/tutorials/tutorial-1#build-an-image-and-upload)

The images are now available in Snowflake.

## Create the Textual service <a href="#spcs-create-api-service" id="spcs-create-api-service"></a>

The Textual service exposes the functions that are used to redact sensitive values in Snowflake.

You create the Textual service in `textual_api_pool`.

```sql
DROP SERVICE IF EXISTS textual;
CREATE SERVICE textual
  IN COMPUTE POOL textual_api_pool
  FROM SPECIFICATION $$
    spec:
      containers:
      - name: textual
        image: your_image_repository_url/textual-snowflake:latest
        env:
          SOLAR_SECRET: your_encryption_string
          SOLAR_ROBERTA_URL: https://textual-roberta-service:8801
          ENVIRONMENT_NAME: your_environment_name
      endpoints:
        - name: textual
          port: 9002
      $$
   QUERY_WAREHOUSE='TEXTUAL'
   MIN_INSTANCES=1
   MAX_INSTANCES=1;
```

## Create the Roberta service <a href="#spcs-create-ml-service" id="spcs-create-ml-service"></a>

Next, you create the Roberta service, which recognizes personally identifiable information (PII) and other sensitive values in text.

You create the Roberta service in `textual_ml_pool`.

### Without model-based custom entity types

If you do not plan to use the service to detect model-based custom entity types, then:

```sql
DROP SERVICE IF EXISTS textual_roberta_service;
CREATE SERVICE textual_roberta_service
  IN COMPUTE POOL textual_ml_pool
  FROM SPECIFICATION $$
    spec:
      containers:
      - name: textualml
        image: your_image_repository_url/textual-roberta-gpu:latest
        env:
            ENVIRONMENT_NAME: your_environment_name
     $$
   MIN_INSTANCES=1
   MAX_INSTANCES=1;
```

### With model-based custom entity types

If you do plan to detect model-based custom entity types, then when you create the service, you must create a volume mount to store the models.

#### Obtain the volume UID and GID

The configuration includes the volume UID and GID.

First, create the version of the service without the custom entity types, with an added command in the `containers` section:

<pre class="language-sql" data-overflow="wrap"><code class="lang-sql">DROP SERVICE IF EXISTS textual_roberta_service;
CREATE SERVICE textual_roberta_service
  IN COMPUTE POOL textual_ml_pool
  FROM SPECIFICATION $$
    spec:
      containers:
      - name: textualml
        image: your_image_repository_url/textual-roberta-gpu:latest
        resources:
          requests:
            nvidia.com/gpu: 1
          limits:
            nvidia.com/gpu: 1
        env:
          ENVIRONMENT_NAME: your_environment_name
<strong>          command:
</strong>          - /bin/sh
          - -c
          - "id &#x26;&#x26; sleep 600"
     $$
   MIN_INSTANCES=1
   MAX_INSTANCES=1;
</code></pre>

When the service starts, it returns the values of the UID and GID.

#### Creating the service with the volume mount

After you obtain the UID and GID, to create the service with the volume mount.

{% code overflow="wrap" %}

```sql
DROP SERVICE IF EXISTS textual_roberta_service;
CREATE SERVICE textual_roberta_service
  IN COMPUTE POOL textual_ml_pool
  FROM SPECIFICATION $$
    spec:
      containers:
      - name: textualml
        image: your_image_repository_url/textual-roberta-gpu:latest
        env:
            ENVIRONMENT_NAME: your_environment_name
        volumeMounts:
          - name: stage-volume  # Must match the volume name below
            mountPath: /usr/bin/textual/custom_models  # Path in the container file system            
      endpoints:
        - name: textualmlendpoint
          port: 8801
          protocol: TCP          
      volumes:
        - name: stage-volume
          source: "@textual_db.public.textual_models"
          uid: <uid_value>
          gid: <gid_value>
      $$
   MIN_INSTANCES=1
   MAX_INSTANCES=1;
```

{% endcode %}

## Create functions <a href="#spcs-create-functions" id="spcs-create-functions"></a>

You can create custom SQL functions that use your API and ML services. These functions are accessible from directly within Snowflake.

{% code overflow="wrap" %}

```sql
CREATE OR REPLACE FUNCTION public.textual_redact(TEXT VARCHAR, REDACT_OPTIONS VARIANT)
  RETURNS varchar
  SERVICE = <api_service_name>
  CONTEXT_HEADERS = (current_user, current_account)
  ENDPOINT = textual
  AS '/api/redact';

CREATE OR REPLACE FUNCTION public.textual_redact(TEXT VARCHAR)
  RETURNS varchar
  SERVICE = <api_service_name>
  CONTEXT_HEADERS = (current_user)
  ENDPOINT = textual
  AS '/api/redact';
  
CREATE OR REPLACE FUNCTION public.textual_parse(PATH VARCHAR, STAGE_NAME VARCHAR, md5sum VARCHAR)
  returns varchar
  SERVICE=core.textual_service
  CONTEXT_HEADERS = (current_user)
  endpoint=textual
  MAX_BATCH_ROWS=10
  as '/api/parse/start';
```

{% endcode %}

## Example usage <a href="#spcs-example-usage" id="spcs-example-usage"></a>

It can take a couple of minutes for the containers to start. After the containers are started, you can use the functions that you created in Snowflake.

To test the functions, use an existing table. You can also create this simple test table:

```sql
CREATE TABLE Messages (
    Message TEXT
);

INSERT INTO Messages (Message) VALUES ('Hi my name is John Smith and I drive a Honda');
INSERT INTO Messages (Message) VALUES ('Hi John, mine is Jane Doe');
```

You use the function in the same way as any other user-defined function. You can pass in additional configuration to determine how to process specific built-in and model-based custom entity types.

For example:

{% code overflow="wrap" %}

```sql
SELECT public.textual_redact('Hi, my name is John Smith and I drive a Honda.', PARSE_JSON('{"generatorConfig":{"CUSTOM_CAR_MAKE":"Redaction","NAME_GIVEN":"Synthesis"},"customPiiEntityIds":["CUSTOM_CAR_MAKE|org1|entity1|model2"]}'));
```

{% endcode %}

Note that to specify custom entity types:

* You must first [mount the entity types to a Snowflake stage](/textual/textual-integrations/snowflake-native-app-and-spcs/snowflake-app-setup.md#mounting-model-based-custom-entity-types).
* You provide the identifier in both `generatorConfig` and `customPiiEntityIds`.
* In `customPiiEntityIds`, the model path must match the mounted folder structure.

By default, the function redacts the entity values. In other words, it replaces the values with a placeholder that includes the type. `Synthesis` indicates to replace the value with a realistic replacement value. `Off` indicates to leave the value as is.&#x20;

The `textual_redact` function works identically to the [`textual_redact` function in the Snowflake Native App](/textual/textual-integrations/snowflake-native-app-and-spcs/snowflake-app-use.md#snowflake-app-textual-redact).

Here are response for the text examples above, showing redacted and synthesized values for the entity types:

<table><thead><tr><th width="220.6484375" valign="top">Message</th><th valign="top">Redacted</th><th valign="top">Synthesized</th></tr></thead><tbody><tr><td valign="top">Hi my name is John Smith and I drive a Honda</td><td valign="top">Hi my name is [NAME_GIVEN_Kx0Y7] [NAME_FAMILY_s9TTP0] and I drive a [CUSTOM_CAR_MAKE_pY3MN]</td><td valign="top">Hi my name is Lamar Jones and I drive a Subaru.</td></tr><tr><td valign="top">Hi John, mine is Jane Doe</td><td valign="top">Hi [NAME_GIVEN_Kx0Y7], mine is [NAME_GIVEN_veAy9] [NAME_FAMILY_6eC2]</td><td valign="top">Hi Lamar, mine is Doris Perez.</td></tr></tbody></table>

The `textual_parse` function works identically to the [`textual_parse` function in the Snowflake Native App](/textual/textual-integrations/snowflake-native-app-and-spcs/snowflake-app-use.md#snowflake-app-textual-parse).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.tonic.ai/textual/textual-integrations/snowflake-native-app-and-spcs/textual-spcs.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
