mirror of
https://github.com/hanzoai/dashscope-go-sdk.git
synced 2026-09-30 21:39:25 +00:00
382 lines
8.0 KiB
Go
382 lines
8.0 KiB
Go
package dashscopego
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
|
|
httpclient "github.com/hanzoai/dashscope-go-sdk/httpclient"
|
|
qwen "github.com/hanzoai/dashscope-go-sdk/qwen"
|
|
wanx "github.com/hanzoai/dashscope-go-sdk/wanx"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"go.uber.org/mock/gomock"
|
|
)
|
|
|
|
func newTongyiClient(t *testing.T, model string) *TongyiClient {
|
|
t.Helper()
|
|
token := os.Getenv("DASHSCOPE_API_KEY")
|
|
|
|
cli := NewTongyiClient(model, token)
|
|
if cli.token == "" {
|
|
t.Skip("token is empty")
|
|
}
|
|
return cli
|
|
}
|
|
|
|
func newMockClient(t *testing.T, model string, ctrl *gomock.Controller, f mockFn) *TongyiClient {
|
|
t.Helper()
|
|
|
|
mockHTTPCli := httpclient.NewMockIHttpClient(ctrl)
|
|
fackToken := ""
|
|
|
|
f(mockHTTPCli)
|
|
|
|
qwenCli := newTongyiCLientWithHTTPCli(model, fackToken, mockHTTPCli)
|
|
return qwenCli
|
|
}
|
|
|
|
type mockFn func(mockHTTPCli *httpclient.MockIHttpClient)
|
|
|
|
func TestBasic(t *testing.T) {
|
|
t.Parallel()
|
|
ctx := context.TODO()
|
|
|
|
cli := newTongyiClient(t, "")
|
|
|
|
text := qwen.TextContent{Text: "Hello"}
|
|
input := TextInput{
|
|
Messages: []TextMessage{
|
|
{Role: "user", Content: &text},
|
|
},
|
|
}
|
|
|
|
req := &TextRequest{
|
|
Model: "qwen-turbo",
|
|
Input: input,
|
|
}
|
|
|
|
resp, err := cli.CreateCompletion(ctx, req)
|
|
|
|
require.NoError(t, err)
|
|
assert.Regexp(t, "hello|hi|how|assist", resp.Output.Choices[0].Message.Content.ToString())
|
|
}
|
|
|
|
func TestStreamingChunk(t *testing.T) {
|
|
t.Parallel()
|
|
ctx := context.TODO()
|
|
|
|
cli := newTongyiClient(t, "qwen-turbo")
|
|
|
|
content := qwen.TextContent{Text: "Hello"}
|
|
|
|
input := TextInput{
|
|
Messages: []TextMessage{
|
|
{Role: "user", Content: &content},
|
|
},
|
|
}
|
|
|
|
output := ""
|
|
streamCallbackFn := func(ctx context.Context, chunk []byte) error {
|
|
output += string(chunk)
|
|
return nil
|
|
}
|
|
|
|
req := &TextRequest{
|
|
// Model: "qwen-turbo",
|
|
Input: input,
|
|
StreamingFn: streamCallbackFn,
|
|
}
|
|
resp, err := cli.CreateCompletion(ctx, req)
|
|
|
|
require.NoError(t, err)
|
|
assert.Regexp(t, "hello|hi|how|assist", resp.Output.Choices[0].Message.Content.ToString())
|
|
assert.Regexp(t, "hello|hi|how|assist", output)
|
|
}
|
|
|
|
func TestVLBasic(t *testing.T) {
|
|
t.Parallel()
|
|
ctx := context.TODO()
|
|
|
|
cli := newTongyiClient(t, "")
|
|
|
|
sysContent := qwen.VLContentList{
|
|
{
|
|
Text: "You are a helpful assistant.",
|
|
},
|
|
}
|
|
userContent := qwen.VLContentList{
|
|
{
|
|
Text: "describe the image",
|
|
},
|
|
{
|
|
Image: "https://dashscope.oss-cn-beijing.aliyuncs.com/images/dog_and_girl.jpeg",
|
|
},
|
|
}
|
|
|
|
input := VLInput{
|
|
Messages: []VLMessage{
|
|
{Role: "system", Content: &sysContent},
|
|
{Role: "user", Content: &userContent},
|
|
},
|
|
}
|
|
|
|
req := &VLRequest{
|
|
Model: "qwen-vl-plus",
|
|
Input: input,
|
|
}
|
|
|
|
req.Parameters = qwen.DefaultParameters()
|
|
|
|
resp, err := cli.CreateVLCompletion(ctx, req)
|
|
|
|
require.NoError(t, err)
|
|
assert.Regexp(t, "dog|person|individual|woman|girl", resp.Output.Choices[0].Message.Content.ToString())
|
|
}
|
|
|
|
func TestVLStreamChund(t *testing.T) {
|
|
t.Parallel()
|
|
ctx := context.TODO()
|
|
|
|
cli := newTongyiClient(t, "")
|
|
|
|
sysContent := qwen.VLContentList{
|
|
{
|
|
Text: "You are a helpful assistant.",
|
|
},
|
|
}
|
|
userContent := qwen.VLContentList{
|
|
{
|
|
Text: "describe the image",
|
|
},
|
|
{
|
|
Image: "https://dashscope.oss-cn-beijing.aliyuncs.com/images/dog_and_girl.jpeg",
|
|
// Image: "https://pic.ntimg.cn/20140113/8800276_184351657000_2.jpg",
|
|
},
|
|
}
|
|
|
|
input := VLInput{
|
|
Messages: []VLMessage{
|
|
{Role: "system", Content: &sysContent},
|
|
{Role: "user", Content: &userContent},
|
|
},
|
|
}
|
|
|
|
output := ""
|
|
streamCallbackFn := func(ctx context.Context, chunk []byte) error {
|
|
output += string(chunk)
|
|
return nil
|
|
}
|
|
|
|
req := &VLRequest{
|
|
Model: "qwen-vl-plus",
|
|
Input: input,
|
|
StreamingFn: streamCallbackFn,
|
|
}
|
|
|
|
resp, err := cli.CreateVLCompletion(ctx, req)
|
|
|
|
require.NoError(t, err)
|
|
assert.Equal(t, output, resp.Output.Choices[0].Message.Content.ToString())
|
|
assert.Regexp(t, "dog|person|individual|woman|girl", strings.ToLower(output))
|
|
}
|
|
|
|
func TestImageGeneration(t *testing.T) {
|
|
t.Parallel()
|
|
ctx := context.TODO()
|
|
|
|
cli := newTongyiClient(t, "wanx-v1")
|
|
|
|
req := &wanx.ImageSynthesisRequest{
|
|
Model: "wanx-v1",
|
|
Input: wanx.ImageSynthesisInput{
|
|
Prompt: "A beautiful sunset",
|
|
},
|
|
Download: true,
|
|
}
|
|
|
|
imgBlobs, err := cli.CreateImageGeneration(ctx, req)
|
|
require.NoError(t, err)
|
|
require.NotEmpty(t, imgBlobs)
|
|
|
|
for _, blob := range imgBlobs {
|
|
assert.NotEmpty(t, blob.Data)
|
|
assert.NotEmpty(t, blob.ImgURL)
|
|
assert.Equal(t, "image/png", blob.ImgType)
|
|
}
|
|
}
|
|
|
|
func TestMockStreamingChunk(t *testing.T) {
|
|
t.Parallel()
|
|
ctx := context.TODO()
|
|
|
|
ctrl := gomock.NewController(t)
|
|
defer ctrl.Finish()
|
|
cli := newMockClient(t, "qwen-turbo", ctrl, _mockAsyncFunc)
|
|
|
|
output := ""
|
|
text := qwen.TextContent{Text: "Hello"}
|
|
input := TextInput{
|
|
Messages: []TextMessage{
|
|
{Role: "user", Content: &text},
|
|
},
|
|
}
|
|
|
|
req := &TextRequest{
|
|
Input: input,
|
|
StreamingFn: func(ctx context.Context, chunk []byte) error {
|
|
output += string(chunk)
|
|
return nil
|
|
},
|
|
}
|
|
|
|
// mockURL := ""
|
|
resp, err := cli.CreateCompletion(ctx, req)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, "Hello! How can I assist you today?", resp.Output.Choices[0].Message.Content.ToString())
|
|
assert.Equal(t, "Hello! How can I assist you today?", output)
|
|
}
|
|
|
|
func TestMockBasic(t *testing.T) {
|
|
t.Parallel()
|
|
ctx := context.TODO()
|
|
ctrl := gomock.NewController(t)
|
|
defer ctrl.Finish()
|
|
cli := newMockClient(t, "qwen-turbo", ctrl, _mockSyncFunc)
|
|
text := qwen.TextContent{Text: "Hello"}
|
|
input := TextInput{
|
|
Messages: []TextMessage{
|
|
{Role: "user", Content: &text},
|
|
},
|
|
}
|
|
|
|
req := &TextRequest{
|
|
Input: input,
|
|
}
|
|
|
|
resp, err := cli.CreateCompletion(ctx, req)
|
|
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, "Hello! This is a mock message.", resp.Output.Choices[0].Message.Content.ToString())
|
|
assert.Equal(t, "mock-ac55-9fd3-8326-8415cbdf5683", resp.RequestID)
|
|
assert.Equal(t, 15, resp.Usage.TotalTokens)
|
|
}
|
|
|
|
func _mockAsyncFunc(mockHTTPCli *httpclient.MockIHttpClient) {
|
|
MockStreamData := []string{
|
|
`id:1`,
|
|
`event:result`,
|
|
`:HTTP_STATUS/200`,
|
|
`data:{
|
|
"output": {
|
|
"choices": [{
|
|
"message": {
|
|
"content": "Hello! How",
|
|
"role": "assistant"
|
|
},
|
|
"finish_reason": "null"
|
|
}]
|
|
},
|
|
"usage": {
|
|
"total_tokens": 9,
|
|
"input_tokens": 6,
|
|
"output_tokens": 3
|
|
},
|
|
"request_id": "95bea986-ac55-9fd3-8326-8415cbdf5683"
|
|
}`,
|
|
` `,
|
|
`id:2`,
|
|
`event:result`,
|
|
`:HTTP_STATUS/200`,
|
|
`data:{
|
|
"output": {
|
|
"choices": [{
|
|
"message": {
|
|
"content": " can I assist you today?",
|
|
"role": "assistant"
|
|
},
|
|
"finish_reason": "null"
|
|
}]
|
|
},
|
|
"usage": {
|
|
"total_tokens": 15,
|
|
"input_tokens": 6,
|
|
"output_tokens": 9
|
|
},
|
|
"request_id": "95bea986-ac55-9fd3-8326-8415cbdf5683"
|
|
}`,
|
|
` `,
|
|
`id:3`,
|
|
`event:result`,
|
|
`:HTTP_STATUS/200`,
|
|
`data:{
|
|
"output": {
|
|
"choices": [{
|
|
"message": {
|
|
"content": "",
|
|
"role": "assistant"
|
|
},
|
|
"finish_reason": "stop"
|
|
}]
|
|
},
|
|
"usage": {
|
|
"total_tokens": 15,
|
|
"input_tokens": 6,
|
|
"output_tokens": 9
|
|
},
|
|
"request_id": "95bea986-ac55-9fd3-8326-8415cbdf5683"
|
|
}`,
|
|
}
|
|
|
|
ctx := context.TODO()
|
|
|
|
_rawStreamOutChannel := make(chan string, 500)
|
|
|
|
mockHTTPCli.EXPECT().
|
|
PostSSE(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(_rawStreamOutChannel, nil)
|
|
go func() {
|
|
for _, line := range MockStreamData {
|
|
_rawStreamOutChannel <- line
|
|
}
|
|
close(_rawStreamOutChannel)
|
|
}()
|
|
}
|
|
|
|
func _mockSyncFunc(mockHTTPCli *httpclient.MockIHttpClient) {
|
|
ctx := context.TODO()
|
|
|
|
text := qwen.TextContent{Text: "Hello! This is a mock message."}
|
|
|
|
mockResp := TextQwenResponse{
|
|
Output: qwen.Output[*qwen.TextContent]{
|
|
Choices: []qwen.Choice[*qwen.TextContent]{
|
|
{
|
|
Message: TextMessage{
|
|
Content: &text,
|
|
Role: "assistant",
|
|
},
|
|
FinishReason: "stop",
|
|
},
|
|
},
|
|
},
|
|
Usage: struct {
|
|
TotalTokens int `json:"total_tokens"`
|
|
InputTokens int `json:"input_tokens"`
|
|
OutputTokens int `json:"output_tokens"`
|
|
}{
|
|
TotalTokens: 15,
|
|
InputTokens: 6,
|
|
OutputTokens: 9,
|
|
},
|
|
RequestID: "mock-ac55-9fd3-8326-8415cbdf5683",
|
|
}
|
|
mockHTTPCli.EXPECT().
|
|
Post(ctx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
|
|
SetArg(3, mockResp).
|
|
Return(nil)
|
|
}
|