提供统一 SDK 的接入形式(需要用 API key 进行鉴权,获取方式请参考 获取 API key),SDK 中可以通过设置环境变量ARK_API_KEY
或者Ark()
初始化时引入 API KEY。
现阶段 SDK V3 仅提供 Python 版本,其他语言将陆续发布,敬请期待。
注意
目前 SDK 只支持python版本3.7及以上。
''' Usage: pip install volcengine-python-sdk ''' from volcenginesdkarkruntime import Ark # gets API Key from environment variable ARK_API_KEY client = Ark() if __name__ == "__main__": # Non-streaming: print("----- standard request -----") completion = client.chat.completions.create( model="${YOUR_ENDPOINT_ID}", messages=[ { "role": "user", "content": "Say this is a test", }, ], extra_headers={"x-ark-beta-vision": "true"} ) print(completion.choices[0].message.content) # Streaming: print("----- streaming request -----") stream = client.chat.completions.create( model="${YOUR_ENDPOINT_ID}", messages=[ { "role": "user", "content": "How do I output all files in a directory using Python?", }, ], stream=True, extra_headers={"x-ark-beta-vision": "true"} ) for chunk in stream: if not chunk.choices: continue print(chunk.choices[0].delta.content, end="") print()
主要参考 OpenAI 和 HuggingFace ,Parameters 记录可选控制参数,具体哪些参数可用依赖模型服务。
字段 | 子字段 | 类型 | 必填 | 描述 | 默认值 |
---|---|---|---|---|---|
model | - | string | 是 | 以 endpoint_id 索引对应的模型接入点。 | - |
messages | - | list | 是 | 本次对话的消息列表,包含用户输入的最后一条消息。 | - |
role | string | 是 | 发出该消息的对话参与者的角色,可选 | - | |
content (role= | string/array | 是 | 消息的内容。多模态模型的 content 可以为 list,list 的元素可以为
【单轮多图】
| - | |
content (role= | string | 是 | 消息的内容。 | - | |
content (role= | string | 是 | 消息的内容。 | - | |
frequency_penalty | - | number | 否 | -2.0 到 2.0 之间的数字。如果为正,会根据新 token 在文本中的出现频率对其进行惩罚,从而降低模型重复相同内容的可能性。 | 1 |
logit_bias | - | map | 否 | 修改指定 token 在模型输出内容中出现的概率。 | null |
logprobs | - | boolean | 否 | 是否返回输出 tokens 的 logprobs。如果为 true,则返回 message (content) 中每个输出 token 的 logprobs。 | false |
top_logprobs | - | integer | 否 | 0 到 20 之间的整数,指定每个 token 位置最有可能返回的 token 数量,每个 token 都有关联的对数概率。 如果使用此参数,则 logprobs 必须设置为 true | null |
max_tokens | - | integer | 否 | 模型最大输出 token 数。 | null |
stop | - | string/array | 否 | 用于指定模型在生成响应时应停止的词语。当模型生成的响应中包含这些词汇时,生成过程将停止。 | null |
stream | - | boolean | 否 | 是否流式返回。如果为 true,则按 SSE 协议返回数据。 | false |
stream_options | - | object | 否 |
| null |
include_usage | bool | 否 | 如果设置,则在 data: [DONE]消息之前会返回一个额外的块。此块上的 usage 字段显示了整个请求的 token 用量,其 choices 字段是一个空数组。所有其他块也将包含 usage 字段,但值为 null。 | false | |
temperature | - | number | 否 | 采样温度在 0 到 2 之间。较高的值(如 0.8)将使输出更加随机,而较低的值(如 0.2)将使输出更加集中和确定。 | 1 |
top_p | - | number | 否 | temperature 抽样的另一种选择,称为核抽样,其中模型考虑具有 top_p 概率质量的 token。所以 0.1 意味着只考虑包含前 10% 概率质量的标记。 | 1 |
字段 | 子字段 | 类型 | 描述 |
---|---|---|---|
id | - | string | 一次 chat completion 接口调用的唯一标识。 |
choices | - | array | 本次 chat 结果列表。长度固定为 1。 |
index | integer | 该元素在 choices 列表的索引。 | |
message | object | 模型输出的消息内容,示例如下:
| |
finish_reason | string | 模型生成结束原因, | |
logprobs | object | 该输出结果的概率信息,其只有一个 content 字段,类型为 array,表示 message 列表中每个元素 content token 的概率信息,content 元素子字段说明如下:
| |
created | - | integer | 本次对话生成时间戳(秒)。 |
model | - | string | 实际使用的模型名称和版本。 |
object | - | string | 固定为 chat.completion。 |
usage | - | object | 本次请求的 tokens 用量。 |
prompt_tokens | integer | 本次请求中输入的 token 数量。 | |
completion_tokens | integer | 模型生成的 token 数量。 | |
total_tokens | integer | 总的 token 数量。 |
字段 | 子字段 | 类型 | 描述 |
---|---|---|---|
id | - | string | 一次 chat completion 接口调用的唯一标识,一次流式调用所有的 chunk 有相同的 id。 |
choices | - | array | 结果列表。长度固定为 1。如果设置了 |
index | integer | 该元素在 choices 列表的索引。 | |
delta | object | 由流式模型响应的模型输出增量,示例如下。
| |
finish_reason | string | 模型生成结束原因, | |
logprobs | object | 该输出结果的概率信息,其只有一个 content 字段,类型为 array,表示 message 列表中每个元素 content token 的概率信息,content 元素子字段说明如下:
| |
created | - | integer | 本次对话生成时间戳(秒)。 |
model | - | string | 实际使用的模型名称和版本。 |
object | - | string | 固定为 chat.completion.chunk。 |
usage | - | object | 本次请求的 tokens 用量。 |
prompt_tokens | integer | 本次请求中输入的 token 数量。 | |
completion_tokens | integer | 模型生成的 token 数量。 | |
total_tokens | integer | 总的 token 数量。 |
在 stream 模式下,基于 SSE (Server-Sent Events) 协议返回生成内容,每次返回结果为生成的部分内容片段:
下面代码实现了“图片压缩 > 上传 TO S> 调用VLM Chat ”的流程,供参考。
示例图片
Pillow volcengine-python-sdk[ark] tos
pip install -r requirements.txt
import os import tos from PIL import Image from tos import HttpMethodType from volcenginesdkarkruntime import Ark # 从环境变量获取 AK/SK/APIKEY信息 ak = os.getenv('VOLC_ACCESSKEY') sk = os.getenv('VOLC_SECRETKEY') api_key = os.getenv('ARK_API_KEY') # 压缩前图片 original_file = "original_image.jpeg" # 压缩后图片存放路径 compressed_file = "comressed_image.jpeg" # 压缩的目标图片大小,300KB target_size = 300 * 1024 # endpoint 和 region 填写Bucket 所在区域对应的Endpoint。 # 以华北2(北京)为例,region 填写 cn-beijing。 # 公网域名endpoint 填写 tos-cn-beijing.volces.com endpoint, region = "tos-cn-beijing.volces.com", "cn-beijing" # 对象桶名称 bucket_name = "demo-bucket-test" # 对象名称,例如 images 下的 compressed_image.jpeg 文件,则填写为 images/compressed_image.jpeg object_key = "images/compressed_image.jpeg" def compress_image(input_path, output_path): img = Image.open(input_path) current_size = os.path.getsize(input_path) # 粗略的估计压缩质量,也可以从常量开始,逐步减小压缩质量,直到文件大小小于目标大小 image_quality = int(float(target_size / current_size) * 100) img.save(output_path, optimize=True, quality=int(float(target_size / current_size) * 100)) # 如果压缩后文件大小仍然大于目标大小,则继续压缩 # 压缩质量递减,直到文件大小小于目标大小 while os.path.getsize(output_path) > target_size: img = Image.open(output_path) image_quality -= 10 if image_quality <= 0: break img.save(output_path, optimize=True, quality=image_quality) return image_quality def upload_tos(filename, tos_endpoint, tos_region, tos_bucket_name, tos_object_key): # 创建 TosClientV2 对象,对桶和对象的操作都通过 TosClientV2 实现 tos_client, inner_tos_client = tos.TosClientV2(ak, sk, tos_endpoint, tos_region), tos.TosClientV2(ak, sk, tos_endpoint, tos_region) try: # 将本地文件上传到目标桶中, filename为本地压缩后图片的完整路径 tos_client.put_object_from_file(tos_bucket_name, tos_object_key, filename) # 获取上传后预签名的 url return inner_tos_client.pre_signed_url(HttpMethodType.Http_Method_Get, tos_bucket_name, tos_object_key) except Exception as e: if isinstance(e, tos.exceptions.TosClientError): # 操作失败,捕获客户端异常,一般情况为非法请求参数或网络异常 print('fail with client error, message:{}, cause: {}'.format(e.message, e.cause)) elif isinstance(e, tos.exceptions.TosServerError): # 操作失败,捕获服务端异常,可从返回信息中获取详细错误信息 print('fail with server error, code: {}'.format(e.code)) # request id 可定位具体问题,强烈建议日志中保存 print('error with request id: {}'.format(e.request_id)) print('error with message: {}'.format(e.message)) print('error with http code: {}'.format(e.status_code)) else: print('fail with unknown error: {}'.format(e)) raise e if __name__ == "__main__": print("----- Compress Image -----") quality = compress_image(original_file, compressed_file) print("Compressed Image Quality: {}".format(quality)) print("----- Upload to Tos -----") pre_signed_url_output = upload_tos(compressed_file, endpoint, region, bucket_name, object_key) print("Pre-signed TOS URL: {}".format(pre_signed_url_output.signed_url)) print("----- Image Input Chat -----") client = Ark(api_key=api_key) # Image input: response = client.chat.completions.create( model="${YOUR_ENDPOINT_ID}", messages=[ { "role": "user", "content": [ {"type": "text", "text": "Which is the most secure payment app according to Americans?"}, { "type": "image_url", "image_url": { "url": pre_signed_url_output.signed_url } }, ], } ], extra_headers={"x-ark-beta-vision": "true"} ) print(response.choices[0])
package main import ( "context" "fmt" "image" "image/jpeg" "os" "github.com/volcengine/ve-tos-golang-sdk/v2/tos" "github.com/volcengine/ve-tos-golang-sdk/v2/tos/enum" "github.com/volcengine/volcengine-go-sdk/service/arkruntime" "github.com/volcengine/volcengine-go-sdk/service/arkruntime/model" ) const ( targetSize = int64(300 * 1024) // 300KB originalImageFile = "original_image.jpeg" // 压缩前图片路径 compressedImageFile = "compressed_image.jpeg" // 压缩后图片存放路径 // Bucket 对应的 Endpoint,以华北2(北京)为例 // 公网域名地址:https://tos-cn-beijing.volces.com endpoint, region = "https://tos-cn-beijing.volces.com", "cn-beijing" // 填写 对象存储BucketName bucketName = "*** Provide your bucket name ***" // 将文件上传到 images 目录下的 compressed_image.jpeg 文件 objectKey = "images/compressed_image.jpeg" ) var ( accessKey = os.Getenv("VOLC_ACCESSKEY") secretKey = os.Getenv("VOLC_SECRETKEY") apiKey = os.Getenv("ARK_API_KEY") ) func compressImage(inputPath, outputPath string, targetSize int64) (int, error) { file, err := os.Open(inputPath) if err != nil { return -1, err } defer file.Close() img, _, err := image.Decode(file) if err != nil { return -1, err } outputFile, err := os.Create(outputPath) if err != nil { return -1, err } defer outputFile.Close() originalImageInfo, err := file.Stat() if err != nil { return -1, err } quality := int(float64(targetSize) / float64(originalImageInfo.Size()) * 100) for { err = jpeg.Encode(outputFile, img, &jpeg.Options{Quality: quality}) if err != nil { return -1, err } info, err := outputFile.Stat() if err != nil { return -1, err } if info.Size() <= targetSize { break } quality -= 10 if quality <= 0 { return -1, fmt.Errorf("无法压缩到目标大小") } outputFile.Close() outputFile, err = os.Create(outputPath) if err != nil { return -1, err } } return quality, nil } func uploadTos(ctx context.Context, endpoint, region, bucketName, objectKey, filePath string) (*tos.PreSignedURLOutput, error) { // 初始化客户端 client, err := tos.NewClientV2(endpoint, tos.WithRegion(region), tos.WithCredentials(tos.NewStaticCredentials(accessKey, secretKey))) if err != nil { return nil, err } // 将压缩后的图片上传到tos output, err := client.PutObjectFromFile(ctx, &tos.PutObjectFromFileInput{ PutObjectBasicInput: tos.PutObjectBasicInput{ Bucket: bucketName, Key: objectKey, }, FilePath: filePath, }) if err != nil { return nil, err } fmt.Println("PutObjectV2 Request ID:", output.RequestID) // 获取预签名下载链接 innerClient, err := tos.NewClientV2(endpoint, tos.WithRegion(region), tos.WithCredentials(tos.NewStaticCredentials(accessKey, secretKey))) if err != nil { return nil, err } return innerClient.PreSignedURL(&tos.PreSignedURLInput{ HTTPMethod: enum.HttpMethodGet, Bucket: bucketName, Key: objectKey, }) } func main() { ctx := context.Background() fmt.Println("----- Compress Image -----") quality, err := compressImage(originalImageFile, compressedImageFile, targetSize) if err != nil { panic(err) } fmt.Println("Compressed Image Quality:", quality) fmt.Println("----- Upload Image To TOS -----") preSignedUrl, err := uploadTos(ctx, endpoint, region, bucketName, objectKey, compressedImageFile) if err != nil { return } fmt.Println("PreSignedUrl:", preSignedUrl.SignedUrl) fmt.Println("----- Image Input Chat -----") client := arkruntime.NewClientWithApiKey(apiKey) req := model.ChatCompletionRequest{ Model: "${YOUR_ENDPOINT_ID}", Messages: []*model.ChatCompletionMessage{ { Role: model.ChatMessageRoleUser, Content: &model.ChatCompletionMessageContent{ ListValue: []*model.ChatCompletionMessageContentPart{ { Type: model.ChatCompletionMessageContentPartTypeText, Text: "Which is the most secure payment app according to Americans?", }, { Type: model.ChatCompletionMessageContentPartTypeImageURL, ImageURL: &model.ChatMessageImageURL{ URL: preSignedUrl.SignedUrl, }, }, }, }, }, }, } resp, err := client.CreateChatCompletion(ctx, req, arkruntime.WithCustomHeaders(map[string]string{ "x-ark-beta-vision": "true", })) if err != nil { fmt.Printf("standard chat error: %v\n", err) return } fmt.Println(*resp.Choices[0].Message.Content.StringValue) }
package com.volcengine.ark.runtime; import com.volcengine.ark.runtime.model.completion.chat.ChatCompletionContentPart; import com.volcengine.ark.runtime.model.completion.chat.ChatMessage; import com.volcengine.ark.runtime.model.completion.chat.ChatMessageRole; import com.volcengine.ark.runtime.service.ArkService; import com.volcengine.tos.TOSV2; import com.volcengine.tos.TOSV2ClientBuilder; import com.volcengine.tos.TosClientException; import com.volcengine.tos.TosServerException; import com.volcengine.tos.comm.HttpMethod; import com.volcengine.tos.model.object.PreSignedURLInput; import com.volcengine.tos.model.object.PreSignedURLOutput; import com.volcengine.tos.model.object.PutObjectInput; import com.volcengine.tos.model.object.PutObjectOutput; import com.volcengine.ark.runtime.model.completion.chat.ChatCompletionRequest; import javax.imageio.ImageIO; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.imageio.stream.ImageOutputStream; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; public class VLMChatExample { private static final String TOS_ENDPOINT = "https://tos-cn-beijing.volces.com"; private static final String REGION = "cn-beijing"; private static final String ARK_API_KEY = System.getenv("ARK_API_KEY"); private static final String VOLC_ACCESSKEY = System.getenv("VOLC_ACCESSKEY"); private static final String VOLC_SECRETKEY = System.getenv("VOLC_SECRETKEY"); private static final long TOS_EXPIRE_TIME = 3600; public static void compressImage(String inputImagePath, String outputImagePath, long targetSizeInBytes) throws IOException { File inputFile = new File(inputImagePath); BufferedImage img = ImageIO.read(inputFile); float quality = targetSizeInBytes * 1.0f / inputFile.length(); try (ImageOutputStream ios = ImageIO.createImageOutputStream(new File(outputImagePath))) { ImageWriter writer = ImageIO.getImageWritersByFormatName("jpeg").next(); ImageWriteParam param = writer.getDefaultWriteParam(); param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); param.setCompressionQuality(quality); writer.setOutput(ios); writer.write(null, new javax.imageio.IIOImage(img, null, null), param); writer.dispose(); } } public static void uploadImageToTOS(String filePath, String bucketName, String objectKey) throws Throwable { TOSV2 tos = new TOSV2ClientBuilder().build(REGION, TOS_ENDPOINT, VOLC_ACCESSKEY, VOLC_SECRETKEY); // step 1. 上传本地图片到tos File file = new File(filePath); try (FileInputStream inputStream = new FileInputStream(file)) { PutObjectInput putObjectInput = new PutObjectInput().setBucket(bucketName) .setKey(objectKey).setContent(inputStream).setContentLength(file.length()); PutObjectOutput output = tos.putObject(putObjectInput); System.out.println("putObject succeed, object's etag is " + output.getEtag()); System.out.println("putObject succeed, object's crc64 is " + output.getHashCrc64ecma()); } catch (IOException e) { System.out.println("putObject read file failed"); e.printStackTrace(); throw e; } catch (TosClientException e) { // 操作失败,捕获客户端异常,一般情况是请求参数错误,此时请求并未发送 System.out.println("putObject failed"); System.out.println("Message: " + e.getMessage()); if (e.getCause() != null) { e.getCause().printStackTrace(); } throw e; } catch (TosServerException e) { // 操作失败,捕获服务端异常,可以获取到从服务端返回的详细错误信息 System.out.println("putObject failed"); System.out.println("StatusCode: " + e.getStatusCode()); System.out.println("Code: " + e.getCode()); System.out.println("Message: " + e.getMessage()); System.out.println("RequestID: " + e.getRequestID()); throw e; } catch (Throwable t) { // 作为兜底捕获其他异常,一般不会执行到这里 System.out.println("putObject failed"); System.out.println("unexpected exception, message: " + t.getMessage()); throw t; } } public static String getPreSignedURL(String bucketName, String objectKey) throws Throwable { TOSV2 tos = new TOSV2ClientBuilder().build(REGION, TOS_ENDPOINT, VOLC_ACCESSKEY, VOLC_SECRETKEY); // 生成预签名链接 try { PreSignedURLInput input = new PreSignedURLInput().setBucket(bucketName).setKey(objectKey) .setHttpMethod(HttpMethod.GET).setExpires(TOS_EXPIRE_TIME); PreSignedURLOutput output = tos.preSignedURL(input); System.out.println("preSignedURL succeed, the signed url is " + output.getSignedUrl()); System.out.println("preSignedURL succeed, the signed header is " + output.getSignedHeader()); return output.getSignedUrl(); } catch (TosClientException e) { // 操作失败,捕获客户端异常,一般情况是请求参数错误,此时请求并未发送 System.out.println("preSignedURL failed"); System.out.println("Message: " + e.getMessage()); if (e.getCause() != null) { e.getCause().printStackTrace(); } throw e; } catch (Throwable t) { // 作为兜底捕获其他异常,一般不会执行到这里 System.out.println("preSignedURL failed"); System.out.println("unexpected exception, message: " + t.getMessage()); throw t; } } public static void main(String[] args) throws Throwable { String filePath = "/your/path/to/your/image.jpeg"; String compressedPath = "/your/path/to/compress/image.jpeg"; String tosBucket = "{your bucket name}"; String objectKey = "{your object key}"; // 1. 压缩图片 try { compressImage(filePath, compressedPath, 300 * 1024); } catch (IOException e) { System.out.println("compressImage failed"); e.printStackTrace(); throw e; } // 2. 上传TOS try { uploadImageToTOS(compressedPath, tosBucket, objectKey); } catch (Throwable t) { System.out.println("uploadImageToTOS failed"); t.printStackTrace(); throw t; } // 3. 生成预签名链接 String preSignedURL = ""; try { preSignedURL = getPreSignedURL(tosBucket, objectKey); } catch (Throwable t) { System.out.println("getPreSignedURL failed"); t.printStackTrace(); throw t; } // 4. 调用大模型Chat ArkService service = new ArkService(ARK_API_KEY); System.out.println("----- image input -----"); final List<ChatMessage> messages = new ArrayList<>(); final List<ChatCompletionContentPart> multiParts = new ArrayList<>(); multiParts.add(ChatCompletionContentPart.builder().type("text").text( "Which is the most secure payment app according to Americans?" ).build()); multiParts.add(ChatCompletionContentPart.builder().type("image_url").imageUrl( new ChatCompletionContentPart.ChatCompletionContentPartImageURL(preSignedURL) ).build()); final ChatMessage userMessage = ChatMessage.builder().role(ChatMessageRole.USER) .multiContent(multiParts).build(); messages.add(userMessage); ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder() .model("{your ark model endpoint id}") .messages(messages) .build(); service.createChatCompletion(chatCompletionRequest, new HashMap<String, String>() {{ put("x-ark-beta-vision", "true"); }}).getChoices().forEach(choice -> System.out.println(choice.getMessage().getContent())); // shutdown service service.shutdownExecutor(); } }