diff --git a/partner-models/claude/computer-use-demo/README.md b/partner-models/claude/computer-use-demo/README.md index b4b6e4e0572..a77a5d198ca 100644 --- a/partner-models/claude/computer-use-demo/README.md +++ b/partner-models/claude/computer-use-demo/README.md @@ -1,4 +1,6 @@ + # Anthropic Computer Use Demo on Google Cloud + [![Deploy in Cloud Shell](https://gstatic.com/cloudssh/images/open-btn.svg)](https://shell.cloud.google.com/cloudshell/editor?cloudshell_git_repo=https%3A%2F%2Fgithub.com%2FGoogleCloudPlatform%2Fgenerative-ai&cloudshell_git_branch=main&cloudshell_workspace=partner-models%2Fclaude%2Fcomputer-use-demo&cloudshell_tutorial=partner-models%2Fclaude%2Fcomputer-use-demo%2FREADME.md) > [!CAUTION] @@ -15,10 +17,10 @@ This repository helps you get started with computer use on Claude, with reference implementations of: -* Build files to create a Docker container with all necessary dependencies -* A computer use agent loop using the Vertex AI and GKE to access the updated Claude 3.5 Sonnet model -* Anthropic-defined computer use tools -* A streamlit app for interacting with the agent loop +- Build files to create a Docker container with all necessary dependencies +- A computer use agent loop using the Vertex AI and GKE to access the updated Claude 3.5 Sonnet model +- Anthropic-defined computer use tools +- A streamlit app for interacting with the agent loop Please use [this form](https://forms.gle/BT1hpBrqDPDUrCqo7) to provide feedback on the quality of the model responses, the API itself, or the quality of the documentation - we cannot wait to hear from you! @@ -34,33 +36,33 @@ We provide a simplified way to deploy this app on Google Cloud using Google Kube 1. Set up the environment variables - ```bash - export PROJECT_ID=%your_project_id% - ``` + ```bash + export PROJECT_ID=%your_project_id% + ``` 2. Authenticate with Google Cloud - ```bash - gcloud auth application-default login - ``` + ```bash + gcloud auth application-default login + ``` 3. Create a Cloud Build job to deploy the app - ```bash - gcloud builds submit --config cloudbuild.yaml - ``` + ```bash + gcloud builds submit --config cloudbuild.yaml + ``` 4. [Optional] Delete all created resources - ```bash - gcloud builds submit --config cloudbuild-destroy.yaml - ``` + ```bash + gcloud builds submit --config cloudbuild-destroy.yaml + ``` ## Local development ### Running the app locally -You'll need to pass in Google Cloud credentials with appropriate permissions to use Claude on Vertex. +You'll need to pass in Google Cloud credentials with appropriate permissions to use Claude on Vertex AI. ```bash docker build . -t computer-use-demo @@ -81,7 +83,7 @@ docker run \ Once the container is running, see the [Accessing the demo app](#accessing-the-demo-app) section below for instructions on how to connect to the interface. -This example shows how to use the Google Cloud Application Default Credentials to authenticate with Vertex. +This example shows how to use the Google Cloud Application Default Credentials to authenticate with Vertex AI. You can also set `GOOGLE_APPLICATION_CREDENTIALS` to use an arbitrary credential file, see the [Google Cloud Authentication documentation](https://cloud.google.com/docs/authentication/application-default-credentials#GAC) for more details. @@ -93,9 +95,9 @@ The container stores settings like the API key and custom system prompt in `~/.a Alternative access points: -* Streamlit interface only: [http://localhost:8501](http://localhost:8501) -* Desktop view only: [http://localhost:6080/vnc.html](http://localhost:6080/vnc.html) -* Direct VNC connection: `vnc://localhost:5900` (for VNC clients) +- Streamlit interface only: [http://localhost:8501](http://localhost:8501) +- Desktop view only: [http://localhost:6080/vnc.html](http://localhost:6080/vnc.html) +- Direct VNC connection: `vnc://localhost:5900` (for VNC clients) ## Screen size @@ -136,4 +138,4 @@ docker run \ -it computer-use-demo:local # can also use ghcr.io/anthropics/anthropic-quickstarts:computer-use-demo-latest ``` -The docker run command above mounts the repo inside the docker image, such that you can edit files from the host. Streamlit is already configured with auto reloading. +The docker run command above mounts the repository inside the docker image, such that you can edit files from the host. Streamlit is already configured with auto reloading. \ No newline at end of file diff --git a/partner-models/claude/computer-use-demo/cloudbuild-destroy.yaml b/partner-models/claude/computer-use-demo/cloudbuild-destroy.yaml index df994d03942..127d018d4ed 100644 --- a/partner-models/claude/computer-use-demo/cloudbuild-destroy.yaml +++ b/partner-models/claude/computer-use-demo/cloudbuild-destroy.yaml @@ -13,70 +13,70 @@ # limitations under the License. steps: -- id: 'delete-k8s-resources' - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' - entrypoint: 'bash' - args: - - '-c' - - | - if gcloud container clusters describe ${_CLUSTER_NAME} \ - --project=${PROJECT_ID} \ - --region=${_REGION} --format="none" 2>/dev/null; then - gcloud container clusters get-credentials ${_CLUSTER_NAME} \ + - id: "delete-k8s-resources" + name: "gcr.io/google.com/cloudsdktool/cloud-sdk" + entrypoint: "bash" + args: + - "-c" + - | + if gcloud container clusters describe ${_CLUSTER_NAME} \ --project=${PROJECT_ID} \ - --region=${_REGION} - - # Delete namespace (this will delete all resources in it) - kubectl delete namespace ${_NAMESPACE} --ignore-not-found - fi + --region=${_REGION} --format="none" 2>/dev/null; then + gcloud container clusters get-credentials ${_CLUSTER_NAME} \ + --project=${PROJECT_ID} \ + --region=${_REGION} + + # Delete namespace (this will delete all resources in it) + kubectl delete namespace ${_NAMESPACE} --ignore-not-found + fi -- id: 'cleanup-iam' - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' - waitFor: ['delete-k8s-resources'] - entrypoint: 'bash' - args: - - '-c' - - | - # Remove IAM bindings - gcloud projects remove-iam-policy-binding ${PROJECT_ID} \ - --member="serviceAccount:${_IAM_SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" \ - --role="roles/aiplatform.admin" \ - --quiet || true + - id: "cleanup-iam" + name: "gcr.io/google.com/cloudsdktool/cloud-sdk" + waitFor: ["delete-k8s-resources"] + entrypoint: "bash" + args: + - "-c" + - | + # Remove IAM bindings + gcloud projects remove-iam-policy-binding ${PROJECT_ID} \ + --member="serviceAccount:${_IAM_SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" \ + --role="roles/aiplatform.admin" \ + --quiet || true - # Delete service account - gcloud iam service-accounts delete ${_IAM_SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com \ - --project=${PROJECT_ID} \ - --quiet || true + # Delete service account + gcloud iam service-accounts delete ${_IAM_SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com \ + --project=${PROJECT_ID} \ + --quiet || true -- id: 'delete-cluster' - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' - waitFor: ['cleanup-iam'] - entrypoint: 'bash' - args: - - '-c' - - | - # Delete GKE cluster - echo "Deleting GKE cluster..." - gcloud container clusters delete ${_CLUSTER_NAME} \ - --project=${PROJECT_ID} \ - --region=${_REGION} \ - --quiet || true + - id: "delete-cluster" + name: "gcr.io/google.com/cloudsdktool/cloud-sdk" + waitFor: ["cleanup-iam"] + entrypoint: "bash" + args: + - "-c" + - | + # Delete GKE cluster + echo "Deleting GKE cluster..." + gcloud container clusters delete ${_CLUSTER_NAME} \ + --project=${PROJECT_ID} \ + --region=${_REGION} \ + --quiet || true -- id: 'delete-registry' - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' - waitFor: ['delete-cluster'] - entrypoint: 'bash' - args: - - '-c' - - | - # Delete Artifact Registry repository - echo "Deleting Artifact Registry repository..." - gcloud artifacts repositories delete ${_ARTIFACT_REGISTRY_ID} \ - --project=${PROJECT_ID} \ - --location=${_REGION} \ - --quiet || true + - id: "delete-registry" + name: "gcr.io/google.com/cloudsdktool/cloud-sdk" + waitFor: ["delete-cluster"] + entrypoint: "bash" + args: + - "-c" + - | + # Delete Artifact Registry repository + echo "Deleting Artifact Registry repository..." + gcloud artifacts repositories delete ${_ARTIFACT_REGISTRY_ID} \ + --project=${PROJECT_ID} \ + --location=${_REGION} \ + --quiet || true -timeout: '1800s' +timeout: "1800s" options: logging: CLOUD_LOGGING_ONLY dynamicSubstitutions: true @@ -85,5 +85,5 @@ substitutions: _CLUSTER_NAME: computer-use-demo-cluster _NAMESPACE: computer-use-demo _IAM_SA_NAME: computer-use-sa - _ARTIFACT_REGISTRY_ID: computer-use-ar-repo # Added this -tags: ['gke-cleanup', '${_CLUSTER_NAME}'] \ No newline at end of file + _ARTIFACT_REGISTRY_ID: computer-use-ar-repo # Added this +tags: ["gke-cleanup", "${_CLUSTER_NAME}"] diff --git a/partner-models/claude/computer-use-demo/cloudbuild.yaml b/partner-models/claude/computer-use-demo/cloudbuild.yaml index 9ba9f458fa2..eeeb8e5ee8f 100644 --- a/partner-models/claude/computer-use-demo/cloudbuild.yaml +++ b/partner-models/claude/computer-use-demo/cloudbuild.yaml @@ -1,9 +1,9 @@ steps: - - id: 'check-cluster' - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' - entrypoint: 'bash' + - id: "check-cluster" + name: "gcr.io/google.com/cloudsdktool/cloud-sdk" + entrypoint: "bash" args: - - '-c' + - "-c" - | if gcloud container clusters describe ${_CLUSTER_NAME} \ --project=${PROJECT_ID} \ @@ -18,12 +18,12 @@ steps: --quiet fi - - id: 'setup-artifact-registry' - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' - waitFor: ['check-cluster'] - entrypoint: 'bash' + - id: "setup-artifact-registry" + name: "gcr.io/google.com/cloudsdktool/cloud-sdk" + waitFor: ["check-cluster"] + entrypoint: "bash" args: - - '-c' + - "-c" - | if gcloud artifacts repositories describe ${_ARTIFACT_REGISTRY_ID} \ --project=${PROJECT_ID} \ @@ -37,21 +37,21 @@ steps: --quiet fi - - id: 'build-push-image' - name: 'gcr.io/cloud-builders/docker' - waitFor: ['setup-artifact-registry'] + - id: "build-push-image" + name: "gcr.io/cloud-builders/docker" + waitFor: ["setup-artifact-registry"] args: - - 'build' - - '-t' - - '${_REGION}-docker.pkg.dev/${PROJECT_ID}/${_ARTIFACT_REGISTRY_ID}/${_IMAGE_NAME}:${_IMAGE_TAG}' - - '.' - - - id: 'setup-k8s-iam' - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' - waitFor: ['build-push-image'] - entrypoint: 'bash' + - "build" + - "-t" + - "${_REGION}-docker.pkg.dev/${PROJECT_ID}/${_ARTIFACT_REGISTRY_ID}/${_IMAGE_NAME}:${_IMAGE_TAG}" + - "." + + - id: "setup-k8s-iam" + name: "gcr.io/google.com/cloudsdktool/cloud-sdk" + waitFor: ["build-push-image"] + entrypoint: "bash" args: - - '-c' + - "-c" - | # Get cluster credentials gcloud container clusters get-credentials ${_CLUSTER_NAME} \ @@ -94,12 +94,12 @@ steps: iam.gke.io/gcp-service-account=${_IAM_SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com \ --overwrite - - id: 'deploy-app' - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' - waitFor: ['setup-k8s-iam'] - entrypoint: 'bash' + - id: "deploy-app" + name: "gcr.io/google.com/cloudsdktool/cloud-sdk" + waitFor: ["setup-k8s-iam"] + entrypoint: "bash" args: - - '-c' + - "-c" - | # Install gettext package which contains envsubst apt-get update && apt-get install -y gettext-base @@ -107,7 +107,7 @@ steps: gcloud container clusters get-credentials ${_CLUSTER_NAME} \ --project=${PROJECT_ID} \ --region=${_REGION} - + # Export all variables that will be used in envsubst export _REGION=${_REGION} export PROJECT_ID=${PROJECT_ID} @@ -117,33 +117,32 @@ steps: export _NAMESPACE=${_NAMESPACE} export _KSA_NAME=${_KSA_NAME} export _IAM_SA_NAME=${_IAM_SA_NAME} - - envsubst < deployment.yaml | kubectl apply -f - + envsubst < deployment.yaml | kubectl apply -f - - - id: 'get-service-ip' - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' - waitFor: ['deploy-app'] - entrypoint: 'bash' + - id: "get-service-ip" + name: "gcr.io/google.com/cloudsdktool/cloud-sdk" + waitFor: ["deploy-app"] + entrypoint: "bash" args: - - '-c' + - "-c" - | echo "Waiting for LoadBalancer IP assignment..." - + # Debug current state echo "Checking service in namespace ${_NAMESPACE}..." kubectl get services -n ${_NAMESPACE} - + get_external_ip() { kubectl get service ${_IMAGE_NAME} -n ${_NAMESPACE} \ -o jsonpath='{.status.loadBalancer.ingress[0].ip}' } - + # Wait for IP with timeout TIMEOUT=300 # 5 minutes timeout INTERVAL=10 # Check every 10 seconds ELAPSED=0 - + until [ -n "$$(get_external_ip)" ] || [ $$ELAPSED -ge $$TIMEOUT ]; do echo "Waiting for external IP... ($$ELAPSED seconds elapsed)" # Debug service state @@ -151,9 +150,9 @@ steps: sleep $$INTERVAL ELAPSED=$$((ELAPSED + INTERVAL)) done - + EXTERNAL_IP=$$(get_external_ip) - + if [ -n "$$EXTERNAL_IP" ]; then echo "✅ Service is ready!" echo "###################################################" @@ -177,10 +176,10 @@ steps: exit 1 fi -timeout: '3600s' +timeout: "3600s" options: logging: CLOUD_LOGGING_ONLY - machineType: 'E2_HIGHCPU_8' + machineType: "E2_HIGHCPU_8" dynamicSubstitutions: true substitutions: _REGION: us-east5 @@ -192,4 +191,4 @@ substitutions: _IAM_SA_DISPLAY_NAME: Computer Use Demo SA _IMAGE_NAME: computer-use-demo _IMAGE_TAG: latest -tags: ['gke-deployment', '${_CLUSTER_NAME}'] \ No newline at end of file +tags: ["gke-deployment", "${_CLUSTER_NAME}"] diff --git a/partner-models/claude/computer-use-demo/deployment.yaml b/partner-models/claude/computer-use-demo/deployment.yaml index 54d69b49037..14b7a79418e 100644 --- a/partner-models/claude/computer-use-demo/deployment.yaml +++ b/partner-models/claude/computer-use-demo/deployment.yaml @@ -108,4 +108,4 @@ spec: targetPort: web name: web selector: - app: ${_IMAGE_NAME} \ No newline at end of file + app: ${_IMAGE_NAME}