github.com/aldelo/common@v1.5.1/wrapper/bedrockruntime/bedrockruntime.go (about)

     1  package bedrockruntime
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"net/http"
     7  
     8  	awshttp2 "github.com/aldelo/common/wrapper/aws"
     9  	"github.com/aldelo/common/wrapper/aws/awsregion"
    10  	"github.com/aldelo/common/wrapper/xray"
    11  	"github.com/aws/aws-sdk-go-v2/config"
    12  	"github.com/aws/aws-sdk-go-v2/service/bedrockruntime"
    13  	"github.com/aws/aws-sdk-go/aws"
    14  )
    15  
    16  /*
    17   * Copyright 2020-2024 Aldelo, LP
    18   *
    19   * Licensed under the Apache License, Version 2.0 (the "License");
    20   * you may not use this file except in compliance with the License.
    21   * You may obtain a copy of the License at
    22   *
    23   *     http://www.apache.org/licenses/LICENSE-2.0
    24   *
    25   * Unless required by applicable law or agreed to in writing, software
    26   * distributed under the License is distributed on an "AS IS" BASIS,
    27   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    28   * See the License for the specific language governing permissions and
    29   * limitations under the License.
    30   */
    31  
    32  // =================================================================================================================
    33  // AWS CREDENTIAL:
    34  //		use $> aws configure (to set aws access key and secret to target machine)
    35  //		Store AWS Access ID and Secret Key into Default Profile Using '$ aws configure' cli
    36  //
    37  // To Install & Setup AWS CLI on Host:
    38  //		1) https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-linux.html
    39  //				On Ubuntu, if host does not have zip and unzip:
    40  //					$> sudo apt install zip
    41  //					$> sudo apt install unzip
    42  //				On Ubuntu, to install AWS CLI v2:
    43  //					$> curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
    44  //					$> unzip awscliv2.zip
    45  //					$> sudo ./aws/install
    46  //		2) $> aws configure set region awsRegionName --profile default
    47  // 		3) $> aws configure
    48  //				follow prompts to enter Access ID and Secret Key
    49  //
    50  // AWS Region Name Reference:
    51  //		us-west-2, us-east-1, ap-northeast-1, etc
    52  //		See: https://docs.aws.amazon.com/general/latest/gr/rande.html
    53  // =================================================================================================================
    54  
    55  // ================================================================================================================
    56  // STRUCTS
    57  // ================================================================================================================
    58  
    59  // BedrockRuntime struct encapsulates the AWS BedrockRuntime access functionality
    60  type BedrockRuntime struct {
    61  	// define the AWS region that BedrockRuntime is located at
    62  	AwsRegion awsregion.AWSRegion
    63  
    64  	// custom http2 client options
    65  	HttpOptions *awshttp2.HttpClientSettings
    66  
    67  	// store BedrockRuntime client object
    68  	bedrockruntimeClient *bedrockruntime.Client
    69  
    70  	_parentSegment *xray.XRayParentSegment
    71  }
    72  
    73  // ================================================================================================================
    74  // STRUCTS FUNCTIONS
    75  // ================================================================================================================
    76  
    77  // ----------------------------------------------------------------------------------------------------------------
    78  // utility functions
    79  // ----------------------------------------------------------------------------------------------------------------
    80  
    81  // Connect will establish a connection to the BedrockRuntime service
    82  func (s *BedrockRuntime) Connect(parentSegment ...*xray.XRayParentSegment) (err error) {
    83  	if xray.XRayServiceOn() {
    84  		if len(parentSegment) > 0 {
    85  			s._parentSegment = parentSegment[0]
    86  		}
    87  
    88  		seg := xray.NewSegment("BedrockRuntime-Connect", s._parentSegment)
    89  		defer seg.Close()
    90  		defer func() {
    91  			_ = seg.Seg.AddMetadata("BedrockRuntime-AWS-Region", s.AwsRegion)
    92  
    93  			if err != nil {
    94  				_ = seg.Seg.AddError(err)
    95  			}
    96  		}()
    97  
    98  		err = s.connectInternal(seg.Ctx)
    99  
   100  		return err
   101  	} else {
   102  		return s.connectInternal(context.Background())
   103  	}
   104  }
   105  
   106  // Connect will establish a connection to the BedrockRuntime service
   107  func (s *BedrockRuntime) connectInternal(ctx context.Context) error {
   108  	// clean up prior bedrockruntime client reference
   109  	s.bedrockruntimeClient = nil
   110  
   111  	if !s.AwsRegion.Valid() || s.AwsRegion == awsregion.UNKNOWN {
   112  		return errors.New("Connect to BedrockRuntime Failed: (AWS Session Error) " + "Region is Required")
   113  	}
   114  
   115  	// create custom http2 client if needed
   116  	var httpCli *http.Client
   117  	var httpErr error
   118  
   119  	if s.HttpOptions == nil {
   120  		s.HttpOptions = new(awshttp2.HttpClientSettings)
   121  	}
   122  
   123  	// use custom http2 client
   124  	h2 := &awshttp2.AwsHttp2Client{
   125  		Options: s.HttpOptions,
   126  	}
   127  
   128  	if httpCli, httpErr = h2.NewHttp2Client(); httpErr != nil {
   129  		return errors.New("Connect to BedrockRuntime Failed: (AWS Session Error) " + "Create Custom http2 Client Errored = " + httpErr.Error())
   130  	}
   131  
   132  	// establish aws session connection
   133  	if cfg, err := config.LoadDefaultConfig(ctx, config.WithHTTPClient(httpCli)); err != nil {
   134  		// aws session error
   135  		return errors.New("Connect to BedrockRuntime Failed: (AWS Session Error) " + err.Error())
   136  	} else {
   137  		// create cached objects for shared use
   138  		s.bedrockruntimeClient = bedrockruntime.NewFromConfig(cfg)
   139  
   140  		if s.bedrockruntimeClient == nil {
   141  			return errors.New("Connect to BedrockRuntime Client Failed: (New BedrockRuntime Client Connection) " + "Connection Object Nil")
   142  		}
   143  
   144  		// connect successful
   145  		return nil
   146  	}
   147  }
   148  
   149  // Disconnect will clear bedrockruntime client
   150  func (s *BedrockRuntime) Disconnect() {
   151  	s.bedrockruntimeClient = nil
   152  }
   153  
   154  // UpdateParentSegment updates this struct's xray parent segment, if no parent segment, set nil
   155  func (s *BedrockRuntime) UpdateParentSegment(parentSegment *xray.XRayParentSegment) {
   156  	s._parentSegment = parentSegment
   157  }
   158  
   159  // ----------------------------------------------------------------------------------------------------------------
   160  // Invoke functions
   161  // ----------------------------------------------------------------------------------------------------------------
   162  
   163  // Invokes the specified Amazon Bedrock model to run inference using the prompt
   164  // and inference parameters provided in the request body. You use model inference
   165  // to generate text, images, and embeddings. For example code, see Invoke model
   166  // code examples in the Amazon Bedrock User Guide. This operation requires
   167  // permission for the bedrock:InvokeModel action.
   168  func (s *BedrockRuntime) InvokeModel(modelId string, requestBody []byte) (responseBody []byte, err error) {
   169  	segCtx := context.Background()
   170  	segCtxSet := false
   171  
   172  	seg := xray.NewSegmentNullable("BedrockRuntime-InvokeModel", s._parentSegment)
   173  
   174  	if seg != nil {
   175  		segCtx = seg.Ctx
   176  		segCtxSet = true
   177  
   178  		defer seg.Close()
   179  		defer func() {
   180  			_ = seg.Seg.AddMetadata("BedrockRuntime-InvokeModel-ResponseBody", responseBody)
   181  
   182  			if err != nil {
   183  				_ = seg.Seg.AddError(err)
   184  			}
   185  		}()
   186  	}
   187  
   188  	// validation
   189  	if s.bedrockruntimeClient == nil {
   190  		err = errors.New("InvokeModel Failed: " + "BedrockRuntime Client is Required")
   191  		return nil, err
   192  	}
   193  
   194  	if len(modelId) <= 0 {
   195  		err = errors.New("InvokeModel Failed: " + "Model ID is Required")
   196  		return nil, err
   197  	}
   198  
   199  	if len(requestBody) <= 0 {
   200  		err = errors.New("InvokeModel Failed: " + "Request Body is Required")
   201  		return nil, err
   202  	}
   203  
   204  	// create input object
   205  	input := &bedrockruntime.InvokeModelInput{
   206  		ModelId:     aws.String(modelId),
   207  		Body:        requestBody,
   208  		Accept:      aws.String("application/json"),
   209  		ContentType: aws.String("application/json"),
   210  	}
   211  
   212  	// perform action
   213  	var output *bedrockruntime.InvokeModelOutput
   214  
   215  	if segCtxSet {
   216  		output, err = s.bedrockruntimeClient.InvokeModel(segCtx, input)
   217  	} else {
   218  		output, err = s.bedrockruntimeClient.InvokeModel(context.Background(), input)
   219  	}
   220  
   221  	// evaluate result
   222  	if err != nil {
   223  		return nil, err
   224  	}
   225  	if len(output.Body) == 0 {
   226  		return nil, errors.New("InvokeModel Failed: " + "No Response Body Returned")
   227  	}
   228  
   229  	return output.Body, nil
   230  }