diff --git a/docs/go/how_to_use/plugin.md b/docs/go/how_to_use/plugin.md new file mode 100644 index 00000000..bea409ee --- /dev/null +++ b/docs/go/how_to_use/plugin.md @@ -0,0 +1,72 @@ +# 在千帆 Go SDK 中使用插件 + +# 0. 准备工作 + +为了使用插件功能,我们需要: + +a. 安装千帆 Go SDK + +```shell +go get github.com/baidubce/bce-qianfan-sdk/go/qianfan +``` + +b. 导入相关包 + +```go +import ( + "github.com/baidubce/bce-qianfan-sdk/go/qianfan" +) +``` + +c. 设置好百度智能云的 Access Key 和 Secret Key + +```shell +export QIANFAN_ACCESS_KEY="" +export QIANFAN_SECRET_KEY="" +``` + +# 1. 初始化 + +我们需要先初始化好所需要使用到的千帆 SDK 对象 + +``` +qianfanClient := qianfan.NewBaseModel() +``` + +# 2. 构造插件请求 + +我们可以使用千帆 Go SDK 提供的接口来自行拼接请求参数,以使用 `ChatFilePlus` 插件为例: + +``` +request, _ := qianfan.NewModelRequest( + "POST", + "/rpc/2.0/ai_custom/v1/wenxinworkshop/erniebot/plugin", + qianfan.RawRequest{ + "messages": []map[string]any{ + { + "role": "user", + "content": `['\''牛奶的营养成本有哪些浅谈牛奶的营养与消费趋势.docxhttps://qianfan-doc.bj.bcebos.com/chatfile/%E6%B5%85%E8%B0%88%E7%89%9B%E5%A5%B6%E7%9A%84%E8%90%A5%E5%85%BB%E4%B8%8E%E6%B6%88%E8%B4%B9%E8%B6%8B%E5%8A%BF.docx'\'']`, + }, + }, + "plugins": []string{ + "ChatFilePlus", + }, + }, +) +``` + +# 3. 发送请求并获取结果 + +在使用 `BaseModel` 调用 `Do` 进行请求时,返回值是一个代表了响应结果的 `RawResponse` 对象。用户可以使用 `json.Unmarshal` 方法将响应结果反序列化为一个 `map[string]any` 对象,方便后续处理 + +``` +resp, err := qianfanClient.Do(context.Background(), request) +if err != nil { + fmt.Println(err) +} else { + result := make(map[string]any) + json.Unmarshal(resp.Body, &result) + fmt.Println(result) +} +``` + diff --git a/docs/go/how_to_use/use_lite-v_model.md b/docs/go/how_to_use/use_lite-v_model.md new file mode 100644 index 00000000..f820ad86 --- /dev/null +++ b/docs/go/how_to_use/use_lite-v_model.md @@ -0,0 +1,135 @@ +# 在千帆 Go SDK 中使用 Lite-V 模型 + +Lite-V 模型是百度针对多模态场景打造的一款模型。本文将介绍如何在千帆 Go SDK 中使用 Lite-V 模型。 + +# 0. 准备工作 + +为了使用 Lite-V 模型,我们需要: + +a. 安装千帆 Go SDK 和百度智能云 Bos SDK + +```shell +go get github.com/baidubce/bce-qianfan-sdk/go/qianfan +go get github.com/baidubce/bce-sdk-go/services/bos +``` + +b. 导入相关包 + +```go +import ( + "context" + "encoding/json" + "fmt" + "image" + _ "image/jpeg" + "os" + + "github.com/baidubce/bce-qianfan-sdk/go/qianfan" + "github.com/baidubce/bce-sdk-go/services/bos" +) +``` + +c. 设置好百度智能云的 Access Key 和 Secret Key 以及相关环境变量 + +Go: +``` +var ( + ak = "" // 百度智能云的 Access Key + sk = "" // 百度智能云的 Secret Key + bucket = "" // 存储图片的 BOS Bucket + bucketImagePath = "" // BOS Bucket 中的图片路径 + localImagePath = "" // 本地图片的路径 +) +``` + +Shell: +```shell +export QIANFAN_ACCESS_KEY="" +export QIANFAN_SECRET_KEY="" +``` + +# 1. 初始化 + +我们需要先初始化好所需要使用到的千帆 SDK 和 Bos SDK 客户端对象 + +``` +qianfanClient := qianfan.NewBaseModel() +bosClient, err := bos.NewClient(ak, sk, "") +if err != nil { + panic(err) +} +``` + +# 2. 读取图片并上传到 BOS + +为了使用 Lite-V 模型的多模态功能,我们需要将其上传到可被访问的服务之中。并且使用传递 URL 的方式来让 Lite-V 模型来读取该图片 + +```go +imageFile, err := os.Open(localImagePath) +if err != nil { + panic(err) +} +defer imageFile.Close() + +imageConfig, _, err := image.DecodeConfig(imageFile) +if err != nil { + panic(err) +} + +imageHeight := imageConfig.Height +imageWidth := imageConfig.Width + +if _, err = bosClient.PutObjectFromFile(bucket, bucketImagePath, localImagePath, nil); err != nil { + panic(err) +} + +url := bosClient.BasicGeneratePresignedUrl(bucket, bucketImagePath, 120) +``` + +# 3. 请求 Lite-V 模型 + +我们可以使用千帆 Go SDK 提供的接口来自行拼接请求参数,实现对 Lite-V 模型的灵活请求,以上面的图片举例: + +``` +request, _ := qianfan.NewModelRequest( + "POST", + "/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/ernie-lite-v", + qianfan.RawRequest{ + "messages": []map[string]any{ + { + "role": "user", + "content": []map[string]any{ + { + "type": "image_url", + "image_url": map[string]any{ + "image_width": imageWidth, + "image_height": imageHeight, + "url": url, + }, + }, + { + "type": "text", + "text": "这个图片展示了什么", + }, + }, + }, + }, + }, +) +``` + +# 4. 发送请求并获取结果 + +在使用 `BaseModel` 调用 `Do` 进行请求时,返回值是一个代表了响应结果的 `RawResponse` 对象。用户可以使用 `json.Unmarshal` 方法将响应结果反序列化为一个 `map[string]any` 对象,方便后续处理 + +``` +resp, err := qianfanClient.Do(context.Background(), request) +if err != nil { + fmt.Println(err) +} else { + result := make(map[string]any) + json.Unmarshal(resp.Body, &result) + fmt.Println(result) +} +``` + diff --git a/go/qianfan/base_model.go b/go/qianfan/base_model.go index 958ca1c2..3369342d 100644 --- a/go/qianfan/base_model.go +++ b/go/qianfan/base_model.go @@ -32,6 +32,10 @@ type BaseModel struct { *Requestor // Requstor 作为基类 } +func NewBaseModel(options ...Option) *BaseModel { + return &BaseModel{Requestor: newRequestor(makeOptions(options...))} +} + // 使用量信息 type ModelUsage struct { PromptTokens int `json:"prompt_tokens"` // 问题tokens数 @@ -44,6 +48,26 @@ type ModelAPIResponse interface { ClearError() } +type RawRequest map[string]any + +func (r RawRequest) SetExtra(extra map[string]any) { + r["extra"] = extra +} + +func (r RawRequest) GetExtra() map[string]any { + extra, ok := r["extra"] + if !ok { + return make(map[string]any) + } else { + return extra.(map[string]any) + } +} + +type RawResponse struct { + baseResponse `json:",omitempty"` + ModelAPIError `json:",omitempty"` +} + // API 错误信息 type ModelAPIError struct { ErrorCode int `json:"error_code"` // 错误码 @@ -179,6 +203,33 @@ func (s *ModelResponseStream) Recv() (*ModelResponse, error) { return &resp, nil } +type RawModelResponseStream struct { + *ModelResponseStream +} + +func newRawModelResponseStream(si *streamInternal) (*RawModelResponseStream, error) { + s := &RawModelResponseStream{} + mrs, err := newModelResponseStream(si) + if err != nil { + return s, err + } + + s.ModelResponseStream = mrs + return s, nil +} + +func (s *RawModelResponseStream) Recv() (*RawResponse, error) { + var resp RawResponse + err := s.streamInternal.Recv(&resp) + if err != nil { + return nil, err + } + if err = checkResponseError(&resp); err != nil { + return &resp, err + } + return &resp, nil +} + func checkResponseError(resp ModelAPIResponse) error { errCode, errMsg := resp.GetError() if errCode != 0 { @@ -272,3 +323,20 @@ func isUnsupportedModelError(err error) bool { } return false } + +func (m *BaseModel) Do(ctx context.Context, request *QfRequest) (*RawResponse, error) { + rawResponse := &RawResponse{} + if err := m.requestResource(ctx, request, rawResponse); err != nil { + return nil, err + } + return rawResponse, nil +} + +func (m *BaseModel) Stream(ctx context.Context, request *QfRequest) (*RawModelResponseStream, error) { + request.Body["stream"] = true + si, err := m.requestStream(ctx, request) + if err != nil { + return nil, err + } + return newRawModelResponseStream(si) +} diff --git a/go/qianfan/chat_completion.go b/go/qianfan/chat_completion.go index 07945ceb..6b34cd89 100644 --- a/go/qianfan/chat_completion.go +++ b/go/qianfan/chat_completion.go @@ -316,7 +316,7 @@ func (c *ChatCompletion) do(ctx context.Context, request *ChatCompletionRequest) c.processWithInputLimit(ctx, request, url) - req, err := newModelRequest("POST", url, request) + req, err := NewModelRequest("POST", url, request) if err != nil { return nil, err } @@ -368,7 +368,7 @@ func (c *ChatCompletion) stream(ctx context.Context, request *ChatCompletionRequ c.processWithInputLimit(ctx, request, url) request.SetStream() - req, err := newModelRequest("POST", url, request) + req, err := NewModelRequest("POST", url, request) if err != nil { return nil, err } diff --git a/go/qianfan/completion.go b/go/qianfan/completion.go index fc8bafaa..9a9200ff 100644 --- a/go/qianfan/completion.go +++ b/go/qianfan/completion.go @@ -145,7 +145,7 @@ func (c *Completion) do(ctx context.Context, request *CompletionRequest) (*Model if err != nil { return nil, err } - req, err := newModelRequest("POST", url, request) + req, err := NewModelRequest("POST", url, request) if err != nil { return nil, err } @@ -195,7 +195,7 @@ func (c *Completion) stream(ctx context.Context, request *CompletionRequest) (*M return nil, err } request.SetStream() - req, err := newModelRequest("POST", url, request) + req, err := NewModelRequest("POST", url, request) if err != nil { return nil, err } diff --git a/go/qianfan/console_action.go b/go/qianfan/console_action.go index 24f67b45..cd39bc87 100644 --- a/go/qianfan/console_action.go +++ b/go/qianfan/console_action.go @@ -30,7 +30,7 @@ func (ca *ConsoleAction) Call(ctx context.Context, route string, action string, reqBody := BaseRequestBody{ Extra: params, } - req, err := newConsoleRequest("POST", ca.baseActionUrl(route, action), &reqBody) + req, err := NewConsoleRequest("POST", ca.baseActionUrl(route, action), &reqBody) if err != nil { logger.Error("new console req error", err) return nil, err diff --git a/go/qianfan/embdding.go b/go/qianfan/embdding.go index 1dee1f9d..4095801b 100644 --- a/go/qianfan/embdding.go +++ b/go/qianfan/embdding.go @@ -118,7 +118,7 @@ func (c *Embedding) do(ctx context.Context, request *EmbeddingRequest) (*Embeddi if err != nil { return nil, err } - req, err := newModelRequest("POST", url, request) + req, err := NewModelRequest("POST", url, request) if err != nil { return nil, err } diff --git a/go/qianfan/requestor.go b/go/qianfan/requestor.go index f07f50fe..da3eb6a7 100644 --- a/go/qianfan/requestor.go +++ b/go/qianfan/requestor.go @@ -97,7 +97,7 @@ type QfRequest struct { } // 创建一个用于模型类请求的 Request -func newModelRequest(method string, url string, body RequestBody) (*QfRequest, error) { +func NewModelRequest(method string, url string, body RequestBody) (*QfRequest, error) { return newRequest(modelRequest, method, url, body) } @@ -107,7 +107,7 @@ func newAuthRequest(method string, url string, body RequestBody) (*QfRequest, er } // 创建一个用于管控类请求的 Request -func newConsoleRequest(method string, url string, body RequestBody) (*QfRequest, error) { +func NewConsoleRequest(method string, url string, body RequestBody) (*QfRequest, error) { return newRequest(consoleRequest, method, url, body) } diff --git a/go/qianfan/service.go b/go/qianfan/service.go index 8d627bd8..30d77503 100644 --- a/go/qianfan/service.go +++ b/go/qianfan/service.go @@ -42,7 +42,7 @@ type ServiceListItemVersion struct { func (service *Service) List(ctx context.Context, request *ServiceListRequest) (*ServiceListResponse, error) { var s ServiceListResponse - req, err := newConsoleRequest("POST", serviceListURL, request) + req, err := NewConsoleRequest("POST", serviceListURL, request) if err != nil { return nil, err } diff --git a/go/qianfan/text2img.go b/go/qianfan/text2img.go index 41128477..4de85a35 100644 --- a/go/qianfan/text2img.go +++ b/go/qianfan/text2img.go @@ -121,7 +121,7 @@ func (c *Text2Image) do(ctx context.Context, request *Text2ImageRequest) (*Text2 if err != nil { return nil, err } - req, err := newModelRequest("POST", url, request) + req, err := NewModelRequest("POST", url, request) if err != nil { return nil, err } diff --git a/go/qianfan/tokenizer.go b/go/qianfan/tokenizer.go index 4d5fa9ac..1daccd00 100644 --- a/go/qianfan/tokenizer.go +++ b/go/qianfan/tokenizer.go @@ -87,7 +87,7 @@ func (t *Tokenizer) remoteCountTokensEB(text string, model string) (int, error) Model: model, } - req, err := newModelRequest("POST", modelAPIPrefix+"/tokenizer/erniebot", request) + req, err := NewModelRequest("POST", modelAPIPrefix+"/tokenizer/erniebot", request) if err != nil { return -1, err } diff --git a/go/qianfan/version.go b/go/qianfan/version.go index fd08a6b7..154c12df 100644 --- a/go/qianfan/version.go +++ b/go/qianfan/version.go @@ -26,5 +26,5 @@ package qianfan // SDK 版本 -const Version = "v0.0.11" +const Version = "v0.0.12" const versionIndicator = "qianfan_go_sdk_" + Version